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