LCOV - code coverage report
Current view: top level - src/libsampler - sampler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 82 84 97.6 %
Date: 2019-02-19 Functions: 18 20 90.0 %

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

Generated by: LCOV version 1.10