brintos

brintos / llvm-project-archived public Read only

0
0
Text · 21.2 KiB · 67b27b9 Raw
499 lines · c
1//===-- MachProcess.h -------------------------------------------*- C++ -*-===//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//  Created by Greg Clayton on 6/15/07.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_MACHPROCESS_H14#define LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_MACHPROCESS_H15 16#include <CoreFoundation/CoreFoundation.h>17#include <mach-o/loader.h>18#include <mach/mach.h>19#include <optional>20#include <pthread.h>21#include <sys/signal.h>22#include <uuid/uuid.h>23#include <vector>24 25#include "DNBBreakpoint.h"26#include "DNBDefs.h"27#include "DNBError.h"28#include "DNBThreadResumeActions.h"29#include "Genealogy.h"30#include "JSONGenerator.h"31#include "MachException.h"32#include "MachTask.h"33#include "MachThreadList.h"34#include "MachVMMemory.h"35#include "PThreadCondition.h"36#include "PThreadEvent.h"37#include "RNBContext.h"38#include "ThreadInfo.h"39 40class DNBThreadResumeActions;41 42class MachProcess {43public:44  // Constructors and Destructors45  MachProcess();46  ~MachProcess();47 48  // A structure that can hold everything debugserver needs to know from49  // a binary's Mach-O header / load commands.50 51  struct mach_o_segment {52    std::string name;53    uint64_t vmaddr;54    uint64_t vmsize;55    uint64_t fileoff;56    uint64_t filesize;57    uint64_t maxprot;58    uint64_t initprot;59    uint64_t nsects;60    uint64_t flags;61  };62 63  struct mach_o_information {64    struct mach_header_64 mach_header;65    std::vector<struct mach_o_segment> segments;66    uuid_t uuid;67    std::string min_version_os_name;68    std::string min_version_os_version;69  };70 71  struct binary_image_information {72    std::string filename;73    uint64_t load_address;74    struct mach_o_information macho_info;75    bool is_valid_mach_header;76 77    binary_image_information()78        : filename(), load_address(INVALID_NUB_ADDRESS),79          is_valid_mach_header(false) {}80  };81 82  // Child process control83  pid_t AttachForDebug(pid_t pid,84                       const RNBContext::IgnoredExceptions &ignored_exceptions,85                       char *err_str,86                       size_t err_len);87  pid_t LaunchForDebug(const char *path, char const *argv[], char const *envp[],88                       const char *working_directory, const char *stdin_path,89                       const char *stdout_path, const char *stderr_path,90                       bool no_stdio, nub_launch_flavor_t launch_flavor,91                       int disable_aslr, const char *event_data,92                       const RNBContext::IgnoredExceptions &ignored_exceptions,93                       DNBError &err);94 95  static uint32_t GetCPUTypeForLocalProcess(pid_t pid);96  static pid_t ForkChildForPTraceDebugging(const char *path, char const *argv[],97                                           char const *envp[],98                                           MachProcess *process, DNBError &err);99  static pid_t PosixSpawnChildForPTraceDebugging(100      const char *path, cpu_type_t cpu_type, cpu_subtype_t cpu_subtype,101      char const *argv[], char const *envp[], const char *working_directory,102      const char *stdin_path, const char *stdout_path, const char *stderr_path,103      bool no_stdio, MachProcess *process, int disable_aslr, DNBError &err);104  nub_addr_t GetDYLDAllImageInfosAddress();105  std::optional<std::pair<cpu_type_t, cpu_subtype_t>>106  GetMainBinaryCPUTypes(nub_process_t pid);107  static const void *PrepareForAttach(const char *path,108                                      nub_launch_flavor_t launch_flavor,109                                      bool waitfor, DNBError &err_str);110  static void CleanupAfterAttach(const void *attach_token,111                                 nub_launch_flavor_t launch_flavor,112                                 bool success, DNBError &err_str);113  static nub_process_t CheckForProcess(const void *attach_token,114                                       nub_launch_flavor_t launch_flavor);115#if defined(WITH_BKS) || defined(WITH_FBS)116  pid_t BoardServiceLaunchForDebug(const char *app_bundle_path,117                                   char const *argv[], char const *envp[],118                                   bool no_stdio, bool disable_aslr,119                                   const char *event_data,120                                   const RNBContext::IgnoredExceptions &ignored_exceptions,121                                   DNBError &launch_err);122  pid_t BoardServiceForkChildForPTraceDebugging(123      const char *path, char const *argv[], char const *envp[], bool no_stdio,124      bool disable_aslr, const char *event_data, DNBError &launch_err);125  bool BoardServiceSendEvent(const char *event, DNBError &error);126#endif127  static bool GetOSVersionNumbers(uint64_t *major, uint64_t *minor,128                                  uint64_t *patch);129  static std::string GetMacCatalystVersionString();130 131  static nub_process_t GetParentProcessID(nub_process_t child_pid);132 133  static bool ProcessIsBeingDebugged(nub_process_t pid);134 135#ifdef WITH_BKS136  static void BKSCleanupAfterAttach(const void *attach_token,137                                    DNBError &err_str);138#endif // WITH_BKS139#ifdef WITH_FBS140  static void FBSCleanupAfterAttach(const void *attach_token,141                                    DNBError &err_str);142#endif // WITH_FBS143#ifdef WITH_SPRINGBOARD144  pid_t SBLaunchForDebug(const char *app_bundle_path, char const *argv[],145                         char const *envp[], bool no_stdio, bool disable_aslr,146                         bool unmask_signals, DNBError &launch_err);147  static pid_t SBForkChildForPTraceDebugging(const char *path,148                                             char const *argv[],149                                             char const *envp[], bool no_stdio,150                                             MachProcess *process,151                                             DNBError &launch_err);152#endif // WITH_SPRINGBOARD153  nub_addr_t LookupSymbol(const char *name, const char *shlib);154  void SetNameToAddressCallback(DNBCallbackNameToAddress callback,155                                void *baton) {156    m_name_to_addr_callback = callback;157    m_name_to_addr_baton = baton;158  }159  void160  SetSharedLibraryInfoCallback(DNBCallbackCopyExecutableImageInfos callback,161                               void *baton) {162    m_image_infos_callback = callback;163    m_image_infos_baton = baton;164  }165 166  bool Resume(const DNBThreadResumeActions &thread_actions);167  bool Signal(int signal, const struct timespec *timeout_abstime = NULL);168  bool Interrupt();169  bool SendEvent(const char *event, DNBError &send_err);170  bool Kill(const struct timespec *timeout_abstime = NULL);171  bool Detach();172  nub_size_t ReadMemory(nub_addr_t addr, nub_size_t size, void *buf);173  nub_size_t WriteMemory(nub_addr_t addr, nub_size_t size, const void *buf);174 175  // Path and arg accessors176  const char *Path() const { return m_path.c_str(); }177  size_t ArgumentCount() const { return m_args.size(); }178  const char *ArgumentAtIndex(size_t arg_idx) const {179    if (arg_idx < m_args.size())180      return m_args[arg_idx].c_str();181    return NULL;182  }183 184  // Breakpoint functions185  DNBBreakpoint *CreateBreakpoint(nub_addr_t addr, nub_size_t length,186                                  bool hardware);187  bool DisableBreakpoint(nub_addr_t addr, bool remove);188  void DisableAllBreakpoints(bool remove);189  bool EnableBreakpoint(nub_addr_t addr);190  DNBBreakpointList &Breakpoints() { return m_breakpoints; }191  const DNBBreakpointList &Breakpoints() const { return m_breakpoints; }192 193  // Watchpoint functions194  DNBBreakpoint *CreateWatchpoint(nub_addr_t addr, nub_size_t length,195                                  uint32_t watch_type, bool hardware);196  bool DisableWatchpoint(nub_addr_t addr, bool remove);197  void DisableAllWatchpoints(bool remove);198  bool EnableWatchpoint(nub_addr_t addr);199  uint32_t GetNumSupportedHardwareWatchpoints() const;200  DNBBreakpointList &Watchpoints() { return m_watchpoints; }201  const DNBBreakpointList &Watchpoints() const { return m_watchpoints; }202 203  // Exception thread functions204  bool StartSTDIOThread();205  static void *STDIOThread(void *arg);206  void ExceptionMessageReceived(const MachException::Message &exceptionMessage);207  task_t ExceptionMessageBundleComplete();208  void SharedLibrariesUpdated();209  nub_size_t CopyImageInfos(struct DNBExecutableImageInfo **image_infos,210                            bool only_changed);211 212  // Profile functions213  void SetEnableAsyncProfiling(bool enable, uint64_t internal_usec,214                               DNBProfileDataScanType scan_type);215  bool IsProfilingEnabled() { return m_profile_enabled; }216  useconds_t ProfileInterval() { return m_profile_interval_usec; }217  bool StartProfileThread();218  static void *ProfileThread(void *arg);219  void SignalAsyncProfileData(const char *info);220  size_t GetAsyncProfileData(char *buf, size_t buf_size);221 222  // Accessors223  pid_t ProcessID() const { return m_pid; }224  bool ProcessIDIsValid() const { return m_pid > 0; }225  pid_t SetProcessID(pid_t pid);226  MachTask &Task() { return m_task; }227  const MachTask &Task() const { return m_task; }228 229  PThreadEvent &Events() { return m_events; }230  const DNBRegisterSetInfo *GetRegisterSetInfo(nub_thread_t tid,231                                               nub_size_t *num_reg_sets) const;232  bool GetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg,233                        DNBRegisterValue *reg_value) const;234  bool SetRegisterValue(nub_thread_t tid, uint32_t set, uint32_t reg,235                        const DNBRegisterValue *value) const;236  nub_bool_t SyncThreadState(nub_thread_t tid);237  const char *ThreadGetName(nub_thread_t tid);238  nub_state_t ThreadGetState(nub_thread_t tid);239  ThreadInfo::QoS GetRequestedQoS(nub_thread_t tid, nub_addr_t tsd,240                                  uint64_t dti_qos_class_index);241  nub_addr_t GetPThreadT(nub_thread_t tid);242  nub_addr_t GetDispatchQueueT(nub_thread_t tid);243  nub_addr_t244  GetTSDAddressForThread(nub_thread_t tid,245                         uint64_t plo_pthread_tsd_base_address_offset,246                         uint64_t plo_pthread_tsd_base_offset,247                         uint64_t plo_pthread_tsd_entry_size);248 249  struct DeploymentInfo {250    DeploymentInfo() = default;251    operator bool() { return platform > 0; }252    /// The Mach-O platform type;253    unsigned char platform = 0;254    uint32_t major_version = 0;255    uint32_t minor_version = 0;256    uint32_t patch_version = 0;257  };258  DeploymentInfo GetDeploymentInfo(const struct load_command &,259                                   uint64_t load_command_address,260                                   bool is_executable);261  static std::optional<std::string> GetPlatformString(unsigned char platform);262  bool GetMachOInformationFromMemory(uint32_t platform,263                                     nub_addr_t mach_o_header_addr,264                                     int wordsize,265                                     struct mach_o_information &inf);266  JSONGenerator::ObjectSP FormatDynamicLibrariesIntoJSON(267      const std::vector<struct binary_image_information> &image_infos,268      bool report_load_commands);269  uint32_t GetPlatform();270  /// Get the runtime platform from DYLD via SPI.271  uint32_t GetProcessPlatformViaDYLDSPI();272  /// Use the dyld SPI present in macOS 10.12, iOS 10, tvOS 10,273  /// watchOS 3 and newer to get the load address, uuid, and filenames274  /// of all the libraries.  This only fills in those three fields in275  /// the 'struct binary_image_information' - call276  /// GetMachOInformationFromMemory to fill in the mach-o header/load277  /// command details.278  void GetAllLoadedBinariesViaDYLDSPI(279      std::vector<struct binary_image_information> &image_infos);280  JSONGenerator::ObjectSP281  GetLibrariesInfoForAddresses(nub_process_t pid,282                               std::vector<uint64_t> &macho_addresses);283  JSONGenerator::ObjectSP284  GetAllLoadedLibrariesInfos(nub_process_t pid,285                             bool fetch_report_load_commands);286  bool GetDebugserverSharedCacheInfo(uuid_t &uuid,287                                     std::string &shared_cache_path);288  bool GetInferiorSharedCacheFilepath(std::string &inferior_sc_path);289  JSONGenerator::ObjectSP GetInferiorSharedCacheInfo(nub_process_t pid);290 291  nub_size_t GetNumThreads() const;292  nub_thread_t GetThreadAtIndex(nub_size_t thread_idx) const;293  nub_thread_t GetCurrentThread();294  nub_thread_t GetCurrentThreadMachPort();295  nub_thread_t SetCurrentThread(nub_thread_t tid);296  MachThreadList &GetThreadList() { return m_thread_list; }297  bool GetThreadStoppedReason(nub_thread_t tid,298                              struct DNBThreadStopInfo *stop_info);299  void DumpThreadStoppedReason(nub_thread_t tid) const;300  const char *GetThreadInfo(nub_thread_t tid) const;301 302  nub_thread_t GetThreadIDForMachPortNumber(thread_t mach_port_number) const;303 304  uint32_t GetCPUType();305  nub_state_t GetState();306  void SetState(nub_state_t state);307  bool IsRunning(nub_state_t state) {308    return state == eStateRunning || IsStepping(state);309  }310  bool IsStepping(nub_state_t state) { return state == eStateStepping; }311  bool CanResume(nub_state_t state) { return state == eStateStopped; }312 313  bool GetExitStatus(int *status) {314    if (GetState() == eStateExited) {315      if (status)316        *status = m_exit_status;317      return true;318    }319    return false;320  }321  void SetExitStatus(int status) {322    m_exit_status = status;323    SetState(eStateExited);324  }325  const char *GetExitInfo() { return m_exit_info.c_str(); }326 327  void SetExitInfo(const char *info);328 329  uint32_t StopCount() const { return m_stop_count; }330  void SetChildFileDescriptors(int stdin_fileno, int stdout_fileno,331                               int stderr_fileno) {332    m_child_stdin = stdin_fileno;333    m_child_stdout = stdout_fileno;334    m_child_stderr = stderr_fileno;335  }336 337  int GetStdinFileDescriptor() const { return m_child_stdin; }338  int GetStdoutFileDescriptor() const { return m_child_stdout; }339  int GetStderrFileDescriptor() const { return m_child_stderr; }340  void AppendSTDOUT(char *s, size_t len);341  size_t GetAvailableSTDOUT(char *buf, size_t buf_size);342  size_t GetAvailableSTDERR(char *buf, size_t buf_size);343  void CloseChildFileDescriptors() {344    if (m_child_stdin >= 0) {345      ::close(m_child_stdin);346      m_child_stdin = -1;347    }348    if (m_child_stdout >= 0) {349      ::close(m_child_stdout);350      m_child_stdout = -1;351    }352    if (m_child_stderr >= 0) {353      ::close(m_child_stderr);354      m_child_stderr = -1;355    }356  }357 358  void CalculateBoardStatus();359 360  bool ProcessUsingBackBoard();361 362  bool ProcessUsingFrontBoard();363 364  // Size of addresses in the inferior process (4 or 8).365  int GetInferiorAddrSize(pid_t pid);366 367  Genealogy::ThreadActivitySP GetGenealogyInfoForThread(nub_thread_t tid,368                                                        bool &timed_out);369 370  Genealogy::ProcessExecutableInfoSP GetGenealogyImageInfo(size_t idx);371 372  DNBProfileDataScanType GetProfileScanType() { return m_profile_scan_type; }373 374  JSONGenerator::ObjectSP GetDyldProcessState();375 376private:377  enum {378    eMachProcessFlagsNone = 0,379    eMachProcessFlagsAttached = (1 << 0),380    eMachProcessFlagsUsingBKS = (1 << 2), // only read via ProcessUsingBackBoard()381    eMachProcessFlagsUsingFBS = (1 << 3), // only read via ProcessUsingFrontBoard()382    eMachProcessFlagsBoardCalculated = (1 << 4)383  };384 385  enum {386    eMachProcessProfileNone = 0,387    eMachProcessProfileCancel = (1 << 0)388  };389 390  void Clear(bool detaching = false);391  void ReplyToAllExceptions();392  void PrivateResume();393  void StopProfileThread();394 395  void RefineWatchpointStopInfo(nub_thread_t tid,396                                struct DNBThreadStopInfo *stop_info);397 398  uint32_t Flags() const { return m_flags; }399  nub_state_t DoSIGSTOP(bool clear_bps_and_wps, bool allow_running,400                        uint32_t *thread_idx_ptr);401 402  pid_t m_pid;           // Process ID of child process403  cpu_type_t m_cpu_type; // The CPU type of this process404  uint32_t m_platform;   // The platform of this process405  int m_child_stdin;406  int m_child_stdout;407  int m_child_stderr;408  std::string m_path; // A path to the executable if we have one409  std::vector<std::string>410      m_args;              // The arguments with which the process was lauched411  int m_exit_status;       // The exit status for the process412  std::string m_exit_info; // Any extra info that we may have about the exit413  MachTask m_task;         // The mach task for this process414  uint32_t m_flags;      // Process specific flags (see eMachProcessFlags enums)415  uint32_t m_stop_count; // A count of many times have we stopped416  pthread_t m_stdio_thread;   // Thread ID for the thread that watches for child417                              // process stdio418  std::recursive_mutex m_stdio_mutex; // Multithreaded protection for stdio419  std::string m_stdout_data;420 421  bool m_profile_enabled; // A flag to indicate if profiling is enabled422  useconds_t m_profile_interval_usec; // If enable, the profiling interval in423                                      // microseconds424  DNBProfileDataScanType425      m_profile_scan_type; // Indicates what needs to be profiled426  pthread_t427      m_profile_thread; // Thread ID for the thread that profiles the inferior428  std::recursive_mutex429      m_profile_data_mutex; // Multithreaded protection for profile info data430  std::vector<std::string>431      m_profile_data; // Profile data, must be protected by m_profile_data_mutex432  PThreadEvent m_profile_events; // Used for the profile thread cancellable wait433  DNBThreadResumeActions m_thread_actions; // The thread actions for the current434                                           // MachProcess::Resume() call435  MachException::Message::collection m_exception_messages; // A collection of436                                                           // exception messages437                                                           // caught when438                                                           // listening to the439                                                           // exception port440  std::recursive_mutex441      m_exception_and_signal_mutex; // Multithreaded protection for442                                    // exceptions and signals.443 444  MachThreadList m_thread_list; // A list of threads that is maintained/updated445                                // after each stop446  Genealogy m_activities; // A list of activities that is updated after every447                          // stop lazily448  nub_state_t m_state;    // The state of our process449  std::recursive_mutex m_state_mutex; // Multithreaded protection for m_state450  PThreadEvent m_events;      // Process related events in the child processes451                              // lifetime can be waited upon452  PThreadEvent m_private_events; // Used to coordinate running and stopping the453                                 // process without affecting m_events454  DNBBreakpointList m_breakpoints; // Breakpoint list for this process455  DNBBreakpointList m_watchpoints; // Watchpoint list for this process456  DNBCallbackNameToAddress m_name_to_addr_callback;457  void *m_name_to_addr_baton;458  DNBCallbackCopyExecutableImageInfos m_image_infos_callback;459  void *m_image_infos_baton;460  std::string461      m_bundle_id; // If we are a SB or BKS process, this will be our bundle ID.462  int m_sent_interrupt_signo; // When we call MachProcess::Interrupt(), we want463                              // to send a single signal464  // to the inferior and only send the signal if we aren't already stopped.465  // If we end up sending a signal to stop the process we store it until we466  // receive an exception with this signal. This helps us to verify we got467  // the signal that interrupted the process. We might stop due to another468  // reason after an interrupt signal is sent, so this helps us ensure that469  // we don't report a spurious stop on the next resume.470  int m_auto_resume_signo; // If we resume the process and still haven't471                           // received our interrupt signal472  // acknowledgement, we will shortly after the next resume. We store the473  // interrupt signal in this variable so when we get the interrupt signal474  // as the sole reason for the process being stopped, we can auto resume475  // the process.476  bool m_did_exec;477 478  void *(*m_dyld_process_info_create)(task_t task, uint64_t timestamp,479                                      kern_return_t *kernelError);480  void *(*m_dyld_process_create_for_task)(task_read_t task, kern_return_t *kr);481  void *(*m_dyld_process_snapshot_create_for_process)(void *process,482                                                      kern_return_t *kr);483  void *(*m_dyld_process_snapshot_get_shared_cache)(void *snapshot);484  void (*m_dyld_shared_cache_for_each_file)(485      void *cache, void (^block)(const char *file_path));486  void (*m_dyld_process_snapshot_dispose)(void *snapshot);487  void (*m_dyld_process_dispose)(void *process);488  void (*m_dyld_process_info_for_each_image)(489      void *info, void (^callback)(uint64_t machHeaderAddress,490                                   const uuid_t uuid, const char *path));491  void (*m_dyld_process_info_release)(void *info);492  void (*m_dyld_process_info_get_cache)(void *info, void *cacheInfo);493  uint32_t (*m_dyld_process_info_get_platform)(void *info);494  void (*m_dyld_process_info_get_state)(void *info, void *stateInfo);495  const char *(*m_dyld_shared_cache_file_path)();496};497 498#endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_MACHPROCESS_H499