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