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 if (command.GetArgumentCount() == 0) 286 { 287 result.AppendError ("No breakpoint specified to which to add the commands"); 288 result.SetStatus (eReturnStatusFailed); 289 return false; 290 } 291 292 BreakpointIDList valid_bp_ids; 293 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 294 295 if (result.Succeeded()) 296 { 297 const size_t count = valid_bp_ids.GetSize(); 298 for (size_t i = 0; i < count; ++i) 299 { 300 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 301 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 302 { 303 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 304 BreakpointOptions *bp_options = NULL; 305 if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) 306 { 307 // This breakpoint does not have an associated location. 308 bp_options = bp->GetOptions(); 309 } 310 else 311 { 312 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 313 // This breakpoint does have an associated location. 314 // Get its breakpoint options. 315 if (bp_loc_sp) 316 bp_options = bp_loc_sp->GetLocationOptions(); 317 } 318 319 // Skip this breakpoiont if bp_options is not good. 320 if (bp_options == NULL) continue; 321 322 // If we are using script language, get the script interpreter 323 // in order to set or collect command callback. Otherwise, call 324 // the methods associated with this object. 325 if (m_options.m_use_script_language) 326 { 327 // Special handling for one-liner specified inline. 328 if (m_options.m_use_one_liner) 329 m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, 330 m_options.m_one_liner.c_str()); 331 else 332 m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options, 333 result); 334 } 335 else 336 { 337 // Special handling for one-liner specified inline. 338 if (m_options.m_use_one_liner) 339 SetBreakpointCommandCallback (bp_options, 340 m_options.m_one_liner.c_str()); 341 else 342 CollectDataForBreakpointCommandCallback (bp_options, 343 result); 344 } 345 } 346 } 347 } 348 349 return result.Succeeded(); 350 } 351 352 Options * 353 CommandObjectBreakpointCommandAdd::GetOptions () 354 { 355 return &m_options; 356 } 357 358 const char *g_reader_instructions = "Enter your debugger command(s). Type 'DONE' to end."; 359 360 void 361 CommandObjectBreakpointCommandAdd::CollectDataForBreakpointCommandCallback 362 ( 363 BreakpointOptions *bp_options, 364 CommandReturnObject &result 365 ) 366 { 367 InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger())); 368 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 369 if (reader_sp && data_ap.get()) 370 { 371 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 372 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp); 373 374 Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback, 375 bp_options, // baton 376 eInputReaderGranularityLine, // token size, to pass to callback function 377 "DONE", // end token 378 "> ", // prompt 379 true)); // echo input 380 if (err.Success()) 381 { 382 m_interpreter.GetDebugger().PushInputReader (reader_sp); 383 result.SetStatus (eReturnStatusSuccessFinishNoResult); 384 } 385 else 386 { 387 result.AppendError (err.AsCString()); 388 result.SetStatus (eReturnStatusFailed); 389 } 390 } 391 else 392 { 393 result.AppendError("out of memory"); 394 result.SetStatus (eReturnStatusFailed); 395 } 396 397 } 398 399 // Set a one-liner as the callback for the breakpoint. 400 void 401 CommandObjectBreakpointCommandAdd::SetBreakpointCommandCallback (BreakpointOptions *bp_options, 402 const char *oneliner) 403 { 404 std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); 405 406 // It's necessary to set both user_source and script_source to the oneliner. 407 // The former is used to generate callback description (as in breakpoint command list) 408 // while the latter is used for Python to interpret during the actual callback. 409 data_ap->user_source.AppendString (oneliner); 410 data_ap->script_source.AppendString (oneliner); 411 412 BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); 413 bp_options->SetCallback (CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction, baton_sp); 414 415 return; 416 } 417 418 size_t 419 CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback 420 ( 421 void *baton, 422 InputReader &reader, 423 lldb::InputReaderAction notification, 424 const char *bytes, 425 size_t bytes_len 426 ) 427 { 428 FILE *out_fh = reader.GetDebugger().GetOutputFileHandle(); 429 430 switch (notification) 431 { 432 case eInputReaderActivate: 433 if (out_fh) 434 { 435 ::fprintf (out_fh, "%s\n", g_reader_instructions); 436 if (reader.GetPrompt()) 437 ::fprintf (out_fh, "%s", reader.GetPrompt()); 438 ::fflush (out_fh); 439 } 440 break; 441 442 case eInputReaderDeactivate: 443 break; 444 445 case eInputReaderReactivate: 446 if (out_fh && reader.GetPrompt()) 447 { 448 ::fprintf (out_fh, "%s", reader.GetPrompt()); 449 ::fflush (out_fh); 450 } 451 break; 452 453 case eInputReaderGotToken: 454 if (bytes && bytes_len && baton) 455 { 456 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 457 if (bp_options) 458 { 459 Baton *bp_options_baton = bp_options->GetBaton(); 460 if (bp_options_baton) 461 ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len); 462 } 463 } 464 if (out_fh && !reader.IsDone() && reader.GetPrompt()) 465 { 466 ::fprintf (out_fh, "%s", reader.GetPrompt()); 467 ::fflush (out_fh); 468 } 469 break; 470 471 case eInputReaderInterrupt: 472 { 473 // Finish, and cancel the breakpoint command. 474 reader.SetIsDone (true); 475 BreakpointOptions *bp_options = (BreakpointOptions *) baton; 476 if (bp_options) 477 { 478 Baton *bp_options_baton = bp_options->GetBaton (); 479 if (bp_options_baton) 480 { 481 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear(); 482 ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.Clear(); 483 } 484 } 485 ::fprintf (out_fh, "Warning: No command attached to breakpoint.\n"); 486 ::fflush (out_fh); 487 } 488 break; 489 490 case eInputReaderEndOfFile: 491 reader.SetIsDone (true); 492 break; 493 494 case eInputReaderDone: 495 break; 496 } 497 498 return bytes_len; 499 } 500 501 502 //------------------------------------------------------------------------- 503 // CommandObjectBreakpointCommandRemove 504 //------------------------------------------------------------------------- 505 506 CommandObjectBreakpointCommandRemove::CommandObjectBreakpointCommandRemove (CommandInterpreter &interpreter) : 507 CommandObject (interpreter, 508 "remove", 509 "Remove the set of commands from a breakpoint.", 510 NULL) 511 { 512 CommandArgumentEntry arg; 513 CommandArgumentData bp_id_arg; 514 515 // Define the first (and only) variant of this arg. 516 bp_id_arg.arg_type = eArgTypeBreakpointID; 517 bp_id_arg.arg_repetition = eArgRepeatPlain; 518 519 // There is only one variant this argument could be; put it into the argument entry. 520 arg.push_back (bp_id_arg); 521 522 // Push the data for the first argument into the m_arguments vector. 523 m_arguments.push_back (arg); 524 } 525 526 CommandObjectBreakpointCommandRemove::~CommandObjectBreakpointCommandRemove () 527 { 528 } 529 530 bool 531 CommandObjectBreakpointCommandRemove::Execute 532 ( 533 Args& command, 534 CommandReturnObject &result 535 ) 536 { 537 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 538 539 if (target == NULL) 540 { 541 result.AppendError ("There is not a current executable; there are no breakpoints from which to remove commands"); 542 result.SetStatus (eReturnStatusFailed); 543 return false; 544 } 545 546 const BreakpointList &breakpoints = target->GetBreakpointList(); 547 size_t num_breakpoints = breakpoints.GetSize(); 548 549 if (num_breakpoints == 0) 550 { 551 result.AppendError ("No breakpoints exist to have commands removed"); 552 result.SetStatus (eReturnStatusFailed); 553 return false; 554 } 555 556 if (command.GetArgumentCount() == 0) 557 { 558 result.AppendError ("No breakpoint specified from which to remove the commands"); 559 result.SetStatus (eReturnStatusFailed); 560 return false; 561 } 562 563 BreakpointIDList valid_bp_ids; 564 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 565 566 if (result.Succeeded()) 567 { 568 const size_t count = valid_bp_ids.GetSize(); 569 for (size_t i = 0; i < count; ++i) 570 { 571 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 572 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 573 { 574 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 575 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 576 { 577 BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID())); 578 if (bp_loc_sp) 579 bp_loc_sp->ClearCallback(); 580 else 581 { 582 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 583 cur_bp_id.GetBreakpointID(), 584 cur_bp_id.GetLocationID()); 585 result.SetStatus (eReturnStatusFailed); 586 return false; 587 } 588 } 589 else 590 { 591 bp->ClearCallback(); 592 } 593 } 594 } 595 } 596 return result.Succeeded(); 597 } 598 599 600 //------------------------------------------------------------------------- 601 // CommandObjectBreakpointCommandList 602 //------------------------------------------------------------------------- 603 604 CommandObjectBreakpointCommandList::CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) : 605 CommandObject (interpreter, 606 "list", 607 "List the script or set of commands to be executed when the breakpoint is hit.", 608 NULL) 609 { 610 CommandArgumentEntry arg; 611 CommandArgumentData bp_id_arg; 612 613 // Define the first (and only) variant of this arg. 614 bp_id_arg.arg_type = eArgTypeBreakpointID; 615 bp_id_arg.arg_repetition = eArgRepeatPlain; 616 617 // There is only one variant this argument could be; put it into the argument entry. 618 arg.push_back (bp_id_arg); 619 620 // Push the data for the first argument into the m_arguments vector. 621 m_arguments.push_back (arg); 622 } 623 624 CommandObjectBreakpointCommandList::~CommandObjectBreakpointCommandList () 625 { 626 } 627 628 bool 629 CommandObjectBreakpointCommandList::Execute 630 ( 631 Args& command, 632 CommandReturnObject &result 633 ) 634 { 635 Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get(); 636 637 if (target == NULL) 638 { 639 result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands"); 640 result.SetStatus (eReturnStatusFailed); 641 return false; 642 } 643 644 const BreakpointList &breakpoints = target->GetBreakpointList(); 645 size_t num_breakpoints = breakpoints.GetSize(); 646 647 if (num_breakpoints == 0) 648 { 649 result.AppendError ("No breakpoints exist for which to list commands"); 650 result.SetStatus (eReturnStatusFailed); 651 return false; 652 } 653 654 if (command.GetArgumentCount() == 0) 655 { 656 result.AppendError ("No breakpoint specified for which to list the commands"); 657 result.SetStatus (eReturnStatusFailed); 658 return false; 659 } 660 661 BreakpointIDList valid_bp_ids; 662 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids); 663 664 if (result.Succeeded()) 665 { 666 const size_t count = valid_bp_ids.GetSize(); 667 for (size_t i = 0; i < count; ++i) 668 { 669 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i); 670 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) 671 { 672 Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get(); 673 674 if (bp) 675 { 676 const BreakpointOptions *bp_options = NULL; 677 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) 678 { 679 BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID())); 680 if (bp_loc_sp) 681 bp_options = bp_loc_sp->GetOptionsNoCreate(); 682 else 683 { 684 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n", 685 cur_bp_id.GetBreakpointID(), 686 cur_bp_id.GetLocationID()); 687 result.SetStatus (eReturnStatusFailed); 688 return false; 689 } 690 } 691 else 692 { 693 bp_options = bp->GetOptions(); 694 } 695 696 if (bp_options) 697 { 698 StreamString id_str; 699 BreakpointID::GetCanonicalReference (&id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); 700 const Baton *baton = bp_options->GetBaton(); 701 if (baton) 702 { 703 result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData()); 704 result.GetOutputStream().IndentMore (); 705 baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull); 706 result.GetOutputStream().IndentLess (); 707 } 708 else 709 { 710 result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n", id_str.GetData()); 711 } 712 } 713 result.SetStatus (eReturnStatusSuccessFinishResult); 714 } 715 else 716 { 717 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID()); 718 result.SetStatus (eReturnStatusFailed); 719 } 720 721 } 722 } 723 } 724 725 return result.Succeeded(); 726 } 727 728 //------------------------------------------------------------------------- 729 // CommandObjectBreakpointCommand 730 //------------------------------------------------------------------------- 731 732 CommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) : 733 CommandObjectMultiword (interpreter, 734 "command", 735 "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').", 736 "command <sub-command> [<sub-command-options>] <breakpoint-id>") 737 { 738 bool status; 739 CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter)); 740 CommandObjectSP remove_command_object (new CommandObjectBreakpointCommandRemove (interpreter)); 741 CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter)); 742 743 add_command_object->SetCommandName ("breakpoint command add"); 744 remove_command_object->SetCommandName ("breakpoint command remove"); 745 list_command_object->SetCommandName ("breakpoint command list"); 746 747 status = LoadSubCommand ("add", add_command_object); 748 status = LoadSubCommand ("remove", remove_command_object); 749 status = LoadSubCommand ("list", list_command_object); 750 } 751 752 753 CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand () 754 { 755 } 756 757 bool 758 CommandObjectBreakpointCommand::BreakpointOptionsCallbackFunction 759 ( 760 void *baton, 761 StoppointCallbackContext *context, 762 lldb::user_id_t break_id, 763 lldb::user_id_t break_loc_id 764 ) 765 { 766 bool ret_value = true; 767 if (baton == NULL) 768 return true; 769 770 771 BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton; 772 StringList &commands = data->user_source; 773 774 if (commands.GetSize() > 0) 775 { 776 uint32_t num_commands = commands.GetSize(); 777 CommandReturnObject result; 778 if (context->exe_ctx.target) 779 { 780 781 Debugger &debugger = context->exe_ctx.target->GetDebugger(); 782 CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); 783 784 FILE *out_fh = debugger.GetOutputFileHandle(); 785 FILE *err_fh = debugger.GetErrorFileHandle(); 786 787 uint32_t i; 788 for (i = 0; i < num_commands; ++i) 789 { 790 791 // First time through we use the context from the stoppoint, after that we use whatever 792 // has been set by the previous command. 793 794 if (!interpreter.HandleCommand (commands.GetStringAtIndex(i), false, result, &context->exe_ctx)) 795 break; 796 797 // FIXME: This isn't really the right way to do this. We should be able to peek at the public 798 // to see if there is any new events, but that is racey, since the internal process thread has to run and 799 // deliver the event to the public queue before a run will show up. So for now we check 800 // the internal thread state. 801 802 lldb::StateType internal_state = context->exe_ctx.process->GetPrivateState(); 803 if (internal_state != eStateStopped) 804 { 805 if (i < num_commands - 1) 806 { 807 if (out_fh) 808 ::fprintf (out_fh, "Short-circuiting command execution because target state changed to %s." 809 " last command: \"%s\"\n", StateAsCString(internal_state), 810 commands.GetStringAtIndex(i)); 811 } 812 break; 813 } 814 815 if (out_fh) 816 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData()); 817 if (err_fh) 818 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData()); 819 result.Clear(); 820 result.SetStatus (eReturnStatusSuccessFinishNoResult); 821 } 822 823 if (err_fh && !result.Succeeded() && i < num_commands) 824 ::fprintf (err_fh, "Attempt to execute '%s' failed.\n", commands.GetStringAtIndex(i)); 825 826 if (out_fh) 827 ::fprintf (out_fh, "%s", result.GetErrorStream().GetData()); 828 829 if (err_fh) 830 ::fprintf (err_fh, "%s", result.GetOutputStream().GetData()); 831 } 832 } 833 return ret_value; 834 } 835 836