1 //===-- SBThread.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 "lldb/API/SBThread.h" 11 12 #include "lldb/API/SBSymbolContext.h" 13 #include "lldb/API/SBFileSpec.h" 14 #include "lldb/Core/Debugger.h" 15 #include "lldb/Core/Stream.h" 16 #include "lldb/Core/StreamFile.h" 17 #include "lldb/Interpreter/CommandInterpreter.h" 18 #include "lldb/Target/Thread.h" 19 #include "lldb/Target/Process.h" 20 #include "lldb/Symbol/SymbolContext.h" 21 #include "lldb/Symbol/CompileUnit.h" 22 #include "lldb/Target/Target.h" 23 #include "lldb/Target/ThreadPlan.h" 24 #include "lldb/Target/ThreadPlanStepInstruction.h" 25 #include "lldb/Target/ThreadPlanStepOut.h" 26 #include "lldb/Target/ThreadPlanStepRange.h" 27 #include "lldb/Target/ThreadPlanStepInRange.h" 28 29 30 #include "lldb/API/SBAddress.h" 31 #include "lldb/API/SBFrame.h" 32 #include "lldb/API/SBSourceManager.h" 33 #include "lldb/API/SBDebugger.h" 34 #include "lldb/API/SBProcess.h" 35 36 using namespace lldb; 37 using namespace lldb_private; 38 39 SBThread::SBThread () : 40 m_opaque_sp () 41 { 42 } 43 44 //---------------------------------------------------------------------- 45 // Thread constructor 46 //---------------------------------------------------------------------- 47 SBThread::SBThread (const ThreadSP& lldb_object_sp) : 48 m_opaque_sp (lldb_object_sp) 49 { 50 } 51 52 SBThread::SBThread (const SBThread &rhs) 53 { 54 m_opaque_sp = rhs.m_opaque_sp; 55 } 56 57 //---------------------------------------------------------------------- 58 // Destructor 59 //---------------------------------------------------------------------- 60 SBThread::~SBThread() 61 { 62 } 63 64 bool 65 SBThread::IsValid() const 66 { 67 return m_opaque_sp != NULL; 68 } 69 70 StopReason 71 SBThread::GetStopReason() 72 { 73 if (m_opaque_sp) 74 { 75 lldb_private::Thread::StopInfo thread_stop_info; 76 if (m_opaque_sp->GetStopInfo(&thread_stop_info)) 77 return thread_stop_info.GetStopReason(); 78 } 79 return eStopReasonInvalid; 80 } 81 82 size_t 83 SBThread::GetStopDescription (char *dst, size_t dst_len) 84 { 85 if (m_opaque_sp) 86 { 87 lldb_private::Thread::StopInfo thread_stop_info; 88 if (m_opaque_sp->GetStopInfo(&thread_stop_info)) 89 { 90 const char *stop_desc = thread_stop_info.GetStopDescription(); 91 if (stop_desc) 92 { 93 if (dst) 94 return ::snprintf (dst, dst_len, "%s", stop_desc); 95 else 96 { 97 // NULL dst passed in, return the length needed to contain the description 98 return ::strlen (stop_desc) + 1; // Include the NULL byte for size 99 } 100 } 101 else 102 { 103 size_t stop_desc_len = 0; 104 switch (thread_stop_info.GetStopReason()) 105 { 106 case eStopReasonTrace: 107 case eStopReasonPlanComplete: 108 { 109 static char trace_desc[] = "step"; 110 stop_desc = trace_desc; 111 stop_desc_len = sizeof(trace_desc); // Include the NULL byte for size 112 } 113 break; 114 115 case eStopReasonBreakpoint: 116 { 117 static char bp_desc[] = "breakpoint hit"; 118 stop_desc = bp_desc; 119 stop_desc_len = sizeof(bp_desc); // Include the NULL byte for size 120 } 121 break; 122 123 case eStopReasonWatchpoint: 124 { 125 static char wp_desc[] = "watchpoint hit"; 126 stop_desc = wp_desc; 127 stop_desc_len = sizeof(wp_desc); // Include the NULL byte for size 128 } 129 break; 130 131 case eStopReasonSignal: 132 { 133 stop_desc = m_opaque_sp->GetProcess().GetUnixSignals ().GetSignalAsCString (thread_stop_info.GetSignal()); 134 if (stop_desc == NULL || stop_desc[0] == '\0') 135 { 136 static char signal_desc[] = "signal"; 137 stop_desc = signal_desc; 138 stop_desc_len = sizeof(signal_desc); // Include the NULL byte for size 139 } 140 } 141 break; 142 143 case eStopReasonException: 144 { 145 char exc_desc[] = "exception"; 146 stop_desc = exc_desc; 147 stop_desc_len = sizeof(exc_desc); // Include the NULL byte for size 148 } 149 break; 150 151 default: 152 break; 153 } 154 155 if (stop_desc && stop_desc[0]) 156 { 157 if (dst) 158 return ::snprintf (dst, dst_len, "%s", stop_desc) + 1; // Include the NULL byte 159 160 if (stop_desc_len == 0) 161 stop_desc_len = ::strlen (stop_desc) + 1; // Include the NULL byte 162 163 return stop_desc_len; 164 } 165 } 166 } 167 } 168 if (dst) 169 *dst = 0; 170 return 0; 171 } 172 173 void 174 SBThread::SetThread (const ThreadSP& lldb_object_sp) 175 { 176 m_opaque_sp = lldb_object_sp; 177 } 178 179 180 lldb::tid_t 181 SBThread::GetThreadID () const 182 { 183 if (m_opaque_sp) 184 return m_opaque_sp->GetID(); 185 else 186 return LLDB_INVALID_THREAD_ID; 187 } 188 189 uint32_t 190 SBThread::GetIndexID () const 191 { 192 if (m_opaque_sp) 193 return m_opaque_sp->GetIndexID(); 194 return LLDB_INVALID_INDEX32; 195 } 196 const char * 197 SBThread::GetName () const 198 { 199 if (m_opaque_sp) 200 return m_opaque_sp->GetName(); 201 return NULL; 202 } 203 204 const char * 205 SBThread::GetQueueName () const 206 { 207 if (m_opaque_sp) 208 return m_opaque_sp->GetQueueName(); 209 return NULL; 210 } 211 212 213 void 214 SBThread::DisplayFramesForCurrentContext (FILE *out, 215 FILE *err, 216 uint32_t first_frame, 217 uint32_t num_frames, 218 bool show_frame_info, 219 uint32_t num_frames_with_source, 220 uint32_t source_lines_before, 221 uint32_t source_lines_after) 222 { 223 if ((out == NULL) || (err == NULL)) 224 return; 225 226 if (m_opaque_sp) 227 { 228 uint32_t num_stack_frames = m_opaque_sp->GetStackFrameCount (); 229 StackFrameSP frame_sp; 230 uint32_t frame_idx = 0; 231 232 for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx) 233 { 234 if (frame_idx >= num_stack_frames) 235 break; 236 237 frame_sp = m_opaque_sp->GetStackFrameAtIndex (frame_idx); 238 if (!frame_sp) 239 break; 240 241 SBFrame sb_frame (frame_sp); 242 if (DisplaySingleFrameForCurrentContext (out, 243 err, 244 sb_frame, 245 show_frame_info, 246 num_frames_with_source > first_frame - frame_idx, 247 source_lines_before, 248 source_lines_after) == false) 249 break; 250 } 251 } 252 } 253 254 bool 255 SBThread::DisplaySingleFrameForCurrentContext (FILE *out, 256 FILE *err, 257 SBFrame &frame, 258 bool show_frame_info, 259 bool show_source, 260 uint32_t source_lines_after, 261 uint32_t source_lines_before) 262 { 263 bool success = false; 264 265 if ((out == NULL) || (err == NULL)) 266 return false; 267 268 if (m_opaque_sp && frame.IsValid()) 269 { 270 StreamFile str (out); 271 272 SBSymbolContext sc(frame.GetSymbolContext(eSymbolContextEverything)); 273 274 if (show_frame_info && sc.IsValid()) 275 { 276 user_id_t frame_idx = (user_id_t) frame.GetFrameID(); 277 lldb::addr_t pc = frame.GetPC(); 278 ::fprintf (out, 279 " frame #%u: tid = 0x%4.4x, pc = 0x%llx ", 280 frame_idx, 281 GetThreadID(), 282 (long long)pc); 283 sc->DumpStopContext (&str, &m_opaque_sp->GetProcess(), *frame.GetPCAddress()); 284 fprintf (out, "\n"); 285 success = true; 286 } 287 288 SBCompileUnit comp_unit(sc.GetCompileUnit()); 289 if (show_source && comp_unit.IsValid()) 290 { 291 success = false; 292 SBLineEntry line_entry; 293 if (line_entry.IsValid()) 294 { 295 SourceManager& source_manager = m_opaque_sp->GetProcess().GetTarget().GetDebugger().GetSourceManager(); 296 SBFileSpec line_entry_file_spec (line_entry.GetFileSpec()); 297 298 if (line_entry_file_spec.IsValid()) 299 { 300 source_manager.DisplaySourceLinesWithLineNumbers (line_entry_file_spec.ref(), 301 line_entry.GetLine(), 302 source_lines_after, 303 source_lines_before, "->", 304 &str); 305 success = true; 306 } 307 } 308 } 309 } 310 return success; 311 } 312 313 void 314 SBThread::StepOver (lldb::RunMode stop_other_threads) 315 { 316 if (m_opaque_sp) 317 { 318 bool abort_other_plans = true; 319 StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0)); 320 321 if (frame_sp) 322 { 323 if (frame_sp->HasDebugInformation ()) 324 { 325 SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); 326 m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans, 327 eStepTypeOver, 328 sc.line_entry.range, 329 sc, 330 stop_other_threads, 331 false); 332 333 } 334 else 335 { 336 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (true, 337 abort_other_plans, 338 stop_other_threads); 339 } 340 } 341 342 Process &process = m_opaque_sp->GetProcess(); 343 // Why do we need to set the current thread by ID here??? 344 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 345 process.Resume(); 346 } 347 } 348 349 void 350 SBThread::StepInto (lldb::RunMode stop_other_threads) 351 { 352 if (m_opaque_sp) 353 { 354 bool abort_other_plans = true; 355 356 StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0)); 357 358 if (frame_sp && frame_sp->HasDebugInformation ()) 359 { 360 bool avoid_code_without_debug_info = true; 361 SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); 362 m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans, 363 eStepTypeInto, 364 sc.line_entry.range, 365 sc, 366 stop_other_threads, 367 avoid_code_without_debug_info); 368 } 369 else 370 { 371 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (false, 372 abort_other_plans, 373 stop_other_threads); 374 } 375 376 Process &process = m_opaque_sp->GetProcess(); 377 // Why do we need to set the current thread by ID here??? 378 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 379 process.Resume(); 380 381 } 382 } 383 384 void 385 SBThread::StepOut () 386 { 387 if (m_opaque_sp) 388 { 389 bool abort_other_plans = true; 390 bool stop_other_threads = true; 391 392 m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, stop_other_threads, eVoteYes, eVoteNoOpinion); 393 394 Process &process = m_opaque_sp->GetProcess(); 395 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 396 process.Resume(); 397 } 398 } 399 400 void 401 SBThread::StepInstruction (bool step_over) 402 { 403 if (m_opaque_sp) 404 { 405 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (step_over, true, true); 406 Process &process = m_opaque_sp->GetProcess(); 407 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 408 process.Resume(); 409 } 410 } 411 412 void 413 SBThread::RunToAddress (lldb::addr_t addr) 414 { 415 if (m_opaque_sp) 416 { 417 bool abort_other_plans = true; 418 bool stop_other_threads = true; 419 420 Address target_addr (NULL, addr); 421 422 m_opaque_sp->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads); 423 Process &process = m_opaque_sp->GetProcess(); 424 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 425 process.Resume(); 426 } 427 428 } 429 430 SBProcess 431 SBThread::GetProcess () 432 { 433 SBProcess process; 434 if (m_opaque_sp) 435 { 436 // Have to go up to the target so we can get a shared pointer to our process... 437 process.SetProcess(m_opaque_sp->GetProcess().GetTarget().GetProcessSP()); 438 } 439 return process; 440 } 441 442 uint32_t 443 SBThread::GetNumFrames () 444 { 445 if (m_opaque_sp) 446 return m_opaque_sp->GetStackFrameCount(); 447 return 0; 448 } 449 450 SBFrame 451 SBThread::GetFrameAtIndex (uint32_t idx) 452 { 453 SBFrame sb_frame; 454 if (m_opaque_sp) 455 sb_frame.SetFrame (m_opaque_sp->GetStackFrameAtIndex (idx)); 456 return sb_frame; 457 } 458 459 const lldb::SBThread & 460 SBThread::operator = (const lldb::SBThread &rhs) 461 { 462 m_opaque_sp = rhs.m_opaque_sp; 463 return *this; 464 } 465 466 bool 467 SBThread::operator == (const SBThread &rhs) const 468 { 469 return m_opaque_sp.get() == rhs.m_opaque_sp.get(); 470 } 471 472 bool 473 SBThread::operator != (const SBThread &rhs) const 474 { 475 return m_opaque_sp.get() != rhs.m_opaque_sp.get(); 476 } 477 478 lldb_private::Thread * 479 SBThread::GetLLDBObjectPtr () 480 { 481 return m_opaque_sp.get(); 482 } 483 484 const lldb_private::Thread * 485 SBThread::operator->() const 486 { 487 return m_opaque_sp.get(); 488 } 489 490 const lldb_private::Thread & 491 SBThread::operator*() const 492 { 493 return *m_opaque_sp; 494 } 495 496 lldb_private::Thread * 497 SBThread::operator->() 498 { 499 return m_opaque_sp.get(); 500 } 501 502 lldb_private::Thread & 503 SBThread::operator*() 504 { 505 return *m_opaque_sp; 506 } 507