brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.3 KiB · d6ef37a Raw
182 lines · cpp
1//===-- sanitizer_stoptheworld_mac.cpp ------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8//9// See sanitizer_stoptheworld.h for details.10//11//===----------------------------------------------------------------------===//12 13#include "sanitizer_platform.h"14 15#if SANITIZER_APPLE && (defined(__x86_64__) || defined(__aarch64__) || \16                      defined(__i386))17 18#include <mach/mach.h>19#include <mach/thread_info.h>20#include <pthread.h>21 22#include "sanitizer_stoptheworld.h"23 24namespace __sanitizer {25typedef struct {26  ThreadID tid;27  thread_t thread;28} SuspendedThreadInfo;29 30class SuspendedThreadsListMac final : public SuspendedThreadsList {31 public:32  SuspendedThreadsListMac() = default;33 34  ThreadID 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);39 40  PtraceRegistersStatus GetRegistersAndSP(uptr index,41                                          InternalMmapVector<uptr> *buffer,42                                          uptr *sp) const override;43 44 private:45  InternalMmapVector<SuspendedThreadInfo> threads_;46};47 48struct RunThreadArgs {49  StopTheWorldCallback callback;50  void *argument;51};52 53void *RunThread(void *arg) {54  struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg;55  SuspendedThreadsListMac suspended_threads_list;56 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);62    return nullptr;63  }64 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;68 69    thread_suspend(threads[i]);70    suspended_threads_list.Append(threads[i]);71  }72 73  run_args->callback(suspended_threads_list, run_args->argument);74 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));78  }79  return nullptr;80}81 82void 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);86}87 88#if defined(__x86_64__)89typedef x86_thread_state64_t regs_struct;90#define regs_flavor x86_THREAD_STATE6491 92#define SP_REG __rsp93 94#elif defined(__aarch64__)95typedef arm_thread_state64_t regs_struct;96#define regs_flavor ARM_THREAD_STATE6497 98# if __DARWIN_UNIX0399#  define SP_REG __sp100# else101#  define SP_REG sp102# endif103 104#elif defined(__i386)105typedef x86_thread_state32_t regs_struct;106#define regs_flavor x86_THREAD_STATE32107 108#define SP_REG __esp109 110#else111#error "Unsupported architecture"112#endif113 114ThreadID SuspendedThreadsListMac::GetThreadID(uptr index) const {115  CHECK_LT(index, threads_.size());116  return threads_[index].tid;117}118 119thread_t SuspendedThreadsListMac::GetThread(uptr index) const {120  CHECK_LT(index, threads_.size());121  return threads_[index].thread;122}123 124uptr SuspendedThreadsListMac::ThreadCount() const {125  return threads_.size();126}127 128bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const {129  for (uptr i = 0; i < threads_.size(); i++) {130    if (threads_[i].thread == thread) return true;131  }132  return false;133}134 135void SuspendedThreadsListMac::Append(thread_t thread) {136  thread_identifier_info_data_t info;137  mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT;138  kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO,139                                  (thread_info_t)&info, &info_count);140  if (err != KERN_SUCCESS) {141    VReport(1, "Error - unable to get thread ident for a thread\n");142    return;143  }144  threads_.push_back({info.thread_id, thread});145}146 147PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(148    uptr index, InternalMmapVector<uptr> *buffer, uptr *sp) const {149  thread_t thread = GetThread(index);150  regs_struct regs;151  int err;152  mach_msg_type_number_t reg_count = sizeof(regs) / sizeof(natural_t);153  err = thread_get_state(thread, regs_flavor, (thread_state_t)&regs,154                         &reg_count);155  if (err != KERN_SUCCESS) {156    VReport(1, "Error - unable to get registers for a thread\n");157    // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's158    // still safe to proceed.159    return err == MIG_ARRAY_TOO_LARGE ? REGISTERS_UNAVAILABLE160                                      : REGISTERS_UNAVAILABLE_FATAL;161  }162 163  buffer->resize(RoundUpTo(sizeof(regs), sizeof(uptr)) / sizeof(uptr));164  internal_memcpy(buffer->data(), &regs, sizeof(regs));165#if defined(__aarch64__) && defined(arm_thread_state64_get_sp)166  *sp = arm_thread_state64_get_sp(regs);167#else168  *sp = regs.SP_REG;169#endif170 171  // On x86_64 and aarch64, we must account for the stack redzone, which is 128172  // bytes.173  if (SANITIZER_WORDSIZE == 64) *sp -= 128;174 175  return REGISTERS_AVAILABLE;176}177 178} // namespace __sanitizer179 180#endif  // SANITIZER_APPLE && (defined(__x86_64__) || defined(__aarch64__)) ||181        //                   defined(__i386))182