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