Index: lib/lsan/lsan_common.cc =================================================================== --- lib/lsan/lsan_common.cc +++ lib/lsan/lsan_common.cc @@ -200,7 +200,7 @@ // Scans thread data (stacks and TLS) for heap pointers. static void ProcessThreads(SuspendedThreadsList const &suspended_threads, Frontier *frontier) { - InternalScopedBuffer registers(SuspendedThreadsList::RegisterCount()); + InternalScopedBuffer registers(suspended_threads.RegisterCount()); uptr registers_begin = reinterpret_cast(registers.data()); uptr registers_end = registers_begin + registers.size(); for (uptr i = 0; i < suspended_threads.thread_count(); i++) { Index: lib/sanitizer_common/sanitizer_stoptheworld.h =================================================================== --- lib/sanitizer_common/sanitizer_stoptheworld.h +++ lib/sanitizer_common/sanitizer_stoptheworld.h @@ -29,31 +29,17 @@ // 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]; - } - PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, - uptr *sp) const; + SuspendedThreadsList() = default; + virtual tid_t GetThreadID(uptr index) const = 0; + + virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const = 0; // 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 = 0; + virtual uptr thread_count() const = 0; + virtual bool ContainsTid(tid_t thread_id) const = 0; private: - InternalMmapVector thread_ids_; - // Prohibit copy and assign. SuspendedThreadsList(const SuspendedThreadsList&); void operator=(const SuspendedThreadsList&); Index: lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc =================================================================== --- lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc +++ lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc @@ -84,6 +84,122 @@ COMPILER_CHECK(sizeof(tid_t) == sizeof(pid_t)); +// Platform-specific methods from SuspendedThreadsList. +#if SANITIZER_ANDROID && defined(__arm__) +typedef pt_regs regs_struct; +#define REG_SP ARM_sp + +#elif SANITIZER_LINUX && defined(__arm__) +typedef user_regs regs_struct; +#define REG_SP uregs[13] + +#elif defined(__i386__) || defined(__x86_64__) +typedef user_regs_struct regs_struct; +#if defined(__i386__) +#define REG_SP esp +#else +#define REG_SP rsp +#endif + +#elif defined(__powerpc__) || defined(__powerpc64__) +typedef pt_regs regs_struct; +#define REG_SP gpr[PT_R1] + +#elif defined(__mips__) +typedef struct user regs_struct; +#if SANITIZER_ANDROID +#define REG_SP regs[EF_R29] +#else +#define REG_SP regs[EF_REG29] +#endif + +#elif defined(__aarch64__) +typedef struct user_pt_regs regs_struct; +#define REG_SP sp +#define ARCH_IOVEC_FOR_GETREGSET + +#elif defined(__s390__) +typedef _user_regs_struct regs_struct; +#define REG_SP gprs[15] +#define ARCH_IOVEC_FOR_GETREGSET + +#else +#error "Unsupported architecture" +#endif // SANITIZER_ANDROID && defined(__arm__) + +class SuspendedThreadsListLinux : public SuspendedThreadsList { + public: + SuspendedThreadsListLinux() : thread_ids_(1024) {} + + tid_t GetThreadID(uptr index) const; + uptr thread_count() 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 thread_ids_; +}; + +tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const { + CHECK_LT(index, thread_ids_.size()); + return thread_ids_[index]; +} + +// The buffer in GetRegistersAndSP should be at least this big. +uptr SuspendedThreadsListLinux::thread_count() 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; +#ifdef ARCH_IOVEC_FOR_GETREGSET + struct iovec regset_io; + regset_io.iov_base = ®s; + regset_io.iov_len = sizeof(regs_struct); + bool isErr = + internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, + (void *)NT_PRSTATUS, (void *)®set_io), + &pterrno); +#else + bool isErr = internal_iserror( + internal_ptrace(PTRACE_GETREGS, tid, nullptr, ®s), &pterrno); +#endif + if (isErr) { + VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, + pterrno); + // ESRCH means that the given thread is not suspended or already dead. + // Therefore it's unsafe to inspect its data (e.g. walk through stack) and + // we should notify caller about this. + return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL + : REGISTERS_UNAVAILABLE; + } + + *sp = regs.REG_SP; + internal_memcpy(buffer, ®s, sizeof(regs)); + return REGISTERS_AVAILABLE; +} + +uptr SuspendedThreadsListLinux::RegisterCount() const { + return sizeof(regs_struct) / sizeof(uptr); +} + // Structure for passing arguments into the tracer thread. struct TracerThreadArgument { StopTheWorldCallback callback; @@ -107,12 +223,12 @@ 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); }; @@ -121,8 +237,7 @@ // 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)) { @@ -450,85 +565,6 @@ } } } - -// Platform-specific methods from SuspendedThreadsList. -#if SANITIZER_ANDROID && defined(__arm__) -typedef pt_regs regs_struct; -#define REG_SP ARM_sp - -#elif SANITIZER_LINUX && defined(__arm__) -typedef user_regs regs_struct; -#define REG_SP uregs[13] - -#elif defined(__i386__) || defined(__x86_64__) -typedef user_regs_struct regs_struct; -#if defined(__i386__) -#define REG_SP esp -#else -#define REG_SP rsp -#endif - -#elif defined(__powerpc__) || defined(__powerpc64__) -typedef pt_regs regs_struct; -#define REG_SP gpr[PT_R1] - -#elif defined(__mips__) -typedef struct user regs_struct; -# if SANITIZER_ANDROID -# define REG_SP regs[EF_R29] -# else -# define REG_SP regs[EF_REG29] -# endif - -#elif defined(__aarch64__) -typedef struct user_pt_regs regs_struct; -#define REG_SP sp -#define ARCH_IOVEC_FOR_GETREGSET - -#elif defined(__s390__) -typedef _user_regs_struct regs_struct; -#define REG_SP gprs[15] -#define ARCH_IOVEC_FOR_GETREGSET - -#else -#error "Unsupported architecture" -#endif // SANITIZER_ANDROID && defined(__arm__) - -PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index, - uptr *buffer, - uptr *sp) const { - pid_t tid = GetThreadID(index); - regs_struct regs; - int pterrno; -#ifdef ARCH_IOVEC_FOR_GETREGSET - struct iovec regset_io; - regset_io.iov_base = ®s; - regset_io.iov_len = sizeof(regs_struct); - bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGSET, tid, - (void*)NT_PRSTATUS, (void*)®set_io), - &pterrno); -#else - bool isErr = internal_iserror(internal_ptrace(PTRACE_GETREGS, tid, nullptr, - ®s), &pterrno); -#endif - if (isErr) { - VReport(1, "Could not get registers from thread %d (errno %d).\n", tid, - pterrno); - // ESRCH means that the given thread is not suspended or already dead. - // Therefore it's unsafe to inspect its data (e.g. walk through stack) and - // we should notify caller about this. - return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL - : REGISTERS_UNAVAILABLE; - } - - *sp = regs.REG_SP; - internal_memcpy(buffer, ®s, sizeof(regs)); - return REGISTERS_AVAILABLE; -} - -uptr SuspendedThreadsList::RegisterCount() { - return sizeof(regs_struct) / sizeof(uptr); -} } // namespace __sanitizer #endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) Index: lib/sanitizer_common/sanitizer_stoptheworld_mac.cc =================================================================== --- lib/sanitizer_common/sanitizer_stoptheworld_mac.cc +++ lib/sanitizer_common/sanitizer_stoptheworld_mac.cc @@ -16,24 +16,65 @@ #if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \ defined(__mips64) || defined(__i386)) +#include + #include "sanitizer_stoptheworld.h" namespace __sanitizer { -void StopTheWorld(StopTheWorldCallback callback, void *argument) { - CHECK(0 && "unimplemented"); +typedef struct { + tid_t tid; + thread_t thread; +} SuspendedThreadInfo; + +class SuspendedThreadsListMac : public SuspendedThreadsList { + public: + SuspendedThreadsListMac() : threads_(1024) {} + + tid_t GetThreadID(uptr index) const; + uptr thread_count() const; + bool ContainsTid(tid_t thread_id) const; + void Append(SuspendedThreadInfo const &info); + + PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer, + uptr *sp) const; + uptr RegisterCount() const; + + private: + InternalMmapVector threads_; +}; + +tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const { + CHECK_LT(index, threads_.size()); + return threads_[index].tid; } -PtraceRegistersStatus SuspendedThreadsList::GetRegistersAndSP(uptr index, - uptr *buffer, - uptr *sp) const { +// The buffer in GetRegistersAndSP should be at least this big. +uptr SuspendedThreadsListMac::thread_count() const { return threads_.size(); } +bool SuspendedThreadsListMac::ContainsTid(tid_t thread_id) const { + for (uptr i = 0; i < threads_.size(); i++) { + if (threads_[i].tid == thread_id) return true; + } + return false; +} + +void SuspendedThreadsListMac::Append(SuspendedThreadInfo const &info) { + threads_.push_back(info); +} + +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; } + +void StopTheWorld(StopTheWorldCallback callback, void *argument) { + CHECK(0 && "unimplemented"); +} } // namespace __sanitizer #endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) ||