1 //===-- sanitizer_stoptheworld_mac.cpp ------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // See sanitizer_stoptheworld.h for details.
11 //===----------------------------------------------------------------------===//
13 #include "sanitizer_platform.h"
15 #if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \
18 #include <mach/mach.h>
19 #include <mach/thread_info.h>
22 #include "sanitizer_stoptheworld.h"
24 namespace __sanitizer
{
28 } SuspendedThreadInfo
;
30 class SuspendedThreadsListMac final
: public SuspendedThreadsList
{
32 SuspendedThreadsListMac() : threads_(1024) {}
34 tid_t
GetThreadID(uptr index
) const override
;
35 thread_t
GetThread(uptr index
) const;
36 uptr
ThreadCount() const override
;
37 bool ContainsThread(thread_t thread
) const;
38 void Append(thread_t thread
);
40 PtraceRegistersStatus
GetRegistersAndSP(uptr index
,
41 InternalMmapVector
<uptr
> *buffer
,
42 uptr
*sp
) const override
;
45 InternalMmapVector
<SuspendedThreadInfo
> threads_
;
48 struct RunThreadArgs
{
49 StopTheWorldCallback callback
;
53 void *RunThread(void *arg
) {
54 struct RunThreadArgs
*run_args
= (struct RunThreadArgs
*)arg
;
55 SuspendedThreadsListMac suspended_threads_list
;
57 thread_array_t threads
;
58 mach_msg_type_number_t num_threads
;
59 kern_return_t err
= task_threads(mach_task_self(), &threads
, &num_threads
);
60 if (err
!= KERN_SUCCESS
) {
61 VReport(1, "Failed to get threads for task (errno %d).\n", err
);
65 thread_t thread_self
= mach_thread_self();
66 for (unsigned int i
= 0; i
< num_threads
; ++i
) {
67 if (threads
[i
] == thread_self
) continue;
69 thread_suspend(threads
[i
]);
70 suspended_threads_list
.Append(threads
[i
]);
73 run_args
->callback(suspended_threads_list
, run_args
->argument
);
75 uptr num_suspended
= suspended_threads_list
.ThreadCount();
76 for (unsigned int i
= 0; i
< num_suspended
; ++i
) {
77 thread_resume(suspended_threads_list
.GetThread(i
));
82 void StopTheWorld(StopTheWorldCallback callback
, void *argument
) {
83 struct RunThreadArgs arg
= {callback
, argument
};
84 pthread_t run_thread
= (pthread_t
)internal_start_thread(RunThread
, &arg
);
85 internal_join_thread(run_thread
);
88 #if defined(__x86_64__)
89 typedef x86_thread_state64_t regs_struct
;
93 #elif defined(__aarch64__)
94 typedef arm_thread_state64_t regs_struct
;
102 #elif defined(__i386)
103 typedef x86_thread_state32_t regs_struct
;
108 #error "Unsupported architecture"
111 tid_t
SuspendedThreadsListMac::GetThreadID(uptr index
) const {
112 CHECK_LT(index
, threads_
.size());
113 return threads_
[index
].tid
;
116 thread_t
SuspendedThreadsListMac::GetThread(uptr index
) const {
117 CHECK_LT(index
, threads_
.size());
118 return threads_
[index
].thread
;
121 uptr
SuspendedThreadsListMac::ThreadCount() const {
122 return threads_
.size();
125 bool SuspendedThreadsListMac::ContainsThread(thread_t thread
) const {
126 for (uptr i
= 0; i
< threads_
.size(); i
++) {
127 if (threads_
[i
].thread
== thread
) return true;
132 void SuspendedThreadsListMac::Append(thread_t thread
) {
133 thread_identifier_info_data_t info
;
134 mach_msg_type_number_t info_count
= THREAD_IDENTIFIER_INFO_COUNT
;
135 kern_return_t err
= thread_info(thread
, THREAD_IDENTIFIER_INFO
,
136 (thread_info_t
)&info
, &info_count
);
137 if (err
!= KERN_SUCCESS
) {
138 VReport(1, "Error - unable to get thread ident for a thread\n");
141 threads_
.push_back({info
.thread_id
, thread
});
144 PtraceRegistersStatus
SuspendedThreadsListMac::GetRegistersAndSP(
145 uptr index
, InternalMmapVector
<uptr
> *buffer
, uptr
*sp
) const {
146 thread_t thread
= GetThread(index
);
149 mach_msg_type_number_t reg_count
= MACHINE_THREAD_STATE_COUNT
;
150 err
= thread_get_state(thread
, MACHINE_THREAD_STATE
, (thread_state_t
)®s
,
152 if (err
!= KERN_SUCCESS
) {
153 VReport(1, "Error - unable to get registers for a thread\n");
154 // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid,
155 // or the thread does not exist. The other possible error case,
156 // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's
157 // still safe to proceed.
158 return err
== KERN_INVALID_ARGUMENT
? REGISTERS_UNAVAILABLE_FATAL
159 : REGISTERS_UNAVAILABLE
;
162 buffer
->resize(RoundUpTo(sizeof(regs
), sizeof(uptr
)) / sizeof(uptr
));
163 internal_memcpy(buffer
->data(), ®s
, sizeof(regs
));
164 #if defined(__aarch64__) && defined(arm_thread_state64_get_sp)
165 *sp
= arm_thread_state64_get_sp(regs
);
170 // On x86_64 and aarch64, we must account for the stack redzone, which is 128
172 if (SANITIZER_WORDSIZE
== 64) *sp
-= 128;
174 return REGISTERS_AVAILABLE
;
177 } // namespace __sanitizer
179 #endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) ||