1 //===-- sanitizer_stoptheworld_mac.cc -------------------------------------===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // See sanitizer_stoptheworld.h for details.
10 //===----------------------------------------------------------------------===//
12 #include "sanitizer_platform.h"
14 #if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \
17 #include <mach/mach.h>
18 #include <mach/thread_info.h>
21 #include "sanitizer_stoptheworld.h"
23 namespace __sanitizer
{
27 } SuspendedThreadInfo
;
29 class SuspendedThreadsListMac
: public SuspendedThreadsList
{
31 SuspendedThreadsListMac() : threads_(1024) {}
33 tid_t
GetThreadID(uptr index
) const;
34 thread_t
GetThread(uptr index
) const;
35 uptr
ThreadCount() const;
36 bool ContainsThread(thread_t thread
) const;
37 void Append(thread_t thread
);
39 PtraceRegistersStatus
GetRegistersAndSP(uptr index
, uptr
*buffer
,
41 uptr
RegisterCount() const;
44 InternalMmapVector
<SuspendedThreadInfo
> threads_
;
47 struct RunThreadArgs
{
48 StopTheWorldCallback callback
;
52 void RunThread(void *arg
) {
53 struct RunThreadArgs
*run_args
= (struct RunThreadArgs
*)arg
;
54 SuspendedThreadsListMac suspended_threads_list
;
56 thread_array_t threads
;
57 mach_msg_type_number_t num_threads
;
58 kern_return_t err
= task_threads(mach_task_self(), &threads
, &num_threads
);
59 if (err
!= KERN_SUCCESS
) {
60 VReport(1, "Failed to get threads for task (errno %d).\n", err
);
64 thread_t thread_self
= mach_thread_self();
65 for (unsigned int i
= 0; i
< num_threads
; ++i
) {
66 if (threads
[i
] == thread_self
) continue;
68 thread_suspend(threads
[i
]);
69 suspended_threads_list
.Append(threads
[i
]);
72 run_args
->callback(suspended_threads_list
, run_args
->argument
);
74 uptr num_suspended
= suspended_threads_list
.ThreadCount();
75 for (unsigned int i
= 0; i
< num_suspended
; ++i
) {
76 thread_resume(suspended_threads_list
.GetThread(i
));
80 void StopTheWorld(StopTheWorldCallback callback
, void *argument
) {
81 struct RunThreadArgs arg
= {callback
, argument
};
82 pthread_t run_thread
= (pthread_t
)internal_start_thread(RunThread
, &arg
);
83 internal_join_thread(run_thread
);
86 #if defined(__x86_64__)
87 typedef x86_thread_state64_t regs_struct
;
91 #elif defined(__aarch64__)
92 typedef arm_thread_state64_t regs_struct
;
100 #elif defined(__i386)
101 typedef x86_thread_state32_t regs_struct
;
106 #error "Unsupported architecture"
109 tid_t
SuspendedThreadsListMac::GetThreadID(uptr index
) const {
110 CHECK_LT(index
, threads_
.size());
111 return threads_
[index
].tid
;
114 thread_t
SuspendedThreadsListMac::GetThread(uptr index
) const {
115 CHECK_LT(index
, threads_
.size());
116 return threads_
[index
].thread
;
119 uptr
SuspendedThreadsListMac::ThreadCount() const {
120 return threads_
.size();
123 bool SuspendedThreadsListMac::ContainsThread(thread_t thread
) const {
124 for (uptr i
= 0; i
< threads_
.size(); i
++) {
125 if (threads_
[i
].thread
== thread
) return true;
130 void SuspendedThreadsListMac::Append(thread_t thread
) {
131 thread_identifier_info_data_t info
;
132 mach_msg_type_number_t info_count
= THREAD_IDENTIFIER_INFO_COUNT
;
133 kern_return_t err
= thread_info(thread
, THREAD_IDENTIFIER_INFO
,
134 (thread_info_t
)&info
, &info_count
);
135 if (err
!= KERN_SUCCESS
) {
136 VReport(1, "Error - unable to get thread ident for a thread\n");
139 threads_
.push_back({info
.thread_id
, thread
});
142 PtraceRegistersStatus
SuspendedThreadsListMac::GetRegistersAndSP(
143 uptr index
, uptr
*buffer
, uptr
*sp
) const {
144 thread_t thread
= GetThread(index
);
147 mach_msg_type_number_t reg_count
= MACHINE_THREAD_STATE_COUNT
;
148 err
= thread_get_state(thread
, MACHINE_THREAD_STATE
, (thread_state_t
)®s
,
150 if (err
!= KERN_SUCCESS
) {
151 VReport(1, "Error - unable to get registers for a thread\n");
152 // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid,
153 // or the thread does not exist. The other possible error case,
154 // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's
155 // still safe to proceed.
156 return err
== KERN_INVALID_ARGUMENT
? REGISTERS_UNAVAILABLE_FATAL
157 : REGISTERS_UNAVAILABLE
;
160 internal_memcpy(buffer
, ®s
, sizeof(regs
));
163 // On x86_64 and aarch64, we must account for the stack redzone, which is 128
165 if (SANITIZER_WORDSIZE
== 64) *sp
-= 128;
167 return REGISTERS_AVAILABLE
;
170 uptr
SuspendedThreadsListMac::RegisterCount() const {
171 return MACHINE_THREAD_STATE_COUNT
;
173 } // namespace __sanitizer
175 #endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) ||