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