| 1 | //===-- MachThread.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-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | // |
| 9 | // Created by Greg Clayton on 6/19/07. |
| 10 | // |
| 11 | //===----------------------------------------------------------------------===// |
| 12 | |
| 13 | #ifndef LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_MACHTHREAD_H |
| 14 | #define LLDB_TOOLS_DEBUGSERVER_SOURCE_MACOSX_MACHTHREAD_H |
| 15 | |
| 16 | #include <mutex> |
| 17 | #include <string> |
| 18 | #include <vector> |
| 19 | |
| 20 | #include <libproc.h> |
| 21 | #include <mach/mach.h> |
| 22 | #include <pthread.h> |
| 23 | #include <sys/signal.h> |
| 24 | |
| 25 | #include "DNBArch.h" |
| 26 | #include "DNBRegisterInfo.h" |
| 27 | #include "MachException.h" |
| 28 | |
| 29 | #include "ThreadInfo.h" |
| 30 | |
| 31 | class DNBBreakpoint; |
| 32 | class MachProcess; |
| 33 | class MachThreadList; |
| 34 | |
| 35 | class MachThread { |
| 36 | public: |
| 37 | MachThread(MachProcess *process, bool is_64_bit, |
| 38 | uint64_t unique_thread_id = 0, thread_t mach_port_number = 0); |
| 39 | ~MachThread(); |
| 40 | |
| 41 | MachProcess *Process() { return m_process; } |
| 42 | const MachProcess *Process() const { return m_process; } |
| 43 | nub_process_t ProcessID() const; |
| 44 | void Dump(uint32_t index); |
| 45 | uint64_t ThreadID() const { return m_unique_id; } |
| 46 | thread_t MachPortNumber() const { return m_mach_port_number; } |
| 47 | thread_t InferiorThreadID() const; |
| 48 | |
| 49 | uint32_t SequenceID() const { return m_seq_id; } |
| 50 | static bool ThreadIDIsValid( |
| 51 | uint64_t thread); // The 64-bit system-wide unique thread identifier |
| 52 | static bool MachPortNumberIsValid(thread_t thread); // The mach port # for |
| 53 | // this thread in |
| 54 | // debugserver namespace |
| 55 | void Resume(bool others_stopped); |
| 56 | void Suspend(); |
| 57 | bool SetSuspendCountBeforeResume(bool others_stopped); |
| 58 | bool RestoreSuspendCountAfterStop(); |
| 59 | |
| 60 | bool GetRegisterState(int flavor, bool force); |
| 61 | bool SetRegisterState(int flavor); |
| 62 | uint64_t |
| 63 | GetPC(uint64_t failValue = INVALID_NUB_ADDRESS); // Get program counter |
| 64 | bool SetPC(uint64_t value); // Set program counter |
| 65 | uint64_t GetSP(uint64_t failValue = INVALID_NUB_ADDRESS); // Get stack pointer |
| 66 | |
| 67 | DNBBreakpoint *CurrentBreakpoint(); |
| 68 | uint32_t EnableHardwareBreakpoint(const DNBBreakpoint *breakpoint, |
| 69 | bool also_set_on_task); |
| 70 | uint32_t EnableHardwareWatchpoint(const DNBBreakpoint *watchpoint, |
| 71 | bool also_set_on_task); |
| 72 | bool DisableHardwareBreakpoint(const DNBBreakpoint *breakpoint, |
| 73 | bool also_set_on_task); |
| 74 | bool DisableHardwareWatchpoint(const DNBBreakpoint *watchpoint, |
| 75 | bool also_set_on_task); |
| 76 | uint32_t NumSupportedHardwareWatchpoints() const; |
| 77 | bool RollbackTransForHWP(); |
| 78 | bool FinishTransForHWP(); |
| 79 | |
| 80 | nub_state_t GetState(); |
| 81 | void SetState(nub_state_t state); |
| 82 | |
| 83 | void ThreadWillResume(const DNBThreadResumeAction *thread_action, |
| 84 | bool others_stopped = false); |
| 85 | bool ShouldStop(bool &step_more); |
| 86 | bool IsStepping(); |
| 87 | bool ThreadDidStop(); |
| 88 | bool NotifyException(MachException::Data &exc); |
| 89 | const MachException::Data &GetStopException() { return m_stop_exception; } |
| 90 | |
| 91 | nub_size_t GetNumRegistersInSet(nub_size_t regSet) const; |
| 92 | const char *GetRegisterSetName(nub_size_t regSet) const; |
| 93 | const DNBRegisterInfo *GetRegisterInfo(nub_size_t regSet, |
| 94 | nub_size_t regIndex) const; |
| 95 | void DumpRegisterState(nub_size_t regSet); |
| 96 | const DNBRegisterSetInfo *GetRegisterSetInfo(nub_size_t *num_reg_sets) const; |
| 97 | bool GetRegisterValue(uint32_t reg_set_idx, uint32_t reg_idx, |
| 98 | DNBRegisterValue *reg_value); |
| 99 | bool SetRegisterValue(uint32_t reg_set_idx, uint32_t reg_idx, |
| 100 | const DNBRegisterValue *reg_value); |
| 101 | nub_size_t GetRegisterContext(void *buf, nub_size_t buf_len); |
| 102 | nub_size_t SetRegisterContext(const void *buf, nub_size_t buf_len); |
| 103 | uint32_t SaveRegisterState(); |
| 104 | bool RestoreRegisterState(uint32_t save_id); |
| 105 | |
| 106 | void NotifyBreakpointChanged(const DNBBreakpoint *bp) {} |
| 107 | |
| 108 | bool IsUserReady(); |
| 109 | struct thread_basic_info *GetBasicInfo(); |
| 110 | struct thread_extended_info *GetExtendedInfo(); |
| 111 | const char *GetBasicInfoAsString() const; |
| 112 | const char *GetName(); |
| 113 | |
| 114 | DNBArchProtocol *GetArchProtocol() { return m_arch_up.get(); } |
| 115 | |
| 116 | ThreadInfo::QoS GetRequestedQoS(nub_addr_t tsd, uint64_t dti_qos_class_index); |
| 117 | nub_addr_t GetPThreadT(); |
| 118 | nub_addr_t GetDispatchQueueT(); |
| 119 | nub_addr_t |
| 120 | GetTSDAddressForThread(uint64_t plo_pthread_tsd_base_address_offset, |
| 121 | uint64_t plo_pthread_tsd_base_offset, |
| 122 | uint64_t plo_pthread_tsd_entry_size); |
| 123 | |
| 124 | static uint64_t GetGloballyUniqueThreadIDForMachPortID(thread_t mach_port_id); |
| 125 | |
| 126 | protected: |
| 127 | static bool GetBasicInfo(thread_t threadID, |
| 128 | struct thread_basic_info *basic_info); |
| 129 | static bool GetExtendedInfo(thread_t threadID, |
| 130 | struct thread_extended_info *extended_info); |
| 131 | |
| 132 | // const char * |
| 133 | // GetDispatchQueueName(); |
| 134 | // |
| 135 | MachProcess *m_process; // The process that owns this thread |
| 136 | uint64_t m_unique_id; // The globally unique ID for this thread (nub_thread_t) |
| 137 | thread_t m_mach_port_number; // The mach port # for this thread in debugserver |
| 138 | // namesp. |
| 139 | uint32_t m_seq_id; // A Sequential ID that increments with each new thread |
| 140 | nub_state_t m_state; // The state of our process |
| 141 | std::recursive_mutex m_state_mutex; // Multithreaded protection for m_state |
| 142 | struct thread_basic_info m_basic_info; // Basic information for a thread used |
| 143 | // to see if a thread is valid |
| 144 | int32_t m_suspend_count; // The current suspend count > 0 means we have |
| 145 | // suspended m_suspendCount times, |
| 146 | // < 0 means we have resumed it m_suspendCount |
| 147 | // times. |
| 148 | MachException::Data m_stop_exception; // The best exception that describes why |
| 149 | // this thread is stopped |
| 150 | std::unique_ptr<DNBArchProtocol> |
| 151 | m_arch_up; // Arch specific information for register state and more |
| 152 | const DNBRegisterSetInfo |
| 153 | *m_reg_sets; // Register set information for this thread |
| 154 | nub_size_t m_num_reg_sets; |
| 155 | thread_extended_info_data_t m_extended_info; |
| 156 | std::string m_dispatch_queue_name; |
| 157 | bool m_is_64_bit; |
| 158 | |
| 159 | // qos_class_t _pthread_qos_class_decode(pthread_priority_t priority, int *, |
| 160 | // unsigned long *); |
| 161 | unsigned int (*m_pthread_qos_class_decode)(unsigned long priority, int *, |
| 162 | unsigned long *); |
| 163 | |
| 164 | private: |
| 165 | friend class MachThreadList; |
| 166 | }; |
| 167 | |
| 168 | typedef std::shared_ptr<MachThread> MachThreadSP; |
| 169 | |
| 170 | #endif |
| 171 | |