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