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 153 if (stop_desc && stop_desc[0]) 154 { 155 if (dst) 156 return ::snprintf (dst, dst_len, "%s", stop_desc) + 1; // Include the NULL byte 157 158 if (stop_desc_len == 0) 159 stop_desc_len = ::strlen (stop_desc) + 1; // Include the NULL byte 160 161 return stop_desc_len; 162 } 163 } 164 } 165 } 166 if (dst) 167 *dst = 0; 168 return 0; 169 } 170 171 void 172 SBThread::SetThread (const ThreadSP& lldb_object_sp) 173 { 174 m_opaque_sp = lldb_object_sp; 175 } 176 177 178 lldb::tid_t 179 SBThread::GetThreadID () const 180 { 181 if (m_opaque_sp) 182 return m_opaque_sp->GetID(); 183 else 184 return LLDB_INVALID_THREAD_ID; 185 } 186 187 uint32_t 188 SBThread::GetIndexID () const 189 { 190 if (m_opaque_sp) 191 return m_opaque_sp->GetIndexID(); 192 return LLDB_INVALID_INDEX32; 193 } 194 const char * 195 SBThread::GetName () const 196 { 197 if (m_opaque_sp) 198 return m_opaque_sp->GetName(); 199 return NULL; 200 } 201 202 const char * 203 SBThread::GetQueueName () const 204 { 205 if (m_opaque_sp) 206 return m_opaque_sp->GetQueueName(); 207 return NULL; 208 } 209 210 211 void 212 SBThread::DisplayFramesForCurrentContext (FILE *out, 213 FILE *err, 214 uint32_t first_frame, 215 uint32_t num_frames, 216 bool show_frame_info, 217 uint32_t num_frames_with_source, 218 uint32_t source_lines_before, 219 uint32_t source_lines_after) 220 { 221 if ((out == NULL) || (err == NULL)) 222 return; 223 224 if (m_opaque_sp) 225 { 226 uint32_t num_stack_frames = m_opaque_sp->GetStackFrameCount (); 227 StackFrameSP frame_sp; 228 int frame_idx = 0; 229 230 for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx) 231 { 232 if (frame_idx >= num_stack_frames) 233 break; 234 235 frame_sp = m_opaque_sp->GetStackFrameAtIndex (frame_idx); 236 if (!frame_sp) 237 break; 238 239 SBFrame sb_frame (frame_sp); 240 if (DisplaySingleFrameForCurrentContext (out, 241 err, 242 sb_frame, 243 show_frame_info, 244 num_frames_with_source > first_frame - frame_idx, 245 source_lines_before, 246 source_lines_after) == false) 247 break; 248 } 249 } 250 } 251 252 bool 253 SBThread::DisplaySingleFrameForCurrentContext (FILE *out, 254 FILE *err, 255 SBFrame &frame, 256 bool show_frame_info, 257 bool show_source, 258 uint32_t source_lines_after, 259 uint32_t source_lines_before) 260 { 261 bool success = false; 262 263 if ((out == NULL) || (err == NULL)) 264 return false; 265 266 if (m_opaque_sp && frame.IsValid()) 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_opaque_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 SourceManager& source_manager = m_opaque_sp->GetProcess().GetTarget().GetDebugger().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.ref(), 299 line_entry.GetLine(), 300 source_lines_after, 301 source_lines_before, "->", 302 &str); 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_opaque_sp) 315 { 316 bool abort_other_plans = true; 317 StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0)); 318 319 if (frame_sp) 320 { 321 if (frame_sp->HasDebugInformation ()) 322 { 323 SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); 324 m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans, 325 eStepTypeOver, 326 sc.line_entry.range, 327 sc, 328 stop_other_threads, 329 false); 330 331 } 332 else 333 { 334 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (true, 335 abort_other_plans, 336 stop_other_threads); 337 } 338 } 339 340 Process &process = m_opaque_sp->GetProcess(); 341 // Why do we need to set the current thread by ID here??? 342 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 343 process.Resume(); 344 } 345 } 346 347 void 348 SBThread::StepInto (lldb::RunMode stop_other_threads) 349 { 350 if (m_opaque_sp) 351 { 352 bool abort_other_plans = true; 353 354 StackFrameSP frame_sp(m_opaque_sp->GetStackFrameAtIndex (0)); 355 356 if (frame_sp && frame_sp->HasDebugInformation ()) 357 { 358 bool avoid_code_without_debug_info = true; 359 SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); 360 m_opaque_sp->QueueThreadPlanForStepRange (abort_other_plans, 361 eStepTypeInto, 362 sc.line_entry.range, 363 sc, 364 stop_other_threads, 365 avoid_code_without_debug_info); 366 } 367 else 368 { 369 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (false, 370 abort_other_plans, 371 stop_other_threads); 372 } 373 374 Process &process = m_opaque_sp->GetProcess(); 375 // Why do we need to set the current thread by ID here??? 376 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 377 process.Resume(); 378 379 } 380 } 381 382 void 383 SBThread::StepOut () 384 { 385 if (m_opaque_sp) 386 { 387 bool abort_other_plans = true; 388 bool stop_other_threads = true; 389 390 m_opaque_sp->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, stop_other_threads, eVoteYes, eVoteNoOpinion); 391 392 Process &process = m_opaque_sp->GetProcess(); 393 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 394 process.Resume(); 395 } 396 } 397 398 void 399 SBThread::StepInstruction (bool step_over) 400 { 401 if (m_opaque_sp) 402 { 403 m_opaque_sp->QueueThreadPlanForStepSingleInstruction (step_over, true, true); 404 Process &process = m_opaque_sp->GetProcess(); 405 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 406 process.Resume(); 407 } 408 } 409 410 void 411 SBThread::RunToAddress (lldb::addr_t addr) 412 { 413 if (m_opaque_sp) 414 { 415 bool abort_other_plans = true; 416 bool stop_other_threads = true; 417 418 Address target_addr (NULL, addr); 419 420 m_opaque_sp->QueueThreadPlanForRunToAddress (abort_other_plans, target_addr, stop_other_threads); 421 Process &process = m_opaque_sp->GetProcess(); 422 process.GetThreadList().SetCurrentThreadByID (m_opaque_sp->GetID()); 423 process.Resume(); 424 } 425 426 } 427 428 SBProcess 429 SBThread::GetProcess () 430 { 431 SBProcess process; 432 if (m_opaque_sp) 433 { 434 // Have to go up to the target so we can get a shared pointer to our process... 435 process.SetProcess(m_opaque_sp->GetProcess().GetTarget().GetProcessSP()); 436 } 437 return process; 438 } 439 440 uint32_t 441 SBThread::GetNumFrames () 442 { 443 if (m_opaque_sp) 444 return m_opaque_sp->GetStackFrameCount(); 445 return 0; 446 } 447 448 SBFrame 449 SBThread::GetFrameAtIndex (uint32_t idx) 450 { 451 SBFrame sb_frame; 452 if (m_opaque_sp) 453 sb_frame.SetFrame (m_opaque_sp->GetStackFrameAtIndex (idx)); 454 return sb_frame; 455 } 456 457 const lldb::SBThread & 458 SBThread::operator = (const lldb::SBThread &rhs) 459 { 460 m_opaque_sp = rhs.m_opaque_sp; 461 return *this; 462 } 463 464 bool 465 SBThread::operator == (const SBThread &rhs) const 466 { 467 return m_opaque_sp.get() == rhs.m_opaque_sp.get(); 468 } 469 470 bool 471 SBThread::operator != (const SBThread &rhs) const 472 { 473 return m_opaque_sp.get() != rhs.m_opaque_sp.get(); 474 } 475 476 lldb_private::Thread * 477 SBThread::GetLLDBObjectPtr () 478 { 479 return m_opaque_sp.get(); 480 } 481 482 const lldb_private::Thread * 483 SBThread::operator->() const 484 { 485 return m_opaque_sp.get(); 486 } 487 488 const lldb_private::Thread & 489 SBThread::operator*() const 490 { 491 return *m_opaque_sp; 492 } 493 494 lldb_private::Thread * 495 SBThread::operator->() 496 { 497 return m_opaque_sp.get(); 498 } 499 500 lldb_private::Thread & 501 SBThread::operator*() 502 { 503 return *m_opaque_sp; 504 } 505