1 //===-- CommandObjectBreakpoint.cpp -----------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "CommandObjectBreakpoint.h" 10 #include "CommandObjectBreakpointCommand.h" 11 #include "lldb/Breakpoint/Breakpoint.h" 12 #include "lldb/Breakpoint/BreakpointIDList.h" 13 #include "lldb/Breakpoint/BreakpointLocation.h" 14 #include "lldb/Host/OptionParser.h" 15 #include "lldb/Interpreter/CommandCompletions.h" 16 #include "lldb/Interpreter/CommandInterpreter.h" 17 #include "lldb/Interpreter/CommandReturnObject.h" 18 #include "lldb/Interpreter/OptionArgParser.h" 19 #include "lldb/Interpreter/OptionValueBoolean.h" 20 #include "lldb/Interpreter/OptionValueString.h" 21 #include "lldb/Interpreter/OptionValueUInt64.h" 22 #include "lldb/Interpreter/Options.h" 23 #include "lldb/Target/Language.h" 24 #include "lldb/Target/StackFrame.h" 25 #include "lldb/Target/Target.h" 26 #include "lldb/Target/Thread.h" 27 #include "lldb/Target/ThreadSpec.h" 28 #include "lldb/Utility/RegularExpression.h" 29 #include "lldb/Utility/StreamString.h" 30 31 #include <memory> 32 #include <vector> 33 34 using namespace lldb; 35 using namespace lldb_private; 36 37 static void AddBreakpointDescription(Stream *s, Breakpoint *bp, 38 lldb::DescriptionLevel level) { 39 s->IndentMore(); 40 bp->GetDescription(s, level, true); 41 s->IndentLess(); 42 s->EOL(); 43 } 44 45 // Modifiable Breakpoint Options 46 #pragma mark Modify::CommandOptions 47 static constexpr OptionDefinition g_breakpoint_modify_options[] = { 48 #define LLDB_OPTIONS_breakpoint_modify 49 #include "CommandOptions.inc" 50 }; 51 class lldb_private::BreakpointOptionGroup : public OptionGroup 52 { 53 public: 54 BreakpointOptionGroup() : 55 OptionGroup(), 56 m_bp_opts(false) {} 57 58 ~BreakpointOptionGroup() override = default; 59 60 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 61 return llvm::makeArrayRef(g_breakpoint_modify_options); 62 } 63 64 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 65 ExecutionContext *execution_context) override { 66 Status error; 67 const int short_option = g_breakpoint_modify_options[option_idx].short_option; 68 69 switch (short_option) { 70 case 'c': 71 // Normally an empty breakpoint condition marks is as unset. But we need 72 // to say it was passed in. 73 m_bp_opts.SetCondition(option_arg.str().c_str()); 74 m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition); 75 break; 76 case 'C': 77 m_commands.push_back(option_arg); 78 break; 79 case 'd': 80 m_bp_opts.SetEnabled(false); 81 break; 82 case 'e': 83 m_bp_opts.SetEnabled(true); 84 break; 85 case 'G': { 86 bool value, success; 87 value = OptionArgParser::ToBoolean(option_arg, false, &success); 88 if (success) { 89 m_bp_opts.SetAutoContinue(value); 90 } else 91 error.SetErrorStringWithFormat( 92 "invalid boolean value '%s' passed for -G option", 93 option_arg.str().c_str()); 94 } 95 break; 96 case 'i': 97 { 98 uint32_t ignore_count; 99 if (option_arg.getAsInteger(0, ignore_count)) 100 error.SetErrorStringWithFormat("invalid ignore count '%s'", 101 option_arg.str().c_str()); 102 else 103 m_bp_opts.SetIgnoreCount(ignore_count); 104 } 105 break; 106 case 'o': { 107 bool value, success; 108 value = OptionArgParser::ToBoolean(option_arg, false, &success); 109 if (success) { 110 m_bp_opts.SetOneShot(value); 111 } else 112 error.SetErrorStringWithFormat( 113 "invalid boolean value '%s' passed for -o option", 114 option_arg.str().c_str()); 115 } break; 116 case 't': 117 { 118 lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID; 119 if (option_arg[0] != '\0') { 120 if (option_arg.getAsInteger(0, thread_id)) 121 error.SetErrorStringWithFormat("invalid thread id string '%s'", 122 option_arg.str().c_str()); 123 } 124 m_bp_opts.SetThreadID(thread_id); 125 } 126 break; 127 case 'T': 128 m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str()); 129 break; 130 case 'q': 131 m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str()); 132 break; 133 case 'x': 134 { 135 uint32_t thread_index = UINT32_MAX; 136 if (option_arg[0] != '\n') { 137 if (option_arg.getAsInteger(0, thread_index)) 138 error.SetErrorStringWithFormat("invalid thread index string '%s'", 139 option_arg.str().c_str()); 140 } 141 m_bp_opts.GetThreadSpec()->SetIndex(thread_index); 142 } 143 break; 144 default: 145 error.SetErrorStringWithFormat("unrecognized option '%c'", 146 short_option); 147 break; 148 } 149 150 return error; 151 } 152 153 void OptionParsingStarting(ExecutionContext *execution_context) override { 154 m_bp_opts.Clear(); 155 m_commands.clear(); 156 } 157 158 Status OptionParsingFinished(ExecutionContext *execution_context) override { 159 if (!m_commands.empty()) 160 { 161 if (!m_commands.empty()) 162 { 163 auto cmd_data = llvm::make_unique<BreakpointOptions::CommandData>(); 164 165 for (std::string &str : m_commands) 166 cmd_data->user_source.AppendString(str); 167 168 cmd_data->stop_on_error = true; 169 m_bp_opts.SetCommandDataCallback(cmd_data); 170 } 171 } 172 return Status(); 173 } 174 175 const BreakpointOptions &GetBreakpointOptions() 176 { 177 return m_bp_opts; 178 } 179 180 std::vector<std::string> m_commands; 181 BreakpointOptions m_bp_opts; 182 183 }; 184 static constexpr OptionDefinition g_breakpoint_dummy_options[] = { 185 #define LLDB_OPTIONS_breakpoint_dummy 186 #include "CommandOptions.inc" 187 }; 188 189 class BreakpointDummyOptionGroup : public OptionGroup 190 { 191 public: 192 BreakpointDummyOptionGroup() : 193 OptionGroup() {} 194 195 ~BreakpointDummyOptionGroup() override = default; 196 197 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 198 return llvm::makeArrayRef(g_breakpoint_dummy_options); 199 } 200 201 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 202 ExecutionContext *execution_context) override { 203 Status error; 204 const int short_option = g_breakpoint_modify_options[option_idx].short_option; 205 206 switch (short_option) { 207 case 'D': 208 m_use_dummy = true; 209 break; 210 default: 211 error.SetErrorStringWithFormat("unrecognized option '%c'", 212 short_option); 213 break; 214 } 215 216 return error; 217 } 218 219 void OptionParsingStarting(ExecutionContext *execution_context) override { 220 m_use_dummy = false; 221 } 222 223 bool m_use_dummy; 224 225 }; 226 227 static constexpr OptionDefinition g_breakpoint_set_options[] = { 228 #define LLDB_OPTIONS_breakpoint_set 229 #include "CommandOptions.inc" 230 }; 231 232 // CommandObjectBreakpointSet 233 234 class CommandObjectBreakpointSet : public CommandObjectParsed { 235 public: 236 enum BreakpointSetType { 237 eSetTypeInvalid, 238 eSetTypeFileAndLine, 239 eSetTypeAddress, 240 eSetTypeFunctionName, 241 eSetTypeFunctionRegexp, 242 eSetTypeSourceRegexp, 243 eSetTypeException, 244 eSetTypeScripted, 245 }; 246 247 CommandObjectBreakpointSet(CommandInterpreter &interpreter) 248 : CommandObjectParsed( 249 interpreter, "breakpoint set", 250 "Sets a breakpoint or set of breakpoints in the executable.", 251 "breakpoint set <cmd-options>"), 252 m_bp_opts(), m_options() { 253 // We're picking up all the normal options, commands and disable. 254 m_all_options.Append(&m_bp_opts, 255 LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4, 256 LLDB_OPT_SET_ALL); 257 m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 258 m_all_options.Append(&m_options); 259 m_all_options.Finalize(); 260 } 261 262 ~CommandObjectBreakpointSet() override = default; 263 264 Options *GetOptions() override { return &m_all_options; } 265 266 class CommandOptions : public OptionGroup { 267 public: 268 CommandOptions() 269 : OptionGroup(), m_condition(), m_filenames(), m_line_num(0), m_column(0), 270 m_func_names(), m_func_name_type_mask(eFunctionNameTypeNone), 271 m_func_regexp(), m_source_text_regexp(), m_modules(), m_load_addr(), 272 m_catch_bp(false), m_throw_bp(true), m_hardware(false), 273 m_exception_language(eLanguageTypeUnknown), 274 m_language(lldb::eLanguageTypeUnknown), 275 m_skip_prologue(eLazyBoolCalculate), 276 m_all_files(false), m_move_to_nearest_code(eLazyBoolCalculate) {} 277 278 ~CommandOptions() override = default; 279 280 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 281 ExecutionContext *execution_context) override { 282 Status error; 283 const int short_option = g_breakpoint_set_options[option_idx].short_option; 284 285 switch (short_option) { 286 case 'a': { 287 m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg, 288 LLDB_INVALID_ADDRESS, &error); 289 } break; 290 291 case 'A': 292 m_all_files = true; 293 break; 294 295 case 'b': 296 m_func_names.push_back(option_arg); 297 m_func_name_type_mask |= eFunctionNameTypeBase; 298 break; 299 300 case 'C': 301 if (option_arg.getAsInteger(0, m_column)) 302 error.SetErrorStringWithFormat("invalid column number: %s", 303 option_arg.str().c_str()); 304 break; 305 306 case 'E': { 307 LanguageType language = Language::GetLanguageTypeFromString(option_arg); 308 309 switch (language) { 310 case eLanguageTypeC89: 311 case eLanguageTypeC: 312 case eLanguageTypeC99: 313 case eLanguageTypeC11: 314 m_exception_language = eLanguageTypeC; 315 break; 316 case eLanguageTypeC_plus_plus: 317 case eLanguageTypeC_plus_plus_03: 318 case eLanguageTypeC_plus_plus_11: 319 case eLanguageTypeC_plus_plus_14: 320 m_exception_language = eLanguageTypeC_plus_plus; 321 break; 322 case eLanguageTypeObjC: 323 m_exception_language = eLanguageTypeObjC; 324 break; 325 case eLanguageTypeObjC_plus_plus: 326 error.SetErrorStringWithFormat( 327 "Set exception breakpoints separately for c++ and objective-c"); 328 break; 329 case eLanguageTypeUnknown: 330 error.SetErrorStringWithFormat( 331 "Unknown language type: '%s' for exception breakpoint", 332 option_arg.str().c_str()); 333 break; 334 default: 335 error.SetErrorStringWithFormat( 336 "Unsupported language type: '%s' for exception breakpoint", 337 option_arg.str().c_str()); 338 } 339 } break; 340 341 case 'f': 342 m_filenames.AppendIfUnique(FileSpec(option_arg)); 343 break; 344 345 case 'F': 346 m_func_names.push_back(option_arg); 347 m_func_name_type_mask |= eFunctionNameTypeFull; 348 break; 349 350 case 'h': { 351 bool success; 352 m_catch_bp = OptionArgParser::ToBoolean(option_arg, true, &success); 353 if (!success) 354 error.SetErrorStringWithFormat( 355 "Invalid boolean value for on-catch option: '%s'", 356 option_arg.str().c_str()); 357 } break; 358 359 case 'H': 360 m_hardware = true; 361 break; 362 363 case 'k': { 364 if (m_current_key.empty()) 365 m_current_key.assign(option_arg); 366 else 367 error.SetErrorStringWithFormat("Key: %s missing value.", 368 m_current_key.c_str()); 369 370 } break; 371 case 'K': { 372 bool success; 373 bool value; 374 value = OptionArgParser::ToBoolean(option_arg, true, &success); 375 if (value) 376 m_skip_prologue = eLazyBoolYes; 377 else 378 m_skip_prologue = eLazyBoolNo; 379 380 if (!success) 381 error.SetErrorStringWithFormat( 382 "Invalid boolean value for skip prologue option: '%s'", 383 option_arg.str().c_str()); 384 } break; 385 386 case 'l': 387 if (option_arg.getAsInteger(0, m_line_num)) 388 error.SetErrorStringWithFormat("invalid line number: %s.", 389 option_arg.str().c_str()); 390 break; 391 392 case 'L': 393 m_language = Language::GetLanguageTypeFromString(option_arg); 394 if (m_language == eLanguageTypeUnknown) 395 error.SetErrorStringWithFormat( 396 "Unknown language type: '%s' for breakpoint", 397 option_arg.str().c_str()); 398 break; 399 400 case 'm': { 401 bool success; 402 bool value; 403 value = OptionArgParser::ToBoolean(option_arg, true, &success); 404 if (value) 405 m_move_to_nearest_code = eLazyBoolYes; 406 else 407 m_move_to_nearest_code = eLazyBoolNo; 408 409 if (!success) 410 error.SetErrorStringWithFormat( 411 "Invalid boolean value for move-to-nearest-code option: '%s'", 412 option_arg.str().c_str()); 413 break; 414 } 415 416 case 'M': 417 m_func_names.push_back(option_arg); 418 m_func_name_type_mask |= eFunctionNameTypeMethod; 419 break; 420 421 case 'n': 422 m_func_names.push_back(option_arg); 423 m_func_name_type_mask |= eFunctionNameTypeAuto; 424 break; 425 426 case 'N': { 427 if (BreakpointID::StringIsBreakpointName(option_arg, error)) 428 m_breakpoint_names.push_back(option_arg); 429 else 430 error.SetErrorStringWithFormat("Invalid breakpoint name: %s", 431 option_arg.str().c_str()); 432 break; 433 } 434 435 case 'R': { 436 lldb::addr_t tmp_offset_addr; 437 tmp_offset_addr = OptionArgParser::ToAddress(execution_context, 438 option_arg, 0, &error); 439 if (error.Success()) 440 m_offset_addr = tmp_offset_addr; 441 } break; 442 443 case 'O': 444 m_exception_extra_args.AppendArgument("-O"); 445 m_exception_extra_args.AppendArgument(option_arg); 446 break; 447 448 case 'p': 449 m_source_text_regexp.assign(option_arg); 450 break; 451 452 case 'P': 453 m_python_class.assign(option_arg); 454 break; 455 456 case 'r': 457 m_func_regexp.assign(option_arg); 458 break; 459 460 case 's': 461 m_modules.AppendIfUnique(FileSpec(option_arg)); 462 break; 463 464 case 'S': 465 m_func_names.push_back(option_arg); 466 m_func_name_type_mask |= eFunctionNameTypeSelector; 467 break; 468 469 case 'v': { 470 if (!m_current_key.empty()) { 471 m_extra_args_sp->AddStringItem(m_current_key, option_arg); 472 m_current_key.clear(); 473 } 474 else 475 error.SetErrorStringWithFormat("Value \"%s\" missing matching key.", 476 option_arg.str().c_str()); 477 } break; 478 479 case 'w': { 480 bool success; 481 m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success); 482 if (!success) 483 error.SetErrorStringWithFormat( 484 "Invalid boolean value for on-throw option: '%s'", 485 option_arg.str().c_str()); 486 } break; 487 488 case 'X': 489 m_source_regex_func_names.insert(option_arg); 490 break; 491 492 default: 493 error.SetErrorStringWithFormat("unrecognized option '%c'", 494 short_option); 495 break; 496 } 497 498 return error; 499 } 500 501 void OptionParsingStarting(ExecutionContext *execution_context) override { 502 m_filenames.Clear(); 503 m_line_num = 0; 504 m_column = 0; 505 m_func_names.clear(); 506 m_func_name_type_mask = eFunctionNameTypeNone; 507 m_func_regexp.clear(); 508 m_source_text_regexp.clear(); 509 m_modules.Clear(); 510 m_load_addr = LLDB_INVALID_ADDRESS; 511 m_offset_addr = 0; 512 m_catch_bp = false; 513 m_throw_bp = true; 514 m_hardware = false; 515 m_exception_language = eLanguageTypeUnknown; 516 m_language = lldb::eLanguageTypeUnknown; 517 m_skip_prologue = eLazyBoolCalculate; 518 m_breakpoint_names.clear(); 519 m_all_files = false; 520 m_exception_extra_args.Clear(); 521 m_move_to_nearest_code = eLazyBoolCalculate; 522 m_source_regex_func_names.clear(); 523 m_python_class.clear(); 524 m_extra_args_sp = std::make_shared<StructuredData::Dictionary>(); 525 m_current_key.clear(); 526 } 527 528 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 529 return llvm::makeArrayRef(g_breakpoint_set_options); 530 } 531 532 // Instance variables to hold the values for command options. 533 534 std::string m_condition; 535 FileSpecList m_filenames; 536 uint32_t m_line_num; 537 uint32_t m_column; 538 std::vector<std::string> m_func_names; 539 std::vector<std::string> m_breakpoint_names; 540 lldb::FunctionNameType m_func_name_type_mask; 541 std::string m_func_regexp; 542 std::string m_source_text_regexp; 543 FileSpecList m_modules; 544 lldb::addr_t m_load_addr; 545 lldb::addr_t m_offset_addr; 546 bool m_catch_bp; 547 bool m_throw_bp; 548 bool m_hardware; // Request to use hardware breakpoints 549 lldb::LanguageType m_exception_language; 550 lldb::LanguageType m_language; 551 LazyBool m_skip_prologue; 552 bool m_all_files; 553 Args m_exception_extra_args; 554 LazyBool m_move_to_nearest_code; 555 std::unordered_set<std::string> m_source_regex_func_names; 556 std::string m_python_class; 557 StructuredData::DictionarySP m_extra_args_sp; 558 std::string m_current_key; 559 }; 560 561 protected: 562 bool DoExecute(Args &command, CommandReturnObject &result) override { 563 Target *target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy); 564 565 if (target == nullptr) { 566 result.AppendError("Invalid target. Must set target before setting " 567 "breakpoints (see 'target create' command)."); 568 result.SetStatus(eReturnStatusFailed); 569 return false; 570 } 571 572 // The following are the various types of breakpoints that could be set: 573 // 1). -f -l -p [-s -g] (setting breakpoint by source location) 574 // 2). -a [-s -g] (setting breakpoint by address) 575 // 3). -n [-s -g] (setting breakpoint by function name) 576 // 4). -r [-s -g] (setting breakpoint by function name regular 577 // expression) 578 // 5). -p -f (setting a breakpoint by comparing a reg-exp 579 // to source text) 580 // 6). -E [-w -h] (setting a breakpoint for exceptions for a 581 // given language.) 582 583 BreakpointSetType break_type = eSetTypeInvalid; 584 585 if (!m_options.m_python_class.empty()) 586 break_type = eSetTypeScripted; 587 else if (m_options.m_line_num != 0) 588 break_type = eSetTypeFileAndLine; 589 else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS) 590 break_type = eSetTypeAddress; 591 else if (!m_options.m_func_names.empty()) 592 break_type = eSetTypeFunctionName; 593 else if (!m_options.m_func_regexp.empty()) 594 break_type = eSetTypeFunctionRegexp; 595 else if (!m_options.m_source_text_regexp.empty()) 596 break_type = eSetTypeSourceRegexp; 597 else if (m_options.m_exception_language != eLanguageTypeUnknown) 598 break_type = eSetTypeException; 599 600 BreakpointSP bp_sp = nullptr; 601 FileSpec module_spec; 602 const bool internal = false; 603 604 // If the user didn't specify skip-prologue, having an offset should turn 605 // that off. 606 if (m_options.m_offset_addr != 0 && 607 m_options.m_skip_prologue == eLazyBoolCalculate) 608 m_options.m_skip_prologue = eLazyBoolNo; 609 610 switch (break_type) { 611 case eSetTypeFileAndLine: // Breakpoint by source position 612 { 613 FileSpec file; 614 const size_t num_files = m_options.m_filenames.GetSize(); 615 if (num_files == 0) { 616 if (!GetDefaultFile(target, file, result)) { 617 result.AppendError("No file supplied and no default file available."); 618 result.SetStatus(eReturnStatusFailed); 619 return false; 620 } 621 } else if (num_files > 1) { 622 result.AppendError("Only one file at a time is allowed for file and " 623 "line breakpoints."); 624 result.SetStatus(eReturnStatusFailed); 625 return false; 626 } else 627 file = m_options.m_filenames.GetFileSpecAtIndex(0); 628 629 // Only check for inline functions if 630 LazyBool check_inlines = eLazyBoolCalculate; 631 632 bp_sp = target->CreateBreakpoint(&(m_options.m_modules), 633 file, 634 m_options.m_line_num, 635 m_options.m_column, 636 m_options.m_offset_addr, 637 check_inlines, 638 m_options.m_skip_prologue, 639 internal, 640 m_options.m_hardware, 641 m_options.m_move_to_nearest_code); 642 } break; 643 644 case eSetTypeAddress: // Breakpoint by address 645 { 646 // If a shared library has been specified, make an lldb_private::Address 647 // with the library, and use that. That way the address breakpoint 648 // will track the load location of the library. 649 size_t num_modules_specified = m_options.m_modules.GetSize(); 650 if (num_modules_specified == 1) { 651 const FileSpec *file_spec = 652 m_options.m_modules.GetFileSpecPointerAtIndex(0); 653 bp_sp = target->CreateAddressInModuleBreakpoint(m_options.m_load_addr, 654 internal, file_spec, 655 m_options.m_hardware); 656 } else if (num_modules_specified == 0) { 657 bp_sp = target->CreateBreakpoint(m_options.m_load_addr, internal, 658 m_options.m_hardware); 659 } else { 660 result.AppendError("Only one shared library can be specified for " 661 "address breakpoints."); 662 result.SetStatus(eReturnStatusFailed); 663 return false; 664 } 665 break; 666 } 667 case eSetTypeFunctionName: // Breakpoint by function name 668 { 669 FunctionNameType name_type_mask = m_options.m_func_name_type_mask; 670 671 if (name_type_mask == 0) 672 name_type_mask = eFunctionNameTypeAuto; 673 674 bp_sp = target->CreateBreakpoint(&(m_options.m_modules), 675 &(m_options.m_filenames), 676 m_options.m_func_names, 677 name_type_mask, 678 m_options.m_language, 679 m_options.m_offset_addr, 680 m_options.m_skip_prologue, 681 internal, 682 m_options.m_hardware); 683 } break; 684 685 case eSetTypeFunctionRegexp: // Breakpoint by regular expression function 686 // name 687 { 688 RegularExpression regexp(m_options.m_func_regexp); 689 if (!regexp.IsValid()) { 690 char err_str[1024]; 691 regexp.GetErrorAsCString(err_str, sizeof(err_str)); 692 result.AppendErrorWithFormat( 693 "Function name regular expression could not be compiled: \"%s\"", 694 err_str); 695 result.SetStatus(eReturnStatusFailed); 696 return false; 697 } 698 699 bp_sp = target->CreateFuncRegexBreakpoint(&(m_options.m_modules), 700 &(m_options.m_filenames), 701 regexp, 702 m_options.m_language, 703 m_options.m_skip_prologue, 704 internal, 705 m_options.m_hardware); 706 } 707 break; 708 case eSetTypeSourceRegexp: // Breakpoint by regexp on source text. 709 { 710 const size_t num_files = m_options.m_filenames.GetSize(); 711 712 if (num_files == 0 && !m_options.m_all_files) { 713 FileSpec file; 714 if (!GetDefaultFile(target, file, result)) { 715 result.AppendError( 716 "No files provided and could not find default file."); 717 result.SetStatus(eReturnStatusFailed); 718 return false; 719 } else { 720 m_options.m_filenames.Append(file); 721 } 722 } 723 724 RegularExpression regexp(m_options.m_source_text_regexp); 725 if (!regexp.IsValid()) { 726 char err_str[1024]; 727 regexp.GetErrorAsCString(err_str, sizeof(err_str)); 728 result.AppendErrorWithFormat( 729 "Source text regular expression could not be compiled: \"%s\"", 730 err_str); 731 result.SetStatus(eReturnStatusFailed); 732 return false; 733 } 734 bp_sp = 735 target->CreateSourceRegexBreakpoint(&(m_options.m_modules), 736 &(m_options.m_filenames), 737 m_options 738 .m_source_regex_func_names, 739 regexp, 740 internal, 741 m_options.m_hardware, 742 m_options.m_move_to_nearest_code); 743 } break; 744 case eSetTypeException: { 745 Status precond_error; 746 bp_sp = target->CreateExceptionBreakpoint(m_options.m_exception_language, 747 m_options.m_catch_bp, 748 m_options.m_throw_bp, 749 internal, 750 &m_options 751 .m_exception_extra_args, 752 &precond_error); 753 if (precond_error.Fail()) { 754 result.AppendErrorWithFormat( 755 "Error setting extra exception arguments: %s", 756 precond_error.AsCString()); 757 target->RemoveBreakpointByID(bp_sp->GetID()); 758 result.SetStatus(eReturnStatusFailed); 759 return false; 760 } 761 } break; 762 case eSetTypeScripted: { 763 764 Status error; 765 bp_sp = target->CreateScriptedBreakpoint(m_options.m_python_class, 766 &(m_options.m_modules), 767 &(m_options.m_filenames), 768 false, 769 m_options.m_hardware, 770 m_options.m_extra_args_sp, 771 &error); 772 if (error.Fail()) { 773 result.AppendErrorWithFormat( 774 "Error setting extra exception arguments: %s", 775 error.AsCString()); 776 target->RemoveBreakpointByID(bp_sp->GetID()); 777 result.SetStatus(eReturnStatusFailed); 778 return false; 779 } 780 } break; 781 default: 782 break; 783 } 784 785 // Now set the various options that were passed in: 786 if (bp_sp) { 787 bp_sp->GetOptions()->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); 788 789 if (!m_options.m_breakpoint_names.empty()) { 790 Status name_error; 791 for (auto name : m_options.m_breakpoint_names) { 792 target->AddNameToBreakpoint(bp_sp, name.c_str(), name_error); 793 if (name_error.Fail()) { 794 result.AppendErrorWithFormat("Invalid breakpoint name: %s", 795 name.c_str()); 796 target->RemoveBreakpointByID(bp_sp->GetID()); 797 result.SetStatus(eReturnStatusFailed); 798 return false; 799 } 800 } 801 } 802 } 803 804 if (bp_sp) { 805 Stream &output_stream = result.GetOutputStream(); 806 const bool show_locations = false; 807 bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, 808 show_locations); 809 if (target == GetDebugger().GetDummyTarget()) 810 output_stream.Printf("Breakpoint set in dummy target, will get copied " 811 "into future targets.\n"); 812 else { 813 // Don't print out this warning for exception breakpoints. They can 814 // get set before the target is set, but we won't know how to actually 815 // set the breakpoint till we run. 816 if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) { 817 output_stream.Printf("WARNING: Unable to resolve breakpoint to any " 818 "actual locations.\n"); 819 } 820 } 821 result.SetStatus(eReturnStatusSuccessFinishResult); 822 } else if (!bp_sp) { 823 result.AppendError("Breakpoint creation failed: No breakpoint created."); 824 result.SetStatus(eReturnStatusFailed); 825 } 826 827 return result.Succeeded(); 828 } 829 830 private: 831 bool GetDefaultFile(Target *target, FileSpec &file, 832 CommandReturnObject &result) { 833 uint32_t default_line; 834 // First use the Source Manager's default file. Then use the current stack 835 // frame's file. 836 if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line)) { 837 StackFrame *cur_frame = m_exe_ctx.GetFramePtr(); 838 if (cur_frame == nullptr) { 839 result.AppendError( 840 "No selected frame to use to find the default file."); 841 result.SetStatus(eReturnStatusFailed); 842 return false; 843 } else if (!cur_frame->HasDebugInformation()) { 844 result.AppendError("Cannot use the selected frame to find the default " 845 "file, it has no debug info."); 846 result.SetStatus(eReturnStatusFailed); 847 return false; 848 } else { 849 const SymbolContext &sc = 850 cur_frame->GetSymbolContext(eSymbolContextLineEntry); 851 if (sc.line_entry.file) { 852 file = sc.line_entry.file; 853 } else { 854 result.AppendError("Can't find the file for the selected frame to " 855 "use as the default file."); 856 result.SetStatus(eReturnStatusFailed); 857 return false; 858 } 859 } 860 } 861 return true; 862 } 863 864 BreakpointOptionGroup m_bp_opts; 865 BreakpointDummyOptionGroup m_dummy_options; 866 CommandOptions m_options; 867 OptionGroupOptions m_all_options; 868 }; 869 870 // CommandObjectBreakpointModify 871 #pragma mark Modify 872 873 class CommandObjectBreakpointModify : public CommandObjectParsed { 874 public: 875 CommandObjectBreakpointModify(CommandInterpreter &interpreter) 876 : CommandObjectParsed(interpreter, "breakpoint modify", 877 "Modify the options on a breakpoint or set of " 878 "breakpoints in the executable. " 879 "If no breakpoint is specified, acts on the last " 880 "created breakpoint. " 881 "With the exception of -e, -d and -i, passing an " 882 "empty argument clears the modification.", 883 nullptr), 884 m_options() { 885 CommandArgumentEntry arg; 886 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 887 eArgTypeBreakpointIDRange); 888 // Add the entry for the first argument for this command to the object's 889 // arguments vector. 890 m_arguments.push_back(arg); 891 892 m_options.Append(&m_bp_opts, 893 LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, 894 LLDB_OPT_SET_ALL); 895 m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 896 m_options.Finalize(); 897 } 898 899 ~CommandObjectBreakpointModify() override = default; 900 901 Options *GetOptions() override { return &m_options; } 902 903 protected: 904 bool DoExecute(Args &command, CommandReturnObject &result) override { 905 Target *target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy); 906 if (target == nullptr) { 907 result.AppendError("Invalid target. No existing target or breakpoints."); 908 result.SetStatus(eReturnStatusFailed); 909 return false; 910 } 911 912 std::unique_lock<std::recursive_mutex> lock; 913 target->GetBreakpointList().GetListMutex(lock); 914 915 BreakpointIDList valid_bp_ids; 916 917 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 918 command, target, result, &valid_bp_ids, 919 BreakpointName::Permissions::PermissionKinds::disablePerm); 920 921 if (result.Succeeded()) { 922 const size_t count = valid_bp_ids.GetSize(); 923 for (size_t i = 0; i < count; ++i) { 924 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 925 926 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 927 Breakpoint *bp = 928 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 929 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 930 BreakpointLocation *location = 931 bp->FindLocationByID(cur_bp_id.GetLocationID()).get(); 932 if (location) 933 location->GetLocationOptions() 934 ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); 935 } else { 936 bp->GetOptions() 937 ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); 938 } 939 } 940 } 941 } 942 943 return result.Succeeded(); 944 } 945 946 private: 947 BreakpointOptionGroup m_bp_opts; 948 BreakpointDummyOptionGroup m_dummy_opts; 949 OptionGroupOptions m_options; 950 }; 951 952 // CommandObjectBreakpointEnable 953 #pragma mark Enable 954 955 class CommandObjectBreakpointEnable : public CommandObjectParsed { 956 public: 957 CommandObjectBreakpointEnable(CommandInterpreter &interpreter) 958 : CommandObjectParsed(interpreter, "enable", 959 "Enable the specified disabled breakpoint(s). If " 960 "no breakpoints are specified, enable all of them.", 961 nullptr) { 962 CommandArgumentEntry arg; 963 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 964 eArgTypeBreakpointIDRange); 965 // Add the entry for the first argument for this command to the object's 966 // arguments vector. 967 m_arguments.push_back(arg); 968 } 969 970 ~CommandObjectBreakpointEnable() override = default; 971 972 protected: 973 bool DoExecute(Args &command, CommandReturnObject &result) override { 974 Target *target = GetSelectedOrDummyTarget(); 975 if (target == nullptr) { 976 result.AppendError("Invalid target. No existing target or breakpoints."); 977 result.SetStatus(eReturnStatusFailed); 978 return false; 979 } 980 981 std::unique_lock<std::recursive_mutex> lock; 982 target->GetBreakpointList().GetListMutex(lock); 983 984 const BreakpointList &breakpoints = target->GetBreakpointList(); 985 986 size_t num_breakpoints = breakpoints.GetSize(); 987 988 if (num_breakpoints == 0) { 989 result.AppendError("No breakpoints exist to be enabled."); 990 result.SetStatus(eReturnStatusFailed); 991 return false; 992 } 993 994 if (command.empty()) { 995 // No breakpoint selected; enable all currently set breakpoints. 996 target->EnableAllowedBreakpoints(); 997 result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64 998 " breakpoints)\n", 999 (uint64_t)num_breakpoints); 1000 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1001 } else { 1002 // Particular breakpoint selected; enable that breakpoint. 1003 BreakpointIDList valid_bp_ids; 1004 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1005 command, target, result, &valid_bp_ids, 1006 BreakpointName::Permissions::PermissionKinds::disablePerm); 1007 1008 if (result.Succeeded()) { 1009 int enable_count = 0; 1010 int loc_count = 0; 1011 const size_t count = valid_bp_ids.GetSize(); 1012 for (size_t i = 0; i < count; ++i) { 1013 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1014 1015 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1016 Breakpoint *breakpoint = 1017 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1018 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1019 BreakpointLocation *location = 1020 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1021 if (location) { 1022 location->SetEnabled(true); 1023 ++loc_count; 1024 } 1025 } else { 1026 breakpoint->SetEnabled(true); 1027 ++enable_count; 1028 } 1029 } 1030 } 1031 result.AppendMessageWithFormat("%d breakpoints enabled.\n", 1032 enable_count + loc_count); 1033 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1034 } 1035 } 1036 1037 return result.Succeeded(); 1038 } 1039 }; 1040 1041 // CommandObjectBreakpointDisable 1042 #pragma mark Disable 1043 1044 class CommandObjectBreakpointDisable : public CommandObjectParsed { 1045 public: 1046 CommandObjectBreakpointDisable(CommandInterpreter &interpreter) 1047 : CommandObjectParsed( 1048 interpreter, "breakpoint disable", 1049 "Disable the specified breakpoint(s) without deleting " 1050 "them. If none are specified, disable all " 1051 "breakpoints.", 1052 nullptr) { 1053 SetHelpLong( 1054 "Disable the specified breakpoint(s) without deleting them. \ 1055 If none are specified, disable all breakpoints." 1056 R"( 1057 1058 )" 1059 "Note: disabling a breakpoint will cause none of its locations to be hit \ 1060 regardless of whether individual locations are enabled or disabled. After the sequence:" 1061 R"( 1062 1063 (lldb) break disable 1 1064 (lldb) break enable 1.1 1065 1066 execution will NOT stop at location 1.1. To achieve that, type: 1067 1068 (lldb) break disable 1.* 1069 (lldb) break enable 1.1 1070 1071 )" 1072 "The first command disables all locations for breakpoint 1, \ 1073 the second re-enables the first location."); 1074 1075 CommandArgumentEntry arg; 1076 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1077 eArgTypeBreakpointIDRange); 1078 // Add the entry for the first argument for this command to the object's 1079 // arguments vector. 1080 m_arguments.push_back(arg); 1081 } 1082 1083 ~CommandObjectBreakpointDisable() override = default; 1084 1085 protected: 1086 bool DoExecute(Args &command, CommandReturnObject &result) override { 1087 Target *target = GetSelectedOrDummyTarget(); 1088 if (target == nullptr) { 1089 result.AppendError("Invalid target. No existing target or breakpoints."); 1090 result.SetStatus(eReturnStatusFailed); 1091 return false; 1092 } 1093 1094 std::unique_lock<std::recursive_mutex> lock; 1095 target->GetBreakpointList().GetListMutex(lock); 1096 1097 const BreakpointList &breakpoints = target->GetBreakpointList(); 1098 size_t num_breakpoints = breakpoints.GetSize(); 1099 1100 if (num_breakpoints == 0) { 1101 result.AppendError("No breakpoints exist to be disabled."); 1102 result.SetStatus(eReturnStatusFailed); 1103 return false; 1104 } 1105 1106 if (command.empty()) { 1107 // No breakpoint selected; disable all currently set breakpoints. 1108 target->DisableAllowedBreakpoints(); 1109 result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64 1110 " breakpoints)\n", 1111 (uint64_t)num_breakpoints); 1112 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1113 } else { 1114 // Particular breakpoint selected; disable that breakpoint. 1115 BreakpointIDList valid_bp_ids; 1116 1117 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1118 command, target, result, &valid_bp_ids, 1119 BreakpointName::Permissions::PermissionKinds::disablePerm); 1120 1121 if (result.Succeeded()) { 1122 int disable_count = 0; 1123 int loc_count = 0; 1124 const size_t count = valid_bp_ids.GetSize(); 1125 for (size_t i = 0; i < count; ++i) { 1126 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1127 1128 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1129 Breakpoint *breakpoint = 1130 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1131 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1132 BreakpointLocation *location = 1133 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1134 if (location) { 1135 location->SetEnabled(false); 1136 ++loc_count; 1137 } 1138 } else { 1139 breakpoint->SetEnabled(false); 1140 ++disable_count; 1141 } 1142 } 1143 } 1144 result.AppendMessageWithFormat("%d breakpoints disabled.\n", 1145 disable_count + loc_count); 1146 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1147 } 1148 } 1149 1150 return result.Succeeded(); 1151 } 1152 }; 1153 1154 // CommandObjectBreakpointList 1155 1156 #pragma mark List::CommandOptions 1157 static constexpr OptionDefinition g_breakpoint_list_options[] = { 1158 #define LLDB_OPTIONS_breakpoint_list 1159 #include "CommandOptions.inc" 1160 }; 1161 1162 #pragma mark List 1163 1164 class CommandObjectBreakpointList : public CommandObjectParsed { 1165 public: 1166 CommandObjectBreakpointList(CommandInterpreter &interpreter) 1167 : CommandObjectParsed( 1168 interpreter, "breakpoint list", 1169 "List some or all breakpoints at configurable levels of detail.", 1170 nullptr), 1171 m_options() { 1172 CommandArgumentEntry arg; 1173 CommandArgumentData bp_id_arg; 1174 1175 // Define the first (and only) variant of this arg. 1176 bp_id_arg.arg_type = eArgTypeBreakpointID; 1177 bp_id_arg.arg_repetition = eArgRepeatOptional; 1178 1179 // There is only one variant this argument could be; put it into the 1180 // argument entry. 1181 arg.push_back(bp_id_arg); 1182 1183 // Push the data for the first argument into the m_arguments vector. 1184 m_arguments.push_back(arg); 1185 } 1186 1187 ~CommandObjectBreakpointList() override = default; 1188 1189 Options *GetOptions() override { return &m_options; } 1190 1191 class CommandOptions : public Options { 1192 public: 1193 CommandOptions() 1194 : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) { 1195 } 1196 1197 ~CommandOptions() override = default; 1198 1199 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1200 ExecutionContext *execution_context) override { 1201 Status error; 1202 const int short_option = m_getopt_table[option_idx].val; 1203 1204 switch (short_option) { 1205 case 'b': 1206 m_level = lldb::eDescriptionLevelBrief; 1207 break; 1208 case 'D': 1209 m_use_dummy = true; 1210 break; 1211 case 'f': 1212 m_level = lldb::eDescriptionLevelFull; 1213 break; 1214 case 'v': 1215 m_level = lldb::eDescriptionLevelVerbose; 1216 break; 1217 case 'i': 1218 m_internal = true; 1219 break; 1220 default: 1221 error.SetErrorStringWithFormat("unrecognized option '%c'", 1222 short_option); 1223 break; 1224 } 1225 1226 return error; 1227 } 1228 1229 void OptionParsingStarting(ExecutionContext *execution_context) override { 1230 m_level = lldb::eDescriptionLevelFull; 1231 m_internal = false; 1232 m_use_dummy = false; 1233 } 1234 1235 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1236 return llvm::makeArrayRef(g_breakpoint_list_options); 1237 } 1238 1239 // Instance variables to hold the values for command options. 1240 1241 lldb::DescriptionLevel m_level; 1242 1243 bool m_internal; 1244 bool m_use_dummy; 1245 }; 1246 1247 protected: 1248 bool DoExecute(Args &command, CommandReturnObject &result) override { 1249 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1250 1251 if (target == nullptr) { 1252 result.AppendError("Invalid target. No current target or breakpoints."); 1253 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1254 return true; 1255 } 1256 1257 const BreakpointList &breakpoints = 1258 target->GetBreakpointList(m_options.m_internal); 1259 std::unique_lock<std::recursive_mutex> lock; 1260 target->GetBreakpointList(m_options.m_internal).GetListMutex(lock); 1261 1262 size_t num_breakpoints = breakpoints.GetSize(); 1263 1264 if (num_breakpoints == 0) { 1265 result.AppendMessage("No breakpoints currently set."); 1266 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1267 return true; 1268 } 1269 1270 Stream &output_stream = result.GetOutputStream(); 1271 1272 if (command.empty()) { 1273 // No breakpoint selected; show info about all currently set breakpoints. 1274 result.AppendMessage("Current breakpoints:"); 1275 for (size_t i = 0; i < num_breakpoints; ++i) { 1276 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get(); 1277 if (breakpoint->AllowList()) 1278 AddBreakpointDescription(&output_stream, breakpoint, 1279 m_options.m_level); 1280 } 1281 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1282 } else { 1283 // Particular breakpoints selected; show info about that breakpoint. 1284 BreakpointIDList valid_bp_ids; 1285 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1286 command, target, result, &valid_bp_ids, 1287 BreakpointName::Permissions::PermissionKinds::listPerm); 1288 1289 if (result.Succeeded()) { 1290 for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) { 1291 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1292 Breakpoint *breakpoint = 1293 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1294 AddBreakpointDescription(&output_stream, breakpoint, 1295 m_options.m_level); 1296 } 1297 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1298 } else { 1299 result.AppendError("Invalid breakpoint ID."); 1300 result.SetStatus(eReturnStatusFailed); 1301 } 1302 } 1303 1304 return result.Succeeded(); 1305 } 1306 1307 private: 1308 CommandOptions m_options; 1309 }; 1310 1311 // CommandObjectBreakpointClear 1312 #pragma mark Clear::CommandOptions 1313 1314 static constexpr OptionDefinition g_breakpoint_clear_options[] = { 1315 #define LLDB_OPTIONS_breakpoint_clear 1316 #include "CommandOptions.inc" 1317 }; 1318 1319 #pragma mark Clear 1320 1321 class CommandObjectBreakpointClear : public CommandObjectParsed { 1322 public: 1323 enum BreakpointClearType { eClearTypeInvalid, eClearTypeFileAndLine }; 1324 1325 CommandObjectBreakpointClear(CommandInterpreter &interpreter) 1326 : CommandObjectParsed(interpreter, "breakpoint clear", 1327 "Delete or disable breakpoints matching the " 1328 "specified source file and line.", 1329 "breakpoint clear <cmd-options>"), 1330 m_options() {} 1331 1332 ~CommandObjectBreakpointClear() override = default; 1333 1334 Options *GetOptions() override { return &m_options; } 1335 1336 class CommandOptions : public Options { 1337 public: 1338 CommandOptions() : Options(), m_filename(), m_line_num(0) {} 1339 1340 ~CommandOptions() override = default; 1341 1342 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1343 ExecutionContext *execution_context) override { 1344 Status error; 1345 const int short_option = m_getopt_table[option_idx].val; 1346 1347 switch (short_option) { 1348 case 'f': 1349 m_filename.assign(option_arg); 1350 break; 1351 1352 case 'l': 1353 option_arg.getAsInteger(0, m_line_num); 1354 break; 1355 1356 default: 1357 error.SetErrorStringWithFormat("unrecognized option '%c'", 1358 short_option); 1359 break; 1360 } 1361 1362 return error; 1363 } 1364 1365 void OptionParsingStarting(ExecutionContext *execution_context) override { 1366 m_filename.clear(); 1367 m_line_num = 0; 1368 } 1369 1370 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1371 return llvm::makeArrayRef(g_breakpoint_clear_options); 1372 } 1373 1374 // Instance variables to hold the values for command options. 1375 1376 std::string m_filename; 1377 uint32_t m_line_num; 1378 }; 1379 1380 protected: 1381 bool DoExecute(Args &command, CommandReturnObject &result) override { 1382 Target *target = GetSelectedOrDummyTarget(); 1383 if (target == nullptr) { 1384 result.AppendError("Invalid target. No existing target or breakpoints."); 1385 result.SetStatus(eReturnStatusFailed); 1386 return false; 1387 } 1388 1389 // The following are the various types of breakpoints that could be 1390 // cleared: 1391 // 1). -f -l (clearing breakpoint by source location) 1392 1393 BreakpointClearType break_type = eClearTypeInvalid; 1394 1395 if (m_options.m_line_num != 0) 1396 break_type = eClearTypeFileAndLine; 1397 1398 std::unique_lock<std::recursive_mutex> lock; 1399 target->GetBreakpointList().GetListMutex(lock); 1400 1401 BreakpointList &breakpoints = target->GetBreakpointList(); 1402 size_t num_breakpoints = breakpoints.GetSize(); 1403 1404 // Early return if there's no breakpoint at all. 1405 if (num_breakpoints == 0) { 1406 result.AppendError("Breakpoint clear: No breakpoint cleared."); 1407 result.SetStatus(eReturnStatusFailed); 1408 return result.Succeeded(); 1409 } 1410 1411 // Find matching breakpoints and delete them. 1412 1413 // First create a copy of all the IDs. 1414 std::vector<break_id_t> BreakIDs; 1415 for (size_t i = 0; i < num_breakpoints; ++i) 1416 BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID()); 1417 1418 int num_cleared = 0; 1419 StreamString ss; 1420 switch (break_type) { 1421 case eClearTypeFileAndLine: // Breakpoint by source position 1422 { 1423 const ConstString filename(m_options.m_filename.c_str()); 1424 BreakpointLocationCollection loc_coll; 1425 1426 for (size_t i = 0; i < num_breakpoints; ++i) { 1427 Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get(); 1428 1429 if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) { 1430 // If the collection size is 0, it's a full match and we can just 1431 // remove the breakpoint. 1432 if (loc_coll.GetSize() == 0) { 1433 bp->GetDescription(&ss, lldb::eDescriptionLevelBrief); 1434 ss.EOL(); 1435 target->RemoveBreakpointByID(bp->GetID()); 1436 ++num_cleared; 1437 } 1438 } 1439 } 1440 } break; 1441 1442 default: 1443 break; 1444 } 1445 1446 if (num_cleared > 0) { 1447 Stream &output_stream = result.GetOutputStream(); 1448 output_stream.Printf("%d breakpoints cleared:\n", num_cleared); 1449 output_stream << ss.GetString(); 1450 output_stream.EOL(); 1451 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1452 } else { 1453 result.AppendError("Breakpoint clear: No breakpoint cleared."); 1454 result.SetStatus(eReturnStatusFailed); 1455 } 1456 1457 return result.Succeeded(); 1458 } 1459 1460 private: 1461 CommandOptions m_options; 1462 }; 1463 1464 // CommandObjectBreakpointDelete 1465 static constexpr OptionDefinition g_breakpoint_delete_options[] = { 1466 #define LLDB_OPTIONS_breakpoint_delete 1467 #include "CommandOptions.inc" 1468 }; 1469 1470 #pragma mark Delete 1471 1472 class CommandObjectBreakpointDelete : public CommandObjectParsed { 1473 public: 1474 CommandObjectBreakpointDelete(CommandInterpreter &interpreter) 1475 : CommandObjectParsed(interpreter, "breakpoint delete", 1476 "Delete the specified breakpoint(s). If no " 1477 "breakpoints are specified, delete them all.", 1478 nullptr), 1479 m_options() { 1480 CommandArgumentEntry arg; 1481 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1482 eArgTypeBreakpointIDRange); 1483 // Add the entry for the first argument for this command to the object's 1484 // arguments vector. 1485 m_arguments.push_back(arg); 1486 } 1487 1488 ~CommandObjectBreakpointDelete() override = default; 1489 1490 Options *GetOptions() override { return &m_options; } 1491 1492 class CommandOptions : public Options { 1493 public: 1494 CommandOptions() : Options(), m_use_dummy(false), m_force(false) {} 1495 1496 ~CommandOptions() override = default; 1497 1498 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1499 ExecutionContext *execution_context) override { 1500 Status error; 1501 const int short_option = m_getopt_table[option_idx].val; 1502 1503 switch (short_option) { 1504 case 'f': 1505 m_force = true; 1506 break; 1507 1508 case 'D': 1509 m_use_dummy = true; 1510 break; 1511 1512 default: 1513 error.SetErrorStringWithFormat("unrecognized option '%c'", 1514 short_option); 1515 break; 1516 } 1517 1518 return error; 1519 } 1520 1521 void OptionParsingStarting(ExecutionContext *execution_context) override { 1522 m_use_dummy = false; 1523 m_force = false; 1524 } 1525 1526 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1527 return llvm::makeArrayRef(g_breakpoint_delete_options); 1528 } 1529 1530 // Instance variables to hold the values for command options. 1531 bool m_use_dummy; 1532 bool m_force; 1533 }; 1534 1535 protected: 1536 bool DoExecute(Args &command, CommandReturnObject &result) override { 1537 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1538 1539 if (target == nullptr) { 1540 result.AppendError("Invalid target. No existing target or breakpoints."); 1541 result.SetStatus(eReturnStatusFailed); 1542 return false; 1543 } 1544 1545 std::unique_lock<std::recursive_mutex> lock; 1546 target->GetBreakpointList().GetListMutex(lock); 1547 1548 const BreakpointList &breakpoints = target->GetBreakpointList(); 1549 1550 size_t num_breakpoints = breakpoints.GetSize(); 1551 1552 if (num_breakpoints == 0) { 1553 result.AppendError("No breakpoints exist to be deleted."); 1554 result.SetStatus(eReturnStatusFailed); 1555 return false; 1556 } 1557 1558 if (command.empty()) { 1559 if (!m_options.m_force && 1560 !m_interpreter.Confirm( 1561 "About to delete all breakpoints, do you want to do that?", 1562 true)) { 1563 result.AppendMessage("Operation cancelled..."); 1564 } else { 1565 target->RemoveAllowedBreakpoints(); 1566 result.AppendMessageWithFormat( 1567 "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n", 1568 (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : ""); 1569 } 1570 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1571 } else { 1572 // Particular breakpoint selected; disable that breakpoint. 1573 BreakpointIDList valid_bp_ids; 1574 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1575 command, target, result, &valid_bp_ids, 1576 BreakpointName::Permissions::PermissionKinds::deletePerm); 1577 1578 if (result.Succeeded()) { 1579 int delete_count = 0; 1580 int disable_count = 0; 1581 const size_t count = valid_bp_ids.GetSize(); 1582 for (size_t i = 0; i < count; ++i) { 1583 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1584 1585 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1586 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1587 Breakpoint *breakpoint = 1588 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1589 BreakpointLocation *location = 1590 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1591 // It makes no sense to try to delete individual locations, so we 1592 // disable them instead. 1593 if (location) { 1594 location->SetEnabled(false); 1595 ++disable_count; 1596 } 1597 } else { 1598 target->RemoveBreakpointByID(cur_bp_id.GetBreakpointID()); 1599 ++delete_count; 1600 } 1601 } 1602 } 1603 result.AppendMessageWithFormat( 1604 "%d breakpoints deleted; %d breakpoint locations disabled.\n", 1605 delete_count, disable_count); 1606 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1607 } 1608 } 1609 return result.Succeeded(); 1610 } 1611 1612 private: 1613 CommandOptions m_options; 1614 }; 1615 1616 // CommandObjectBreakpointName 1617 1618 static constexpr OptionDefinition g_breakpoint_name_options[] = { 1619 #define LLDB_OPTIONS_breakpoint_name 1620 #include "CommandOptions.inc" 1621 }; 1622 class BreakpointNameOptionGroup : public OptionGroup { 1623 public: 1624 BreakpointNameOptionGroup() 1625 : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) { 1626 } 1627 1628 ~BreakpointNameOptionGroup() override = default; 1629 1630 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1631 return llvm::makeArrayRef(g_breakpoint_name_options); 1632 } 1633 1634 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1635 ExecutionContext *execution_context) override { 1636 Status error; 1637 const int short_option = g_breakpoint_name_options[option_idx].short_option; 1638 1639 switch (short_option) { 1640 case 'N': 1641 if (BreakpointID::StringIsBreakpointName(option_arg, error) && 1642 error.Success()) 1643 m_name.SetValueFromString(option_arg); 1644 break; 1645 case 'B': 1646 if (m_breakpoint.SetValueFromString(option_arg).Fail()) 1647 error.SetErrorStringWithFormat( 1648 "unrecognized value \"%s\" for breakpoint", 1649 option_arg.str().c_str()); 1650 break; 1651 case 'D': 1652 if (m_use_dummy.SetValueFromString(option_arg).Fail()) 1653 error.SetErrorStringWithFormat( 1654 "unrecognized value \"%s\" for use-dummy", 1655 option_arg.str().c_str()); 1656 break; 1657 case 'H': 1658 m_help_string.SetValueFromString(option_arg); 1659 break; 1660 1661 default: 1662 error.SetErrorStringWithFormat("unrecognized short option '%c'", 1663 short_option); 1664 break; 1665 } 1666 return error; 1667 } 1668 1669 void OptionParsingStarting(ExecutionContext *execution_context) override { 1670 m_name.Clear(); 1671 m_breakpoint.Clear(); 1672 m_use_dummy.Clear(); 1673 m_use_dummy.SetDefaultValue(false); 1674 m_help_string.Clear(); 1675 } 1676 1677 OptionValueString m_name; 1678 OptionValueUInt64 m_breakpoint; 1679 OptionValueBoolean m_use_dummy; 1680 OptionValueString m_help_string; 1681 }; 1682 1683 static constexpr OptionDefinition g_breakpoint_access_options[] = { 1684 #define LLDB_OPTIONS_breakpoint_access 1685 #include "CommandOptions.inc" 1686 }; 1687 1688 class BreakpointAccessOptionGroup : public OptionGroup { 1689 public: 1690 BreakpointAccessOptionGroup() : OptionGroup() {} 1691 1692 ~BreakpointAccessOptionGroup() override = default; 1693 1694 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1695 return llvm::makeArrayRef(g_breakpoint_access_options); 1696 } 1697 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1698 ExecutionContext *execution_context) override { 1699 Status error; 1700 const int short_option 1701 = g_breakpoint_access_options[option_idx].short_option; 1702 1703 switch (short_option) { 1704 case 'L': { 1705 bool value, success; 1706 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1707 if (success) { 1708 m_permissions.SetAllowList(value); 1709 } else 1710 error.SetErrorStringWithFormat( 1711 "invalid boolean value '%s' passed for -L option", 1712 option_arg.str().c_str()); 1713 } break; 1714 case 'A': { 1715 bool value, success; 1716 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1717 if (success) { 1718 m_permissions.SetAllowDisable(value); 1719 } else 1720 error.SetErrorStringWithFormat( 1721 "invalid boolean value '%s' passed for -L option", 1722 option_arg.str().c_str()); 1723 } break; 1724 case 'D': { 1725 bool value, success; 1726 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1727 if (success) { 1728 m_permissions.SetAllowDelete(value); 1729 } else 1730 error.SetErrorStringWithFormat( 1731 "invalid boolean value '%s' passed for -L option", 1732 option_arg.str().c_str()); 1733 } break; 1734 1735 } 1736 1737 return error; 1738 } 1739 1740 void OptionParsingStarting(ExecutionContext *execution_context) override { 1741 } 1742 1743 const BreakpointName::Permissions &GetPermissions() const 1744 { 1745 return m_permissions; 1746 } 1747 BreakpointName::Permissions m_permissions; 1748 }; 1749 1750 class CommandObjectBreakpointNameConfigure : public CommandObjectParsed { 1751 public: 1752 CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter) 1753 : CommandObjectParsed( 1754 interpreter, "configure", "Configure the options for the breakpoint" 1755 " name provided. " 1756 "If you provide a breakpoint id, the options will be copied from " 1757 "the breakpoint, otherwise only the options specified will be set " 1758 "on the name.", 1759 "breakpoint name configure <command-options> " 1760 "<breakpoint-name-list>"), 1761 m_bp_opts(), m_option_group() { 1762 // Create the first variant for the first (and only) argument for this 1763 // command. 1764 CommandArgumentEntry arg1; 1765 CommandArgumentData id_arg; 1766 id_arg.arg_type = eArgTypeBreakpointName; 1767 id_arg.arg_repetition = eArgRepeatOptional; 1768 arg1.push_back(id_arg); 1769 m_arguments.push_back(arg1); 1770 1771 m_option_group.Append(&m_bp_opts, 1772 LLDB_OPT_SET_ALL, 1773 LLDB_OPT_SET_1); 1774 m_option_group.Append(&m_access_options, 1775 LLDB_OPT_SET_ALL, 1776 LLDB_OPT_SET_ALL); 1777 m_option_group.Append(&m_bp_id, 1778 LLDB_OPT_SET_2|LLDB_OPT_SET_4, 1779 LLDB_OPT_SET_ALL); 1780 m_option_group.Finalize(); 1781 } 1782 1783 ~CommandObjectBreakpointNameConfigure() override = default; 1784 1785 Options *GetOptions() override { return &m_option_group; } 1786 1787 protected: 1788 bool DoExecute(Args &command, CommandReturnObject &result) override { 1789 1790 const size_t argc = command.GetArgumentCount(); 1791 if (argc == 0) { 1792 result.AppendError("No names provided."); 1793 result.SetStatus(eReturnStatusFailed); 1794 return false; 1795 } 1796 1797 Target *target = 1798 GetSelectedOrDummyTarget(false); 1799 1800 if (target == nullptr) { 1801 result.AppendError("Invalid target. No existing target or breakpoints."); 1802 result.SetStatus(eReturnStatusFailed); 1803 return false; 1804 } 1805 1806 std::unique_lock<std::recursive_mutex> lock; 1807 target->GetBreakpointList().GetListMutex(lock); 1808 1809 // Make a pass through first to see that all the names are legal. 1810 for (auto &entry : command.entries()) { 1811 Status error; 1812 if (!BreakpointID::StringIsBreakpointName(entry.ref, error)) 1813 { 1814 result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s", 1815 entry.c_str(), error.AsCString()); 1816 result.SetStatus(eReturnStatusFailed); 1817 return false; 1818 } 1819 } 1820 // Now configure them, we already pre-checked the names so we don't need to 1821 // check the error: 1822 BreakpointSP bp_sp; 1823 if (m_bp_id.m_breakpoint.OptionWasSet()) 1824 { 1825 lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value(); 1826 bp_sp = target->GetBreakpointByID(bp_id); 1827 if (!bp_sp) 1828 { 1829 result.AppendErrorWithFormatv("Could not find specified breakpoint {0}", 1830 bp_id); 1831 result.SetStatus(eReturnStatusFailed); 1832 return false; 1833 } 1834 } 1835 1836 Status error; 1837 for (auto &entry : command.entries()) { 1838 ConstString name(entry.c_str()); 1839 BreakpointName *bp_name = target->FindBreakpointName(name, true, error); 1840 if (!bp_name) 1841 continue; 1842 if (m_bp_id.m_help_string.OptionWasSet()) 1843 bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str()); 1844 1845 if (bp_sp) 1846 target->ConfigureBreakpointName(*bp_name, 1847 *bp_sp->GetOptions(), 1848 m_access_options.GetPermissions()); 1849 else 1850 target->ConfigureBreakpointName(*bp_name, 1851 m_bp_opts.GetBreakpointOptions(), 1852 m_access_options.GetPermissions()); 1853 } 1854 return true; 1855 } 1856 1857 private: 1858 BreakpointNameOptionGroup m_bp_id; // Only using the id part of this. 1859 BreakpointOptionGroup m_bp_opts; 1860 BreakpointAccessOptionGroup m_access_options; 1861 OptionGroupOptions m_option_group; 1862 }; 1863 1864 class CommandObjectBreakpointNameAdd : public CommandObjectParsed { 1865 public: 1866 CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter) 1867 : CommandObjectParsed( 1868 interpreter, "add", "Add a name to the breakpoints provided.", 1869 "breakpoint name add <command-options> <breakpoint-id-list>"), 1870 m_name_options(), m_option_group() { 1871 // Create the first variant for the first (and only) argument for this 1872 // command. 1873 CommandArgumentEntry arg1; 1874 CommandArgumentData id_arg; 1875 id_arg.arg_type = eArgTypeBreakpointID; 1876 id_arg.arg_repetition = eArgRepeatOptional; 1877 arg1.push_back(id_arg); 1878 m_arguments.push_back(arg1); 1879 1880 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 1881 m_option_group.Finalize(); 1882 } 1883 1884 ~CommandObjectBreakpointNameAdd() override = default; 1885 1886 Options *GetOptions() override { return &m_option_group; } 1887 1888 protected: 1889 bool DoExecute(Args &command, CommandReturnObject &result) override { 1890 if (!m_name_options.m_name.OptionWasSet()) { 1891 result.SetError("No name option provided."); 1892 return false; 1893 } 1894 1895 Target *target = 1896 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 1897 1898 if (target == nullptr) { 1899 result.AppendError("Invalid target. No existing target or breakpoints."); 1900 result.SetStatus(eReturnStatusFailed); 1901 return false; 1902 } 1903 1904 std::unique_lock<std::recursive_mutex> lock; 1905 target->GetBreakpointList().GetListMutex(lock); 1906 1907 const BreakpointList &breakpoints = target->GetBreakpointList(); 1908 1909 size_t num_breakpoints = breakpoints.GetSize(); 1910 if (num_breakpoints == 0) { 1911 result.SetError("No breakpoints, cannot add names."); 1912 result.SetStatus(eReturnStatusFailed); 1913 return false; 1914 } 1915 1916 // Particular breakpoint selected; disable that breakpoint. 1917 BreakpointIDList valid_bp_ids; 1918 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 1919 command, target, result, &valid_bp_ids, 1920 BreakpointName::Permissions::PermissionKinds::listPerm); 1921 1922 if (result.Succeeded()) { 1923 if (valid_bp_ids.GetSize() == 0) { 1924 result.SetError("No breakpoints specified, cannot add names."); 1925 result.SetStatus(eReturnStatusFailed); 1926 return false; 1927 } 1928 size_t num_valid_ids = valid_bp_ids.GetSize(); 1929 const char *bp_name = m_name_options.m_name.GetCurrentValue(); 1930 Status error; // This error reports illegal names, but we've already 1931 // checked that, so we don't need to check it again here. 1932 for (size_t index = 0; index < num_valid_ids; index++) { 1933 lldb::break_id_t bp_id = 1934 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); 1935 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); 1936 target->AddNameToBreakpoint(bp_sp, bp_name, error); 1937 } 1938 } 1939 1940 return true; 1941 } 1942 1943 private: 1944 BreakpointNameOptionGroup m_name_options; 1945 OptionGroupOptions m_option_group; 1946 }; 1947 1948 class CommandObjectBreakpointNameDelete : public CommandObjectParsed { 1949 public: 1950 CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter) 1951 : CommandObjectParsed( 1952 interpreter, "delete", 1953 "Delete a name from the breakpoints provided.", 1954 "breakpoint name delete <command-options> <breakpoint-id-list>"), 1955 m_name_options(), m_option_group() { 1956 // Create the first variant for the first (and only) argument for this 1957 // command. 1958 CommandArgumentEntry arg1; 1959 CommandArgumentData id_arg; 1960 id_arg.arg_type = eArgTypeBreakpointID; 1961 id_arg.arg_repetition = eArgRepeatOptional; 1962 arg1.push_back(id_arg); 1963 m_arguments.push_back(arg1); 1964 1965 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 1966 m_option_group.Finalize(); 1967 } 1968 1969 ~CommandObjectBreakpointNameDelete() override = default; 1970 1971 Options *GetOptions() override { return &m_option_group; } 1972 1973 protected: 1974 bool DoExecute(Args &command, CommandReturnObject &result) override { 1975 if (!m_name_options.m_name.OptionWasSet()) { 1976 result.SetError("No name option provided."); 1977 return false; 1978 } 1979 1980 Target *target = 1981 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 1982 1983 if (target == nullptr) { 1984 result.AppendError("Invalid target. No existing target or breakpoints."); 1985 result.SetStatus(eReturnStatusFailed); 1986 return false; 1987 } 1988 1989 std::unique_lock<std::recursive_mutex> lock; 1990 target->GetBreakpointList().GetListMutex(lock); 1991 1992 const BreakpointList &breakpoints = target->GetBreakpointList(); 1993 1994 size_t num_breakpoints = breakpoints.GetSize(); 1995 if (num_breakpoints == 0) { 1996 result.SetError("No breakpoints, cannot delete names."); 1997 result.SetStatus(eReturnStatusFailed); 1998 return false; 1999 } 2000 2001 // Particular breakpoint selected; disable that breakpoint. 2002 BreakpointIDList valid_bp_ids; 2003 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 2004 command, target, result, &valid_bp_ids, 2005 BreakpointName::Permissions::PermissionKinds::deletePerm); 2006 2007 if (result.Succeeded()) { 2008 if (valid_bp_ids.GetSize() == 0) { 2009 result.SetError("No breakpoints specified, cannot delete names."); 2010 result.SetStatus(eReturnStatusFailed); 2011 return false; 2012 } 2013 ConstString bp_name(m_name_options.m_name.GetCurrentValue()); 2014 size_t num_valid_ids = valid_bp_ids.GetSize(); 2015 for (size_t index = 0; index < num_valid_ids; index++) { 2016 lldb::break_id_t bp_id = 2017 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); 2018 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); 2019 target->RemoveNameFromBreakpoint(bp_sp, bp_name); 2020 } 2021 } 2022 2023 return true; 2024 } 2025 2026 private: 2027 BreakpointNameOptionGroup m_name_options; 2028 OptionGroupOptions m_option_group; 2029 }; 2030 2031 class CommandObjectBreakpointNameList : public CommandObjectParsed { 2032 public: 2033 CommandObjectBreakpointNameList(CommandInterpreter &interpreter) 2034 : CommandObjectParsed(interpreter, "list", 2035 "List either the names for a breakpoint or info " 2036 "about a given name. With no arguments, lists all " 2037 "names", 2038 "breakpoint name list <command-options>"), 2039 m_name_options(), m_option_group() { 2040 m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL); 2041 m_option_group.Finalize(); 2042 } 2043 2044 ~CommandObjectBreakpointNameList() override = default; 2045 2046 Options *GetOptions() override { return &m_option_group; } 2047 2048 protected: 2049 bool DoExecute(Args &command, CommandReturnObject &result) override { 2050 Target *target = 2051 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 2052 2053 if (target == nullptr) { 2054 result.AppendError("Invalid target. No existing target or breakpoints."); 2055 result.SetStatus(eReturnStatusFailed); 2056 return false; 2057 } 2058 2059 2060 std::vector<std::string> name_list; 2061 if (command.empty()) { 2062 target->GetBreakpointNames(name_list); 2063 } else { 2064 for (const Args::ArgEntry &arg : command) 2065 { 2066 name_list.push_back(arg.c_str()); 2067 } 2068 } 2069 2070 if (name_list.empty()) { 2071 result.AppendMessage("No breakpoint names found."); 2072 } else { 2073 for (const std::string &name_str : name_list) { 2074 const char *name = name_str.c_str(); 2075 // First print out the options for the name: 2076 Status error; 2077 BreakpointName *bp_name = target->FindBreakpointName(ConstString(name), 2078 false, 2079 error); 2080 if (bp_name) 2081 { 2082 StreamString s; 2083 result.AppendMessageWithFormat("Name: %s\n", name); 2084 if (bp_name->GetDescription(&s, eDescriptionLevelFull)) 2085 { 2086 result.AppendMessage(s.GetString()); 2087 } 2088 2089 std::unique_lock<std::recursive_mutex> lock; 2090 target->GetBreakpointList().GetListMutex(lock); 2091 2092 BreakpointList &breakpoints = target->GetBreakpointList(); 2093 bool any_set = false; 2094 for (BreakpointSP bp_sp : breakpoints.Breakpoints()) { 2095 if (bp_sp->MatchesName(name)) { 2096 StreamString s; 2097 any_set = true; 2098 bp_sp->GetDescription(&s, eDescriptionLevelBrief); 2099 s.EOL(); 2100 result.AppendMessage(s.GetString()); 2101 } 2102 } 2103 if (!any_set) 2104 result.AppendMessage("No breakpoints using this name."); 2105 } else { 2106 result.AppendMessageWithFormat("Name: %s not found.\n", name); 2107 } 2108 } 2109 } 2110 return true; 2111 } 2112 2113 private: 2114 BreakpointNameOptionGroup m_name_options; 2115 OptionGroupOptions m_option_group; 2116 }; 2117 2118 // CommandObjectBreakpointName 2119 class CommandObjectBreakpointName : public CommandObjectMultiword { 2120 public: 2121 CommandObjectBreakpointName(CommandInterpreter &interpreter) 2122 : CommandObjectMultiword( 2123 interpreter, "name", "Commands to manage name tags for breakpoints", 2124 "breakpoint name <subcommand> [<command-options>]") { 2125 CommandObjectSP add_command_object( 2126 new CommandObjectBreakpointNameAdd(interpreter)); 2127 CommandObjectSP delete_command_object( 2128 new CommandObjectBreakpointNameDelete(interpreter)); 2129 CommandObjectSP list_command_object( 2130 new CommandObjectBreakpointNameList(interpreter)); 2131 CommandObjectSP configure_command_object( 2132 new CommandObjectBreakpointNameConfigure(interpreter)); 2133 2134 LoadSubCommand("add", add_command_object); 2135 LoadSubCommand("delete", delete_command_object); 2136 LoadSubCommand("list", list_command_object); 2137 LoadSubCommand("configure", configure_command_object); 2138 } 2139 2140 ~CommandObjectBreakpointName() override = default; 2141 }; 2142 2143 // CommandObjectBreakpointRead 2144 #pragma mark Read::CommandOptions 2145 static constexpr OptionDefinition g_breakpoint_read_options[] = { 2146 #define LLDB_OPTIONS_breakpoint_read 2147 #include "CommandOptions.inc" 2148 }; 2149 2150 #pragma mark Read 2151 2152 class CommandObjectBreakpointRead : public CommandObjectParsed { 2153 public: 2154 CommandObjectBreakpointRead(CommandInterpreter &interpreter) 2155 : CommandObjectParsed(interpreter, "breakpoint read", 2156 "Read and set the breakpoints previously saved to " 2157 "a file with \"breakpoint write\". ", 2158 nullptr), 2159 m_options() { 2160 CommandArgumentEntry arg; 2161 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 2162 eArgTypeBreakpointIDRange); 2163 // Add the entry for the first argument for this command to the object's 2164 // arguments vector. 2165 m_arguments.push_back(arg); 2166 } 2167 2168 ~CommandObjectBreakpointRead() override = default; 2169 2170 Options *GetOptions() override { return &m_options; } 2171 2172 class CommandOptions : public Options { 2173 public: 2174 CommandOptions() : Options() {} 2175 2176 ~CommandOptions() override = default; 2177 2178 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2179 ExecutionContext *execution_context) override { 2180 Status error; 2181 const int short_option = m_getopt_table[option_idx].val; 2182 2183 switch (short_option) { 2184 case 'f': 2185 m_filename.assign(option_arg); 2186 break; 2187 case 'N': { 2188 Status name_error; 2189 if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg), 2190 name_error)) { 2191 error.SetErrorStringWithFormat("Invalid breakpoint name: %s", 2192 name_error.AsCString()); 2193 } 2194 m_names.push_back(option_arg); 2195 break; 2196 } 2197 default: 2198 error.SetErrorStringWithFormat("unrecognized option '%c'", 2199 short_option); 2200 break; 2201 } 2202 2203 return error; 2204 } 2205 2206 void OptionParsingStarting(ExecutionContext *execution_context) override { 2207 m_filename.clear(); 2208 m_names.clear(); 2209 } 2210 2211 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2212 return llvm::makeArrayRef(g_breakpoint_read_options); 2213 } 2214 2215 // Instance variables to hold the values for command options. 2216 2217 std::string m_filename; 2218 std::vector<std::string> m_names; 2219 }; 2220 2221 protected: 2222 bool DoExecute(Args &command, CommandReturnObject &result) override { 2223 Target *target = GetSelectedOrDummyTarget(); 2224 if (target == nullptr) { 2225 result.AppendError("Invalid target. No existing target or breakpoints."); 2226 result.SetStatus(eReturnStatusFailed); 2227 return false; 2228 } 2229 2230 std::unique_lock<std::recursive_mutex> lock; 2231 target->GetBreakpointList().GetListMutex(lock); 2232 2233 FileSpec input_spec(m_options.m_filename); 2234 FileSystem::Instance().Resolve(input_spec); 2235 BreakpointIDList new_bps; 2236 Status error = target->CreateBreakpointsFromFile( 2237 input_spec, m_options.m_names, new_bps); 2238 2239 if (!error.Success()) { 2240 result.AppendError(error.AsCString()); 2241 result.SetStatus(eReturnStatusFailed); 2242 return false; 2243 } 2244 2245 Stream &output_stream = result.GetOutputStream(); 2246 2247 size_t num_breakpoints = new_bps.GetSize(); 2248 if (num_breakpoints == 0) { 2249 result.AppendMessage("No breakpoints added."); 2250 } else { 2251 // No breakpoint selected; show info about all currently set breakpoints. 2252 result.AppendMessage("New breakpoints:"); 2253 for (size_t i = 0; i < num_breakpoints; ++i) { 2254 BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i); 2255 Breakpoint *bp = target->GetBreakpointList() 2256 .FindBreakpointByID(bp_id.GetBreakpointID()) 2257 .get(); 2258 if (bp) 2259 bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, 2260 false); 2261 } 2262 } 2263 return result.Succeeded(); 2264 } 2265 2266 private: 2267 CommandOptions m_options; 2268 }; 2269 2270 // CommandObjectBreakpointWrite 2271 #pragma mark Write::CommandOptions 2272 static constexpr OptionDefinition g_breakpoint_write_options[] = { 2273 #define LLDB_OPTIONS_breakpoint_write 2274 #include "CommandOptions.inc" 2275 }; 2276 2277 #pragma mark Write 2278 class CommandObjectBreakpointWrite : public CommandObjectParsed { 2279 public: 2280 CommandObjectBreakpointWrite(CommandInterpreter &interpreter) 2281 : CommandObjectParsed(interpreter, "breakpoint write", 2282 "Write the breakpoints listed to a file that can " 2283 "be read in with \"breakpoint read\". " 2284 "If given no arguments, writes all breakpoints.", 2285 nullptr), 2286 m_options() { 2287 CommandArgumentEntry arg; 2288 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 2289 eArgTypeBreakpointIDRange); 2290 // Add the entry for the first argument for this command to the object's 2291 // arguments vector. 2292 m_arguments.push_back(arg); 2293 } 2294 2295 ~CommandObjectBreakpointWrite() override = default; 2296 2297 Options *GetOptions() override { return &m_options; } 2298 2299 class CommandOptions : public Options { 2300 public: 2301 CommandOptions() : Options() {} 2302 2303 ~CommandOptions() override = default; 2304 2305 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2306 ExecutionContext *execution_context) override { 2307 Status error; 2308 const int short_option = m_getopt_table[option_idx].val; 2309 2310 switch (short_option) { 2311 case 'f': 2312 m_filename.assign(option_arg); 2313 break; 2314 case 'a': 2315 m_append = true; 2316 break; 2317 default: 2318 error.SetErrorStringWithFormat("unrecognized option '%c'", 2319 short_option); 2320 break; 2321 } 2322 2323 return error; 2324 } 2325 2326 void OptionParsingStarting(ExecutionContext *execution_context) override { 2327 m_filename.clear(); 2328 m_append = false; 2329 } 2330 2331 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2332 return llvm::makeArrayRef(g_breakpoint_write_options); 2333 } 2334 2335 // Instance variables to hold the values for command options. 2336 2337 std::string m_filename; 2338 bool m_append = false; 2339 }; 2340 2341 protected: 2342 bool DoExecute(Args &command, CommandReturnObject &result) override { 2343 Target *target = GetSelectedOrDummyTarget(); 2344 if (target == nullptr) { 2345 result.AppendError("Invalid target. No existing target or breakpoints."); 2346 result.SetStatus(eReturnStatusFailed); 2347 return false; 2348 } 2349 2350 std::unique_lock<std::recursive_mutex> lock; 2351 target->GetBreakpointList().GetListMutex(lock); 2352 2353 BreakpointIDList valid_bp_ids; 2354 if (!command.empty()) { 2355 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 2356 command, target, result, &valid_bp_ids, 2357 BreakpointName::Permissions::PermissionKinds::listPerm); 2358 2359 if (!result.Succeeded()) { 2360 result.SetStatus(eReturnStatusFailed); 2361 return false; 2362 } 2363 } 2364 FileSpec file_spec(m_options.m_filename); 2365 FileSystem::Instance().Resolve(file_spec); 2366 Status error = target->SerializeBreakpointsToFile(file_spec, valid_bp_ids, 2367 m_options.m_append); 2368 if (!error.Success()) { 2369 result.AppendErrorWithFormat("error serializing breakpoints: %s.", 2370 error.AsCString()); 2371 result.SetStatus(eReturnStatusFailed); 2372 } 2373 return result.Succeeded(); 2374 } 2375 2376 private: 2377 CommandOptions m_options; 2378 }; 2379 2380 // CommandObjectMultiwordBreakpoint 2381 #pragma mark MultiwordBreakpoint 2382 2383 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint( 2384 CommandInterpreter &interpreter) 2385 : CommandObjectMultiword( 2386 interpreter, "breakpoint", 2387 "Commands for operating on breakpoints (see 'help b' for shorthand.)", 2388 "breakpoint <subcommand> [<command-options>]") { 2389 CommandObjectSP list_command_object( 2390 new CommandObjectBreakpointList(interpreter)); 2391 CommandObjectSP enable_command_object( 2392 new CommandObjectBreakpointEnable(interpreter)); 2393 CommandObjectSP disable_command_object( 2394 new CommandObjectBreakpointDisable(interpreter)); 2395 CommandObjectSP clear_command_object( 2396 new CommandObjectBreakpointClear(interpreter)); 2397 CommandObjectSP delete_command_object( 2398 new CommandObjectBreakpointDelete(interpreter)); 2399 CommandObjectSP set_command_object( 2400 new CommandObjectBreakpointSet(interpreter)); 2401 CommandObjectSP command_command_object( 2402 new CommandObjectBreakpointCommand(interpreter)); 2403 CommandObjectSP modify_command_object( 2404 new CommandObjectBreakpointModify(interpreter)); 2405 CommandObjectSP name_command_object( 2406 new CommandObjectBreakpointName(interpreter)); 2407 CommandObjectSP write_command_object( 2408 new CommandObjectBreakpointWrite(interpreter)); 2409 CommandObjectSP read_command_object( 2410 new CommandObjectBreakpointRead(interpreter)); 2411 2412 list_command_object->SetCommandName("breakpoint list"); 2413 enable_command_object->SetCommandName("breakpoint enable"); 2414 disable_command_object->SetCommandName("breakpoint disable"); 2415 clear_command_object->SetCommandName("breakpoint clear"); 2416 delete_command_object->SetCommandName("breakpoint delete"); 2417 set_command_object->SetCommandName("breakpoint set"); 2418 command_command_object->SetCommandName("breakpoint command"); 2419 modify_command_object->SetCommandName("breakpoint modify"); 2420 name_command_object->SetCommandName("breakpoint name"); 2421 write_command_object->SetCommandName("breakpoint write"); 2422 read_command_object->SetCommandName("breakpoint read"); 2423 2424 LoadSubCommand("list", list_command_object); 2425 LoadSubCommand("enable", enable_command_object); 2426 LoadSubCommand("disable", disable_command_object); 2427 LoadSubCommand("clear", clear_command_object); 2428 LoadSubCommand("delete", delete_command_object); 2429 LoadSubCommand("set", set_command_object); 2430 LoadSubCommand("command", command_command_object); 2431 LoadSubCommand("modify", modify_command_object); 2432 LoadSubCommand("name", name_command_object); 2433 LoadSubCommand("write", write_command_object); 2434 LoadSubCommand("read", read_command_object); 2435 } 2436 2437 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default; 2438 2439 void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target, 2440 bool allow_locations, 2441 CommandReturnObject &result, 2442 BreakpointIDList *valid_ids, 2443 BreakpointName::Permissions 2444 ::PermissionKinds 2445 purpose) { 2446 // args can be strings representing 1). integers (for breakpoint ids) 2447 // 2). the full breakpoint & location 2448 // canonical representation 2449 // 3). the word "to" or a hyphen, 2450 // representing a range (in which case there 2451 // had *better* be an entry both before & 2452 // after of one of the first two types. 2453 // 4). A breakpoint name 2454 // If args is empty, we will use the last created breakpoint (if there is 2455 // one.) 2456 2457 Args temp_args; 2458 2459 if (args.empty()) { 2460 if (target->GetLastCreatedBreakpoint()) { 2461 valid_ids->AddBreakpointID(BreakpointID( 2462 target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID)); 2463 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2464 } else { 2465 result.AppendError( 2466 "No breakpoint specified and no last created breakpoint."); 2467 result.SetStatus(eReturnStatusFailed); 2468 } 2469 return; 2470 } 2471 2472 // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff 2473 // directly from the old ARGS to the new TEMP_ARGS. Do not copy breakpoint 2474 // id range strings over; instead generate a list of strings for all the 2475 // breakpoint ids in the range, and shove all of those breakpoint id strings 2476 // into TEMP_ARGS. 2477 2478 BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations, 2479 purpose, result, temp_args); 2480 2481 // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual 2482 // BreakpointIDList: 2483 2484 valid_ids->InsertStringArray(temp_args.GetArgumentArrayRef(), result); 2485 2486 // At this point, all of the breakpoint ids that the user passed in have 2487 // been converted to breakpoint IDs and put into valid_ids. 2488 2489 if (result.Succeeded()) { 2490 // Now that we've converted everything from args into a list of breakpoint 2491 // ids, go through our tentative list of breakpoint id's and verify that 2492 // they correspond to valid/currently set breakpoints. 2493 2494 const size_t count = valid_ids->GetSize(); 2495 for (size_t i = 0; i < count; ++i) { 2496 BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i); 2497 Breakpoint *breakpoint = 2498 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 2499 if (breakpoint != nullptr) { 2500 const size_t num_locations = breakpoint->GetNumLocations(); 2501 if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) { 2502 StreamString id_str; 2503 BreakpointID::GetCanonicalReference( 2504 &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); 2505 i = valid_ids->GetSize() + 1; 2506 result.AppendErrorWithFormat( 2507 "'%s' is not a currently valid breakpoint/location id.\n", 2508 id_str.GetData()); 2509 result.SetStatus(eReturnStatusFailed); 2510 } 2511 } else { 2512 i = valid_ids->GetSize() + 1; 2513 result.AppendErrorWithFormat( 2514 "'%d' is not a currently valid breakpoint ID.\n", 2515 cur_bp_id.GetBreakpointID()); 2516 result.SetStatus(eReturnStatusFailed); 2517 } 2518 } 2519 } 2520 } 2521