forked from OSchip/llvm-project
Update suspended threads info to be compatible with darwin
Summary: On Darwin, we need to track thread and tid as separate values. This patch splits out the implementation of the suspended threads list to be OS-specific. Reviewers: glider, kubamracek, kcc Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D31474 llvm-svn: 300491
This commit is contained in:
parent
f7a4f3dd95
commit
5989dd241e
|
|
@ -200,10 +200,10 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
|
|||
// Scans thread data (stacks and TLS) for heap pointers.
|
||||
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
|
||||
Frontier *frontier) {
|
||||
InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount());
|
||||
InternalScopedBuffer<uptr> registers(suspended_threads.RegisterCount());
|
||||
uptr registers_begin = reinterpret_cast<uptr>(registers.data());
|
||||
uptr registers_end = registers_begin + registers.size();
|
||||
for (uptr i = 0; i < suspended_threads.thread_count(); i++) {
|
||||
for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
|
||||
tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i));
|
||||
LOG_THREADS("Processing thread %d.\n", os_id);
|
||||
uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
|
||||
|
|
|
|||
|
|
@ -29,31 +29,21 @@ enum PtraceRegistersStatus {
|
|||
// register contexts.
|
||||
class SuspendedThreadsList {
|
||||
public:
|
||||
SuspendedThreadsList()
|
||||
: thread_ids_(1024) {}
|
||||
tid_t GetThreadID(uptr index) const {
|
||||
CHECK_LT(index, thread_ids_.size());
|
||||
return thread_ids_[index];
|
||||
SuspendedThreadsList() = default;
|
||||
|
||||
// Can't declare pure virtual functions in sanitizer runtimes:
|
||||
// __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead.
|
||||
virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
|
||||
uptr *sp) const {
|
||||
UNIMPLEMENTED();
|
||||
}
|
||||
PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
|
||||
uptr *sp) const;
|
||||
|
||||
// The buffer in GetRegistersAndSP should be at least this big.
|
||||
static uptr RegisterCount();
|
||||
uptr thread_count() const { return thread_ids_.size(); }
|
||||
bool Contains(tid_t thread_id) const {
|
||||
for (uptr i = 0; i < thread_ids_.size(); i++) {
|
||||
if (thread_ids_[i] == thread_id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void Append(tid_t thread_id) {
|
||||
thread_ids_.push_back(thread_id);
|
||||
}
|
||||
virtual uptr RegisterCount() const { UNIMPLEMENTED(); }
|
||||
virtual uptr ThreadCount() const { UNIMPLEMENTED(); }
|
||||
virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); }
|
||||
|
||||
private:
|
||||
InternalMmapVector<tid_t> thread_ids_;
|
||||
|
||||
// Prohibit copy and assign.
|
||||
SuspendedThreadsList(const SuspendedThreadsList&);
|
||||
void operator=(const SuspendedThreadsList&);
|
||||
|
|
|
|||
|
|
@ -82,6 +82,23 @@
|
|||
|
||||
namespace __sanitizer {
|
||||
|
||||
class SuspendedThreadsListLinux : public SuspendedThreadsList {
|
||||
public:
|
||||
SuspendedThreadsListLinux() : thread_ids_(1024) {}
|
||||
|
||||
tid_t GetThreadID(uptr index) const;
|
||||
uptr ThreadCount() const;
|
||||
bool ContainsTid(tid_t thread_id) const;
|
||||
void Append(tid_t tid);
|
||||
|
||||
PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
|
||||
uptr *sp) const;
|
||||
uptr RegisterCount() const;
|
||||
|
||||
private:
|
||||
InternalMmapVector<tid_t> thread_ids_;
|
||||
};
|
||||
|
||||
// Structure for passing arguments into the tracer thread.
|
||||
struct TracerThreadArgument {
|
||||
StopTheWorldCallback callback;
|
||||
|
|
@ -105,12 +122,12 @@ class ThreadSuspender {
|
|||
bool SuspendAllThreads();
|
||||
void ResumeAllThreads();
|
||||
void KillAllThreads();
|
||||
SuspendedThreadsList &suspended_threads_list() {
|
||||
SuspendedThreadsListLinux &suspended_threads_list() {
|
||||
return suspended_threads_list_;
|
||||
}
|
||||
TracerThreadArgument *arg;
|
||||
private:
|
||||
SuspendedThreadsList suspended_threads_list_;
|
||||
SuspendedThreadsListLinux suspended_threads_list_;
|
||||
pid_t pid_;
|
||||
bool SuspendThread(tid_t thread_id);
|
||||
};
|
||||
|
|
@ -119,8 +136,7 @@ bool ThreadSuspender::SuspendThread(tid_t tid) {
|
|||
// Are we already attached to this thread?
|
||||
// Currently this check takes linear time, however the number of threads is
|
||||
// usually small.
|
||||
if (suspended_threads_list_.Contains(tid))
|
||||
return false;
|
||||
if (suspended_threads_list_.ContainsTid(tid)) return false;
|
||||
int pterrno;
|
||||
if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr),
|
||||
&pterrno)) {
|
||||
|
|
@ -165,7 +181,7 @@ bool ThreadSuspender::SuspendThread(tid_t tid) {
|
|||
}
|
||||
|
||||
void ThreadSuspender::ResumeAllThreads() {
|
||||
for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) {
|
||||
for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) {
|
||||
pid_t tid = suspended_threads_list_.GetThreadID(i);
|
||||
int pterrno;
|
||||
if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr),
|
||||
|
|
@ -181,7 +197,7 @@ void ThreadSuspender::ResumeAllThreads() {
|
|||
}
|
||||
|
||||
void ThreadSuspender::KillAllThreads() {
|
||||
for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++)
|
||||
for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++)
|
||||
internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i),
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
|
@ -492,9 +508,28 @@ typedef _user_regs_struct regs_struct;
|
|||
#error "Unsupported architecture"
|
||||
#endif // SANITIZER_ANDROID && defined(__arm__)
|
||||
|
||||
PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index,
|
||||
uptr *buffer,
|
||||
uptr *sp) const {
|
||||
tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const {
|
||||
CHECK_LT(index, thread_ids_.size());
|
||||
return thread_ids_[index];
|
||||
}
|
||||
|
||||
uptr SuspendedThreadsListLinux::ThreadCount() const {
|
||||
return thread_ids_.size();
|
||||
}
|
||||
|
||||
bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const {
|
||||
for (uptr i = 0; i < thread_ids_.size(); i++) {
|
||||
if (thread_ids_[i] == thread_id) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SuspendedThreadsListLinux::Append(tid_t tid) {
|
||||
thread_ids_.push_back(tid);
|
||||
}
|
||||
|
||||
PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP(
|
||||
uptr index, uptr *buffer, uptr *sp) const {
|
||||
pid_t tid = GetThreadID(index);
|
||||
regs_struct regs;
|
||||
int pterrno;
|
||||
|
|
@ -524,7 +559,7 @@ PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index,
|
|||
return REGISTERS_AVAILABLE;
|
||||
}
|
||||
|
||||
uptr SuspendedThreadsList::RegisterCount() {
|
||||
uptr SuspendedThreadsListLinux::RegisterCount() const {
|
||||
return sizeof(regs_struct) / sizeof(uptr);
|
||||
}
|
||||
} // namespace __sanitizer
|
||||
|
|
|
|||
|
|
@ -16,21 +16,78 @@
|
|||
#if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \
|
||||
defined(__mips64) || defined(__i386))
|
||||
|
||||
#include <mach/mach.h>
|
||||
|
||||
#include "sanitizer_stoptheworld.h"
|
||||
|
||||
namespace __sanitizer {
|
||||
typedef struct {
|
||||
tid_t tid;
|
||||
thread_t thread;
|
||||
} SuspendedThreadInfo;
|
||||
|
||||
class SuspendedThreadsListMac : public SuspendedThreadsList {
|
||||
public:
|
||||
SuspendedThreadsListMac() : threads_(1024) {}
|
||||
|
||||
tid_t GetThreadID(uptr index) const;
|
||||
thread_t GetThread(uptr index) const;
|
||||
uptr ThreadCount() const;
|
||||
bool ContainsThread(thread_t thread) const;
|
||||
void Append(thread_t thread);
|
||||
|
||||
PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
|
||||
uptr *sp) const;
|
||||
uptr RegisterCount() const;
|
||||
|
||||
private:
|
||||
InternalMmapVector<SuspendedThreadInfo> threads_;
|
||||
};
|
||||
|
||||
void StopTheWorld(StopTheWorldCallback callback, void *argument) {
|
||||
CHECK(0 && "unimplemented");
|
||||
}
|
||||
|
||||
PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index,
|
||||
uptr *buffer,
|
||||
uptr *sp) const {
|
||||
tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const {
|
||||
CHECK_LT(index, threads_.size());
|
||||
return threads_[index].tid;
|
||||
}
|
||||
|
||||
thread_t SuspendedThreadsListMac::GetThread(uptr index) const {
|
||||
CHECK_LT(index, threads_.size());
|
||||
return threads_[index].thread;
|
||||
}
|
||||
|
||||
uptr SuspendedThreadsListMac::ThreadCount() const {
|
||||
return threads_.size();
|
||||
}
|
||||
|
||||
bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const {
|
||||
for (uptr i = 0; i < threads_.size(); i++) {
|
||||
if (threads_[i].thread == thread) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SuspendedThreadsListMac::Append(thread_t thread) {
|
||||
thread_identifier_info_data_t info;
|
||||
mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT;
|
||||
kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO,
|
||||
(thread_info_t)&info, &info_count);
|
||||
if (err != KERN_SUCCESS) {
|
||||
VReport(1, "Error - unable to get thread ident for a thread\n");
|
||||
return;
|
||||
}
|
||||
threads_.push_back({info.thread_id, thread});
|
||||
}
|
||||
|
||||
PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
|
||||
uptr index, uptr *buffer, uptr *sp) const {
|
||||
CHECK(0 && "unimplemented");
|
||||
return REGISTERS_UNAVAILABLE_FATAL;
|
||||
}
|
||||
|
||||
uptr SuspendedThreadsList::RegisterCount() {
|
||||
uptr SuspendedThreadsListMac::RegisterCount() const {
|
||||
CHECK(0 && "unimplemented");
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue