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 File &out_file = reader.GetDebugger().GetOutputFile(); 449 450 switch (notification) 451 { 452 case eInputReaderActivate: 453 out_file.Printf ("%s\n", g_reader_instructions); 454 if (reader.GetPrompt()) 455 out_file.Printf ("%s", reader.GetPrompt()); 456 out_file.Flush(); 457 break; 458 459 case eInputReaderDeactivate: 460 break; 461 462 case eInputReaderReactivate: 463 if (reader.GetPrompt()) 464 { 465 out_file.Printf ("%s", reader.GetPrompt()); 466 out_file.Flush(); 467 } 468 break; 469 470 case eInputReaderAsynchronousOutputWritten: 471 break; 472 473 case eInputReaderGotToken: 474 if (bytes && bytes_len && baton) 475 { 476 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 477 if (bp_options) 478 { 479 Baton *bp_options_baton = bp_options->GetBaton(); 480 if (bp_options_baton) 481 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 482 } 483 } 484 if (!reader.IsDone() && reader.GetPrompt()) 485 { 486 out_file.Printf ("%s", reader.GetPrompt()); 487 out_file.Flush(); 488 } 489 break; 490 491 case eInputReaderInterrupt: 492 { 493 // Finish, and cancel the breakpoint command. 494 reader.SetIsDone (true); 495 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 496 if (bp_options) 497 { 498 Baton *bp_options_baton = bp_options->GetBaton (); 499 if (bp_options_baton) 500 { 501 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear(); 502 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.Clear(); 503 } 504 } 505 out_file.Printf ("Warning: No command attached to breakpoint.\n"); 506 out_file.Flush(); 507 } 508 break; 509 510 case eInputReaderEndOfFile: 511 reader.SetIsDone (true); 512 break; 513 514 case eInputReaderDone: 515 break; 516 } 517 518 return bytes_len; 519 } 520 521 522 //------------------------------------------------------------------------- 523 // CommandObjectBreakpointCommandDelete 524 //------------------------------------------------------------------------- 525 526 CommandObjectBreakpointCommandDelete::CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) : 527 CommandObject (interpreter, 528 "delete", 529 "Delete the set of commands from a breakpoint.", 530 NULL) 531 { 532 CommandArgumentEntry arg; 533 CommandArgumentData bp_id_arg; 534 535 // Define the first (and only) variant of this arg. 536 bp_id_arg.arg_type = eArgTypeBreakpointID; 537 bp_id_arg.arg_repetition = eArgRepeatPlain; 538 539 // There is only one variant this argument could be; put it into the argument entry. 540 arg.push_back (bp_id_arg); 541 542 // Push the data for the first argument into the m_arguments vector. 543 m_arguments.push_back (arg); 544 } 545 546 CommandObjectBreakpointCommandDelete::~CommandObjectBreakpointCommandDelete () 547 { 548 } 549 550 bool 551 CommandObjectBreakpointCommandDelete::Execute 552 ( 553 Args& command, 554 CommandReturnObject &result 555 ) 556 { 557 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 558 559 if (target == NULL) 560 { 561 result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands"); 562 result.SetStatus (eReturnStatusFailed); 563 return false; 564 } 565 566 const BreakpointList &breakpoints = target->GetBreakpointList(); 567 size_t num_breakpoints = breakpoints.GetSize(); 568 569 if (num_breakpoints == 0) 570 { 571 result.AppendError ("No breakpoints exist to have commands deleted"); 572 result.SetStatus (eReturnStatusFailed); 573 return false; 574 } 575 576 if (command.GetArgumentCount() == 0) 577 { 578 result.AppendError ("No breakpoint specified from which to delete the commands"); 579 result.SetStatus (eReturnStatusFailed); 580 return false; 581 } 582 583 BreakpointIDList valid_bp_ids; 584 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 585 586 if (result.Succeeded()) 587 { 588 const size_t count = valid_bp_ids.GetSize(); 589 for (size_t i = 0; i < count; ++i) 590 { 591 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 592 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 593 { 594 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 595 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 596 { 597 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 598 if (bp_loc_sp) 599 bp_loc_sp->ClearCallback(); 600 else 601 { 602 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 603 cur_bp_id.GetBreakpointID(), 604 cur_bp_id.GetLocationID()); 605 result.SetStatus (eReturnStatusFailed); 606 return false; 607 } 608 } 609 else 610 { 611 bp->ClearCallback(); 612 } 613 } 614 } 615 } 616 return result.Succeeded(); 617 } 618 619 620 //------------------------------------------------------------------------- 621 // CommandObjectBreakpointCommandList 622 //------------------------------------------------------------------------- 623 624 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 625 CommandObject (interpreter, 626 "list", 627 "List the script or set of commands to be executed when the breakpoint is hit.", 628 NULL) 629 { 630 CommandArgumentEntry arg; 631 CommandArgumentData bp_id_arg; 632 633 // Define the first (and only) variant of this arg. 634 bp_id_arg.arg_type = eArgTypeBreakpointID; 635 bp_id_arg.arg_repetition = eArgRepeatPlain; 636 637 // There is only one variant this argument could be; put it into the argument entry. 638 arg.push_back (bp_id_arg); 639 640 // Push the data for the first argument into the m_arguments vector. 641 m_arguments.push_back (arg); 642 } 643 644 CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList () 645 { 646 } 647 648 bool 649 CommandObjectBreakpointCommandList::Execute 650 ( 651 Args& command, 652 CommandReturnObject &result 653 ) 654 { 655 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 656 657 if (target == NULL) 658 { 659 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 660 result.SetStatus (eReturnStatusFailed); 661 return false; 662 } 663 664 const BreakpointList &breakpoints = target->GetBreakpointList(); 665 size_t num_breakpoints = breakpoints.GetSize(); 666 667 if (num_breakpoints == 0) 668 { 669 result.AppendError ("No breakpoints exist for which to list commands"); 670 result.SetStatus (eReturnStatusFailed); 671 return false; 672 } 673 674 if (command.GetArgumentCount() == 0) 675 { 676 result.AppendError ("No breakpoint specified for which to list the commands"); 677 result.SetStatus (eReturnStatusFailed); 678 return false; 679 } 680 681 BreakpointIDList valid_bp_ids; 682 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 683 684 if (result.Succeeded()) 685 { 686 const size_t count = valid_bp_ids.GetSize(); 687 for (size_t i = 0; i < count; ++i) 688 { 689 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 690 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 691 { 692 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 693 694 if (bp) 695 { 696 const BreakpointOptions *bp_options = NULL; 697 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 698 { 699 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 700 if (bp_loc_sp) 701 bp_options = bp_loc_sp->GetOptionsNoCreate(); 702 else 703 { 704 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 705 cur_bp_id.GetBreakpointID(), 706 cur_bp_id.GetLocationID()); 707 result.SetStatus (eReturnStatusFailed); 708 return false; 709 } 710 } 711 else 712 { 713 bp_options = bp->GetOptions(); 714 } 715 716 if (bp_options) 717 { 718 StreamString id_str; 719 BreakpointID::GetCanonicalReference (&id_str, 720 cur_bp_id.GetBreakpointID(), 721 cur_bp_id.GetLocationID()); 722 const Baton *baton = bp_options->GetBaton(); 723 if (baton) 724 { 725 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 726 result.GetOutputStream().IndentMore (); 727 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 728 result.GetOutputStream().IndentLess (); 729 } 730 else 731 { 732 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", 733 id_str.GetData()); 734 } 735 } 736 result.SetStatus (eReturnStatusSuccessFinishResult); 737 } 738 else 739 { 740 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 741 result.SetStatus (eReturnStatusFailed); 742 } 743 744 } 745 } 746 } 747 748 return result.Succeeded(); 749 } 750 751 //------------------------------------------------------------------------- 752 // CommandObjectBreakpointCommand 753 //------------------------------------------------------------------------- 754 755 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 756 CommandObjectMultiword (interpreter, 757 "command", 758 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').", 759 "command <sub-command> [<sub-command-options>] <breakpoint-id>") 760 { 761 bool status; 762 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); 763 CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter)); 764 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 765 766 add_command_object->SetCommandName ("breakpoint command add"); 767 delete_command_object->SetCommandName ("breakpoint command delete"); 768 list_command_object->SetCommandName ("breakpoint command list"); 769 770 status = LoadSubCommand ("add", add_command_object); 771 status = LoadSubCommand ("delete", delete_command_object); 772 status = LoadSubCommand ("list", list_command_object); 773 } 774 775 776 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () 777 { 778 } 779 780 bool 781 CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction 782 ( 783 void *baton, 784 StoppointCallbackContext *context, 785 lldb::user_id_t break_id, 786 lldb::user_id_t break_loc_id 787 ) 788 { 789 bool ret_value = true; 790 if (baton == NULL) 791 return true; 792 793 794 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; 795 StringList &commands = data->user_source; 796 797 if (commands.GetSize() > 0) 798 { 799 if (context->exe_ctx.target) 800 { 801 CommandReturnObject result; 802 Debugger &debugger = context->exe_ctx.target->GetDebugger(); 803 // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously 804 // if the debugger is set up that way. 805 806 StreamSP output_stream (new StreamAsynchronousIO (debugger.GetCommandInterpreter(), 807 CommandInterpreter::eBroadcastBitAsynchronousOutputData)); 808 StreamSP error_stream (new StreamAsynchronousIO (debugger.GetCommandInterpreter(), 809 CommandInterpreter::eBroadcastBitAsynchronousErrorData)); 810 result.SetImmediateOutputStream (output_stream); 811 result.SetImmediateErrorStream (error_stream); 812 813 bool stop_on_continue = true; 814 bool echo_commands = false; 815 bool print_results = true; 816 817 debugger.GetCommandInterpreter().HandleCommands (commands, 818 &(context->exe_ctx), 819 stop_on_continue, 820 data->stop_on_error, 821 echo_commands, 822 print_results, 823 result); 824 result.GetImmediateOutputStream()->Flush(); 825 result.GetImmediateErrorStream()->Flush(); 826 } 827 } 828 return ret_value; 829 } 830 831