1 //===-- CommandObjectTarget.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 "CommandObjectTarget.h" 11 12 // C Includes 13 #include <errno.h> 14 15 // C++ Includes 16 // Other libraries and framework includes 17 // Project includes 18 #include "lldb/Interpreter/Args.h" 19 #include "lldb/Core/Debugger.h" 20 #include "lldb/Core/InputReader.h" 21 #include "lldb/Core/Timer.h" 22 #include "lldb/Interpreter/CommandInterpreter.h" 23 #include "lldb/Interpreter/CommandReturnObject.h" 24 #include "lldb/Target/Process.h" 25 #include "lldb/Target/StackFrame.h" 26 #include "lldb/Target/Thread.h" 27 #include "lldb/Target/ThreadSpec.h" 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 #pragma mark CommandObjectTargetImageSearchPaths 33 34 class CommandObjectTargetImageSearchPathsAdd : public CommandObject 35 { 36 public: 37 38 CommandObjectTargetImageSearchPathsAdd (CommandInterpreter &interpreter) : 39 CommandObject (interpreter, 40 "target image-search-paths add", 41 "Add new image search paths substitution pairs to the current target.", 42 NULL) 43 { 44 CommandArgumentEntry arg; 45 CommandArgumentData old_prefix_arg; 46 CommandArgumentData new_prefix_arg; 47 48 // Define the first variant of this arg pair. 49 old_prefix_arg.arg_type = eArgTypeOldPathPrefix; 50 old_prefix_arg.arg_repetition = eArgRepeatPairPlus; 51 52 // Define the first variant of this arg pair. 53 new_prefix_arg.arg_type = eArgTypeNewPathPrefix; 54 new_prefix_arg.arg_repetition = eArgRepeatPairPlus; 55 56 // There are two required arguments that must always occur together, i.e. an argument "pair". Because they 57 // must always occur together, they are treated as two variants of one argument rather than two independent 58 // arguments. Push them both into the first argument position for m_arguments... 59 60 arg.push_back (old_prefix_arg); 61 arg.push_back (new_prefix_arg); 62 63 m_arguments.push_back (arg); 64 } 65 66 ~CommandObjectTargetImageSearchPathsAdd () 67 { 68 } 69 70 bool 71 Execute (Args& command, 72 CommandReturnObject &result) 73 { 74 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 75 if (target) 76 { 77 uint32_t argc = command.GetArgumentCount(); 78 if (argc & 1) 79 { 80 result.AppendError ("add requires an even number of arguments"); 81 result.SetStatus (eReturnStatusFailed); 82 } 83 else 84 { 85 for (uint32_t i=0; i<argc; i+=2) 86 { 87 const char *from = command.GetArgumentAtIndex(i); 88 const char *to = command.GetArgumentAtIndex(i+1); 89 90 if (from[0] && to[0]) 91 { 92 bool last_pair = ((argc - i) == 2); 93 target->GetImageSearchPathList().Append (ConstString(from), 94 ConstString(to), 95 last_pair); // Notify if this is the last pair 96 result.SetStatus (eReturnStatusSuccessFinishNoResult); 97 } 98 else 99 { 100 if (from[0]) 101 result.AppendError ("<path-prefix> can't be empty"); 102 else 103 result.AppendError ("<new-path-prefix> can't be empty"); 104 result.SetStatus (eReturnStatusFailed); 105 } 106 } 107 } 108 } 109 else 110 { 111 result.AppendError ("invalid target"); 112 result.SetStatus (eReturnStatusFailed); 113 } 114 return result.Succeeded(); 115 } 116 }; 117 118 class CommandObjectTargetImageSearchPathsClear : public CommandObject 119 { 120 public: 121 122 CommandObjectTargetImageSearchPathsClear (CommandInterpreter &interpreter) : 123 CommandObject (interpreter, 124 "target image-search-paths clear", 125 "Clear all current image search path substitution pairs from the current target.", 126 "target image-search-paths clear") 127 { 128 } 129 130 ~CommandObjectTargetImageSearchPathsClear () 131 { 132 } 133 134 bool 135 Execute (Args& command, 136 CommandReturnObject &result) 137 { 138 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 139 if (target) 140 { 141 bool notify = true; 142 target->GetImageSearchPathList().Clear(notify); 143 result.SetStatus (eReturnStatusSuccessFinishNoResult); 144 } 145 else 146 { 147 result.AppendError ("invalid target"); 148 result.SetStatus (eReturnStatusFailed); 149 } 150 return result.Succeeded(); 151 } 152 }; 153 154 class CommandObjectTargetImageSearchPathsInsert : public CommandObject 155 { 156 public: 157 158 CommandObjectTargetImageSearchPathsInsert (CommandInterpreter &interpreter) : 159 CommandObject (interpreter, 160 "target image-search-paths insert", 161 "Insert a new image search path substitution pair into the current target at the specified index.", 162 NULL) 163 { 164 CommandArgumentEntry arg1; 165 CommandArgumentEntry arg2; 166 CommandArgumentData index_arg; 167 CommandArgumentData old_prefix_arg; 168 CommandArgumentData new_prefix_arg; 169 170 // Define the first and only variant of this arg. 171 index_arg.arg_type = eArgTypeIndex; 172 index_arg.arg_repetition = eArgRepeatPlain; 173 174 // Put the one and only variant into the first arg for m_arguments: 175 arg1.push_back (index_arg); 176 177 // Define the first variant of this arg pair. 178 old_prefix_arg.arg_type = eArgTypeOldPathPrefix; 179 old_prefix_arg.arg_repetition = eArgRepeatPairPlus; 180 181 // Define the first variant of this arg pair. 182 new_prefix_arg.arg_type = eArgTypeNewPathPrefix; 183 new_prefix_arg.arg_repetition = eArgRepeatPairPlus; 184 185 // There are two required arguments that must always occur together, i.e. an argument "pair". Because they 186 // must always occur together, they are treated as two variants of one argument rather than two independent 187 // arguments. Push them both into the same argument position for m_arguments... 188 189 arg2.push_back (old_prefix_arg); 190 arg2.push_back (new_prefix_arg); 191 192 // Add arguments to m_arguments. 193 m_arguments.push_back (arg1); 194 m_arguments.push_back (arg2); 195 } 196 197 ~CommandObjectTargetImageSearchPathsInsert () 198 { 199 } 200 201 bool 202 Execute (Args& command, 203 CommandReturnObject &result) 204 { 205 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 206 if (target) 207 { 208 uint32_t argc = command.GetArgumentCount(); 209 // check for at least 3 arguments and an odd nubmer of parameters 210 if (argc >= 3 && argc & 1) 211 { 212 bool success = false; 213 214 uint32_t insert_idx = Args::StringToUInt32(command.GetArgumentAtIndex(0), UINT32_MAX, 0, &success); 215 216 if (!success) 217 { 218 result.AppendErrorWithFormat("<index> parameter is not an integer: '%s'.\n", command.GetArgumentAtIndex(0)); 219 result.SetStatus (eReturnStatusFailed); 220 return result.Succeeded(); 221 } 222 223 // shift off the index 224 command.Shift(); 225 argc = command.GetArgumentCount(); 226 227 for (uint32_t i=0; i<argc; i+=2, ++insert_idx) 228 { 229 const char *from = command.GetArgumentAtIndex(i); 230 const char *to = command.GetArgumentAtIndex(i+1); 231 232 if (from[0] && to[0]) 233 { 234 bool last_pair = ((argc - i) == 2); 235 target->GetImageSearchPathList().Insert (ConstString(from), 236 ConstString(to), 237 insert_idx, 238 last_pair); 239 result.SetStatus (eReturnStatusSuccessFinishNoResult); 240 } 241 else 242 { 243 if (from[0]) 244 result.AppendError ("<path-prefix> can't be empty"); 245 else 246 result.AppendError ("<new-path-prefix> can't be empty"); 247 result.SetStatus (eReturnStatusFailed); 248 return false; 249 } 250 } 251 } 252 else 253 { 254 result.AppendError ("insert requires at least three arguments"); 255 result.SetStatus (eReturnStatusFailed); 256 return result.Succeeded(); 257 } 258 259 } 260 else 261 { 262 result.AppendError ("invalid target"); 263 result.SetStatus (eReturnStatusFailed); 264 } 265 return result.Succeeded(); 266 } 267 }; 268 269 class CommandObjectTargetImageSearchPathsList : public CommandObject 270 { 271 public: 272 273 CommandObjectTargetImageSearchPathsList (CommandInterpreter &interpreter) : 274 CommandObject (interpreter, 275 "target image-search-paths list", 276 "List all current image search path substitution pairs in the current target.", 277 "target image-search-paths list") 278 { 279 } 280 281 ~CommandObjectTargetImageSearchPathsList () 282 { 283 } 284 285 bool 286 Execute (Args& command, 287 CommandReturnObject &result) 288 { 289 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 290 if (target) 291 { 292 if (command.GetArgumentCount() != 0) 293 { 294 result.AppendError ("list takes no arguments"); 295 result.SetStatus (eReturnStatusFailed); 296 return result.Succeeded(); 297 } 298 299 target->GetImageSearchPathList().Dump(&result.GetOutputStream()); 300 result.SetStatus (eReturnStatusSuccessFinishResult); 301 } 302 else 303 { 304 result.AppendError ("invalid target"); 305 result.SetStatus (eReturnStatusFailed); 306 } 307 return result.Succeeded(); 308 } 309 }; 310 311 class CommandObjectTargetImageSearchPathsQuery : public CommandObject 312 { 313 public: 314 315 CommandObjectTargetImageSearchPathsQuery (CommandInterpreter &interpreter) : 316 CommandObject (interpreter, 317 "target image-search-paths query", 318 "Transform a path using the first applicable image search path.", 319 NULL) 320 { 321 CommandArgumentEntry arg; 322 CommandArgumentData path_arg; 323 324 // Define the first (and only) variant of this arg. 325 path_arg.arg_type = eArgTypePath; 326 path_arg.arg_repetition = eArgRepeatPlain; 327 328 // There is only one variant this argument could be; put it into the argument entry. 329 arg.push_back (path_arg); 330 331 // Push the data for the first argument into the m_arguments vector. 332 m_arguments.push_back (arg); 333 } 334 335 ~CommandObjectTargetImageSearchPathsQuery () 336 { 337 } 338 339 bool 340 Execute (Args& command, 341 CommandReturnObject &result) 342 { 343 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 344 if (target) 345 { 346 if (command.GetArgumentCount() != 1) 347 { 348 result.AppendError ("query requires one argument"); 349 result.SetStatus (eReturnStatusFailed); 350 return result.Succeeded(); 351 } 352 353 ConstString orig(command.GetArgumentAtIndex(0)); 354 ConstString transformed; 355 if (target->GetImageSearchPathList().RemapPath(orig, transformed)) 356 result.GetOutputStream().Printf("%s\n", transformed.GetCString()); 357 else 358 result.GetOutputStream().Printf("%s\n", orig.GetCString()); 359 360 result.SetStatus (eReturnStatusSuccessFinishResult); 361 } 362 else 363 { 364 result.AppendError ("invalid target"); 365 result.SetStatus (eReturnStatusFailed); 366 } 367 return result.Succeeded(); 368 } 369 }; 370 371 // TODO: implement the target select later when we start doing multiple targets 372 //#pragma mark CommandObjectTargetSelect 373 // 374 ////------------------------------------------------------------------------- 375 //// CommandObjectTargetSelect 376 ////------------------------------------------------------------------------- 377 // 378 //class CommandObjectTargetSelect : public CommandObject 379 //{ 380 //public: 381 // 382 // CommandObjectTargetSelect () : 383 // CommandObject (interpreter, 384 // frame select", 385 // "Select the current frame by index in the current thread.", 386 // "frame select <frame-index>") 387 // { 388 // } 389 // 390 // ~CommandObjectTargetSelect () 391 // { 392 // } 393 // 394 // bool 395 // Execute (Args& command, 396 // Debugger *context, 397 // CommandInterpreter &m_interpreter, 398 // CommandReturnObject &result) 399 // { 400 // ExecutionContext exe_ctx (context->GetExecutionContext()); 401 // if (exe_ctx.thread) 402 // { 403 // if (command.GetArgumentCount() == 1) 404 // { 405 // const char *frame_idx_cstr = command.GetArgumentAtIndex(0); 406 // 407 // const uint32_t num_frames = exe_ctx.thread->GetStackFrameCount(); 408 // const uint32_t frame_idx = Args::StringToUInt32 (frame_idx_cstr, UINT32_MAX, 0); 409 // if (frame_idx < num_frames) 410 // { 411 // exe_ctx.thread->SetSelectedFrameByIndex (frame_idx); 412 // exe_ctx.frame = exe_ctx.thread->GetSelectedFrame ().get(); 413 // 414 // if (exe_ctx.frame) 415 // { 416 // if (DisplayFrameForExecutionContext (exe_ctx.thread, 417 // exe_ctx.frame, 418 // m_interpreter, 419 // result.GetOutputStream(), 420 // true, 421 // true, 422 // 3, 423 // 3)) 424 // { 425 // result.SetStatus (eReturnStatusSuccessFinishResult); 426 // return result.Succeeded(); 427 // } 428 // } 429 // } 430 // if (frame_idx == UINT32_MAX) 431 // result.AppendErrorWithFormat ("Invalid frame index: %s.\n", frame_idx_cstr); 432 // else 433 // result.AppendErrorWithFormat ("Frame index (%u) out of range.\n", frame_idx); 434 // } 435 // else 436 // { 437 // result.AppendError ("invalid arguments"); 438 // result.AppendErrorWithFormat ("Usage: %s\n", m_cmd_syntax.c_str()); 439 // } 440 // } 441 // else 442 // { 443 // result.AppendError ("no current thread"); 444 // } 445 // result.SetStatus (eReturnStatusFailed); 446 // return false; 447 // } 448 //}; 449 450 451 #pragma mark CommandObjectMultiwordImageSearchPaths 452 453 //------------------------------------------------------------------------- 454 // CommandObjectMultiwordImageSearchPaths 455 //------------------------------------------------------------------------- 456 457 class CommandObjectMultiwordImageSearchPaths : public CommandObjectMultiword 458 { 459 public: 460 461 CommandObjectMultiwordImageSearchPaths (CommandInterpreter &interpreter) : 462 CommandObjectMultiword (interpreter, 463 "target image-search-paths", 464 "A set of commands for operating on debugger target image search paths.", 465 "target image-search-paths <subcommand> [<subcommand-options>]") 466 { 467 LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetImageSearchPathsAdd (interpreter))); 468 LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTargetImageSearchPathsClear (interpreter))); 469 LoadSubCommand ("insert", CommandObjectSP (new CommandObjectTargetImageSearchPathsInsert (interpreter))); 470 LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetImageSearchPathsList (interpreter))); 471 LoadSubCommand ("query", CommandObjectSP (new CommandObjectTargetImageSearchPathsQuery (interpreter))); 472 } 473 474 ~CommandObjectMultiwordImageSearchPaths() 475 { 476 } 477 }; 478 479 #pragma mark CommandObjectTargetStopHookAdd 480 481 //------------------------------------------------------------------------- 482 // CommandObjectTargetStopHookAdd 483 //------------------------------------------------------------------------- 484 485 class CommandObjectTargetStopHookAdd : public CommandObject 486 { 487 public: 488 489 class CommandOptions : public Options 490 { 491 public: 492 CommandOptions (CommandInterpreter &interpreter) : 493 Options(interpreter), 494 m_line_start(0), 495 m_line_end (UINT_MAX), 496 m_func_name_type_mask (eFunctionNameTypeAuto), 497 m_sym_ctx_specified (false), 498 m_thread_specified (false) 499 { 500 } 501 502 ~CommandOptions () {} 503 504 const OptionDefinition* 505 GetDefinitions () 506 { 507 return g_option_table; 508 } 509 510 virtual Error 511 SetOptionValue (uint32_t option_idx, const char *option_arg) 512 { 513 Error error; 514 char short_option = (char) m_getopt_table[option_idx].val; 515 bool success; 516 517 switch (short_option) 518 { 519 case 'c': 520 m_class_name = option_arg; 521 m_sym_ctx_specified = true; 522 break; 523 524 case 'e': 525 m_line_end = Args::StringToUInt32 (option_arg, UINT_MAX, 0, &success); 526 if (!success) 527 { 528 error.SetErrorStringWithFormat ("Invalid end line number: \"%s\".", option_arg); 529 break; 530 } 531 m_sym_ctx_specified = true; 532 break; 533 534 case 'l': 535 m_line_start = Args::StringToUInt32 (option_arg, 0, 0, &success); 536 if (!success) 537 { 538 error.SetErrorStringWithFormat ("Invalid start line number: \"%s\".", option_arg); 539 break; 540 } 541 m_sym_ctx_specified = true; 542 break; 543 544 case 'n': 545 m_function_name = option_arg; 546 m_func_name_type_mask |= eFunctionNameTypeAuto; 547 m_sym_ctx_specified = true; 548 break; 549 550 case 'f': 551 m_file_name = option_arg; 552 m_sym_ctx_specified = true; 553 break; 554 case 's': 555 m_module_name = option_arg; 556 m_sym_ctx_specified = true; 557 break; 558 case 't' : 559 { 560 m_thread_id = Args::StringToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); 561 if (m_thread_id == LLDB_INVALID_THREAD_ID) 562 error.SetErrorStringWithFormat ("Invalid thread id string '%s'.\n", option_arg); 563 m_thread_specified = true; 564 } 565 break; 566 case 'T': 567 m_thread_name = option_arg; 568 m_thread_specified = true; 569 break; 570 case 'q': 571 m_queue_name = option_arg; 572 m_thread_specified = true; 573 break; 574 case 'x': 575 { 576 m_thread_index = Args::StringToUInt32(option_arg, UINT32_MAX, 0); 577 if (m_thread_id == UINT32_MAX) 578 error.SetErrorStringWithFormat ("Invalid thread index string '%s'.\n", option_arg); 579 m_thread_specified = true; 580 } 581 break; 582 default: 583 error.SetErrorStringWithFormat ("Unrecognized option %c."); 584 break; 585 } 586 return error; 587 } 588 589 void 590 OptionParsingStarting () 591 { 592 m_class_name.clear(); 593 m_function_name.clear(); 594 m_line_start = 0; 595 m_line_end = UINT_MAX; 596 m_file_name.clear(); 597 m_module_name.clear(); 598 m_func_name_type_mask = eFunctionNameTypeAuto; 599 m_thread_id = LLDB_INVALID_THREAD_ID; 600 m_thread_index = UINT32_MAX; 601 m_thread_name.clear(); 602 m_queue_name.clear(); 603 604 m_sym_ctx_specified = false; 605 m_thread_specified = false; 606 } 607 608 609 static OptionDefinition g_option_table[]; 610 611 std::string m_class_name; 612 std::string m_function_name; 613 uint32_t m_line_start; 614 uint32_t m_line_end; 615 std::string m_file_name; 616 std::string m_module_name; 617 uint32_t m_func_name_type_mask; // A pick from lldb::FunctionNameType. 618 lldb::tid_t m_thread_id; 619 uint32_t m_thread_index; 620 std::string m_thread_name; 621 std::string m_queue_name; 622 bool m_sym_ctx_specified; 623 bool m_thread_specified; 624 625 }; 626 627 Options * 628 GetOptions () 629 { 630 return &m_options; 631 } 632 633 CommandObjectTargetStopHookAdd (CommandInterpreter &interpreter) : 634 CommandObject (interpreter, 635 "target stop-hook add ", 636 "Add a hook to be executed when the target stops.", 637 "target stop-hook add"), 638 m_options (interpreter) 639 { 640 } 641 642 ~CommandObjectTargetStopHookAdd () 643 { 644 } 645 646 static size_t 647 ReadCommandsCallbackFunction (void *baton, 648 InputReader &reader, 649 lldb::InputReaderAction notification, 650 const char *bytes, 651 size_t bytes_len) 652 { 653 File &out_file = reader.GetDebugger().GetOutputFile(); 654 Target::StopHook *new_stop_hook = ((Target::StopHook *) baton); 655 656 switch (notification) 657 { 658 case eInputReaderActivate: 659 out_file.Printf ("%s\n", "Enter your stop hook command(s). Type 'DONE' to end."); 660 if (reader.GetPrompt()) 661 out_file.Printf ("%s", reader.GetPrompt()); 662 out_file.Flush(); 663 break; 664 665 case eInputReaderDeactivate: 666 break; 667 668 case eInputReaderReactivate: 669 if (reader.GetPrompt()) 670 { 671 out_file.Printf ("%s", reader.GetPrompt()); 672 out_file.Flush(); 673 } 674 break; 675 676 case eInputReaderGotToken: 677 if (bytes && bytes_len && baton) 678 { 679 StringList *commands = new_stop_hook->GetCommandPointer(); 680 if (commands) 681 { 682 commands->AppendString (bytes, bytes_len); 683 } 684 } 685 if (!reader.IsDone() && reader.GetPrompt()) 686 { 687 out_file.Printf ("%s", reader.GetPrompt()); 688 out_file.Flush(); 689 } 690 break; 691 692 case eInputReaderInterrupt: 693 { 694 // Finish, and cancel the stop hook. 695 new_stop_hook->GetTarget()->RemoveStopHookByID(new_stop_hook->GetID()); 696 out_file.Printf ("Stop hook cancelled.\n"); 697 698 reader.SetIsDone (true); 699 } 700 break; 701 702 case eInputReaderEndOfFile: 703 reader.SetIsDone (true); 704 break; 705 706 case eInputReaderDone: 707 out_file.Printf ("Stop hook #%d added.\n", new_stop_hook->GetID()); 708 break; 709 } 710 711 return bytes_len; 712 } 713 714 bool 715 Execute (Args& command, 716 CommandReturnObject &result) 717 { 718 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 719 if (target) 720 { 721 Target::StopHookSP new_hook_sp; 722 target->AddStopHook (new_hook_sp); 723 724 // First step, make the specifier. 725 std::auto_ptr<SymbolContextSpecifier> specifier_ap; 726 if (m_options.m_sym_ctx_specified) 727 { 728 specifier_ap.reset(new SymbolContextSpecifier(m_interpreter.GetDebugger().GetSelectedTarget())); 729 730 if (!m_options.m_module_name.empty()) 731 { 732 specifier_ap->AddSpecification (m_options.m_module_name.c_str(), SymbolContextSpecifier::eModuleSpecified); 733 } 734 735 if (!m_options.m_class_name.empty()) 736 { 737 specifier_ap->AddSpecification (m_options.m_class_name.c_str(), SymbolContextSpecifier::eClassOrNamespaceSpecified); 738 } 739 740 if (!m_options.m_file_name.empty()) 741 { 742 specifier_ap->AddSpecification (m_options.m_file_name.c_str(), SymbolContextSpecifier::eFileSpecified); 743 } 744 745 if (m_options.m_line_start != 0) 746 { 747 specifier_ap->AddLineSpecification (m_options.m_line_start, SymbolContextSpecifier::eLineStartSpecified); 748 } 749 750 if (m_options.m_line_end != UINT_MAX) 751 { 752 specifier_ap->AddLineSpecification (m_options.m_line_end, SymbolContextSpecifier::eLineEndSpecified); 753 } 754 755 if (!m_options.m_function_name.empty()) 756 { 757 specifier_ap->AddSpecification (m_options.m_function_name.c_str(), SymbolContextSpecifier::eFunctionSpecified); 758 } 759 } 760 761 if (specifier_ap.get()) 762 new_hook_sp->SetSpecifier (specifier_ap.release()); 763 764 // Next see if any of the thread options have been entered: 765 766 if (m_options.m_thread_specified) 767 { 768 ThreadSpec *thread_spec = new ThreadSpec(); 769 770 if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID) 771 { 772 thread_spec->SetTID (m_options.m_thread_id); 773 } 774 775 if (m_options.m_thread_index != UINT32_MAX) 776 thread_spec->SetIndex (m_options.m_thread_index); 777 778 if (!m_options.m_thread_name.empty()) 779 thread_spec->SetName (m_options.m_thread_name.c_str()); 780 781 if (!m_options.m_queue_name.empty()) 782 thread_spec->SetQueueName (m_options.m_queue_name.c_str()); 783 784 new_hook_sp->SetThreadSpecifier (thread_spec); 785 786 } 787 // Next gather up the command list, we'll push an input reader and suck the data from that directly into 788 // the new stop hook's command string. 789 790 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 791 if (!reader_sp) 792 { 793 result.AppendError("out of memory"); 794 result.SetStatus (eReturnStatusFailed); 795 target->RemoveStopHookByID (new_hook_sp->GetID()); 796 return false; 797 } 798 799 Error err (reader_sp->Initialize (CommandObjectTargetStopHookAdd::ReadCommandsCallbackFunction, 800 new_hook_sp.get(), // baton 801 eInputReaderGranularityLine, // token size, to pass to callback function 802 "DONE", // end token 803 "> ", // prompt 804 true)); // echo input 805 if (!err.Success()) 806 { 807 result.AppendError (err.AsCString()); 808 result.SetStatus (eReturnStatusFailed); 809 target->RemoveStopHookByID (new_hook_sp->GetID()); 810 return false; 811 } 812 m_interpreter.GetDebugger().PushInputReader (reader_sp); 813 814 result.SetStatus (eReturnStatusSuccessFinishNoResult); 815 } 816 else 817 { 818 result.AppendError ("invalid target"); 819 result.SetStatus (eReturnStatusFailed); 820 } 821 822 return result.Succeeded(); 823 } 824 private: 825 CommandOptions m_options; 826 }; 827 828 OptionDefinition 829 CommandObjectTargetStopHookAdd::CommandOptions::g_option_table[] = 830 { 831 { LLDB_OPT_SET_ALL, false, "shlib", 's', required_argument, NULL, CommandCompletions::eModuleCompletion, eArgTypeShlibName, 832 "Set the module within which the stop-hook is to be run."}, 833 { LLDB_OPT_SET_ALL, false, "thread-index", 'x', required_argument, NULL, NULL, eArgTypeThreadIndex, 834 "The stop hook is run only for the thread whose index matches this argument."}, 835 { LLDB_OPT_SET_ALL, false, "thread-id", 't', required_argument, NULL, NULL, eArgTypeThreadID, 836 "The stop hook is run only for the thread whose TID matches this argument."}, 837 { LLDB_OPT_SET_ALL, false, "thread-name", 'T', required_argument, NULL, NULL, eArgTypeThreadName, 838 "The stop hook is run only for the thread whose thread name matches this argument."}, 839 { LLDB_OPT_SET_ALL, false, "queue-name", 'q', required_argument, NULL, NULL, eArgTypeQueueName, 840 "The stop hook is run only for threads in the queue whose name is given by this argument."}, 841 { LLDB_OPT_SET_1, false, "file", 'f', required_argument, NULL, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, 842 "Specify the source file within which the stop-hook is to be run." }, 843 { LLDB_OPT_SET_1, false, "start-line", 'l', required_argument, NULL, 0, eArgTypeLineNum, 844 "Set the start of the line range for which the stop-hook is to be run."}, 845 { LLDB_OPT_SET_1, false, "end-line", 'e', required_argument, NULL, 0, eArgTypeLineNum, 846 "Set the end of the line range for which the stop-hook is to be run."}, 847 { LLDB_OPT_SET_2, false, "classname", 'c', required_argument, NULL, NULL, eArgTypeClassName, 848 "Specify the class within which the stop-hook is to be run." }, 849 { LLDB_OPT_SET_3, false, "name", 'n', required_argument, NULL, CommandCompletions::eSymbolCompletion, eArgTypeFunctionName, 850 "Set the function name within which the stop hook will be run." }, 851 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 852 }; 853 854 #pragma mark CommandObjectTargetStopHookDelete 855 856 //------------------------------------------------------------------------- 857 // CommandObjectTargetStopHookDelete 858 //------------------------------------------------------------------------- 859 860 class CommandObjectTargetStopHookDelete : public CommandObject 861 { 862 public: 863 864 CommandObjectTargetStopHookDelete (CommandInterpreter &interpreter) : 865 CommandObject (interpreter, 866 "target stop-hook delete [<id>]", 867 "Delete a stop-hook.", 868 "target stop-hook delete") 869 { 870 } 871 872 ~CommandObjectTargetStopHookDelete () 873 { 874 } 875 876 bool 877 Execute (Args& command, 878 CommandReturnObject &result) 879 { 880 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 881 if (target) 882 { 883 // FIXME: see if we can use the breakpoint id style parser? 884 size_t num_args = command.GetArgumentCount(); 885 if (num_args == 0) 886 { 887 if (!m_interpreter.Confirm ("Delete all stop hooks?", true)) 888 { 889 result.SetStatus (eReturnStatusFailed); 890 return false; 891 } 892 else 893 { 894 target->RemoveAllStopHooks(); 895 } 896 } 897 else 898 { 899 bool success; 900 for (size_t i = 0; i < num_args; i++) 901 { 902 lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success); 903 if (!success) 904 { 905 result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".", command.GetArgumentAtIndex(i)); 906 result.SetStatus(eReturnStatusFailed); 907 return false; 908 } 909 success = target->RemoveStopHookByID (user_id); 910 if (!success) 911 { 912 result.AppendErrorWithFormat ("unknown stop hook id: \"%s\".", command.GetArgumentAtIndex(i)); 913 result.SetStatus(eReturnStatusFailed); 914 return false; 915 } 916 } 917 } 918 result.SetStatus (eReturnStatusSuccessFinishNoResult); 919 } 920 else 921 { 922 result.AppendError ("invalid target"); 923 result.SetStatus (eReturnStatusFailed); 924 } 925 926 return result.Succeeded(); 927 } 928 }; 929 #pragma mark CommandObjectTargetStopHookEnableDisable 930 931 //------------------------------------------------------------------------- 932 // CommandObjectTargetStopHookEnableDisable 933 //------------------------------------------------------------------------- 934 935 class CommandObjectTargetStopHookEnableDisable : public CommandObject 936 { 937 public: 938 939 CommandObjectTargetStopHookEnableDisable (CommandInterpreter &interpreter, bool enable, const char *name, const char *help, const char *syntax) : 940 CommandObject (interpreter, 941 name, 942 help, 943 syntax), 944 m_enable (enable) 945 { 946 } 947 948 ~CommandObjectTargetStopHookEnableDisable () 949 { 950 } 951 952 bool 953 Execute (Args& command, 954 CommandReturnObject &result) 955 { 956 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 957 if (target) 958 { 959 // FIXME: see if we can use the breakpoint id style parser? 960 size_t num_args = command.GetArgumentCount(); 961 bool success; 962 963 if (num_args == 0) 964 { 965 target->SetAllStopHooksActiveState (m_enable); 966 } 967 else 968 { 969 for (size_t i = 0; i < num_args; i++) 970 { 971 lldb::user_id_t user_id = Args::StringToUInt32 (command.GetArgumentAtIndex(i), 0, 0, &success); 972 if (!success) 973 { 974 result.AppendErrorWithFormat ("invalid stop hook id: \"%s\".", command.GetArgumentAtIndex(i)); 975 result.SetStatus(eReturnStatusFailed); 976 return false; 977 } 978 success = target->SetStopHookActiveStateByID (user_id, m_enable); 979 if (!success) 980 { 981 result.AppendErrorWithFormat ("unknown stop hook id: \"%s\".", command.GetArgumentAtIndex(i)); 982 result.SetStatus(eReturnStatusFailed); 983 return false; 984 } 985 } 986 } 987 result.SetStatus (eReturnStatusSuccessFinishNoResult); 988 } 989 else 990 { 991 result.AppendError ("invalid target"); 992 result.SetStatus (eReturnStatusFailed); 993 } 994 return result.Succeeded(); 995 } 996 private: 997 bool m_enable; 998 }; 999 1000 #pragma mark CommandObjectTargetStopHookList 1001 1002 //------------------------------------------------------------------------- 1003 // CommandObjectTargetStopHookList 1004 //------------------------------------------------------------------------- 1005 1006 class CommandObjectTargetStopHookList : public CommandObject 1007 { 1008 public: 1009 1010 CommandObjectTargetStopHookList (CommandInterpreter &interpreter) : 1011 CommandObject (interpreter, 1012 "target stop-hook list [<type>]", 1013 "List all stop-hooks.", 1014 "target stop-hook list") 1015 { 1016 } 1017 1018 ~CommandObjectTargetStopHookList () 1019 { 1020 } 1021 1022 bool 1023 Execute (Args& command, 1024 CommandReturnObject &result) 1025 { 1026 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 1027 if (target) 1028 { 1029 bool notify = true; 1030 target->GetImageSearchPathList().Clear(notify); 1031 result.SetStatus (eReturnStatusSuccessFinishNoResult); 1032 } 1033 else 1034 { 1035 result.AppendError ("invalid target"); 1036 result.SetStatus (eReturnStatusFailed); 1037 } 1038 1039 size_t num_hooks = target->GetNumStopHooks (); 1040 if (num_hooks == 0) 1041 { 1042 result.GetOutputStream().PutCString ("No stop hooks.\n"); 1043 } 1044 else 1045 { 1046 for (size_t i = 0; i < num_hooks; i++) 1047 { 1048 Target::StopHookSP this_hook = target->GetStopHookAtIndex (i); 1049 if (i > 0) 1050 result.GetOutputStream().PutCString ("\n"); 1051 this_hook->GetDescription (&(result.GetOutputStream()), eDescriptionLevelFull); 1052 } 1053 } 1054 return result.Succeeded(); 1055 } 1056 }; 1057 1058 #pragma mark CommandObjectMultiwordTargetStopHooks 1059 //------------------------------------------------------------------------- 1060 // CommandObjectMultiwordTargetStopHooks 1061 //------------------------------------------------------------------------- 1062 1063 class CommandObjectMultiwordTargetStopHooks : public CommandObjectMultiword 1064 { 1065 public: 1066 1067 CommandObjectMultiwordTargetStopHooks (CommandInterpreter &interpreter) : 1068 CommandObjectMultiword (interpreter, 1069 "target stop-hook", 1070 "A set of commands for operating on debugger target stop-hooks.", 1071 "target stop-hook <subcommand> [<subcommand-options>]") 1072 { 1073 LoadSubCommand ("add", CommandObjectSP (new CommandObjectTargetStopHookAdd (interpreter))); 1074 LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTargetStopHookDelete (interpreter))); 1075 LoadSubCommand ("disable", CommandObjectSP (new CommandObjectTargetStopHookEnableDisable (interpreter, 1076 false, 1077 "target stop-hook disable [<id>]", 1078 "Disable a stop-hook.", 1079 "target stop-hook disable"))); 1080 LoadSubCommand ("enable", CommandObjectSP (new CommandObjectTargetStopHookEnableDisable (interpreter, 1081 true, 1082 "target stop-hook enable [<id>]", 1083 "Enable a stop-hook.", 1084 "target stop-hook enable"))); 1085 LoadSubCommand ("list", CommandObjectSP (new CommandObjectTargetStopHookList (interpreter))); 1086 } 1087 1088 ~CommandObjectMultiwordTargetStopHooks() 1089 { 1090 } 1091 }; 1092 1093 1094 1095 #pragma mark CommandObjectMultiwordTarget 1096 1097 //------------------------------------------------------------------------- 1098 // CommandObjectMultiwordTarget 1099 //------------------------------------------------------------------------- 1100 1101 CommandObjectMultiwordTarget::CommandObjectMultiwordTarget (CommandInterpreter &interpreter) : 1102 CommandObjectMultiword (interpreter, 1103 "target", 1104 "A set of commands for operating on debugger targets.", 1105 "target <subcommand> [<subcommand-options>]") 1106 { 1107 LoadSubCommand ("image-search-paths", CommandObjectSP (new CommandObjectMultiwordImageSearchPaths (interpreter))); 1108 LoadSubCommand ("stop-hook", CommandObjectSP (new CommandObjectMultiwordTargetStopHooks (interpreter))); 1109 } 1110 1111 CommandObjectMultiwordTarget::~CommandObjectMultiwordTarget () 1112 { 1113 } 1114 1115