1 //===-- CommandObjectBreakpointCommand.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/lldb-python.h" 11 12 // C Includes 13 // C++ Includes 14 15 16 #include "CommandObjectBreakpointCommand.h" 17 #include "CommandObjectBreakpoint.h" 18 19 #include "lldb/Interpreter/CommandInterpreter.h" 20 #include "lldb/Interpreter/CommandReturnObject.h" 21 #include "lldb/Target/Target.h" 22 #include "lldb/Target/Thread.h" 23 #include "lldb/Breakpoint/BreakpointIDList.h" 24 #include "lldb/Breakpoint/Breakpoint.h" 25 #include "lldb/Breakpoint/BreakpointLocation.h" 26 #include "lldb/Breakpoint/StoppointCallbackContext.h" 27 #include "lldb/Core/State.h" 28 29 using namespace lldb; 30 using namespace lldb_private; 31 32 //------------------------------------------------------------------------- 33 // CommandObjectBreakpointCommandAdd 34 //------------------------------------------------------------------------- 35 36 37 class CommandObjectBreakpointCommandAdd : public CommandObjectParsed 38 { 39 public: 40 41 CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) : 42 CommandObjectParsed (interpreter, 43 "add", 44 "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.", 45 NULL), 46 m_options (interpreter) 47 { 48 SetHelpLong ( 49 "\nGeneral information about entering breakpoint commands\n\ 50 ------------------------------------------------------\n\ 51 \n\ 52 This command will cause you to be prompted to enter the command or set of\n\ 53 commands you wish to be executed when the specified breakpoint is hit. You\n\ 54 will be told to enter your command(s), and will see a '> 'prompt. Because\n\ 55 you can enter one or many commands to be executed when a breakpoint is hit,\n\ 56 you will continue to be prompted after each new-line that you enter, until you\n\ 57 enter the word 'DONE', which will cause the commands you have entered to be\n\ 58 stored with the breakpoint and executed when the breakpoint is hit.\n\ 59 \n\ 60 Syntax checking is not necessarily done when breakpoint commands are entered.\n\ 61 An improperly written breakpoint command will attempt to get executed when the\n\ 62 breakpoint gets hit, and usually silently fail. If your breakpoint command does\n\ 63 not appear to be getting executed, go back and check your syntax.\n\ 64 \n\ 65 Special information about PYTHON breakpoint commands\n\ 66 ----------------------------------------------------\n\ 67 \n\ 68 You may enter either one line of Python, multiple lines of Python (including\n\ 69 function definitions), or specify a Python function in a module that has already,\n\ 70 or will be imported. If you enter a single line of Python, that will be passed\n\ 71 to the Python interpreter 'as is' when the breakpoint gets hit. If you enter\n\ 72 function definitions, they will be passed to the Python interpreter as soon as\n\ 73 you finish entering the breakpoint command, and they can be called later (don't\n\ 74 forget to add calls to them, if you want them called when the breakpoint is\n\ 75 hit). If you enter multiple lines of Python that are not function definitions,\n\ 76 they will be collected into a new, automatically generated Python function, and\n\ 77 a call to the newly generated function will be attached to the breakpoint.\n\ 78 \n\ 79 \n\ 80 This auto-generated function is passed in three arguments:\n\ 81 \n\ 82 frame: a lldb.SBFrame object for the frame which hit breakpoint.\n\ 83 bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint\n\ 84 location that was hit.\n\ 85 dict: the python session dictionary hit.\n\ 86 \n\ 87 When specifying a python function with the --python-function option, you need\n\ 88 to supply the function name prepended by the module name. So if you import a\n\ 89 module named 'myutils' that contains a 'breakpoint_callback' function, you would\n\ 90 specify the option as:\n\ 91 \n\ 92 --python-function myutils.breakpoint_callback\n\ 93 \n\ 94 The function itself must have the following prototype:\n\ 95 \n\ 96 def breakpoint_callback(frame, bp_loc, dict):\n\ 97 # Your code goes here\n\ 98 \n\ 99 The arguments are the same as the 3 auto generation function arguments listed\n\ 100 above. Note that the global variable 'lldb.frame' will NOT be setup when this\n\ 101 function is called, so be sure to use the 'frame' argument. The 'frame' argument\n\ 102 can get you to the thread (frame.GetThread()), the thread can get you to the\n\ 103 process (thread.GetProcess()), and the process can get you back to the target\n\ 104 (process.GetTarget()).\n\ 105 \n\ 106 Important Note: Because loose Python code gets collected into functions, if you\n\ 107 want to access global variables in the 'loose' code, you need to specify that\n\ 108 they are global, using the 'global' keyword. Be sure to use correct Python\n\ 109 syntax, including indentation, when entering Python breakpoint commands.\n\ 110 \n\ 111 As a third option, you can pass the name of an already existing Python function\n\ 112 and that function will be attached to the breakpoint. It will get passed the\n\ 113 frame and bp_loc arguments mentioned above.\n\ 114 \n\ 115 Example Python one-line breakpoint command:\n\ 116 \n\ 117 (lldb) breakpoint command add -s python 1\n\ 118 Enter your Python command(s). Type 'DONE' to end.\n\ 119 > print \"Hit this breakpoint!\"\n\ 120 > DONE\n\ 121 \n\ 122 As a convenience, this also works for a short Python one-liner:\n\ 123 (lldb) breakpoint command add -s python 1 -o \"import time; print time.asctime()\"\n\ 124 (lldb) run\n\ 125 Launching '.../a.out' (x86_64)\n\ 126 (lldb) Fri Sep 10 12:17:45 2010\n\ 127 Process 21778 Stopped\n\ 128 * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread\n\ 129 36 \n\ 130 37 int c(int val)\n\ 131 38 {\n\ 132 39 -> return val + 3;\n\ 133 40 }\n\ 134 41 \n\ 135 42 int main (int argc, char const *argv[])\n\ 136 (lldb)\n\ 137 \n\ 138 Example multiple line Python breakpoint command, using function definition:\n\ 139 \n\ 140 (lldb) breakpoint command add -s python 1\n\ 141 Enter your Python command(s). Type 'DONE' to end.\n\ 142 > def breakpoint_output (bp_no):\n\ 143 > out_string = \"Hit breakpoint number \" + repr (bp_no)\n\ 144 > print out_string\n\ 145 > return True\n\ 146 > breakpoint_output (1)\n\ 147 > DONE\n\ 148 \n\ 149 \n\ 150 Example multiple line Python breakpoint command, using 'loose' Python:\n\ 151 \n\ 152 (lldb) breakpoint command add -s p 1\n\ 153 Enter your Python command(s). Type 'DONE' to end.\n\ 154 > global bp_count\n\ 155 > bp_count = bp_count + 1\n\ 156 > print \"Hit this breakpoint \" + repr(bp_count) + \" times!\"\n\ 157 > DONE\n\ 158 \n\ 159 In this case, since there is a reference to a global variable,\n\ 160 'bp_count', you will also need to make sure 'bp_count' exists and is\n\ 161 initialized:\n\ 162 \n\ 163 (lldb) script\n\ 164 >>> bp_count = 0\n\ 165 >>> quit()\n\ 166 \n\ 167 (lldb)\n\ 168 \n\ 169 \n\ 170 Final Note: If you get a warning that no breakpoint command was generated, but\n\ 171 you did not get any syntax errors, you probably forgot to add a call to your\n\ 172 functions.\n\ 173 \n\ 174 Special information about debugger command breakpoint commands\n\ 175 --------------------------------------------------------------\n\ 176 \n\ 177 You may enter any debugger command, exactly as you would at the debugger prompt.\n\ 178 You may enter as many debugger commands as you like, but do NOT enter more than\n\ 179 one command per line.\n" ); 180 181 CommandArgumentEntry arg; 182 CommandArgumentData bp_id_arg; 183 184 // Define the first (and only) variant of this arg. 185 bp_id_arg.arg_type = eArgTypeBreakpointID; 186 bp_id_arg.arg_repetition = eArgRepeatPlain; 187 188 // There is only one variant this argument could be; put it into the argument entry. 189 arg.push_back (bp_id_arg); 190 191 // Push the data for the first argument into the m_arguments vector. 192 m_arguments.push_back (arg); 193 } 194 195 virtual 196 ~CommandObjectBreakpointCommandAdd () {} 197 198 virtual Options * 199 GetOptions () 200 { 201 return &m_options; 202 } 203 204 void 205 CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, 206 CommandReturnObject &result) 207 { 208 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 209 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 210 if (reader_sp && data_ap.get()) 211 { 212 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 213 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); 214 215 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback, 216 bp_options, // baton 217 eInputReaderGranularityLine, // token size, to pass to callback function 218 "DONE", // end token 219 "> ", // prompt 220 true)); // echo input 221 if (err.Success()) 222 { 223 m_interpreter.GetDebugger().PushInputReader (reader_sp); 224 result.SetStatus (eReturnStatusSuccessFinishNoResult); 225 } 226 else 227 { 228 result.AppendError (err.AsCString()); 229 result.SetStatus (eReturnStatusFailed); 230 } 231 } 232 else 233 { 234 result.AppendError("out of memory"); 235 result.SetStatus (eReturnStatusFailed); 236 } 237 238 } 239 240 /// Set a one-liner as the callback for the breakpoint. 241 void 242 SetBreakpointCommandCallback (BreakpointOptions *bp_options, 243 const char *oneliner) 244 { 245 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 246 247 // It's necessary to set both user_source and script_source to the oneliner. 248 // The former is used to generate callback description (as in breakpoint command list) 249 // while the latter is used for Python to interpret during the actual callback. 250 data_ap->user_source.AppendString (oneliner); 251 data_ap->script_source.assign (oneliner); 252 data_ap->stop_on_error = m_options.m_stop_on_error; 253 254 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 255 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); 256 257 return; 258 } 259 260 static size_t 261 GenerateBreakpointCommandCallback (void *baton, 262 InputReader &reader, 263 lldb::InputReaderAction notification, 264 const char *bytes, 265 size_t bytes_len) 266 { 267 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); 268 bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); 269 270 switch (notification) 271 { 272 case eInputReaderActivate: 273 if (!batch_mode) 274 { 275 out_stream->Printf ("%s\n", g_reader_instructions); 276 if (reader.GetPrompt()) 277 out_stream->Printf ("%s", reader.GetPrompt()); 278 out_stream->Flush(); 279 } 280 break; 281 282 case eInputReaderDeactivate: 283 break; 284 285 case eInputReaderReactivate: 286 if (reader.GetPrompt() && !batch_mode) 287 { 288 out_stream->Printf ("%s", reader.GetPrompt()); 289 out_stream->Flush(); 290 } 291 break; 292 293 case eInputReaderAsynchronousOutputWritten: 294 break; 295 296 case eInputReaderGotToken: 297 if (bytes && bytes_len && baton) 298 { 299 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 300 if (bp_options) 301 { 302 Baton *bp_options_baton = bp_options->GetBaton(); 303 if (bp_options_baton) 304 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 305 } 306 } 307 if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) 308 { 309 out_stream->Printf ("%s", reader.GetPrompt()); 310 out_stream->Flush(); 311 } 312 break; 313 314 case eInputReaderInterrupt: 315 { 316 // Finish, and cancel the breakpoint command. 317 reader.SetIsDone (true); 318 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 319 if (bp_options) 320 { 321 Baton *bp_options_baton = bp_options->GetBaton (); 322 if (bp_options_baton) 323 { 324 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear(); 325 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.clear(); 326 } 327 } 328 if (!batch_mode) 329 { 330 out_stream->Printf ("Warning: No command attached to breakpoint.\n"); 331 out_stream->Flush(); 332 } 333 } 334 break; 335 336 case eInputReaderEndOfFile: 337 reader.SetIsDone (true); 338 break; 339 340 case eInputReaderDone: 341 break; 342 } 343 344 return bytes_len; 345 } 346 347 static bool 348 BreakpointOptionsCallbackFunction (void *baton, 349 StoppointCallbackContext *context, 350 lldb::user_id_t break_id, 351 lldb::user_id_t break_loc_id) 352 { 353 bool ret_value = true; 354 if (baton == NULL) 355 return true; 356 357 358 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; 359 StringList &commands = data->user_source; 360 361 if (commands.GetSize() > 0) 362 { 363 ExecutionContext exe_ctx (context->exe_ctx_ref); 364 Target *target = exe_ctx.GetTargetPtr(); 365 if (target) 366 { 367 CommandReturnObject result; 368 Debugger &debugger = target->GetDebugger(); 369 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 370 // if the debugger is set up that way. 371 372 StreamSP output_stream (debugger.GetAsyncOutputStream()); 373 StreamSP error_stream (debugger.GetAsyncErrorStream()); 374 result.SetImmediateOutputStream (output_stream); 375 result.SetImmediateErrorStream (error_stream); 376 377 bool stop_on_continue = true; 378 bool echo_commands = false; 379 bool print_results = true; 380 381 debugger.GetCommandInterpreter().HandleCommands (commands, 382 &exe_ctx, 383 stop_on_continue, 384 data->stop_on_error, 385 echo_commands, 386 print_results, 387 eLazyBoolNo, 388 result); 389 result.GetImmediateOutputStream()->Flush(); 390 result.GetImmediateErrorStream()->Flush(); 391 } 392 } 393 return ret_value; 394 } 395 396 class CommandOptions : public Options 397 { 398 public: 399 400 CommandOptions (CommandInterpreter &interpreter) : 401 Options (interpreter), 402 m_use_commands (false), 403 m_use_script_language (false), 404 m_script_language (eScriptLanguageNone), 405 m_use_one_liner (false), 406 m_one_liner(), 407 m_function_name() 408 { 409 } 410 411 virtual 412 ~CommandOptions () {} 413 414 virtual Error 415 SetOptionValue (uint32_t option_idx, const char *option_arg) 416 { 417 Error error; 418 const int short_option = m_getopt_table[option_idx].val; 419 420 switch (short_option) 421 { 422 case 'o': 423 m_use_one_liner = true; 424 m_one_liner = option_arg; 425 break; 426 427 case 's': 428 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 429 g_option_table[option_idx].enum_values, 430 eScriptLanguageNone, 431 error); 432 433 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault) 434 { 435 m_use_script_language = true; 436 } 437 else 438 { 439 m_use_script_language = false; 440 } 441 break; 442 443 case 'e': 444 { 445 bool success = false; 446 m_stop_on_error = Args::StringToBoolean(option_arg, false, &success); 447 if (!success) 448 error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg); 449 } 450 break; 451 452 case 'F': 453 { 454 m_use_one_liner = false; 455 m_use_script_language = true; 456 m_function_name.assign(option_arg); 457 } 458 break; 459 460 default: 461 break; 462 } 463 return error; 464 } 465 void 466 OptionParsingStarting () 467 { 468 m_use_commands = true; 469 m_use_script_language = false; 470 m_script_language = eScriptLanguageNone; 471 472 m_use_one_liner = false; 473 m_stop_on_error = true; 474 m_one_liner.clear(); 475 m_function_name.clear(); 476 } 477 478 const OptionDefinition* 479 GetDefinitions () 480 { 481 return g_option_table; 482 } 483 484 // Options table: Required for subclasses of Options. 485 486 static OptionDefinition g_option_table[]; 487 488 // Instance variables to hold the values for command options. 489 490 bool m_use_commands; 491 bool m_use_script_language; 492 lldb::ScriptLanguage m_script_language; 493 494 // Instance variables to hold the values for one_liner options. 495 bool m_use_one_liner; 496 std::string m_one_liner; 497 bool m_stop_on_error; 498 std::string m_function_name; 499 }; 500 501 protected: 502 virtual bool 503 DoExecute (Args& command, CommandReturnObject &result) 504 { 505 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 506 507 if (target == NULL) 508 { 509 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands"); 510 result.SetStatus (eReturnStatusFailed); 511 return false; 512 } 513 514 const BreakpointList &breakpoints = target->GetBreakpointList(); 515 size_t num_breakpoints = breakpoints.GetSize(); 516 517 if (num_breakpoints == 0) 518 { 519 result.AppendError ("No breakpoints exist to have commands added"); 520 result.SetStatus (eReturnStatusFailed); 521 return false; 522 } 523 524 if (m_options.m_use_script_language == false && m_options.m_function_name.size()) 525 { 526 result.AppendError ("need to enable scripting to have a function run as a breakpoint command"); 527 result.SetStatus (eReturnStatusFailed); 528 return false; 529 } 530 531 BreakpointIDList valid_bp_ids; 532 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 533 534 if (result.Succeeded()) 535 { 536 const size_t count = valid_bp_ids.GetSize(); 537 if (count > 1) 538 { 539 result.AppendError ("can only add commands to one breakpoint at a time."); 540 result.SetStatus (eReturnStatusFailed); 541 return false; 542 } 543 544 for (size_t i = 0; i < count; ++i) 545 { 546 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 547 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 548 { 549 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 550 BreakpointOptions *bp_options = NULL; 551 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) 552 { 553 // This breakpoint does not have an associated location. 554 bp_options = bp->GetOptions(); 555 } 556 else 557 { 558 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 559 // This breakpoint does have an associated location. 560 // Get its breakpoint options. 561 if (bp_loc_sp) 562 bp_options = bp_loc_sp->GetLocationOptions(); 563 } 564 565 // Skip this breakpoint if bp_options is not good. 566 if (bp_options == NULL) continue; 567 568 // If we are using script language, get the script interpreter 569 // in order to set or collect command callback. Otherwise, call 570 // the methods associated with this object. 571 if (m_options.m_use_script_language) 572 { 573 // Special handling for one-liner specified inline. 574 if (m_options.m_use_one_liner) 575 { 576 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, 577 m_options.m_one_liner.c_str()); 578 } 579 // Special handling for using a Python function by name 580 // instead of extending the breakpoint callback data structures, we just automatize 581 // what the user would do manually: make their breakpoint command be a function call 582 else if (m_options.m_function_name.size()) 583 { 584 std::string oneliner(m_options.m_function_name); 585 oneliner += "(frame, bp_loc, internal_dict)"; 586 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, 587 oneliner.c_str()); 588 } 589 else 590 { 591 m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options, 592 result); 593 } 594 } 595 else 596 { 597 // Special handling for one-liner specified inline. 598 if (m_options.m_use_one_liner) 599 SetBreakpointCommandCallback (bp_options, 600 m_options.m_one_liner.c_str()); 601 else 602 CollectDataForBreakpointCommandCallback (bp_options, 603 result); 604 } 605 } 606 } 607 } 608 609 return result.Succeeded(); 610 } 611 612 private: 613 CommandOptions m_options; 614 static const char *g_reader_instructions; 615 616 }; 617 618 const char * 619 CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; 620 621 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting 622 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. 623 624 static OptionEnumValueElement 625 g_script_option_enumeration[4] = 626 { 627 { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"}, 628 { eScriptLanguagePython, "python", "Commands are in the Python language."}, 629 { eSortOrderByName, "default-script", "Commands are in the default scripting language."}, 630 { 0, NULL, NULL } 631 }; 632 633 OptionDefinition 634 CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] = 635 { 636 { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner, 637 "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." }, 638 639 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, 640 "Specify whether breakpoint command execution should terminate on error." }, 641 642 { LLDB_OPT_SET_ALL, false, "script-type", 's', required_argument, g_script_option_enumeration, 0, eArgTypeNone, 643 "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."}, 644 645 { LLDB_OPT_SET_2, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction, 646 "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."}, 647 648 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 649 }; 650 651 //------------------------------------------------------------------------- 652 // CommandObjectBreakpointCommandDelete 653 //------------------------------------------------------------------------- 654 655 class CommandObjectBreakpointCommandDelete : public CommandObjectParsed 656 { 657 public: 658 CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) : 659 CommandObjectParsed (interpreter, 660 "delete", 661 "Delete the set of commands from a breakpoint.", 662 NULL) 663 { 664 CommandArgumentEntry arg; 665 CommandArgumentData bp_id_arg; 666 667 // Define the first (and only) variant of this arg. 668 bp_id_arg.arg_type = eArgTypeBreakpointID; 669 bp_id_arg.arg_repetition = eArgRepeatPlain; 670 671 // There is only one variant this argument could be; put it into the argument entry. 672 arg.push_back (bp_id_arg); 673 674 // Push the data for the first argument into the m_arguments vector. 675 m_arguments.push_back (arg); 676 } 677 678 679 virtual 680 ~CommandObjectBreakpointCommandDelete () {} 681 682 protected: 683 virtual bool 684 DoExecute (Args& command, CommandReturnObject &result) 685 { 686 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 687 688 if (target == NULL) 689 { 690 result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands"); 691 result.SetStatus (eReturnStatusFailed); 692 return false; 693 } 694 695 const BreakpointList &breakpoints = target->GetBreakpointList(); 696 size_t num_breakpoints = breakpoints.GetSize(); 697 698 if (num_breakpoints == 0) 699 { 700 result.AppendError ("No breakpoints exist to have commands deleted"); 701 result.SetStatus (eReturnStatusFailed); 702 return false; 703 } 704 705 if (command.GetArgumentCount() == 0) 706 { 707 result.AppendError ("No breakpoint specified from which to delete the commands"); 708 result.SetStatus (eReturnStatusFailed); 709 return false; 710 } 711 712 BreakpointIDList valid_bp_ids; 713 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 714 715 if (result.Succeeded()) 716 { 717 const size_t count = valid_bp_ids.GetSize(); 718 for (size_t i = 0; i < count; ++i) 719 { 720 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 721 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 722 { 723 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 724 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 725 { 726 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 727 if (bp_loc_sp) 728 bp_loc_sp->ClearCallback(); 729 else 730 { 731 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 732 cur_bp_id.GetBreakpointID(), 733 cur_bp_id.GetLocationID()); 734 result.SetStatus (eReturnStatusFailed); 735 return false; 736 } 737 } 738 else 739 { 740 bp->ClearCallback(); 741 } 742 } 743 } 744 } 745 return result.Succeeded(); 746 } 747 }; 748 749 //------------------------------------------------------------------------- 750 // CommandObjectBreakpointCommandList 751 //------------------------------------------------------------------------- 752 753 class CommandObjectBreakpointCommandList : public CommandObjectParsed 754 { 755 public: 756 CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 757 CommandObjectParsed (interpreter, 758 "list", 759 "List the script or set of commands to be executed when the breakpoint is hit.", 760 NULL) 761 { 762 CommandArgumentEntry arg; 763 CommandArgumentData bp_id_arg; 764 765 // Define the first (and only) variant of this arg. 766 bp_id_arg.arg_type = eArgTypeBreakpointID; 767 bp_id_arg.arg_repetition = eArgRepeatPlain; 768 769 // There is only one variant this argument could be; put it into the argument entry. 770 arg.push_back (bp_id_arg); 771 772 // Push the data for the first argument into the m_arguments vector. 773 m_arguments.push_back (arg); 774 } 775 776 virtual 777 ~CommandObjectBreakpointCommandList () {} 778 779 protected: 780 virtual bool 781 DoExecute (Args& command, 782 CommandReturnObject &result) 783 { 784 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 785 786 if (target == NULL) 787 { 788 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 789 result.SetStatus (eReturnStatusFailed); 790 return false; 791 } 792 793 const BreakpointList &breakpoints = target->GetBreakpointList(); 794 size_t num_breakpoints = breakpoints.GetSize(); 795 796 if (num_breakpoints == 0) 797 { 798 result.AppendError ("No breakpoints exist for which to list commands"); 799 result.SetStatus (eReturnStatusFailed); 800 return false; 801 } 802 803 if (command.GetArgumentCount() == 0) 804 { 805 result.AppendError ("No breakpoint specified for which to list the commands"); 806 result.SetStatus (eReturnStatusFailed); 807 return false; 808 } 809 810 BreakpointIDList valid_bp_ids; 811 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 812 813 if (result.Succeeded()) 814 { 815 const size_t count = valid_bp_ids.GetSize(); 816 for (size_t i = 0; i < count; ++i) 817 { 818 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 819 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 820 { 821 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 822 823 if (bp) 824 { 825 const BreakpointOptions *bp_options = NULL; 826 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 827 { 828 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 829 if (bp_loc_sp) 830 bp_options = bp_loc_sp->GetOptionsNoCreate(); 831 else 832 { 833 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 834 cur_bp_id.GetBreakpointID(), 835 cur_bp_id.GetLocationID()); 836 result.SetStatus (eReturnStatusFailed); 837 return false; 838 } 839 } 840 else 841 { 842 bp_options = bp->GetOptions(); 843 } 844 845 if (bp_options) 846 { 847 StreamString id_str; 848 BreakpointID::GetCanonicalReference (&id_str, 849 cur_bp_id.GetBreakpointID(), 850 cur_bp_id.GetLocationID()); 851 const Baton *baton = bp_options->GetBaton(); 852 if (baton) 853 { 854 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 855 result.GetOutputStream().IndentMore (); 856 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 857 result.GetOutputStream().IndentLess (); 858 } 859 else 860 { 861 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", 862 id_str.GetData()); 863 } 864 } 865 result.SetStatus (eReturnStatusSuccessFinishResult); 866 } 867 else 868 { 869 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 870 result.SetStatus (eReturnStatusFailed); 871 } 872 873 } 874 } 875 } 876 877 return result.Succeeded(); 878 } 879 }; 880 881 //------------------------------------------------------------------------- 882 // CommandObjectBreakpointCommand 883 //------------------------------------------------------------------------- 884 885 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 886 CommandObjectMultiword (interpreter, 887 "command", 888 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').", 889 "command <sub-command> [<sub-command-options>] <breakpoint-id>") 890 { 891 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); 892 CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter)); 893 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 894 895 add_command_object->SetCommandName ("breakpoint command add"); 896 delete_command_object->SetCommandName ("breakpoint command delete"); 897 list_command_object->SetCommandName ("breakpoint command list"); 898 899 LoadSubCommand ("add", add_command_object); 900 LoadSubCommand ("delete", delete_command_object); 901 LoadSubCommand ("list", list_command_object); 902 } 903 904 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () 905 { 906 } 907 908 909