1 // Copyright 2016 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/libsampler/sampler.h" 6 7 #if V8_OS_POSIX && !V8_OS_CYGWIN && !V8_OS_FUCHSIA 8 9 #define USE_SIGNALS 10 11 #include <errno.h> 12 #include <pthread.h> 13 #include <signal.h> 14 #include <sys/time.h> 15 16 #if !V8_OS_QNX && !V8_OS_AIX 17 #include <sys/syscall.h> // NOLINT 18 #endif 19 20 #if V8_OS_MACOSX 21 #include <mach/mach.h> 22 // OpenBSD doesn't have <ucontext.h>. ucontext_t lives in <signal.h> 23 // and is a typedef for struct sigcontext. There is no uc_mcontext. 24 #elif(!V8_OS_ANDROID || defined(__BIONIC_HAVE_UCONTEXT_T)) && !V8_OS_OPENBSD 25 #include <ucontext.h> 26 #endif 27 28 #include <unistd.h> 29 30 // GLibc on ARM defines mcontext_t has a typedef for 'struct sigcontext'. 31 // Old versions of the C library <signal.h> didn't define the type. 32 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) && \ 33 (defined(__arm__) || defined(__aarch64__)) && \ 34 !defined(__BIONIC_HAVE_STRUCT_SIGCONTEXT) 35 #include <asm/sigcontext.h> // NOLINT 36 #endif 37 38 #elif V8_OS_WIN || V8_OS_CYGWIN 39 40 #include "src/base/win32-headers.h" 41 42 #elif V8_OS_FUCHSIA 43 44 #include <zircon/process.h> 45 #include <zircon/syscalls.h> 46 #include <zircon/syscalls/debug.h> 47 #include <zircon/types.h> 48 49 // TODO(wez): Remove this once the Fuchsia SDK has rolled. 50 #if defined(ZX_THREAD_STATE_REGSET0) 51 #define ZX_THREAD_STATE_GENERAL_REGS ZX_THREAD_STATE_REGSET0 52 zx_status_t zx_thread_read_state(zx_handle_t h, uint32_t k, void* b, size_t l) { 53 uint32_t dummy_out_len = 0; 54 return zx_thread_read_state(h, k, b, static_cast<uint32_t>(l), 55 &dummy_out_len); 56 } 57 #if defined(__x86_64__) 58 typedef zx_x86_64_general_regs_t zx_thread_state_general_regs_t; 59 #else 60 typedef zx_arm64_general_regs_t zx_thread_state_general_regs_t; 61 #endif 62 #endif // !defined(ZX_THREAD_STATE_GENERAL_REGS) 63 64 #endif 65 66 #include <algorithm> 67 #include <vector> 68 #include <map> 69 70 #include "src/base/atomic-utils.h" 71 #include "src/base/hashmap.h" 72 #include "src/base/platform/platform.h" 73 74 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) 75 76 // Not all versions of Android's C library provide ucontext_t. 77 // Detect this and provide custom but compatible definitions. Note that these 78 // follow the GLibc naming convention to access register values from 79 // mcontext_t. 80 // 81 // See http://code.google.com/p/android/issues/detail?id=34784 82 83 #if defined(__arm__) 84 85 typedef struct sigcontext mcontext_t; 86 87 typedef struct ucontext { 88 uint32_t uc_flags; 89 struct ucontext* uc_link; 90 stack_t uc_stack; 91 mcontext_t uc_mcontext; 92 // Other fields are not used by V8, don't define them here. 93 } ucontext_t; 94 95 #elif defined(__aarch64__) 96 97 typedef struct sigcontext mcontext_t; 98 99 typedef struct ucontext { 100 uint64_t uc_flags; 101 struct ucontext *uc_link; 102 stack_t uc_stack; 103 mcontext_t uc_mcontext; 104 // Other fields are not used by V8, don't define them here. 105 } ucontext_t; 106 107 #elif defined(__mips__) 108 // MIPS version of sigcontext, for Android bionic. 109 typedef struct { 110 uint32_t regmask; 111 uint32_t status; 112 uint64_t pc; 113 uint64_t gregs[32]; 114 uint64_t fpregs[32]; 115 uint32_t acx; 116 uint32_t fpc_csr; 117 uint32_t fpc_eir; 118 uint32_t used_math; 119 uint32_t dsp; 120 uint64_t mdhi; 121 uint64_t mdlo; 122 uint32_t hi1; 123 uint32_t lo1; 124 uint32_t hi2; 125 uint32_t lo2; 126 uint32_t hi3; 127 uint32_t lo3; 128 } mcontext_t; 129 130 typedef struct ucontext { 131 uint32_t uc_flags; 132 struct ucontext* uc_link; 133 stack_t uc_stack; 134 mcontext_t uc_mcontext; 135 // Other fields are not used by V8, don't define them here. 136 } ucontext_t; 137 138 #elif defined(__i386__) 139 // x86 version for Android. 140 typedef struct { 141 uint32_t gregs[19]; 142 void* fpregs; 143 uint32_t oldmask; 144 uint32_t cr2; 145 } mcontext_t; 146 147 typedef uint32_t kernel_sigset_t[2]; // x86 kernel uses 64-bit signal masks 148 typedef struct ucontext { 149 uint32_t uc_flags; 150 struct ucontext* uc_link; 151 stack_t uc_stack; 152 mcontext_t uc_mcontext; 153 // Other fields are not used by V8, don't define them here. 154 } ucontext_t; 155 enum { REG_EBP = 6, REG_ESP = 7, REG_EIP = 14 }; 156 157 #elif defined(__x86_64__) 158 // x64 version for Android. 159 typedef struct { 160 uint64_t gregs[23]; 161 void* fpregs; 162 uint64_t __reserved1[8]; 163 } mcontext_t; 164 165 typedef struct ucontext { 166 uint64_t uc_flags; 167 struct ucontext *uc_link; 168 stack_t uc_stack; 169 mcontext_t uc_mcontext; 170 // Other fields are not used by V8, don't define them here. 171 } ucontext_t; 172 enum { REG_RBP = 10, REG_RSP = 15, REG_RIP = 16 }; 173 #endif 174 175 #endif // V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) 176 177 178 namespace v8 { 179 namespace sampler { 180 181 namespace { 182 183 #if defined(USE_SIGNALS) 184 typedef std::vector<Sampler*> SamplerList; 185 typedef SamplerList::iterator SamplerListIterator; 186 typedef base::AtomicValue<bool> AtomicMutex; 187 188 class AtomicGuard { 189 public: 190 explicit AtomicGuard(AtomicMutex* atomic, bool is_blocking = true) 191 : atomic_(atomic), is_success_(false) { 192 do { 193 // Use Acquire_Load to gain mutual exclusion. 194 USE(atomic_->Value()); 195 is_success_ = atomic_->TrySetValue(false, true); 196 } while (is_blocking && !is_success_); 197 } 198 199 bool is_success() const { return is_success_; } 200 201 ~AtomicGuard() { 202 if (!is_success_) return; 203 atomic_->SetValue(false); 204 } 205 206 private: 207 AtomicMutex* const atomic_; 208 bool is_success_; 209 }; 210 211 // Returns key for hash map. 212 void* ThreadKey(pthread_t thread_id) { 213 return reinterpret_cast<void*>(thread_id); 214 } 215 216 // Returns hash value for hash map. 217 uint32_t ThreadHash(pthread_t thread_id) { 218 #if V8_OS_BSD 219 return static_cast<uint32_t>(reinterpret_cast<intptr_t>(thread_id)); 220 #else 221 return static_cast<uint32_t>(thread_id); 222 #endif 223 } 224 225 #endif // USE_SIGNALS 226 227 } // namespace 228 229 #if defined(USE_SIGNALS) 230 231 class Sampler::PlatformData { 232 public: 233 PlatformData() : vm_tid_(pthread_self()) {} 234 pthread_t vm_tid() const { return vm_tid_; } 235 236 private: 237 pthread_t vm_tid_; 238 }; 239 240 class SamplerManager { 241 public: 242 SamplerManager() : sampler_map_() {} 243 244 void AddSampler(Sampler* sampler) { 245 AtomicGuard atomic_guard(&samplers_access_counter_); 246 DCHECK(sampler->IsActive() || !sampler->IsRegistered()); 247 // Add sampler into map if needed. 248 pthread_t thread_id = sampler->platform_data()->vm_tid(); 249 base::HashMap::Entry* entry = 250 sampler_map_.LookupOrInsert(ThreadKey(thread_id), 251 ThreadHash(thread_id)); 252 DCHECK_NOT_NULL(entry); 253 if (entry->value == nullptr) { 254 SamplerList* samplers = new SamplerList(); 255 samplers->push_back(sampler); 256 entry->value = samplers; 257 } else { 258 SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); 259 bool exists = false; 260 for (SamplerListIterator iter = samplers->begin(); 261 iter != samplers->end(); ++iter) { 262 if (*iter == sampler) { 263 exists = true; 264 break; 265 } 266 } 267 if (!exists) { 268 samplers->push_back(sampler); 269 } 270 } 271 } 272 273 void RemoveSampler(Sampler* sampler) { 274 AtomicGuard atomic_guard(&samplers_access_counter_); 275 DCHECK(sampler->IsActive() || sampler->IsRegistered()); 276 // Remove sampler from map. 277 pthread_t thread_id = sampler->platform_data()->vm_tid(); 278 void* thread_key = ThreadKey(thread_id); 279 uint32_t thread_hash = ThreadHash(thread_id); 280 base::HashMap::Entry* entry = sampler_map_.Lookup(thread_key, thread_hash); 281 DCHECK_NOT_NULL(entry); 282 SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); 283 for (SamplerListIterator iter = samplers->begin(); iter != samplers->end(); 284 ++iter) { 285 if (*iter == sampler) { 286 samplers->erase(iter); 287 break; 288 } 289 } 290 if (samplers->empty()) { 291 sampler_map_.Remove(thread_key, thread_hash); 292 delete samplers; 293 } 294 } 295 296 #if defined(USE_SIGNALS) 297 void DoSample(const v8::RegisterState& state) { 298 AtomicGuard atomic_guard(&SamplerManager::samplers_access_counter_, false); 299 if (!atomic_guard.is_success()) return; 300 pthread_t thread_id = pthread_self(); 301 base::HashMap::Entry* entry = 302 sampler_map_.Lookup(ThreadKey(thread_id), ThreadHash(thread_id)); 303 if (!entry) return; 304 SamplerList& samplers = *static_cast<SamplerList*>(entry->value); 305 306 for (size_t i = 0; i < samplers.size(); ++i) { 307 Sampler* sampler = samplers[i]; 308 Isolate* isolate = sampler->isolate(); 309 // We require a fully initialized and entered isolate. 310 if (isolate == nullptr || !isolate->IsInUse()) continue; 311 if (v8::Locker::IsActive() && !Locker::IsLocked(isolate)) continue; 312 sampler->SampleStack(state); 313 } 314 } 315 #endif 316 317 static SamplerManager* instance() { return instance_.Pointer(); } 318 319 private: 320 base::HashMap sampler_map_; 321 static AtomicMutex samplers_access_counter_; 322 static base::LazyInstance<SamplerManager>::type instance_; 323 }; 324 325 AtomicMutex SamplerManager::samplers_access_counter_; 326 base::LazyInstance<SamplerManager>::type SamplerManager::instance_ = 327 LAZY_INSTANCE_INITIALIZER; 328 329 #elif V8_OS_WIN || V8_OS_CYGWIN 330 331 // ---------------------------------------------------------------------------- 332 // Win32 profiler support. On Cygwin we use the same sampler implementation as 333 // on Win32. 334 335 class Sampler::PlatformData { 336 public: 337 // Get a handle to the calling thread. This is the thread that we are 338 // going to profile. We need to make a copy of the handle because we are 339 // going to use it in the sampler thread. Using GetThreadHandle() will 340 // not work in this case. We're using OpenThread because DuplicateHandle 341 // for some reason doesn't work in Chrome's sandbox. 342 PlatformData() 343 : profiled_thread_(OpenThread(THREAD_GET_CONTEXT | 344 THREAD_SUSPEND_RESUME | 345 THREAD_QUERY_INFORMATION, 346 false, 347 GetCurrentThreadId())) {} 348 349 ~PlatformData() { 350 if (profiled_thread_ != nullptr) { 351 CloseHandle(profiled_thread_); 352 profiled_thread_ = nullptr; 353 } 354 } 355 356 HANDLE profiled_thread() { return profiled_thread_; } 357 358 private: 359 HANDLE profiled_thread_; 360 }; 361 362 #elif V8_OS_FUCHSIA 363 364 class Sampler::PlatformData { 365 public: 366 PlatformData() { 367 zx_handle_duplicate(zx_thread_self(), ZX_RIGHT_SAME_RIGHTS, 368 &profiled_thread_); 369 } 370 ~PlatformData() { 371 if (profiled_thread_ != ZX_HANDLE_INVALID) { 372 zx_handle_close(profiled_thread_); 373 profiled_thread_ = ZX_HANDLE_INVALID; 374 } 375 } 376 377 zx_handle_t profiled_thread() { return profiled_thread_; } 378 379 private: 380 zx_handle_t profiled_thread_ = ZX_HANDLE_INVALID; 381 }; 382 383 #endif // USE_SIGNALS 384 385 386 #if defined(USE_SIGNALS) 387 class SignalHandler { 388 public: 389 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } 390 static void TearDown() { 391 delete mutex_; 392 mutex_ = nullptr; 393 } 394 395 static void IncreaseSamplerCount() { 396 base::LockGuard<base::Mutex> lock_guard(mutex_); 397 if (++client_count_ == 1) Install(); 398 } 399 400 static void DecreaseSamplerCount() { 401 base::LockGuard<base::Mutex> lock_guard(mutex_); 402 if (--client_count_ == 0) Restore(); 403 } 404 405 static bool Installed() { 406 base::LockGuard<base::Mutex> lock_guard(mutex_); 407 return signal_handler_installed_; 408 } 409 410 private: 411 static void Install() { 412 struct sigaction sa; 413 sa.sa_sigaction = &HandleProfilerSignal; 414 sigemptyset(&sa.sa_mask); 415 #if V8_OS_QNX 416 sa.sa_flags = SA_SIGINFO; 417 #else 418 sa.sa_flags = SA_RESTART | SA_SIGINFO; 419 #endif 420 signal_handler_installed_ = 421 (sigaction(SIGPROF, &sa, &old_signal_handler_) == 0); 422 } 423 424 static void Restore() { 425 if (signal_handler_installed_) { 426 sigaction(SIGPROF, &old_signal_handler_, 0); 427 signal_handler_installed_ = false; 428 } 429 } 430 431 static void FillRegisterState(void* context, RegisterState* regs); 432 static void HandleProfilerSignal(int signal, siginfo_t* info, void* context); 433 434 // Protects the process wide state below. 435 static base::Mutex* mutex_; 436 static int client_count_; 437 static bool signal_handler_installed_; 438 static struct sigaction old_signal_handler_; 439 }; 440 441 base::Mutex* SignalHandler::mutex_ = nullptr; 442 int SignalHandler::client_count_ = 0; 443 struct sigaction SignalHandler::old_signal_handler_; 444 bool SignalHandler::signal_handler_installed_ = false; 445 446 447 void SignalHandler::HandleProfilerSignal(int signal, siginfo_t* info, 448 void* context) { 449 USE(info); 450 if (signal != SIGPROF) return; 451 v8::RegisterState state; 452 FillRegisterState(context, &state); 453 SamplerManager::instance()->DoSample(state); 454 } 455 456 void SignalHandler::FillRegisterState(void* context, RegisterState* state) { 457 // Extracting the sample from the context is extremely machine dependent. 458 ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context); 459 #if !(V8_OS_OPENBSD || (V8_OS_LINUX && (V8_HOST_ARCH_PPC || V8_HOST_ARCH_S390))) 460 mcontext_t& mcontext = ucontext->uc_mcontext; 461 #endif 462 #if V8_OS_LINUX 463 #if V8_HOST_ARCH_IA32 464 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_EIP]); 465 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_ESP]); 466 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_EBP]); 467 #elif V8_HOST_ARCH_X64 468 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]); 469 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_RSP]); 470 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_RBP]); 471 #elif V8_HOST_ARCH_ARM 472 #if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) 473 // Old GLibc ARM versions used a gregs[] array to access the register 474 // values from mcontext_t. 475 state->pc = reinterpret_cast<void*>(mcontext.gregs[R15]); 476 state->sp = reinterpret_cast<void*>(mcontext.gregs[R13]); 477 state->fp = reinterpret_cast<void*>(mcontext.gregs[R11]); 478 #else 479 state->pc = reinterpret_cast<void*>(mcontext.arm_pc); 480 state->sp = reinterpret_cast<void*>(mcontext.arm_sp); 481 state->fp = reinterpret_cast<void*>(mcontext.arm_fp); 482 #endif // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4) 483 #elif V8_HOST_ARCH_ARM64 484 state->pc = reinterpret_cast<void*>(mcontext.pc); 485 state->sp = reinterpret_cast<void*>(mcontext.sp); 486 // FP is an alias for x29. 487 state->fp = reinterpret_cast<void*>(mcontext.regs[29]); 488 #elif V8_HOST_ARCH_MIPS 489 state->pc = reinterpret_cast<void*>(mcontext.pc); 490 state->sp = reinterpret_cast<void*>(mcontext.gregs[29]); 491 state->fp = reinterpret_cast<void*>(mcontext.gregs[30]); 492 #elif V8_HOST_ARCH_MIPS64 493 state->pc = reinterpret_cast<void*>(mcontext.pc); 494 state->sp = reinterpret_cast<void*>(mcontext.gregs[29]); 495 state->fp = reinterpret_cast<void*>(mcontext.gregs[30]); 496 #elif V8_HOST_ARCH_PPC 497 #if V8_LIBC_GLIBC 498 state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.regs->nip); 499 state->sp = 500 reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R1]); 501 state->fp = 502 reinterpret_cast<void*>(ucontext->uc_mcontext.regs->gpr[PT_R31]); 503 #else 504 // Some C libraries, notably Musl, define the regs member as a void pointer 505 state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[32]); 506 state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[1]); 507 state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gp_regs[31]); 508 #endif 509 #elif V8_HOST_ARCH_S390 510 #if V8_TARGET_ARCH_32_BIT 511 // 31-bit target will have bit 0 (MSB) of the PSW set to denote addressing 512 // mode. This bit needs to be masked out to resolve actual address. 513 state->pc = 514 reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr & 0x7FFFFFFF); 515 #else 516 state->pc = reinterpret_cast<void*>(ucontext->uc_mcontext.psw.addr); 517 #endif // V8_TARGET_ARCH_32_BIT 518 state->sp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[15]); 519 state->fp = reinterpret_cast<void*>(ucontext->uc_mcontext.gregs[11]); 520 #endif // V8_HOST_ARCH_* 521 #elif V8_OS_MACOSX 522 #if V8_HOST_ARCH_X64 523 #if __DARWIN_UNIX03 524 state->pc = reinterpret_cast<void*>(mcontext->__ss.__rip); 525 state->sp = reinterpret_cast<void*>(mcontext->__ss.__rsp); 526 state->fp = reinterpret_cast<void*>(mcontext->__ss.__rbp); 527 #else // !__DARWIN_UNIX03 528 state->pc = reinterpret_cast<void*>(mcontext->ss.rip); 529 state->sp = reinterpret_cast<void*>(mcontext->ss.rsp); 530 state->fp = reinterpret_cast<void*>(mcontext->ss.rbp); 531 #endif // __DARWIN_UNIX03 532 #elif V8_HOST_ARCH_IA32 533 #if __DARWIN_UNIX03 534 state->pc = reinterpret_cast<void*>(mcontext->__ss.__eip); 535 state->sp = reinterpret_cast<void*>(mcontext->__ss.__esp); 536 state->fp = reinterpret_cast<void*>(mcontext->__ss.__ebp); 537 #else // !__DARWIN_UNIX03 538 state->pc = reinterpret_cast<void*>(mcontext->ss.eip); 539 state->sp = reinterpret_cast<void*>(mcontext->ss.esp); 540 state->fp = reinterpret_cast<void*>(mcontext->ss.ebp); 541 #endif // __DARWIN_UNIX03 542 #endif // V8_HOST_ARCH_IA32 543 #elif V8_OS_FREEBSD 544 #if V8_HOST_ARCH_IA32 545 state->pc = reinterpret_cast<void*>(mcontext.mc_eip); 546 state->sp = reinterpret_cast<void*>(mcontext.mc_esp); 547 state->fp = reinterpret_cast<void*>(mcontext.mc_ebp); 548 #elif V8_HOST_ARCH_X64 549 state->pc = reinterpret_cast<void*>(mcontext.mc_rip); 550 state->sp = reinterpret_cast<void*>(mcontext.mc_rsp); 551 state->fp = reinterpret_cast<void*>(mcontext.mc_rbp); 552 #elif V8_HOST_ARCH_ARM 553 state->pc = reinterpret_cast<void*>(mcontext.mc_r15); 554 state->sp = reinterpret_cast<void*>(mcontext.mc_r13); 555 state->fp = reinterpret_cast<void*>(mcontext.mc_r11); 556 #endif // V8_HOST_ARCH_* 557 #elif V8_OS_NETBSD 558 #if V8_HOST_ARCH_IA32 559 state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_EIP]); 560 state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_ESP]); 561 state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_EBP]); 562 #elif V8_HOST_ARCH_X64 563 state->pc = reinterpret_cast<void*>(mcontext.__gregs[_REG_RIP]); 564 state->sp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RSP]); 565 state->fp = reinterpret_cast<void*>(mcontext.__gregs[_REG_RBP]); 566 #endif // V8_HOST_ARCH_* 567 #elif V8_OS_OPENBSD 568 #if V8_HOST_ARCH_IA32 569 state->pc = reinterpret_cast<void*>(ucontext->sc_eip); 570 state->sp = reinterpret_cast<void*>(ucontext->sc_esp); 571 state->fp = reinterpret_cast<void*>(ucontext->sc_ebp); 572 #elif V8_HOST_ARCH_X64 573 state->pc = reinterpret_cast<void*>(ucontext->sc_rip); 574 state->sp = reinterpret_cast<void*>(ucontext->sc_rsp); 575 state->fp = reinterpret_cast<void*>(ucontext->sc_rbp); 576 #endif // V8_HOST_ARCH_* 577 #elif V8_OS_SOLARIS 578 state->pc = reinterpret_cast<void*>(mcontext.gregs[REG_PC]); 579 state->sp = reinterpret_cast<void*>(mcontext.gregs[REG_SP]); 580 state->fp = reinterpret_cast<void*>(mcontext.gregs[REG_FP]); 581 #elif V8_OS_QNX 582 #if V8_HOST_ARCH_IA32 583 state->pc = reinterpret_cast<void*>(mcontext.cpu.eip); 584 state->sp = reinterpret_cast<void*>(mcontext.cpu.esp); 585 state->fp = reinterpret_cast<void*>(mcontext.cpu.ebp); 586 #elif V8_HOST_ARCH_ARM 587 state->pc = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_PC]); 588 state->sp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_SP]); 589 state->fp = reinterpret_cast<void*>(mcontext.cpu.gpr[ARM_REG_FP]); 590 #endif // V8_HOST_ARCH_* 591 #elif V8_OS_AIX 592 state->pc = reinterpret_cast<void*>(mcontext.jmp_context.iar); 593 state->sp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[1]); 594 state->fp = reinterpret_cast<void*>(mcontext.jmp_context.gpr[31]); 595 #endif // V8_OS_AIX 596 } 597 598 #endif // USE_SIGNALS 599 600 601 void Sampler::SetUp() { 602 #if defined(USE_SIGNALS) 603 SignalHandler::SetUp(); 604 #endif 605 } 606 607 608 void Sampler::TearDown() { 609 #if defined(USE_SIGNALS) 610 SignalHandler::TearDown(); 611 #endif 612 } 613 614 Sampler::Sampler(Isolate* isolate) 615 : is_counting_samples_(false), 616 js_sample_count_(0), 617 external_sample_count_(0), 618 isolate_(isolate), 619 profiling_(false), 620 has_processing_thread_(false), 621 active_(false), 622 registered_(false) { 623 data_ = new PlatformData; 624 } 625 626 Sampler::~Sampler() { 627 DCHECK(!IsActive()); 628 #if defined(USE_SIGNALS) 629 if (IsRegistered()) { 630 SamplerManager::instance()->RemoveSampler(this); 631 } 632 #endif 633 delete data_; 634 } 635 636 void Sampler::Start() { 637 DCHECK(!IsActive()); 638 SetActive(true); 639 #if defined(USE_SIGNALS) 640 SamplerManager::instance()->AddSampler(this); 641 #endif 642 } 643 644 645 void Sampler::Stop() { 646 #if defined(USE_SIGNALS) 647 SamplerManager::instance()->RemoveSampler(this); 648 #endif 649 DCHECK(IsActive()); 650 SetActive(false); 651 SetRegistered(false); 652 } 653 654 655 void Sampler::IncreaseProfilingDepth() { 656 base::Relaxed_AtomicIncrement(&profiling_, 1); 657 #if defined(USE_SIGNALS) 658 SignalHandler::IncreaseSamplerCount(); 659 #endif 660 } 661 662 663 void Sampler::DecreaseProfilingDepth() { 664 #if defined(USE_SIGNALS) 665 SignalHandler::DecreaseSamplerCount(); 666 #endif 667 base::Relaxed_AtomicIncrement(&profiling_, -1); 668 } 669 670 671 #if defined(USE_SIGNALS) 672 673 void Sampler::DoSample() { 674 if (!SignalHandler::Installed()) return; 675 if (!IsActive() && !IsRegistered()) { 676 SamplerManager::instance()->AddSampler(this); 677 SetRegistered(true); 678 } 679 pthread_kill(platform_data()->vm_tid(), SIGPROF); 680 } 681 682 #elif V8_OS_WIN || V8_OS_CYGWIN 683 684 void Sampler::DoSample() { 685 HANDLE profiled_thread = platform_data()->profiled_thread(); 686 if (profiled_thread == nullptr) return; 687 688 const DWORD kSuspendFailed = static_cast<DWORD>(-1); 689 if (SuspendThread(profiled_thread) == kSuspendFailed) return; 690 691 // Context used for sampling the register state of the profiled thread. 692 CONTEXT context; 693 memset(&context, 0, sizeof(context)); 694 context.ContextFlags = CONTEXT_FULL; 695 if (GetThreadContext(profiled_thread, &context) != 0) { 696 v8::RegisterState state; 697 #if V8_HOST_ARCH_X64 698 state.pc = reinterpret_cast<void*>(context.Rip); 699 state.sp = reinterpret_cast<void*>(context.Rsp); 700 state.fp = reinterpret_cast<void*>(context.Rbp); 701 #else 702 state.pc = reinterpret_cast<void*>(context.Eip); 703 state.sp = reinterpret_cast<void*>(context.Esp); 704 state.fp = reinterpret_cast<void*>(context.Ebp); 705 #endif 706 SampleStack(state); 707 } 708 ResumeThread(profiled_thread); 709 } 710 711 #elif V8_OS_FUCHSIA 712 713 void Sampler::DoSample() { 714 zx_handle_t profiled_thread = platform_data()->profiled_thread(); 715 if (profiled_thread == ZX_HANDLE_INVALID) return; 716 717 zx_handle_t suspend_token = ZX_HANDLE_INVALID; 718 if (zx_task_suspend_token(profiled_thread, &suspend_token) != ZX_OK) return; 719 720 // Wait for the target thread to become suspended, or to exit. 721 // TODO(wez): There is currently no suspension count for threads, so there 722 // is a risk that some other caller resumes the thread in-between our suspend 723 // and wait calls, causing us to miss the SUSPENDED signal. We apply a 100ms 724 // deadline to protect against hanging the sampler thread in this case. 725 zx_signals_t signals = 0; 726 zx_status_t suspended = zx_object_wait_one( 727 profiled_thread, ZX_THREAD_SUSPENDED | ZX_THREAD_TERMINATED, 728 zx_deadline_after(ZX_MSEC(100)), &signals); 729 if (suspended != ZX_OK || (signals & ZX_THREAD_SUSPENDED) == 0) { 730 zx_handle_close(suspend_token); 731 return; 732 } 733 734 // Fetch a copy of its "general register" states. 735 zx_thread_state_general_regs_t thread_state = {}; 736 if (zx_thread_read_state(profiled_thread, ZX_THREAD_STATE_GENERAL_REGS, 737 &thread_state, sizeof(thread_state)) == ZX_OK) { 738 v8::RegisterState state; 739 #if V8_HOST_ARCH_X64 740 state.pc = reinterpret_cast<void*>(thread_state.rip); 741 state.sp = reinterpret_cast<void*>(thread_state.rsp); 742 state.fp = reinterpret_cast<void*>(thread_state.rbp); 743 #elif V8_HOST_ARCH_ARM64 744 state.pc = reinterpret_cast<void*>(thread_state.pc); 745 state.sp = reinterpret_cast<void*>(thread_state.sp); 746 state.fp = reinterpret_cast<void*>(thread_state.r[29]); 747 #endif 748 SampleStack(state); 749 } 750 751 zx_handle_close(suspend_token); 752 } 753 754 // TODO(wez): Remove this once the Fuchsia SDK has rolled. 755 #if defined(ZX_THREAD_STATE_REGSET0) 756 #undef ZX_THREAD_STATE_GENERAL_REGS 757 #endif 758 759 #endif // USE_SIGNALS 760 761 } // namespace sampler 762 } // namespace v8 763