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