1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include "platform/globals.h"
6#if defined(HOST_OS_MACOS)
7
8#include <assert.h> // NOLINT
9#include <errno.h> // NOLINT
10#include <stdbool.h> // NOLINT
11#include <sys/sysctl.h> // NOLINT
12#include <sys/types.h> // NOLINT
13#include <unistd.h> // NOLINT
14
15#include "vm/flags.h"
16#include "vm/os.h"
17#include "vm/profiler.h"
18#include "vm/signal_handler.h"
19#include "vm/thread_interrupter.h"
20
21namespace dart {
22
23#ifndef PRODUCT
24
25DECLARE_FLAG(bool, trace_thread_interrupter);
26
27// Returns true if the current process is being debugged (either
28// running under the debugger or has a debugger attached post facto).
29// Code from https://developer.apple.com/library/content/qa/qa1361/_index.html
30bool ThreadInterrupter::IsDebuggerAttached() {
31 struct kinfo_proc info;
32 // Initialize the flags so that, if sysctl fails for some bizarre
33 // reason, we get a predictable result.
34 info.kp_proc.p_flag = 0;
35 // Initialize mib, which tells sysctl the info we want, in this case
36 // we're looking for information about a specific process ID.
37 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()};
38 size_t size = sizeof(info);
39
40 // Call sysctl.
41 size = sizeof(info);
42 int junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
43 ASSERT(junk == 0);
44 // We're being debugged if the P_TRACED flag is set.
45 return ((info.kp_proc.p_flag & P_TRACED) != 0);
46}
47
48class ThreadInterrupterMacOS : public AllStatic {
49 public:
50 static void ThreadInterruptSignalHandler(int signal,
51 siginfo_t* info,
52 void* context_) {
53 if (signal != SIGPROF) {
54 return;
55 }
56 Thread* thread = Thread::Current();
57 if (thread == NULL) {
58 return;
59 }
60 ThreadInterrupter::SampleBufferWriterScope scope;
61 if (!scope.CanSample()) {
62 return;
63 }
64 // Extract thread state.
65 ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
66 mcontext_t mcontext = context->uc_mcontext;
67 InterruptedThreadState its;
68 its.pc = SignalHandler::GetProgramCounter(mcontext);
69 its.fp = SignalHandler::GetFramePointer(mcontext);
70 its.csp = SignalHandler::GetCStackPointer(mcontext);
71 its.dsp = SignalHandler::GetDartStackPointer(mcontext);
72 its.lr = SignalHandler::GetLinkRegister(mcontext);
73 Profiler::SampleThread(thread, its);
74 }
75};
76
77void ThreadInterrupter::InterruptThread(OSThread* thread) {
78 if (FLAG_trace_thread_interrupter) {
79 OS::PrintErr("ThreadInterrupter interrupting %p\n", thread->id());
80 }
81 int result = pthread_kill(thread->id(), SIGPROF);
82 ASSERT((result == 0) || (result == ESRCH));
83}
84
85void ThreadInterrupter::InstallSignalHandler() {
86 SignalHandler::Install<
87 ThreadInterrupterMacOS::ThreadInterruptSignalHandler>();
88}
89
90void ThreadInterrupter::RemoveSignalHandler() {
91 SignalHandler::Remove();
92}
93
94#endif // !PRODUCT
95
96} // namespace dart
97
98#endif // defined(HOST_OS_MACOS)
99