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