1 //===-- NativeThreadDarwin.cpp -------------------------------- -*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "NativeThreadDarwin.h" 11 12 // C includes 13 #include <libproc.h> 14 15 // LLDB includes 16 #include "lldb/Utility/Stream.h" 17 18 #include "NativeProcessDarwin.h" 19 20 using namespace lldb; 21 using namespace lldb_private; 22 using namespace lldb_private::process_darwin; 23 24 uint64_t NativeThreadDarwin::GetGloballyUniqueThreadIDForMachPortID( 25 ::thread_t mach_port_id) { 26 thread_identifier_info_data_t tident; 27 mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT; 28 29 auto mach_err = ::thread_info(mach_port_id, THREAD_IDENTIFIER_INFO, 30 (thread_info_t)&tident, &tident_count); 31 if (mach_err != KERN_SUCCESS) { 32 // When we fail to get thread info for the supposed port, assume it is 33 // really a globally unique thread id already, or return the best thing 34 // we can, which is the thread port. 35 return mach_port_id; 36 } 37 return tident.thread_id; 38 } 39 40 NativeThreadDarwin::NativeThreadDarwin(NativeProcessDarwin *process, 41 bool is_64_bit, 42 lldb::tid_t unique_thread_id, 43 ::thread_t mach_thread_port) 44 : NativeThreadProtocol(process, unique_thread_id), 45 m_mach_thread_port(mach_thread_port), m_basic_info(), 46 m_proc_threadinfo() {} 47 48 bool NativeThreadDarwin::GetIdentifierInfo() { 49 // Don't try to get the thread info once and cache it for the life of the 50 // thread. It changes over time, for instance 51 // if the thread name changes, then the thread_handle also changes... So you 52 // have to refetch it every time. 53 mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT; 54 kern_return_t kret = ::thread_info(m_mach_thread_port, THREAD_IDENTIFIER_INFO, 55 (thread_info_t)&m_ident_info, &count); 56 return kret == KERN_SUCCESS; 57 58 return false; 59 } 60 61 std::string NativeThreadDarwin::GetName() { 62 std::string name; 63 64 if (GetIdentifierInfo()) { 65 auto process_sp = GetProcess(); 66 if (!process_sp) { 67 name = "<unavailable>"; 68 return name; 69 } 70 71 int len = ::proc_pidinfo(process_sp->GetID(), PROC_PIDTHREADINFO, 72 m_ident_info.thread_handle, &m_proc_threadinfo, 73 sizeof(m_proc_threadinfo)); 74 75 if (len && m_proc_threadinfo.pth_name[0]) 76 name = m_proc_threadinfo.pth_name; 77 } 78 return name; 79 } 80 81 lldb::StateType NativeThreadDarwin::GetState() { 82 // TODO implement 83 return eStateInvalid; 84 } 85 86 bool NativeThreadDarwin::GetStopReason(ThreadStopInfo &stop_info, 87 std::string &description) { 88 // TODO implement 89 return false; 90 } 91 92 NativeRegisterContextSP NativeThreadDarwin::GetRegisterContext() { 93 // TODO implement 94 return NativeRegisterContextSP(); 95 } 96 97 Status NativeThreadDarwin::SetWatchpoint(lldb::addr_t addr, size_t size, 98 uint32_t watch_flags, bool hardware) { 99 Status error; 100 error.SetErrorString("not yet implemented"); 101 return error; 102 } 103 104 Status NativeThreadDarwin::RemoveWatchpoint(lldb::addr_t addr) { 105 Status error; 106 error.SetErrorString("not yet implemented"); 107 return error; 108 } 109 110 void NativeThreadDarwin::Dump(Stream &stream) const { 111 // This is what we really want once we have the thread class wired up. 112 #if 0 113 DNBLogThreaded("[%3u] #%3u tid: 0x%8.8" PRIx64 ", pc: 0x%16.16" PRIx64 ", sp: 0x%16.16" PRIx64 ", user: %d.%6.6d, system: %d.%6.6d, cpu: %2d, policy: %2d, run_state: %2d (%s), flags: %2d, suspend_count: %2d (current %2d), sleep_time: %d", 114 index, 115 m_seq_id, 116 m_unique_id, 117 GetPC(INVALID_NUB_ADDRESS), 118 GetSP(INVALID_NUB_ADDRESS), 119 m_basic_info.user_time.seconds, m_basic_info.user_time.microseconds, 120 m_basic_info.system_time.seconds, m_basic_info.system_time.microseconds, 121 m_basic_info.cpu_usage, 122 m_basic_info.policy, 123 m_basic_info.run_state, 124 thread_run_state, 125 m_basic_info.flags, 126 m_basic_info.suspend_count, m_suspend_count, 127 m_basic_info.sleep_time); 128 129 #else 130 // Here's all we have right now. 131 stream.Printf("tid: 0x%8.8" PRIx64 ", thread port: 0x%4.4x", GetID(), 132 m_mach_thread_port); 133 #endif 134 } 135 136 bool NativeThreadDarwin::NotifyException(MachException::Data &exc) { 137 // TODO implement this. 138 #if 0 139 // Allow the arch specific protocol to process (MachException::Data &)exc 140 // first before possible reassignment of m_stop_exception with exc. 141 // See also MachThread::GetStopException(). 142 bool handled = m_arch_ap->NotifyException(exc); 143 144 if (m_stop_exception.IsValid()) 145 { 146 // We may have more than one exception for a thread, but we need to 147 // only remember the one that we will say is the reason we stopped. 148 // We may have been single stepping and also gotten a signal exception, 149 // so just remember the most pertinent one. 150 if (m_stop_exception.IsBreakpoint()) 151 m_stop_exception = exc; 152 } 153 else 154 { 155 m_stop_exception = exc; 156 } 157 158 return handled; 159 #else 160 // Pretend we handled it. 161 return true; 162 #endif 163 } 164 165 bool NativeThreadDarwin::ShouldStop(bool &step_more) const { 166 // TODO: implement this 167 #if 0 168 // See if this thread is at a breakpoint? 169 DNBBreakpoint *bp = CurrentBreakpoint(); 170 171 if (bp) 172 { 173 // This thread is sitting at a breakpoint, ask the breakpoint 174 // if we should be stopping here. 175 return true; 176 } 177 else 178 { 179 if (m_arch_ap->StepNotComplete()) 180 { 181 step_more = true; 182 return false; 183 } 184 // The thread state is used to let us know what the thread was 185 // trying to do. MachThread::ThreadWillResume() will set the 186 // thread state to various values depending if the thread was 187 // the current thread and if it was to be single stepped, or 188 // resumed. 189 if (GetState() == eStateRunning) 190 { 191 // If our state is running, then we should continue as we are in 192 // the process of stepping over a breakpoint. 193 return false; 194 } 195 else 196 { 197 // Stop if we have any kind of valid exception for this 198 // thread. 199 if (GetStopException().IsValid()) 200 return true; 201 } 202 } 203 return false; 204 #else 205 return false; 206 #endif 207 } 208 209 void NativeThreadDarwin::ThreadDidStop() { 210 // TODO implement this. 211 #if 0 212 // This thread has existed prior to resuming under debug nub control, 213 // and has just been stopped. Do any cleanup that needs to be done 214 // after running. 215 216 // The thread state and breakpoint will still have the same values 217 // as they had prior to resuming the thread, so it makes it easy to check 218 // if we were trying to step a thread, or we tried to resume while being 219 // at a breakpoint. 220 221 // When this method gets called, the process state is still in the 222 // state it was in while running so we can act accordingly. 223 m_arch_ap->ThreadDidStop(); 224 225 226 // We may have suspended this thread so the primary thread could step 227 // without worrying about race conditions, so lets restore our suspend 228 // count. 229 RestoreSuspendCountAfterStop(); 230 231 // Update the basic information for a thread 232 MachThread::GetBasicInfo(m_mach_port_number, &m_basic_info); 233 234 if (m_basic_info.suspend_count > 0) 235 SetState(eStateSuspended); 236 else 237 SetState(eStateStopped); 238 #endif 239 } 240 241 bool NativeThreadDarwin::MachPortNumberIsValid(::thread_t thread) { 242 return thread != (::thread_t)(0); 243 } 244 245 const struct thread_basic_info *NativeThreadDarwin::GetBasicInfo() const { 246 if (GetBasicInfo(m_mach_thread_port, &m_basic_info)) 247 return &m_basic_info; 248 return NULL; 249 } 250 251 bool NativeThreadDarwin::GetBasicInfo(::thread_t thread, 252 struct thread_basic_info *basicInfoPtr) { 253 if (MachPortNumberIsValid(thread)) { 254 unsigned int info_count = THREAD_BASIC_INFO_COUNT; 255 kern_return_t err = ::thread_info(thread, THREAD_BASIC_INFO, 256 (thread_info_t)basicInfoPtr, &info_count); 257 if (err == KERN_SUCCESS) 258 return true; 259 } 260 ::memset(basicInfoPtr, 0, sizeof(struct thread_basic_info)); 261 return false; 262 } 263 264 bool NativeThreadDarwin::IsUserReady() const { 265 if (m_basic_info.run_state == 0) 266 GetBasicInfo(); 267 268 switch (m_basic_info.run_state) { 269 default: 270 case TH_STATE_UNINTERRUPTIBLE: 271 break; 272 273 case TH_STATE_RUNNING: 274 case TH_STATE_STOPPED: 275 case TH_STATE_WAITING: 276 case TH_STATE_HALTED: 277 return true; 278 } 279 return false; 280 } 281 282 NativeProcessDarwinSP NativeThreadDarwin::GetNativeProcessDarwinSP() { 283 return std::static_pointer_cast<NativeProcessDarwin>(GetProcess()); 284 } 285