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