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 Your Python code, however organized, can optionally return a value.\n\ 171 If the returned value is False, that tells LLDB not to stop at the breakpoint\n\ 172 to which the code is associated. Returning anything other than False, or even\n\ 173 returning None, or even omitting a return statement entirely, will cause\n\ 174 LLDB to stop.\n\ 175 \n\ 176 Final Note: If you get a warning that no breakpoint command was generated, but\n\ 177 you did not get any syntax errors, you probably forgot to add a call to your\n\ 178 functions.\n\ 179 \n\ 180 Special information about debugger command breakpoint commands\n\ 181 --------------------------------------------------------------\n\ 182 \n\ 183 You may enter any debugger command, exactly as you would at the debugger prompt.\n\ 184 You may enter as many debugger commands as you like, but do NOT enter more than\n\ 185 one command per line.\n" ); 186 187 CommandArgumentEntry arg; 188 CommandArgumentData bp_id_arg; 189 190 // Define the first (and only) variant of this arg. 191 bp_id_arg.arg_type = eArgTypeBreakpointID; 192 bp_id_arg.arg_repetition = eArgRepeatPlain; 193 194 // There is only one variant this argument could be; put it into the argument entry. 195 arg.push_back (bp_id_arg); 196 197 // Push the data for the first argument into the m_arguments vector. 198 m_arguments.push_back (arg); 199 } 200 201 virtual 202 ~CommandObjectBreakpointCommandAdd () {} 203 204 virtual Options * 205 GetOptions () 206 { 207 return &m_options; 208 } 209 210 void 211 CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options, 212 CommandReturnObject &result) 213 { 214 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 215 std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 216 if (reader_sp && data_ap.get()) 217 { 218 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 219 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); 220 221 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback, 222 bp_options, // baton 223 eInputReaderGranularityLine, // token size, to pass to callback function 224 "DONE", // end token 225 "> ", // prompt 226 true)); // echo input 227 if (err.Success()) 228 { 229 m_interpreter.GetDebugger().PushInputReader (reader_sp); 230 result.SetStatus (eReturnStatusSuccessFinishNoResult); 231 } 232 else 233 { 234 result.AppendError (err.AsCString()); 235 result.SetStatus (eReturnStatusFailed); 236 } 237 } 238 else 239 { 240 result.AppendError("out of memory"); 241 result.SetStatus (eReturnStatusFailed); 242 } 243 244 } 245 246 /// Set a one-liner as the callback for the breakpoint. 247 void 248 SetBreakpointCommandCallback (BreakpointOptions *bp_options, 249 const char *oneliner) 250 { 251 std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 252 253 // It's necessary to set both user_source and script_source to the oneliner. 254 // The former is used to generate callback description (as in breakpoint command list) 255 // while the latter is used for Python to interpret during the actual callback. 256 data_ap->user_source.AppendString (oneliner); 257 data_ap->script_source.assign (oneliner); 258 data_ap->stop_on_error = m_options.m_stop_on_error; 259 260 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 261 bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp); 262 263 return; 264 } 265 266 static size_t 267 GenerateBreakpointCommandCallback (void *baton, 268 InputReader &reader, 269 lldb::InputReaderAction notification, 270 const char *bytes, 271 size_t bytes_len) 272 { 273 StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream(); 274 bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode(); 275 276 switch (notification) 277 { 278 case eInputReaderActivate: 279 if (!batch_mode) 280 { 281 out_stream->Printf ("%s\n", g_reader_instructions); 282 if (reader.GetPrompt()) 283 out_stream->Printf ("%s", reader.GetPrompt()); 284 out_stream->Flush(); 285 } 286 break; 287 288 case eInputReaderDeactivate: 289 break; 290 291 case eInputReaderReactivate: 292 if (reader.GetPrompt() && !batch_mode) 293 { 294 out_stream->Printf ("%s", reader.GetPrompt()); 295 out_stream->Flush(); 296 } 297 break; 298 299 case eInputReaderAsynchronousOutputWritten: 300 break; 301 302 case eInputReaderGotToken: 303 if (bytes && bytes_len && baton) 304 { 305 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 306 if (bp_options) 307 { 308 Baton *bp_options_baton = bp_options->GetBaton(); 309 if (bp_options_baton) 310 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 311 } 312 } 313 if (!reader.IsDone() && reader.GetPrompt() && !batch_mode) 314 { 315 out_stream->Printf ("%s", reader.GetPrompt()); 316 out_stream->Flush(); 317 } 318 break; 319 320 case eInputReaderInterrupt: 321 { 322 // Finish, and cancel the breakpoint command. 323 reader.SetIsDone (true); 324 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 325 if (bp_options) 326 { 327 Baton *bp_options_baton = bp_options->GetBaton (); 328 if (bp_options_baton) 329 { 330 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear(); 331 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.clear(); 332 } 333 } 334 if (!batch_mode) 335 { 336 out_stream->Printf ("Warning: No command attached to breakpoint.\n"); 337 out_stream->Flush(); 338 } 339 } 340 break; 341 342 case eInputReaderEndOfFile: 343 reader.SetIsDone (true); 344 break; 345 346 case eInputReaderDone: 347 break; 348 } 349 350 return bytes_len; 351 } 352 353 static bool 354 BreakpointOptionsCallbackFunction (void *baton, 355 StoppointCallbackContext *context, 356 lldb::user_id_t break_id, 357 lldb::user_id_t break_loc_id) 358 { 359 bool ret_value = true; 360 if (baton == NULL) 361 return true; 362 363 364 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; 365 StringList &commands = data->user_source; 366 367 if (commands.GetSize() > 0) 368 { 369 ExecutionContext exe_ctx (context->exe_ctx_ref); 370 Target *target = exe_ctx.GetTargetPtr(); 371 if (target) 372 { 373 CommandReturnObject result; 374 Debugger &debugger = target->GetDebugger(); 375 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 376 // if the debugger is set up that way. 377 378 StreamSP output_stream (debugger.GetAsyncOutputStream()); 379 StreamSP error_stream (debugger.GetAsyncErrorStream()); 380 result.SetImmediateOutputStream (output_stream); 381 result.SetImmediateErrorStream (error_stream); 382 383 bool stop_on_continue = true; 384 bool echo_commands = false; 385 bool print_results = true; 386 387 debugger.GetCommandInterpreter().HandleCommands (commands, 388 &exe_ctx, 389 stop_on_continue, 390 data->stop_on_error, 391 echo_commands, 392 print_results, 393 eLazyBoolNo, 394 result); 395 result.GetImmediateOutputStream()->Flush(); 396 result.GetImmediateErrorStream()->Flush(); 397 } 398 } 399 return ret_value; 400 } 401 402 class CommandOptions : public Options 403 { 404 public: 405 406 CommandOptions (CommandInterpreter &interpreter) : 407 Options (interpreter), 408 m_use_commands (false), 409 m_use_script_language (false), 410 m_script_language (eScriptLanguageNone), 411 m_use_one_liner (false), 412 m_one_liner(), 413 m_function_name() 414 { 415 } 416 417 virtual 418 ~CommandOptions () {} 419 420 virtual Error 421 SetOptionValue (uint32_t option_idx, const char *option_arg) 422 { 423 Error error; 424 const int short_option = m_getopt_table[option_idx].val; 425 426 switch (short_option) 427 { 428 case 'o': 429 m_use_one_liner = true; 430 m_one_liner = option_arg; 431 break; 432 433 case 's': 434 m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg, 435 g_option_table[option_idx].enum_values, 436 eScriptLanguageNone, 437 error); 438 439 if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault) 440 { 441 m_use_script_language = true; 442 } 443 else 444 { 445 m_use_script_language = false; 446 } 447 break; 448 449 case 'e': 450 { 451 bool success = false; 452 m_stop_on_error = Args::StringToBoolean(option_arg, false, &success); 453 if (!success) 454 error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg); 455 } 456 break; 457 458 case 'F': 459 { 460 m_use_one_liner = false; 461 m_use_script_language = true; 462 m_function_name.assign(option_arg); 463 } 464 break; 465 466 default: 467 break; 468 } 469 return error; 470 } 471 void 472 OptionParsingStarting () 473 { 474 m_use_commands = true; 475 m_use_script_language = false; 476 m_script_language = eScriptLanguageNone; 477 478 m_use_one_liner = false; 479 m_stop_on_error = true; 480 m_one_liner.clear(); 481 m_function_name.clear(); 482 } 483 484 const OptionDefinition* 485 GetDefinitions () 486 { 487 return g_option_table; 488 } 489 490 // Options table: Required for subclasses of Options. 491 492 static OptionDefinition g_option_table[]; 493 494 // Instance variables to hold the values for command options. 495 496 bool m_use_commands; 497 bool m_use_script_language; 498 lldb::ScriptLanguage m_script_language; 499 500 // Instance variables to hold the values for one_liner options. 501 bool m_use_one_liner; 502 std::string m_one_liner; 503 bool m_stop_on_error; 504 std::string m_function_name; 505 }; 506 507 protected: 508 virtual bool 509 DoExecute (Args& command, CommandReturnObject &result) 510 { 511 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 512 513 if (target == NULL) 514 { 515 result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands"); 516 result.SetStatus (eReturnStatusFailed); 517 return false; 518 } 519 520 const BreakpointList &breakpoints = target->GetBreakpointList(); 521 size_t num_breakpoints = breakpoints.GetSize(); 522 523 if (num_breakpoints == 0) 524 { 525 result.AppendError ("No breakpoints exist to have commands added"); 526 result.SetStatus (eReturnStatusFailed); 527 return false; 528 } 529 530 if (m_options.m_use_script_language == false && m_options.m_function_name.size()) 531 { 532 result.AppendError ("need to enable scripting to have a function run as a breakpoint command"); 533 result.SetStatus (eReturnStatusFailed); 534 return false; 535 } 536 537 BreakpointIDList valid_bp_ids; 538 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 539 540 if (result.Succeeded()) 541 { 542 const size_t count = valid_bp_ids.GetSize(); 543 if (count > 1) 544 { 545 result.AppendError ("can only add commands to one breakpoint at a time."); 546 result.SetStatus (eReturnStatusFailed); 547 return false; 548 } 549 550 for (size_t i = 0; i < count; ++i) 551 { 552 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 553 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 554 { 555 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 556 BreakpointOptions *bp_options = NULL; 557 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) 558 { 559 // This breakpoint does not have an associated location. 560 bp_options = bp->GetOptions(); 561 } 562 else 563 { 564 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 565 // This breakpoint does have an associated location. 566 // Get its breakpoint options. 567 if (bp_loc_sp) 568 bp_options = bp_loc_sp->GetLocationOptions(); 569 } 570 571 // Skip this breakpoint if bp_options is not good. 572 if (bp_options == NULL) continue; 573 574 // If we are using script language, get the script interpreter 575 // in order to set or collect command callback. Otherwise, call 576 // the methods associated with this object. 577 if (m_options.m_use_script_language) 578 { 579 // Special handling for one-liner specified inline. 580 if (m_options.m_use_one_liner) 581 { 582 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, 583 m_options.m_one_liner.c_str()); 584 } 585 // Special handling for using a Python function by name 586 // instead of extending the breakpoint callback data structures, we just automatize 587 // what the user would do manually: make their breakpoint command be a function call 588 else if (m_options.m_function_name.size()) 589 { 590 std::string oneliner("return "); 591 oneliner += m_options.m_function_name; 592 oneliner += "(frame, bp_loc, internal_dict)"; 593 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, 594 oneliner.c_str()); 595 } 596 else 597 { 598 m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options, 599 result); 600 } 601 } 602 else 603 { 604 // Special handling for one-liner specified inline. 605 if (m_options.m_use_one_liner) 606 SetBreakpointCommandCallback (bp_options, 607 m_options.m_one_liner.c_str()); 608 else 609 CollectDataForBreakpointCommandCallback (bp_options, 610 result); 611 } 612 } 613 } 614 } 615 616 return result.Succeeded(); 617 } 618 619 private: 620 CommandOptions m_options; 621 static const char *g_reader_instructions; 622 623 }; 624 625 const char * 626 CommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; 627 628 // FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting 629 // language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper. 630 631 static OptionEnumValueElement 632 g_script_option_enumeration[4] = 633 { 634 { eScriptLanguageNone, "command", "Commands are in the lldb command interpreter language"}, 635 { eScriptLanguagePython, "python", "Commands are in the Python language."}, 636 { eSortOrderByName, "default-script", "Commands are in the default scripting language."}, 637 { 0, NULL, NULL } 638 }; 639 640 OptionDefinition 641 CommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] = 642 { 643 { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner, 644 "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." }, 645 646 { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean, 647 "Specify whether breakpoint command execution should terminate on error." }, 648 649 { LLDB_OPT_SET_ALL, false, "script-type", 's', required_argument, g_script_option_enumeration, 0, eArgTypeNone, 650 "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."}, 651 652 { LLDB_OPT_SET_2, false, "python-function", 'F', required_argument, NULL, 0, eArgTypePythonFunction, 653 "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."}, 654 655 { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL } 656 }; 657 658 //------------------------------------------------------------------------- 659 // CommandObjectBreakpointCommandDelete 660 //------------------------------------------------------------------------- 661 662 class CommandObjectBreakpointCommandDelete : public CommandObjectParsed 663 { 664 public: 665 CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) : 666 CommandObjectParsed (interpreter, 667 "delete", 668 "Delete the set of commands from a breakpoint.", 669 NULL) 670 { 671 CommandArgumentEntry arg; 672 CommandArgumentData bp_id_arg; 673 674 // Define the first (and only) variant of this arg. 675 bp_id_arg.arg_type = eArgTypeBreakpointID; 676 bp_id_arg.arg_repetition = eArgRepeatPlain; 677 678 // There is only one variant this argument could be; put it into the argument entry. 679 arg.push_back (bp_id_arg); 680 681 // Push the data for the first argument into the m_arguments vector. 682 m_arguments.push_back (arg); 683 } 684 685 686 virtual 687 ~CommandObjectBreakpointCommandDelete () {} 688 689 protected: 690 virtual bool 691 DoExecute (Args& command, CommandReturnObject &result) 692 { 693 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 694 695 if (target == NULL) 696 { 697 result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands"); 698 result.SetStatus (eReturnStatusFailed); 699 return false; 700 } 701 702 const BreakpointList &breakpoints = target->GetBreakpointList(); 703 size_t num_breakpoints = breakpoints.GetSize(); 704 705 if (num_breakpoints == 0) 706 { 707 result.AppendError ("No breakpoints exist to have commands deleted"); 708 result.SetStatus (eReturnStatusFailed); 709 return false; 710 } 711 712 if (command.GetArgumentCount() == 0) 713 { 714 result.AppendError ("No breakpoint specified from which to delete the commands"); 715 result.SetStatus (eReturnStatusFailed); 716 return false; 717 } 718 719 BreakpointIDList valid_bp_ids; 720 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 721 722 if (result.Succeeded()) 723 { 724 const size_t count = valid_bp_ids.GetSize(); 725 for (size_t i = 0; i < count; ++i) 726 { 727 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 728 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 729 { 730 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 731 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 732 { 733 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 734 if (bp_loc_sp) 735 bp_loc_sp->ClearCallback(); 736 else 737 { 738 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 739 cur_bp_id.GetBreakpointID(), 740 cur_bp_id.GetLocationID()); 741 result.SetStatus (eReturnStatusFailed); 742 return false; 743 } 744 } 745 else 746 { 747 bp->ClearCallback(); 748 } 749 } 750 } 751 } 752 return result.Succeeded(); 753 } 754 }; 755 756 //------------------------------------------------------------------------- 757 // CommandObjectBreakpointCommandList 758 //------------------------------------------------------------------------- 759 760 class CommandObjectBreakpointCommandList : public CommandObjectParsed 761 { 762 public: 763 CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 764 CommandObjectParsed (interpreter, 765 "list", 766 "List the script or set of commands to be executed when the breakpoint is hit.", 767 NULL) 768 { 769 CommandArgumentEntry arg; 770 CommandArgumentData bp_id_arg; 771 772 // Define the first (and only) variant of this arg. 773 bp_id_arg.arg_type = eArgTypeBreakpointID; 774 bp_id_arg.arg_repetition = eArgRepeatPlain; 775 776 // There is only one variant this argument could be; put it into the argument entry. 777 arg.push_back (bp_id_arg); 778 779 // Push the data for the first argument into the m_arguments vector. 780 m_arguments.push_back (arg); 781 } 782 783 virtual 784 ~CommandObjectBreakpointCommandList () {} 785 786 protected: 787 virtual bool 788 DoExecute (Args& command, 789 CommandReturnObject &result) 790 { 791 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 792 793 if (target == NULL) 794 { 795 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 796 result.SetStatus (eReturnStatusFailed); 797 return false; 798 } 799 800 const BreakpointList &breakpoints = target->GetBreakpointList(); 801 size_t num_breakpoints = breakpoints.GetSize(); 802 803 if (num_breakpoints == 0) 804 { 805 result.AppendError ("No breakpoints exist for which to list commands"); 806 result.SetStatus (eReturnStatusFailed); 807 return false; 808 } 809 810 if (command.GetArgumentCount() == 0) 811 { 812 result.AppendError ("No breakpoint specified for which to list the commands"); 813 result.SetStatus (eReturnStatusFailed); 814 return false; 815 } 816 817 BreakpointIDList valid_bp_ids; 818 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 819 820 if (result.Succeeded()) 821 { 822 const size_t count = valid_bp_ids.GetSize(); 823 for (size_t i = 0; i < count; ++i) 824 { 825 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 826 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 827 { 828 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 829 830 if (bp) 831 { 832 const BreakpointOptions *bp_options = NULL; 833 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 834 { 835 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 836 if (bp_loc_sp) 837 bp_options = bp_loc_sp->GetOptionsNoCreate(); 838 else 839 { 840 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 841 cur_bp_id.GetBreakpointID(), 842 cur_bp_id.GetLocationID()); 843 result.SetStatus (eReturnStatusFailed); 844 return false; 845 } 846 } 847 else 848 { 849 bp_options = bp->GetOptions(); 850 } 851 852 if (bp_options) 853 { 854 StreamString id_str; 855 BreakpointID::GetCanonicalReference (&id_str, 856 cur_bp_id.GetBreakpointID(), 857 cur_bp_id.GetLocationID()); 858 const Baton *baton = bp_options->GetBaton(); 859 if (baton) 860 { 861 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 862 result.GetOutputStream().IndentMore (); 863 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 864 result.GetOutputStream().IndentLess (); 865 } 866 else 867 { 868 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", 869 id_str.GetData()); 870 } 871 } 872 result.SetStatus (eReturnStatusSuccessFinishResult); 873 } 874 else 875 { 876 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 877 result.SetStatus (eReturnStatusFailed); 878 } 879 880 } 881 } 882 } 883 884 return result.Succeeded(); 885 } 886 }; 887 888 //------------------------------------------------------------------------- 889 // CommandObjectBreakpointCommand 890 //------------------------------------------------------------------------- 891 892 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 893 CommandObjectMultiword (interpreter, 894 "command", 895 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').", 896 "command <sub-command> [<sub-command-options>] <breakpoint-id>") 897 { 898 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); 899 CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter)); 900 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 901 902 add_command_object->SetCommandName ("breakpoint command add"); 903 delete_command_object->SetCommandName ("breakpoint command delete"); 904 list_command_object->SetCommandName ("breakpoint command list"); 905 906 LoadSubCommand ("add", add_command_object); 907 LoadSubCommand ("delete", delete_command_object); 908 LoadSubCommand ("list", list_command_object); 909 } 910 911 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () 912 { 913 } 914 915 916