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