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