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