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