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