1 //===-- CommandObjectThread.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 "CommandObjectThread.h" 11 12 // C Includes 13 // C++ Includes 14 // Other libraries and framework includes 15 // Project includes 16 #include "lldb/Interpreter/Options.h" 17 #include "lldb/Core/State.h" 18 #include "lldb/Core/SourceManager.h" 19 20 #include "lldb/Interpreter/CommandInterpreter.h" 21 #include "lldb/Interpreter/CommandReturnObject.h" 22 23 #include "lldb/Target/Process.h" 24 #include "lldb/Target/RegisterContext.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 #include "lldb/Target/ThreadPlan.h" 28 #include "lldb/Target/ThreadPlanStepInstruction.h" 29 #include "lldb/Target/ThreadPlanStepOut.h" 30 #include "lldb/Target/ThreadPlanStepRange.h" 31 #include "lldb/Target/ThreadPlanStepInRange.h" 32 #include "lldb/Symbol/LineTable.h" 33 #include "lldb/Symbol/LineEntry.h" 34 35 using namespace lldb; 36 using namespace lldb_private; 37 38 39 bool 40 lldb_private::DisplayThreadInfo 41 ( 42 CommandInterpreter &interpreter, 43 Stream &strm, 44 Thread *thread, 45 bool only_threads_with_stop_reason, 46 bool show_source 47 ) 48 { 49 if (thread) 50 { 51 if (only_threads_with_stop_reason) 52 { 53 if (thread->GetStopInfo() == NULL) 54 return false; 55 } 56 57 strm.Indent(); 58 strm.Printf("%c ", thread->GetProcess().GetThreadList().GetCurrentThread().get() == thread ? '*' : ' '); 59 60 // Show one frame with only the first showing source 61 if (show_source) 62 { 63 DisplayFramesForExecutionContext (thread, 64 interpreter, 65 strm, 66 true, 67 0, // Start at first frame 68 1, // Number of frames to show 69 false,// Don't show the frame info since we already displayed most of it above... 70 1, // Show source for the first frame 71 3, // lines of source context before 72 3); // lines of source context after 73 } 74 else 75 { 76 thread->DumpInfo (strm, 77 true, // Dump the stop reason? 78 true, // Dump the thread name? 79 true, // Dump the queue name? 80 0); // Display context info for stack frame zero 81 82 strm.EOL(); 83 } 84 85 return true; 86 } 87 return false; 88 } 89 90 size_t 91 lldb_private::DisplayThreadsInfo 92 ( 93 CommandInterpreter &interpreter, 94 ExecutionContext *exe_ctx, 95 CommandReturnObject &result, 96 bool only_threads_with_stop_reason, 97 bool show_source 98 ) 99 { 100 StreamString strm; 101 102 size_t num_thread_infos_dumped = 0; 103 104 if (!exe_ctx->process) 105 return 0; 106 107 const size_t num_threads = exe_ctx->process->GetThreadList().GetSize(); 108 if (num_threads > 0) 109 { 110 111 for (uint32_t i = 0; i < num_threads; i++) 112 { 113 Thread *thread = exe_ctx->process->GetThreadList().GetThreadAtIndex(i).get(); 114 if (thread) 115 { 116 if (DisplayThreadInfo (interpreter, 117 strm, 118 thread, 119 only_threads_with_stop_reason, 120 show_source)) 121 ++num_thread_infos_dumped; 122 } 123 } 124 } 125 126 if (num_thread_infos_dumped > 0) 127 { 128 if (num_thread_infos_dumped < num_threads) 129 result.GetOutputStream().Printf("%u of %u threads stopped with reasons:\n", num_thread_infos_dumped, num_threads); 130 131 result.GetOutputStream().GetString().append(strm.GetString()); 132 result.SetStatus (eReturnStatusSuccessFinishNoResult); 133 } 134 return num_thread_infos_dumped; 135 } 136 137 138 size_t 139 lldb_private::DisplayFramesForExecutionContext 140 ( 141 Thread *thread, 142 CommandInterpreter &interpreter, 143 Stream& strm, 144 bool ascending, 145 uint32_t first_frame, 146 uint32_t num_frames, 147 bool show_frame_info, 148 uint32_t num_frames_with_source, 149 uint32_t source_lines_before, 150 uint32_t source_lines_after 151 ) 152 { 153 if (thread == NULL) 154 return 0; 155 156 size_t num_frames_displayed = 0; 157 158 if (num_frames == 0) 159 return 0; 160 161 thread->DumpInfo (strm, 162 true, // Dump the stop reason? 163 true, // Dump the thread name? 164 true, // Dump the queue name? 165 num_frames > 1 ? UINT32_MAX : first_frame); // Dump info for the first stack frame if we are showing only on frame 166 strm.EOL(); 167 strm.IndentMore(); 168 169 StackFrameSP frame_sp; 170 uint32_t frame_idx = 0; 171 172 if (ascending) 173 { 174 for (frame_idx = first_frame; frame_idx < first_frame + num_frames; ++frame_idx) 175 { 176 frame_sp = thread->GetStackFrameAtIndex (frame_idx); 177 if (frame_sp.get() == NULL) 178 break; 179 180 if (DisplayFrameForExecutionContext (thread, 181 frame_sp.get(), 182 interpreter, 183 strm, 184 show_frame_info, 185 num_frames_with_source > first_frame - frame_idx, 186 source_lines_before, 187 source_lines_after) == false) 188 break; 189 190 ++num_frames_displayed; 191 } 192 } 193 else 194 { 195 for (frame_idx = first_frame + num_frames - 1; frame_idx >= first_frame; --frame_idx) 196 { 197 frame_sp = thread->GetStackFrameAtIndex (frame_idx); 198 if (frame_sp == NULL) 199 break; 200 201 if (DisplayFrameForExecutionContext (thread, 202 frame_sp.get(), 203 interpreter, 204 strm, 205 show_frame_info, 206 num_frames_with_source > first_frame - frame_idx, 207 source_lines_before, 208 source_lines_after) == false) 209 break; 210 211 ++num_frames_displayed; 212 } 213 } 214 strm.IndentLess(); 215 return num_frames_displayed; 216 } 217 218 bool 219 lldb_private::DisplayFrameForExecutionContext 220 ( 221 Thread *thread, 222 StackFrame *frame, 223 CommandInterpreter &interpreter, 224 Stream& strm, 225 bool show_frame_info, 226 bool show_source, 227 uint32_t source_lines_before, 228 uint32_t source_lines_after 229 ) 230 { 231 // thread and frame must be filled in prior to calling this function 232 if (thread && frame) 233 { 234 if (show_frame_info) 235 { 236 strm.Indent(); 237 frame->Dump (&strm, true); 238 strm.EOL(); 239 } 240 241 SymbolContext sc (frame->GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry)); 242 243 if (show_source && sc.comp_unit && sc.line_entry.IsValid()) 244 { 245 interpreter.GetDebugger().GetSourceManager().DisplaySourceLinesWithLineNumbers ( 246 sc.line_entry.file, 247 sc.line_entry.line, 248 3, 249 3, 250 "->", 251 &strm); 252 253 } 254 return true; 255 } 256 return false; 257 } 258 259 260 //------------------------------------------------------------------------- 261 // CommandObjectThreadBacktrace 262 //------------------------------------------------------------------------- 263 264 class CommandObjectThreadBacktrace : public CommandObject 265 { 266 public: 267 268 CommandObjectThreadBacktrace () : 269 CommandObject ("thread backtrace", 270 "Shows the stack for one or more threads.", 271 "thread backtrace [<thread-idx>] ...", 272 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), 273 m_ascending (true) 274 { 275 } 276 277 ~CommandObjectThreadBacktrace() 278 { 279 } 280 281 282 virtual bool 283 Execute 284 ( 285 CommandInterpreter &interpreter, 286 Args& command, 287 CommandReturnObject &result 288 ) 289 { 290 if (command.GetArgumentCount() == 0) 291 { 292 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext()); 293 if (exe_ctx.thread) 294 { 295 bool show_frame_info = true; 296 uint32_t num_frames_with_source = 0; // Don't show any frasmes with source when backtracing 297 if (DisplayFramesForExecutionContext (exe_ctx.thread, 298 interpreter, 299 result.GetOutputStream(), 300 m_ascending, 301 0, 302 UINT32_MAX, 303 show_frame_info, 304 num_frames_with_source, 305 3, 306 3)) 307 { 308 result.SetStatus (eReturnStatusSuccessFinishResult); 309 } 310 } 311 else 312 { 313 result.AppendError ("invalid thread"); 314 result.SetStatus (eReturnStatusFailed); 315 } 316 } 317 else 318 { 319 result.AppendError ("backtrace doesn't take arguments (for now)"); 320 result.SetStatus (eReturnStatusFailed); 321 } 322 return result.Succeeded(); 323 } 324 protected: 325 bool m_ascending; 326 }; 327 328 329 enum StepScope 330 { 331 eStepScopeSource, 332 eStepScopeInstruction 333 }; 334 335 class CommandObjectThreadStepWithTypeAndScope : public CommandObject 336 { 337 public: 338 339 class CommandOptions : public Options 340 { 341 public: 342 343 CommandOptions () : 344 Options() 345 { 346 // Keep default values of all options in one place: ResetOptionValues () 347 ResetOptionValues (); 348 } 349 350 virtual 351 ~CommandOptions () 352 { 353 } 354 355 virtual Error 356 SetOptionValue (int option_idx, const char *option_arg) 357 { 358 Error error; 359 char short_option = (char) m_getopt_table[option_idx].val; 360 361 switch (short_option) 362 { 363 case 'a': 364 { 365 bool success; 366 m_avoid_no_debug = Args::StringToBoolean (option_arg, true, &success); 367 if (!success) 368 error.SetErrorStringWithFormat("Invalid boolean value for option '%c'.\n", short_option); 369 } 370 break; 371 case 'm': 372 { 373 bool found_one = false; 374 OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; 375 m_run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one); 376 if (!found_one) 377 error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option); 378 } 379 break; 380 case 'r': 381 { 382 m_avoid_regexp.clear(); 383 m_avoid_regexp.assign(option_arg); 384 } 385 break; 386 default: 387 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 388 break; 389 390 } 391 return error; 392 } 393 394 void 395 ResetOptionValues () 396 { 397 Options::ResetOptionValues(); 398 m_avoid_no_debug = true; 399 m_run_mode = eOnlyDuringStepping; 400 m_avoid_regexp.clear(); 401 } 402 403 const lldb::OptionDefinition* 404 GetDefinitions () 405 { 406 return g_option_table; 407 } 408 409 // Options table: Required for subclasses of Options. 410 411 static lldb::OptionDefinition g_option_table[]; 412 413 // Instance variables to hold the values for command options. 414 bool m_avoid_no_debug; 415 RunMode m_run_mode; 416 std::string m_avoid_regexp; 417 }; 418 419 CommandObjectThreadStepWithTypeAndScope (const char *name, 420 const char *help, 421 const char *syntax, 422 uint32_t flags, 423 StepType step_type, 424 StepScope step_scope) : 425 CommandObject (name, help, syntax, flags), 426 m_step_type (step_type), 427 m_step_scope (step_scope), 428 m_options () 429 { 430 } 431 432 virtual 433 ~CommandObjectThreadStepWithTypeAndScope () 434 { 435 } 436 437 virtual 438 Options * 439 GetOptions () 440 { 441 return &m_options; 442 } 443 444 virtual bool 445 Execute 446 ( 447 CommandInterpreter &interpreter, 448 Args& command, 449 CommandReturnObject &result 450 ) 451 { 452 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 453 bool synchronous_execution = interpreter.GetSynchronous(); 454 455 if (process == NULL) 456 { 457 result.AppendError ("need a valid process to step"); 458 result.SetStatus (eReturnStatusFailed); 459 460 } 461 else 462 { 463 const uint32_t num_threads = process->GetThreadList().GetSize(); 464 Thread *thread = NULL; 465 466 if (command.GetArgumentCount() == 0) 467 { 468 thread = process->GetThreadList().GetCurrentThread().get(); 469 if (thread == NULL) 470 { 471 result.AppendError ("no current thread in process"); 472 result.SetStatus (eReturnStatusFailed); 473 return false; 474 } 475 } 476 else 477 { 478 const char *thread_idx_cstr = command.GetArgumentAtIndex(0); 479 uint32_t step_thread_idx = Args::StringToUInt32 (thread_idx_cstr, LLDB_INVALID_INDEX32); 480 if (step_thread_idx == LLDB_INVALID_INDEX32) 481 { 482 result.AppendErrorWithFormat ("Invalid thread index '%s'.\n", thread_idx_cstr); 483 result.SetStatus (eReturnStatusFailed); 484 return false; 485 } 486 thread = process->GetThreadList().FindThreadByIndexID(step_thread_idx).get(); 487 if (thread == NULL) 488 { 489 result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", 490 step_thread_idx, 0, num_threads); 491 result.SetStatus (eReturnStatusFailed); 492 return false; 493 } 494 } 495 496 const bool abort_other_plans = false; 497 const lldb::RunMode stop_other_threads = m_options.m_run_mode; 498 499 // This is a bit unfortunate, but not all the commands in this command object support 500 // only while stepping, so I use the bool for them. 501 bool bool_stop_other_threads; 502 if (m_options.m_run_mode == eAllThreads) 503 bool_stop_other_threads = false; 504 else 505 bool_stop_other_threads = true; 506 507 if (m_step_type == eStepTypeInto) 508 { 509 StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 510 ThreadPlan *new_plan; 511 512 if (frame->HasDebugInformation ()) 513 { 514 new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, m_step_type, 515 frame->GetSymbolContext(eSymbolContextEverything).line_entry.range, 516 frame->GetSymbolContext(eSymbolContextEverything), 517 stop_other_threads, 518 m_options.m_avoid_no_debug); 519 if (new_plan && !m_options.m_avoid_regexp.empty()) 520 { 521 ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (new_plan); 522 step_in_range_plan->SetAvoidRegexp(m_options.m_avoid_regexp.c_str()); 523 } 524 } 525 else 526 new_plan = thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads); 527 528 process->GetThreadList().SetCurrentThreadByID (thread->GetID()); 529 process->Resume (); 530 } 531 else if (m_step_type == eStepTypeOver) 532 { 533 StackFrame *frame = thread->GetStackFrameAtIndex(0).get(); 534 ThreadPlan *new_plan; 535 536 if (frame->HasDebugInformation()) 537 new_plan = thread->QueueThreadPlanForStepRange (abort_other_plans, 538 m_step_type, 539 frame->GetSymbolContext(eSymbolContextEverything).line_entry.range, 540 frame->GetSymbolContext(eSymbolContextEverything), 541 stop_other_threads, 542 false); 543 else 544 new_plan = thread->QueueThreadPlanForStepSingleInstruction (true, 545 abort_other_plans, 546 bool_stop_other_threads); 547 548 // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over. 549 // Maybe there should be a parameter to control this. 550 new_plan->SetOkayToDiscard(false); 551 552 process->GetThreadList().SetCurrentThreadByID (thread->GetID()); 553 process->Resume (); 554 } 555 else if (m_step_type == eStepTypeTrace) 556 { 557 thread->QueueThreadPlanForStepSingleInstruction (false, abort_other_plans, bool_stop_other_threads); 558 process->GetThreadList().SetCurrentThreadByID (thread->GetID()); 559 process->Resume (); 560 } 561 else if (m_step_type == eStepTypeTraceOver) 562 { 563 thread->QueueThreadPlanForStepSingleInstruction (true, abort_other_plans, bool_stop_other_threads); 564 process->GetThreadList().SetCurrentThreadByID (thread->GetID()); 565 process->Resume (); 566 } 567 else if (m_step_type == eStepTypeOut) 568 { 569 ThreadPlan *new_plan; 570 571 new_plan = thread->QueueThreadPlanForStepOut (abort_other_plans, NULL, false, bool_stop_other_threads, eVoteYes, eVoteNoOpinion); 572 // FIXME: This will keep the step plan on the thread stack when we hit a breakpoint while stepping over. 573 // Maybe there should be a parameter to control this. 574 new_plan->SetOkayToDiscard(false); 575 576 process->GetThreadList().SetCurrentThreadByID (thread->GetID()); 577 process->Resume (); 578 } 579 else 580 { 581 result.AppendError ("step type is not supported"); 582 result.SetStatus (eReturnStatusFailed); 583 } 584 if (synchronous_execution) 585 { 586 StateType state = process->WaitForProcessToStop (NULL); 587 588 //EventSP event_sp; 589 //StateType state = process->WaitForStateChangedEvents (NULL, event_sp); 590 //while (! StateIsStoppedState (state)) 591 // { 592 // state = process->WaitForStateChangedEvents (NULL, event_sp); 593 // } 594 process->GetThreadList().SetCurrentThreadByID (thread->GetID()); 595 result.SetDidChangeProcessState (true); 596 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); 597 result.SetStatus (eReturnStatusSuccessFinishNoResult); 598 } 599 } 600 return result.Succeeded(); 601 } 602 603 protected: 604 StepType m_step_type; 605 StepScope m_step_scope; 606 CommandOptions m_options; 607 }; 608 609 static lldb::OptionEnumValueElement 610 g_tri_running_mode[] = 611 { 612 { eOnlyThisThread, "thisThread", "Run only this thread"}, 613 { eAllThreads, "allThreads", "Run all threads"}, 614 { eOnlyDuringStepping, "whileStepping", "Run only this thread while stepping"}, 615 { 0, NULL, NULL } 616 }; 617 618 static lldb::OptionEnumValueElement 619 g_duo_running_mode[] = 620 { 621 { eOnlyThisThread, "thisThread", "Run only this thread"}, 622 { eAllThreads, "allThreads", "Run all threads"}, 623 { 0, NULL, NULL } 624 }; 625 626 lldb::OptionDefinition 627 CommandObjectThreadStepWithTypeAndScope::CommandOptions::g_option_table[] = 628 { 629 { LLDB_OPT_SET_1, false, "avoid_no_debug", 'a', required_argument, NULL, 0, "<avoid_no_debug>", "Should step-in step over functions with no debug information"}, 630 { LLDB_OPT_SET_1, false, "run_mode", 'm', required_argument, g_tri_running_mode, 0, "<run_mode>", "Determine how to run other threads while stepping this one"}, 631 { LLDB_OPT_SET_1, false, "regexp_to_avoid",'r', required_argument, NULL, 0, "<avoid_regexp>", "Should step-in step over functions matching this regexp"}, 632 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 633 }; 634 635 636 //------------------------------------------------------------------------- 637 // CommandObjectThreadContinue 638 //------------------------------------------------------------------------- 639 640 class CommandObjectThreadContinue : public CommandObject 641 { 642 public: 643 644 CommandObjectThreadContinue () : 645 CommandObject ("thread continue", 646 "Continues execution of one or more threads in an active process.", 647 "thread continue <thread-index> [<thread-index> ...]", 648 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 649 { 650 } 651 652 653 virtual 654 ~CommandObjectThreadContinue () 655 { 656 } 657 658 virtual bool 659 Execute 660 ( 661 CommandInterpreter &interpreter, 662 Args& command, 663 CommandReturnObject &result 664 ) 665 { 666 bool synchronous_execution = interpreter.GetSynchronous (); 667 668 if (!interpreter.GetDebugger().GetCurrentTarget().get()) 669 { 670 result.AppendError ("invalid target, set executable file using 'file' command"); 671 result.SetStatus (eReturnStatusFailed); 672 return false; 673 } 674 675 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 676 if (process == NULL) 677 { 678 result.AppendError ("no process exists. Cannot continue"); 679 result.SetStatus (eReturnStatusFailed); 680 return false; 681 } 682 683 StateType state = process->GetState(); 684 if ((state == eStateCrashed) || (state == eStateStopped) || (state == eStateSuspended)) 685 { 686 const uint32_t num_threads = process->GetThreadList().GetSize(); 687 uint32_t idx; 688 const size_t argc = command.GetArgumentCount(); 689 if (argc > 0) 690 { 691 std::vector<uint32_t> resume_thread_indexes; 692 for (uint32_t i=0; i<argc; ++i) 693 { 694 idx = Args::StringToUInt32 (command.GetArgumentAtIndex(0), LLDB_INVALID_INDEX32); 695 if (idx < num_threads) 696 resume_thread_indexes.push_back(idx); 697 else 698 result.AppendWarningWithFormat("Thread index %u out of range.\n", idx); 699 } 700 701 if (resume_thread_indexes.empty()) 702 { 703 result.AppendError ("no valid thread indexes were specified"); 704 result.SetStatus (eReturnStatusFailed); 705 return false; 706 } 707 else 708 { 709 result.AppendMessage ("Resuming thread "); 710 for (idx=0; idx<num_threads; ++idx) 711 { 712 Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); 713 if (find(resume_thread_indexes.begin(), resume_thread_indexes.end(), idx) != resume_thread_indexes.end()) 714 { 715 result.AppendMessageWithFormat ("%u ", idx); 716 thread->SetResumeState (eStateRunning); 717 } 718 else 719 { 720 thread->SetResumeState (eStateSuspended); 721 } 722 } 723 result.AppendMessageWithFormat ("in process %i\n", process->GetID()); 724 } 725 } 726 else 727 { 728 Thread *current_thread = process->GetThreadList().GetCurrentThread().get(); 729 if (current_thread == NULL) 730 { 731 result.AppendError ("the process doesn't have a current thread"); 732 result.SetStatus (eReturnStatusFailed); 733 return false; 734 } 735 // Set the actions that the threads should each take when resuming 736 for (idx=0; idx<num_threads; ++idx) 737 { 738 Thread *thread = process->GetThreadList().GetThreadAtIndex(idx).get(); 739 if (thread == current_thread) 740 { 741 result.AppendMessageWithFormat ("Resuming thread 0x%4.4x in process %i\n", thread->GetID(), process->GetID()); 742 thread->SetResumeState (eStateRunning); 743 } 744 else 745 { 746 thread->SetResumeState (eStateSuspended); 747 } 748 } 749 } 750 751 Error error (process->Resume()); 752 if (error.Success()) 753 { 754 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); 755 if (synchronous_execution) 756 { 757 state = process->WaitForProcessToStop (NULL); 758 759 result.SetDidChangeProcessState (true); 760 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); 761 result.SetStatus (eReturnStatusSuccessFinishNoResult); 762 } 763 else 764 { 765 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 766 } 767 } 768 else 769 { 770 result.AppendErrorWithFormat("Failed to resume process: %s\n", error.AsCString()); 771 result.SetStatus (eReturnStatusFailed); 772 } 773 } 774 else 775 { 776 result.AppendErrorWithFormat ("Process cannot be continued from its current state (%s).\n", 777 StateAsCString(state)); 778 result.SetStatus (eReturnStatusFailed); 779 } 780 781 return result.Succeeded(); 782 } 783 784 }; 785 786 //------------------------------------------------------------------------- 787 // CommandObjectThreadUntil 788 //------------------------------------------------------------------------- 789 790 class CommandObjectThreadUntil : public CommandObject 791 { 792 public: 793 794 class CommandOptions : public Options 795 { 796 public: 797 uint32_t m_thread_idx; 798 uint32_t m_frame_idx; 799 800 CommandOptions () : 801 Options(), 802 m_thread_idx(LLDB_INVALID_THREAD_ID), 803 m_frame_idx(LLDB_INVALID_FRAME_ID) 804 { 805 // Keep default values of all options in one place: ResetOptionValues () 806 ResetOptionValues (); 807 } 808 809 virtual 810 ~CommandOptions () 811 { 812 } 813 814 virtual Error 815 SetOptionValue (int option_idx, const char *option_arg) 816 { 817 Error error; 818 char short_option = (char) m_getopt_table[option_idx].val; 819 820 switch (short_option) 821 { 822 case 't': 823 { 824 m_thread_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_INDEX32); 825 if (m_thread_idx == LLDB_INVALID_INDEX32) 826 { 827 error.SetErrorStringWithFormat ("Invalid thread index '%s'.\n", option_arg); 828 } 829 } 830 break; 831 case 'f': 832 { 833 m_frame_idx = Args::StringToUInt32 (option_arg, LLDB_INVALID_FRAME_ID); 834 if (m_frame_idx == LLDB_INVALID_FRAME_ID) 835 { 836 error.SetErrorStringWithFormat ("Invalid frame index '%s'.\n", option_arg); 837 } 838 } 839 break; 840 case 'm': 841 { 842 bool found_one = false; 843 OptionEnumValueElement *enum_values = g_option_table[option_idx].enum_values; 844 lldb::RunMode run_mode = (lldb::RunMode) Args::StringToOptionEnum(option_arg, enum_values, eOnlyDuringStepping, &found_one); 845 846 if (!found_one) 847 error.SetErrorStringWithFormat("Invalid enumeration value for option '%c'.\n", short_option); 848 else if (run_mode == eAllThreads) 849 m_stop_others = false; 850 else 851 m_stop_others = true; 852 853 } 854 break; 855 default: 856 error.SetErrorStringWithFormat("Invalid short option character '%c'.\n", short_option); 857 break; 858 859 } 860 return error; 861 } 862 863 void 864 ResetOptionValues () 865 { 866 Options::ResetOptionValues(); 867 m_thread_idx = LLDB_INVALID_THREAD_ID; 868 m_frame_idx = 0; 869 m_stop_others = false; 870 } 871 872 const lldb::OptionDefinition* 873 GetDefinitions () 874 { 875 return g_option_table; 876 } 877 878 uint32_t m_step_thread_idx; 879 bool m_stop_others; 880 881 // Options table: Required for subclasses of Options. 882 883 static lldb::OptionDefinition g_option_table[]; 884 885 // Instance variables to hold the values for command options. 886 }; 887 888 CommandObjectThreadUntil () : 889 CommandObject ("thread until", 890 "Runs the current or specified thread until it reaches a given line number or leaves the current function.", 891 "thread until [<cmd-options>] <line-number>", 892 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused), 893 m_options () 894 { 895 } 896 897 898 virtual 899 ~CommandObjectThreadUntil () 900 { 901 } 902 903 virtual 904 Options * 905 GetOptions () 906 { 907 return &m_options; 908 } 909 910 virtual bool 911 Execute 912 ( 913 CommandInterpreter &interpreter, 914 Args& command, 915 CommandReturnObject &result 916 ) 917 { 918 bool synchronous_execution = interpreter.GetSynchronous (); 919 920 if (!interpreter.GetDebugger().GetCurrentTarget().get()) 921 { 922 result.AppendError ("invalid target, set executable file using 'file' command"); 923 result.SetStatus (eReturnStatusFailed); 924 return false; 925 } 926 927 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 928 if (process == NULL) 929 { 930 result.AppendError ("need a valid process to step"); 931 result.SetStatus (eReturnStatusFailed); 932 933 } 934 else 935 { 936 Thread *thread = NULL; 937 uint32_t line_number; 938 939 if (command.GetArgumentCount() != 1) 940 { 941 result.AppendErrorWithFormat ("No line number provided:\n%s", GetSyntax()); 942 result.SetStatus (eReturnStatusFailed); 943 return false; 944 } 945 946 line_number = Args::StringToUInt32 (command.GetArgumentAtIndex(0), UINT32_MAX); 947 if (line_number == UINT32_MAX) 948 { 949 result.AppendErrorWithFormat ("Invalid line number: '%s'.\n", command.GetArgumentAtIndex(0)); 950 result.SetStatus (eReturnStatusFailed); 951 return false; 952 } 953 954 if (m_options.m_thread_idx == LLDB_INVALID_THREAD_ID) 955 { 956 thread = process->GetThreadList().GetCurrentThread().get(); 957 } 958 else 959 { 960 thread = process->GetThreadList().GetThreadAtIndex(m_options.m_thread_idx).get(); 961 } 962 963 if (thread == NULL) 964 { 965 const uint32_t num_threads = process->GetThreadList().GetSize(); 966 result.AppendErrorWithFormat ("Thread index %u is out of range (valid values are 0 - %u).\n", m_options.m_thread_idx, 0, num_threads); 967 result.SetStatus (eReturnStatusFailed); 968 return false; 969 } 970 971 const bool abort_other_plans = true; 972 973 StackFrame *frame = thread->GetStackFrameAtIndex(m_options.m_frame_idx).get(); 974 if (frame == NULL) 975 { 976 977 result.AppendErrorWithFormat ("Frame index %u is out of range for thread %u.\n", m_options.m_frame_idx, m_options.m_thread_idx); 978 result.SetStatus (eReturnStatusFailed); 979 return false; 980 } 981 982 ThreadPlan *new_plan; 983 984 if (frame->HasDebugInformation ()) 985 { 986 // Finally we got here... Translate the given line number to a bunch of addresses: 987 SymbolContext sc(frame->GetSymbolContext (eSymbolContextCompUnit)); 988 LineTable *line_table = NULL; 989 if (sc.comp_unit) 990 line_table = sc.comp_unit->GetLineTable(); 991 992 if (line_table == NULL) 993 { 994 result.AppendErrorWithFormat ("Failed to resolve the line table for frame %u of thread index %u.\n", 995 m_options.m_frame_idx, m_options.m_thread_idx); 996 result.SetStatus (eReturnStatusFailed); 997 return false; 998 } 999 1000 LineEntry function_start; 1001 uint32_t index_ptr = 0, end_ptr; 1002 std::vector<addr_t> address_list; 1003 1004 // Find the beginning & end index of the 1005 AddressRange fun_addr_range = sc.function->GetAddressRange(); 1006 Address fun_start_addr = fun_addr_range.GetBaseAddress(); 1007 line_table->FindLineEntryByAddress (fun_start_addr, function_start, &index_ptr); 1008 1009 Address fun_end_addr(fun_start_addr.GetSection(), fun_start_addr.GetOffset() + fun_addr_range.GetByteSize()); 1010 line_table->FindLineEntryByAddress (fun_end_addr, function_start, &end_ptr); 1011 1012 while (index_ptr <= end_ptr) 1013 { 1014 LineEntry line_entry; 1015 index_ptr = sc.comp_unit->FindLineEntry(index_ptr, line_number, sc.comp_unit, &line_entry); 1016 if (index_ptr == UINT32_MAX) 1017 break; 1018 1019 addr_t address = line_entry.range.GetBaseAddress().GetLoadAddress(process); 1020 if (address != LLDB_INVALID_ADDRESS) 1021 address_list.push_back (address); 1022 index_ptr++; 1023 } 1024 1025 new_plan = thread->QueueThreadPlanForStepUntil (abort_other_plans, &address_list.front(), address_list.size(), m_options.m_stop_others); 1026 new_plan->SetOkayToDiscard(false); 1027 } 1028 else 1029 { 1030 result.AppendErrorWithFormat ("Frame index %u of thread %u has no debug information.\n", m_options.m_frame_idx, m_options.m_thread_idx); 1031 result.SetStatus (eReturnStatusFailed); 1032 return false; 1033 1034 } 1035 1036 process->GetThreadList().SetCurrentThreadByID (m_options.m_thread_idx); 1037 Error error (process->Resume ()); 1038 if (error.Success()) 1039 { 1040 result.AppendMessageWithFormat ("Resuming process %i\n", process->GetID()); 1041 if (synchronous_execution) 1042 { 1043 StateType state = process->WaitForProcessToStop (NULL); 1044 1045 result.SetDidChangeProcessState (true); 1046 result.AppendMessageWithFormat ("Process %i %s\n", process->GetID(), StateAsCString (state)); 1047 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1048 } 1049 else 1050 { 1051 result.SetStatus (eReturnStatusSuccessContinuingNoResult); 1052 } 1053 } 1054 else 1055 { 1056 result.AppendErrorWithFormat("Failed to resume process: %s.\n", error.AsCString()); 1057 result.SetStatus (eReturnStatusFailed); 1058 } 1059 1060 } 1061 return result.Succeeded(); 1062 } 1063 protected: 1064 CommandOptions m_options; 1065 1066 }; 1067 1068 lldb::OptionDefinition 1069 CommandObjectThreadUntil::CommandOptions::g_option_table[] = 1070 { 1071 { LLDB_OPT_SET_1, false, "frame", 'f', required_argument, NULL, 0, "<frame>", "Frame index for until operation - defaults to 0"}, 1072 { LLDB_OPT_SET_1, false, "thread", 't', required_argument, NULL, 0, "<thread>", "Thread index for the thread for until operation"}, 1073 { LLDB_OPT_SET_1, false, "run_mode",'m', required_argument, g_duo_running_mode, 0, "<run_mode>","Determine how to run other threads while stepping this one"}, 1074 { 0, false, NULL, 0, 0, NULL, 0, NULL, NULL } 1075 }; 1076 1077 1078 //------------------------------------------------------------------------- 1079 // CommandObjectThreadSelect 1080 //------------------------------------------------------------------------- 1081 1082 class CommandObjectThreadSelect : public CommandObject 1083 { 1084 public: 1085 1086 CommandObjectThreadSelect () : 1087 CommandObject ("thread select", 1088 "Selects a threads as the currently active thread.", 1089 "thread select <thread-index>", 1090 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 1091 { 1092 } 1093 1094 1095 virtual 1096 ~CommandObjectThreadSelect () 1097 { 1098 } 1099 1100 virtual bool 1101 Execute 1102 ( 1103 CommandInterpreter &interpreter, 1104 Args& command, 1105 CommandReturnObject &result 1106 ) 1107 { 1108 Process *process = interpreter.GetDebugger().GetExecutionContext().process; 1109 if (process == NULL) 1110 { 1111 result.AppendError ("no process"); 1112 result.SetStatus (eReturnStatusFailed); 1113 return false; 1114 } 1115 else if (command.GetArgumentCount() != 1) 1116 { 1117 result.AppendErrorWithFormat("'%s' takes exactly one thread index argument:\nUsage: \n", m_cmd_name.c_str(), m_cmd_syntax.c_str()); 1118 result.SetStatus (eReturnStatusFailed); 1119 return false; 1120 } 1121 1122 uint32_t index_id = Args::StringToUInt32(command.GetArgumentAtIndex(0), 0, 0); 1123 1124 Thread *new_thread = process->GetThreadList().FindThreadByIndexID(index_id).get(); 1125 if (new_thread == NULL) 1126 { 1127 result.AppendErrorWithFormat ("Invalid thread #%s.\n", command.GetArgumentAtIndex(0)); 1128 result.SetStatus (eReturnStatusFailed); 1129 return false; 1130 } 1131 1132 process->GetThreadList().SetCurrentThreadByID(new_thread->GetID()); 1133 1134 DisplayThreadInfo (interpreter, 1135 result.GetOutputStream(), 1136 new_thread, 1137 false, 1138 true); 1139 1140 return result.Succeeded(); 1141 } 1142 1143 }; 1144 1145 1146 //------------------------------------------------------------------------- 1147 // CommandObjectThreadList 1148 //------------------------------------------------------------------------- 1149 1150 class CommandObjectThreadList : public CommandObject 1151 { 1152 public: 1153 1154 1155 CommandObjectThreadList (): 1156 CommandObject ("thread list", 1157 "Shows a summary of all current threads in a process.", 1158 "thread list", 1159 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused) 1160 { 1161 } 1162 1163 ~CommandObjectThreadList() 1164 { 1165 } 1166 1167 bool 1168 Execute 1169 ( 1170 CommandInterpreter &interpreter, 1171 Args& command, 1172 CommandReturnObject &result 1173 ) 1174 { 1175 StreamString &strm = result.GetOutputStream(); 1176 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1177 ExecutionContext exe_ctx(interpreter.GetDebugger().GetExecutionContext()); 1178 if (exe_ctx.process) 1179 { 1180 const StateType state = exe_ctx.process->GetState(); 1181 1182 if (StateIsStoppedState(state)) 1183 { 1184 if (state == eStateExited) 1185 { 1186 int exit_status = exe_ctx.process->GetExitStatus(); 1187 const char *exit_description = exe_ctx.process->GetExitDescription(); 1188 strm.Printf ("Process %d exited with status = %i (0x%8.8x) %s\n", 1189 exe_ctx.process->GetID(), 1190 exit_status, 1191 exit_status, 1192 exit_description ? exit_description : ""); 1193 } 1194 else 1195 { 1196 strm.Printf ("Process %d state is %s\n", exe_ctx.process->GetID(), StateAsCString (state)); 1197 if (exe_ctx.thread == NULL) 1198 exe_ctx.thread = exe_ctx.process->GetThreadList().GetThreadAtIndex(0).get(); 1199 if (exe_ctx.thread != NULL) 1200 { 1201 DisplayThreadsInfo (interpreter, &exe_ctx, result, false, false); 1202 } 1203 else 1204 { 1205 result.AppendError ("no valid thread found in current process"); 1206 result.SetStatus (eReturnStatusFailed); 1207 } 1208 } 1209 } 1210 else 1211 { 1212 result.AppendError ("process is currently running"); 1213 result.SetStatus (eReturnStatusFailed); 1214 } 1215 } 1216 else 1217 { 1218 result.AppendError ("no current location or status available"); 1219 result.SetStatus (eReturnStatusFailed); 1220 } 1221 return result.Succeeded(); 1222 } 1223 }; 1224 1225 //------------------------------------------------------------------------- 1226 // CommandObjectMultiwordThread 1227 //------------------------------------------------------------------------- 1228 1229 CommandObjectMultiwordThread::CommandObjectMultiwordThread (CommandInterpreter &interpreter) : 1230 CommandObjectMultiword ("thread", 1231 "A set of commands for operating on one or more thread within a running process.", 1232 "thread <subcommand> [<subcommand-options>]") 1233 { 1234 LoadSubCommand (interpreter, "backtrace", CommandObjectSP (new CommandObjectThreadBacktrace ())); 1235 LoadSubCommand (interpreter, "continue", CommandObjectSP (new CommandObjectThreadContinue ())); 1236 LoadSubCommand (interpreter, "list", CommandObjectSP (new CommandObjectThreadList ())); 1237 LoadSubCommand (interpreter, "select", CommandObjectSP (new CommandObjectThreadSelect ())); 1238 LoadSubCommand (interpreter, "until", CommandObjectSP (new CommandObjectThreadUntil ())); 1239 LoadSubCommand (interpreter, "step-in", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ( 1240 "thread step-in", 1241 "Source level single step in in specified thread (current thread, if none specified).", 1242 "thread step-in [<thread-id>]", 1243 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1244 eStepTypeInto, 1245 eStepScopeSource))); 1246 1247 LoadSubCommand (interpreter, "step-out", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-out", 1248 "Source level single step out in specified thread (current thread, if none specified).", 1249 "thread step-out [<thread-id>]", 1250 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1251 eStepTypeOut, 1252 eStepScopeSource))); 1253 1254 LoadSubCommand (interpreter, "step-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-over", 1255 "Source level single step over in specified thread (current thread, if none specified).", 1256 "thread step-over [<thread-id>]", 1257 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1258 eStepTypeOver, 1259 eStepScopeSource))); 1260 1261 LoadSubCommand (interpreter, "step-inst", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst", 1262 "Single step one instruction in specified thread (current thread, if none specified).", 1263 "thread step-inst [<thread-id>]", 1264 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1265 eStepTypeTrace, 1266 eStepScopeInstruction))); 1267 1268 LoadSubCommand (interpreter, "step-inst-over", CommandObjectSP (new CommandObjectThreadStepWithTypeAndScope ("thread step-inst-over", 1269 "Single step one instruction in specified thread (current thread, if none specified), stepping over calls.", 1270 "thread step-inst-over [<thread-id>]", 1271 eFlagProcessMustBeLaunched | eFlagProcessMustBePaused, 1272 eStepTypeTraceOver, 1273 eStepScopeInstruction))); 1274 } 1275 1276 CommandObjectMultiwordThread::~CommandObjectMultiwordThread () 1277 { 1278 } 1279 1280 1281