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 } break; 545 case eSetTypeSourceRegexp: // Breakpoint by regexp on source text. 546 { 547 const size_t num_files = m_options.m_filenames.GetSize(); 548 549 if (num_files == 0 && !m_options.m_all_files) { 550 FileSpec file; 551 if (!GetDefaultFile(target, file, result)) { 552 result.AppendError( 553 "No files provided and could not find default file."); 554 result.SetStatus(eReturnStatusFailed); 555 return false; 556 } else { 557 m_options.m_filenames.Append(file); 558 } 559 } 560 561 RegularExpression regexp(m_options.m_source_text_regexp.c_str()); 562 if (!regexp.IsValid()) { 563 char err_str[1024]; 564 regexp.GetErrorAsCString(err_str, sizeof(err_str)); 565 result.AppendErrorWithFormat( 566 "Source text regular expression could not be compiled: \"%s\"", 567 err_str); 568 result.SetStatus(eReturnStatusFailed); 569 return false; 570 } 571 bp = target 572 ->CreateSourceRegexBreakpoint( 573 &(m_options.m_modules), &(m_options.m_filenames), 574 m_options.m_source_regex_func_names, regexp, internal, 575 m_options.m_hardware, m_options.m_move_to_nearest_code) 576 .get(); 577 } break; 578 case eSetTypeException: { 579 Error precond_error; 580 bp = target 581 ->CreateExceptionBreakpoint( 582 m_options.m_exception_language, m_options.m_catch_bp, 583 m_options.m_throw_bp, internal, 584 &m_options.m_exception_extra_args, &precond_error) 585 .get(); 586 if (precond_error.Fail()) { 587 result.AppendErrorWithFormat( 588 "Error setting extra exception arguments: %s", 589 precond_error.AsCString()); 590 target->RemoveBreakpointByID(bp->GetID()); 591 result.SetStatus(eReturnStatusFailed); 592 return false; 593 } 594 } break; 595 default: 596 break; 597 } 598 599 // Now set the various options that were passed in: 600 if (bp) { 601 if (m_options.m_thread_id != LLDB_INVALID_THREAD_ID) 602 bp->SetThreadID(m_options.m_thread_id); 603 604 if (m_options.m_thread_index != UINT32_MAX) 605 bp->GetOptions()->GetThreadSpec()->SetIndex(m_options.m_thread_index); 606 607 if (!m_options.m_thread_name.empty()) 608 bp->GetOptions()->GetThreadSpec()->SetName( 609 m_options.m_thread_name.c_str()); 610 611 if (!m_options.m_queue_name.empty()) 612 bp->GetOptions()->GetThreadSpec()->SetQueueName( 613 m_options.m_queue_name.c_str()); 614 615 if (m_options.m_ignore_count != 0) 616 bp->GetOptions()->SetIgnoreCount(m_options.m_ignore_count); 617 618 if (!m_options.m_condition.empty()) 619 bp->GetOptions()->SetCondition(m_options.m_condition.c_str()); 620 621 if (!m_options.m_breakpoint_names.empty()) { 622 Error error; // We don't need to check the error here, since the option 623 // parser checked it... 624 for (auto name : m_options.m_breakpoint_names) 625 bp->AddName(name.c_str(), error); 626 } 627 628 bp->SetOneShot(m_options.m_one_shot); 629 } 630 631 if (bp) { 632 Stream &output_stream = result.GetOutputStream(); 633 const bool show_locations = false; 634 bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, 635 show_locations); 636 if (target == m_interpreter.GetDebugger().GetDummyTarget()) 637 output_stream.Printf("Breakpoint set in dummy target, will get copied " 638 "into future targets.\n"); 639 else { 640 // Don't print out this warning for exception breakpoints. They can get 641 // set before the target 642 // is set, but we won't know how to actually set the breakpoint till we 643 // run. 644 if (bp->GetNumLocations() == 0 && break_type != eSetTypeException) { 645 output_stream.Printf("WARNING: Unable to resolve breakpoint to any " 646 "actual locations.\n"); 647 } 648 } 649 result.SetStatus(eReturnStatusSuccessFinishResult); 650 } else if (!bp) { 651 result.AppendError("Breakpoint creation failed: No breakpoint created."); 652 result.SetStatus(eReturnStatusFailed); 653 } 654 655 return result.Succeeded(); 656 } 657 658 private: 659 bool GetDefaultFile(Target *target, FileSpec &file, 660 CommandReturnObject &result) { 661 uint32_t default_line; 662 // First use the Source Manager's default file. 663 // Then use the current stack frame's file. 664 if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line)) { 665 StackFrame *cur_frame = m_exe_ctx.GetFramePtr(); 666 if (cur_frame == nullptr) { 667 result.AppendError( 668 "No selected frame to use to find the default file."); 669 result.SetStatus(eReturnStatusFailed); 670 return false; 671 } else if (!cur_frame->HasDebugInformation()) { 672 result.AppendError("Cannot use the selected frame to find the default " 673 "file, it has no debug info."); 674 result.SetStatus(eReturnStatusFailed); 675 return false; 676 } else { 677 const SymbolContext &sc = 678 cur_frame->GetSymbolContext(eSymbolContextLineEntry); 679 if (sc.line_entry.file) { 680 file = sc.line_entry.file; 681 } else { 682 result.AppendError("Can't find the file for the selected frame to " 683 "use as the default file."); 684 result.SetStatus(eReturnStatusFailed); 685 return false; 686 } 687 } 688 } 689 return true; 690 } 691 692 CommandOptions m_options; 693 }; 694 695 // If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to 696 // update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately. 697 #define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2) 698 #define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10) 699 #define LLDB_OPT_SKIP_PROLOGUE (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8)) 700 #define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8)) 701 #define LLDB_OPT_MOVE_TO_NEAREST_CODE (LLDB_OPT_SET_1 | LLDB_OPT_SET_9) 702 #define LLDB_OPT_EXPR_LANGUAGE (LLDB_OPT_SET_FROM_TO(3, 8)) 703 704 OptionDefinition CommandObjectBreakpointSet::CommandOptions::g_option_table[] = 705 { 706 // clang-format off 707 {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 " 708 "multiple times to specify multiple shared libraries."}, 709 {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." }, 710 {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." }, 711 {LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."}, 712 {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."}, 713 {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."}, 714 {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 " 715 "argument."}, 716 {LLDB_OPT_SET_ALL, false, "hardware", 'H', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Require the breakpoint to use hardware breakpoints."}, 717 {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 " 718 "this argument."}, 719 {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 " 720 "lldb only looks for files that are #included if they use the standard include " 721 "file extensions. To set breakpoints on .c/.cpp/.m/.mm files that are " 722 "#included, set target.inline-breakpoint-strategy to \"always\"."}, 723 {LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "Specifies the line number on which to set this breakpoint."}, 724 725 // Comment out this option for the moment, as we don't actually use it, but will in the future. 726 // This way users won't see it, but the infrastructure is left in place. 727 // { 0, false, "column", 'C', OptionParser::eRequiredArgument, nullptr, "<column>", 728 // "Set the breakpoint by source location at this particular column."}, 729 730 {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 " 731 "a particular binary, then the address will be converted to a \"file\" " 732 "address, so that the breakpoint will track that binary+offset no matter where " 733 "the binary eventually loads. Alternately, if you also specify the module - " 734 "with the -s option - then the address will be treated as a file address in " 735 "that module, and resolved accordingly. Again, this will allow lldb to track " 736 "that offset on subsequent reloads. The module need not have been loaded at " 737 "the time you specify this breakpoint, and will get resolved when the module " 738 "is loaded."}, 739 {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 " 740 "one breakpoint for multiple names"}, 741 {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 " 742 "functions. Can be repeated multiple times."}, 743 {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 " 744 "namespaces and all arguments, and for Objective C this means a full function " 745 "prototype with class and selector. Can be repeated multiple times to make " 746 "one breakpoint for multiple names."}, 747 {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 " 748 "make one breakpoint for multiple Selectors."}, 749 {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 " 750 "make one breakpoint for multiple methods."}, 751 {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 " 752 "the function name(s)."}, 753 {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 " 754 "ignored). Can be repeated multiple times to make one breakpoint for multiple " 755 "symbols."}, 756 {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 " 757 "against the source text in a source file or files specified with the -f " 758 "option. The -f option can be specified more than once. If no source files " 759 "are specified, uses the current \"default source file\". If you want to " 760 "match against all source files, pass the \"--all-files\" option."}, 761 {LLDB_OPT_SET_9, false, "all-files", 'A', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "All files are searched for source pattern matches."}, 762 {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 " 763 "options, on throw but not catch.)"}, 764 {LLDB_OPT_SET_10, false, "on-throw", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Set the breakpoint on exception throW."}, 765 {LLDB_OPT_SET_10, false, "on-catch", 'h', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Set the breakpoint on exception catcH."}, 766 767 // Don't add this option till it actually does something useful... 768 // { LLDB_OPT_SET_10, false, "exception-typename", 'O', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeTypeName, 769 // "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" }, 770 771 {LLDB_OPT_EXPR_LANGUAGE, false, "language", 'L', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLanguage, "Specifies the Language to use when interpreting the breakpoint's expression " 772 "(note: currently only implemented for setting breakpoints on identifiers). " 773 "If not set the target.language setting is used."}, 774 {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. " 775 "If not set the target.skip-prologue setting is used."}, 776 {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, " 777 "which prime new targets."}, 778 {LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Adds this to the list of names for this breakpoint."}, 779 {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. " 780 "At present this applies the offset directly as given, and doesn't try to align it to instruction boundaries."}, 781 {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 " 782 "setting is used."}, 783 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 784 // clang-format on 785 }; 786 787 //------------------------------------------------------------------------- 788 // CommandObjectBreakpointModify 789 //------------------------------------------------------------------------- 790 #pragma mark Modify 791 792 class CommandObjectBreakpointModify : public CommandObjectParsed { 793 public: 794 CommandObjectBreakpointModify(CommandInterpreter &interpreter) 795 : CommandObjectParsed(interpreter, "breakpoint modify", 796 "Modify the options on a breakpoint or set of " 797 "breakpoints in the executable. " 798 "If no breakpoint is specified, acts on the last " 799 "created breakpoint. " 800 "With the exception of -e, -d and -i, passing an " 801 "empty argument clears the modification.", 802 nullptr), 803 m_options() { 804 CommandArgumentEntry arg; 805 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 806 eArgTypeBreakpointIDRange); 807 // Add the entry for the first argument for this command to the object's 808 // arguments vector. 809 m_arguments.push_back(arg); 810 } 811 812 ~CommandObjectBreakpointModify() override = default; 813 814 Options *GetOptions() override { return &m_options; } 815 816 class CommandOptions : public Options { 817 public: 818 CommandOptions() 819 : Options(), m_ignore_count(0), m_thread_id(LLDB_INVALID_THREAD_ID), 820 m_thread_id_passed(false), m_thread_index(UINT32_MAX), 821 m_thread_index_passed(false), m_thread_name(), m_queue_name(), 822 m_condition(), m_one_shot(false), m_enable_passed(false), 823 m_enable_value(false), m_name_passed(false), m_queue_passed(false), 824 m_condition_passed(false), m_one_shot_passed(false), 825 m_use_dummy(false) {} 826 827 ~CommandOptions() override = default; 828 829 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 830 ExecutionContext *execution_context) override { 831 Error error; 832 const int short_option = m_getopt_table[option_idx].val; 833 834 switch (short_option) { 835 case 'c': 836 if (option_arg != nullptr) 837 m_condition.assign(option_arg); 838 else 839 m_condition.clear(); 840 m_condition_passed = true; 841 break; 842 case 'd': 843 m_enable_passed = true; 844 m_enable_value = false; 845 break; 846 case 'D': 847 m_use_dummy = true; 848 break; 849 case 'e': 850 m_enable_passed = true; 851 m_enable_value = true; 852 break; 853 case 'i': 854 m_ignore_count = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); 855 if (m_ignore_count == UINT32_MAX) 856 error.SetErrorStringWithFormat("invalid ignore count '%s'", 857 option_arg); 858 break; 859 case 'o': { 860 bool value, success; 861 value = Args::StringToBoolean(option_arg, false, &success); 862 if (success) { 863 m_one_shot_passed = true; 864 m_one_shot = value; 865 } else 866 error.SetErrorStringWithFormat( 867 "invalid boolean value '%s' passed for -o option", option_arg); 868 } break; 869 case 't': 870 if (option_arg[0] == '\0') { 871 m_thread_id = LLDB_INVALID_THREAD_ID; 872 m_thread_id_passed = true; 873 } else { 874 m_thread_id = 875 StringConvert::ToUInt64(option_arg, LLDB_INVALID_THREAD_ID, 0); 876 if (m_thread_id == LLDB_INVALID_THREAD_ID) 877 error.SetErrorStringWithFormat("invalid thread id string '%s'", 878 option_arg); 879 else 880 m_thread_id_passed = true; 881 } 882 break; 883 case 'T': 884 if (option_arg != nullptr) 885 m_thread_name.assign(option_arg); 886 else 887 m_thread_name.clear(); 888 m_name_passed = true; 889 break; 890 case 'q': 891 if (option_arg != nullptr) 892 m_queue_name.assign(option_arg); 893 else 894 m_queue_name.clear(); 895 m_queue_passed = true; 896 break; 897 case 'x': 898 if (option_arg[0] == '\n') { 899 m_thread_index = UINT32_MAX; 900 m_thread_index_passed = true; 901 } else { 902 m_thread_index = StringConvert::ToUInt32(option_arg, UINT32_MAX, 0); 903 if (m_thread_id == UINT32_MAX) 904 error.SetErrorStringWithFormat("invalid thread index string '%s'", 905 option_arg); 906 else 907 m_thread_index_passed = true; 908 } 909 break; 910 default: 911 error.SetErrorStringWithFormat("unrecognized option '%c'", 912 short_option); 913 break; 914 } 915 916 return error; 917 } 918 919 void OptionParsingStarting(ExecutionContext *execution_context) override { 920 m_ignore_count = 0; 921 m_thread_id = LLDB_INVALID_THREAD_ID; 922 m_thread_id_passed = false; 923 m_thread_index = UINT32_MAX; 924 m_thread_index_passed = false; 925 m_thread_name.clear(); 926 m_queue_name.clear(); 927 m_condition.clear(); 928 m_one_shot = false; 929 m_enable_passed = false; 930 m_queue_passed = false; 931 m_name_passed = false; 932 m_condition_passed = false; 933 m_one_shot_passed = false; 934 m_use_dummy = false; 935 } 936 937 const OptionDefinition *GetDefinitions() override { return g_option_table; } 938 939 // Options table: Required for subclasses of Options. 940 941 static OptionDefinition g_option_table[]; 942 943 // Instance variables to hold the values for command options. 944 945 uint32_t m_ignore_count; 946 lldb::tid_t m_thread_id; 947 bool m_thread_id_passed; 948 uint32_t m_thread_index; 949 bool m_thread_index_passed; 950 std::string m_thread_name; 951 std::string m_queue_name; 952 std::string m_condition; 953 bool m_one_shot; 954 bool m_enable_passed; 955 bool m_enable_value; 956 bool m_name_passed; 957 bool m_queue_passed; 958 bool m_condition_passed; 959 bool m_one_shot_passed; 960 bool m_use_dummy; 961 }; 962 963 protected: 964 bool DoExecute(Args &command, CommandReturnObject &result) override { 965 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 966 if (target == nullptr) { 967 result.AppendError("Invalid target. No existing target or breakpoints."); 968 result.SetStatus(eReturnStatusFailed); 969 return false; 970 } 971 972 std::unique_lock<std::recursive_mutex> lock; 973 target->GetBreakpointList().GetListMutex(lock); 974 975 BreakpointIDList valid_bp_ids; 976 977 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 978 command, target, result, &valid_bp_ids); 979 980 if (result.Succeeded()) { 981 const size_t count = valid_bp_ids.GetSize(); 982 for (size_t i = 0; i < count; ++i) { 983 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 984 985 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 986 Breakpoint *bp = 987 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 988 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 989 BreakpointLocation *location = 990 bp->FindLocationByID(cur_bp_id.GetLocationID()).get(); 991 if (location) { 992 if (m_options.m_thread_id_passed) 993 location->SetThreadID(m_options.m_thread_id); 994 995 if (m_options.m_thread_index_passed) 996 location->SetThreadIndex(m_options.m_thread_index); 997 998 if (m_options.m_name_passed) 999 location->SetThreadName(m_options.m_thread_name.c_str()); 1000 1001 if (m_options.m_queue_passed) 1002 location->SetQueueName(m_options.m_queue_name.c_str()); 1003 1004 if (m_options.m_ignore_count != 0) 1005 location->SetIgnoreCount(m_options.m_ignore_count); 1006 1007 if (m_options.m_enable_passed) 1008 location->SetEnabled(m_options.m_enable_value); 1009 1010 if (m_options.m_condition_passed) 1011 location->SetCondition(m_options.m_condition.c_str()); 1012 } 1013 } else { 1014 if (m_options.m_thread_id_passed) 1015 bp->SetThreadID(m_options.m_thread_id); 1016 1017 if (m_options.m_thread_index_passed) 1018 bp->SetThreadIndex(m_options.m_thread_index); 1019 1020 if (m_options.m_name_passed) 1021 bp->SetThreadName(m_options.m_thread_name.c_str()); 1022 1023 if (m_options.m_queue_passed) 1024 bp->SetQueueName(m_options.m_queue_name.c_str()); 1025 1026 if (m_options.m_ignore_count != 0) 1027 bp->SetIgnoreCount(m_options.m_ignore_count); 1028 1029 if (m_options.m_enable_passed) 1030 bp->SetEnabled(m_options.m_enable_value); 1031 1032 if (m_options.m_condition_passed) 1033 bp->SetCondition(m_options.m_condition.c_str()); 1034 } 1035 } 1036 } 1037 } 1038 1039 return result.Succeeded(); 1040 } 1041 1042 private: 1043 CommandOptions m_options; 1044 }; 1045 1046 #pragma mark Modify::CommandOptions 1047 OptionDefinition 1048 CommandObjectBreakpointModify::CommandOptions::g_option_table[] = { 1049 // clang-format off 1050 {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."}, 1051 {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."}, 1052 {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."}, 1053 {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."}, 1054 {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."}, 1055 {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."}, 1056 {LLDB_OPT_SET_ALL, false, "condition", 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression, "The breakpoint stops only if this condition expression evaluates to true."}, 1057 {LLDB_OPT_SET_1, false, "enable", 'e', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Enable the breakpoint."}, 1058 {LLDB_OPT_SET_2, false, "disable", 'd', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Disable the breakpoint."}, 1059 {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."}, 1060 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 1061 // clang-format on 1062 }; 1063 1064 //------------------------------------------------------------------------- 1065 // CommandObjectBreakpointEnable 1066 //------------------------------------------------------------------------- 1067 #pragma mark Enable 1068 1069 class CommandObjectBreakpointEnable : public CommandObjectParsed { 1070 public: 1071 CommandObjectBreakpointEnable(CommandInterpreter &interpreter) 1072 : CommandObjectParsed(interpreter, "enable", 1073 "Enable the specified disabled breakpoint(s). If " 1074 "no breakpoints are specified, enable all of them.", 1075 nullptr) { 1076 CommandArgumentEntry arg; 1077 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1078 eArgTypeBreakpointIDRange); 1079 // Add the entry for the first argument for this command to the object's 1080 // arguments vector. 1081 m_arguments.push_back(arg); 1082 } 1083 1084 ~CommandObjectBreakpointEnable() override = default; 1085 1086 protected: 1087 bool DoExecute(Args &command, CommandReturnObject &result) override { 1088 Target *target = GetSelectedOrDummyTarget(); 1089 if (target == nullptr) { 1090 result.AppendError("Invalid target. No existing target or breakpoints."); 1091 result.SetStatus(eReturnStatusFailed); 1092 return false; 1093 } 1094 1095 std::unique_lock<std::recursive_mutex> lock; 1096 target->GetBreakpointList().GetListMutex(lock); 1097 1098 const BreakpointList &breakpoints = target->GetBreakpointList(); 1099 1100 size_t num_breakpoints = breakpoints.GetSize(); 1101 1102 if (num_breakpoints == 0) { 1103 result.AppendError("No breakpoints exist to be enabled."); 1104 result.SetStatus(eReturnStatusFailed); 1105 return false; 1106 } 1107 1108 if (command.GetArgumentCount() == 0) { 1109 // No breakpoint selected; enable all currently set breakpoints. 1110 target->EnableAllBreakpoints(); 1111 result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64 1112 " breakpoints)\n", 1113 (uint64_t)num_breakpoints); 1114 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1115 } else { 1116 // Particular breakpoint selected; enable that breakpoint. 1117 BreakpointIDList valid_bp_ids; 1118 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1119 command, target, result, &valid_bp_ids); 1120 1121 if (result.Succeeded()) { 1122 int enable_count = 0; 1123 int loc_count = 0; 1124 const size_t count = valid_bp_ids.GetSize(); 1125 for (size_t i = 0; i < count; ++i) { 1126 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1127 1128 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1129 Breakpoint *breakpoint = 1130 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1131 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1132 BreakpointLocation *location = 1133 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1134 if (location) { 1135 location->SetEnabled(true); 1136 ++loc_count; 1137 } 1138 } else { 1139 breakpoint->SetEnabled(true); 1140 ++enable_count; 1141 } 1142 } 1143 } 1144 result.AppendMessageWithFormat("%d breakpoints enabled.\n", 1145 enable_count + loc_count); 1146 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1147 } 1148 } 1149 1150 return result.Succeeded(); 1151 } 1152 }; 1153 1154 //------------------------------------------------------------------------- 1155 // CommandObjectBreakpointDisable 1156 //------------------------------------------------------------------------- 1157 #pragma mark Disable 1158 1159 class CommandObjectBreakpointDisable : public CommandObjectParsed { 1160 public: 1161 CommandObjectBreakpointDisable(CommandInterpreter &interpreter) 1162 : CommandObjectParsed( 1163 interpreter, "breakpoint disable", 1164 "Disable the specified breakpoint(s) without deleting " 1165 "them. If none are specified, disable all " 1166 "breakpoints.", 1167 nullptr) { 1168 SetHelpLong( 1169 "Disable the specified breakpoint(s) without deleting them. \ 1170 If none are specified, disable all breakpoints." 1171 R"( 1172 1173 )" 1174 "Note: disabling a breakpoint will cause none of its locations to be hit \ 1175 regardless of whether individual locations are enabled or disabled. After the sequence:" 1176 R"( 1177 1178 (lldb) break disable 1 1179 (lldb) break enable 1.1 1180 1181 execution will NOT stop at location 1.1. To achieve that, type: 1182 1183 (lldb) break disable 1.* 1184 (lldb) break enable 1.1 1185 1186 )" 1187 "The first command disables all locations for breakpoint 1, \ 1188 the second re-enables the first location."); 1189 1190 CommandArgumentEntry arg; 1191 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1192 eArgTypeBreakpointIDRange); 1193 // Add the entry for the first argument for this command to the object's 1194 // arguments vector. 1195 m_arguments.push_back(arg); 1196 } 1197 1198 ~CommandObjectBreakpointDisable() override = default; 1199 1200 protected: 1201 bool DoExecute(Args &command, CommandReturnObject &result) override { 1202 Target *target = GetSelectedOrDummyTarget(); 1203 if (target == nullptr) { 1204 result.AppendError("Invalid target. No existing target or breakpoints."); 1205 result.SetStatus(eReturnStatusFailed); 1206 return false; 1207 } 1208 1209 std::unique_lock<std::recursive_mutex> lock; 1210 target->GetBreakpointList().GetListMutex(lock); 1211 1212 const BreakpointList &breakpoints = target->GetBreakpointList(); 1213 size_t num_breakpoints = breakpoints.GetSize(); 1214 1215 if (num_breakpoints == 0) { 1216 result.AppendError("No breakpoints exist to be disabled."); 1217 result.SetStatus(eReturnStatusFailed); 1218 return false; 1219 } 1220 1221 if (command.GetArgumentCount() == 0) { 1222 // No breakpoint selected; disable all currently set breakpoints. 1223 target->DisableAllBreakpoints(); 1224 result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64 1225 " breakpoints)\n", 1226 (uint64_t)num_breakpoints); 1227 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1228 } else { 1229 // Particular breakpoint selected; disable that breakpoint. 1230 BreakpointIDList valid_bp_ids; 1231 1232 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1233 command, target, result, &valid_bp_ids); 1234 1235 if (result.Succeeded()) { 1236 int disable_count = 0; 1237 int loc_count = 0; 1238 const size_t count = valid_bp_ids.GetSize(); 1239 for (size_t i = 0; i < count; ++i) { 1240 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1241 1242 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1243 Breakpoint *breakpoint = 1244 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1245 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1246 BreakpointLocation *location = 1247 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1248 if (location) { 1249 location->SetEnabled(false); 1250 ++loc_count; 1251 } 1252 } else { 1253 breakpoint->SetEnabled(false); 1254 ++disable_count; 1255 } 1256 } 1257 } 1258 result.AppendMessageWithFormat("%d breakpoints disabled.\n", 1259 disable_count + loc_count); 1260 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1261 } 1262 } 1263 1264 return result.Succeeded(); 1265 } 1266 }; 1267 1268 //------------------------------------------------------------------------- 1269 // CommandObjectBreakpointList 1270 //------------------------------------------------------------------------- 1271 #pragma mark List 1272 1273 class CommandObjectBreakpointList : public CommandObjectParsed { 1274 public: 1275 CommandObjectBreakpointList(CommandInterpreter &interpreter) 1276 : CommandObjectParsed( 1277 interpreter, "breakpoint list", 1278 "List some or all breakpoints at configurable levels of detail.", 1279 nullptr), 1280 m_options() { 1281 CommandArgumentEntry arg; 1282 CommandArgumentData bp_id_arg; 1283 1284 // Define the first (and only) variant of this arg. 1285 bp_id_arg.arg_type = eArgTypeBreakpointID; 1286 bp_id_arg.arg_repetition = eArgRepeatOptional; 1287 1288 // There is only one variant this argument could be; put it into the 1289 // argument entry. 1290 arg.push_back(bp_id_arg); 1291 1292 // Push the data for the first argument into the m_arguments vector. 1293 m_arguments.push_back(arg); 1294 } 1295 1296 ~CommandObjectBreakpointList() override = default; 1297 1298 Options *GetOptions() override { return &m_options; } 1299 1300 class CommandOptions : public Options { 1301 public: 1302 CommandOptions() 1303 : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) { 1304 } 1305 1306 ~CommandOptions() override = default; 1307 1308 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 1309 ExecutionContext *execution_context) override { 1310 Error error; 1311 const int short_option = m_getopt_table[option_idx].val; 1312 1313 switch (short_option) { 1314 case 'b': 1315 m_level = lldb::eDescriptionLevelBrief; 1316 break; 1317 case 'D': 1318 m_use_dummy = true; 1319 break; 1320 case 'f': 1321 m_level = lldb::eDescriptionLevelFull; 1322 break; 1323 case 'v': 1324 m_level = lldb::eDescriptionLevelVerbose; 1325 break; 1326 case 'i': 1327 m_internal = true; 1328 break; 1329 default: 1330 error.SetErrorStringWithFormat("unrecognized option '%c'", 1331 short_option); 1332 break; 1333 } 1334 1335 return error; 1336 } 1337 1338 void OptionParsingStarting(ExecutionContext *execution_context) override { 1339 m_level = lldb::eDescriptionLevelFull; 1340 m_internal = false; 1341 m_use_dummy = false; 1342 } 1343 1344 const OptionDefinition *GetDefinitions() override { return g_option_table; } 1345 1346 // Options table: Required for subclasses of Options. 1347 1348 static OptionDefinition g_option_table[]; 1349 1350 // Instance variables to hold the values for command options. 1351 1352 lldb::DescriptionLevel m_level; 1353 1354 bool m_internal; 1355 bool m_use_dummy; 1356 }; 1357 1358 protected: 1359 bool DoExecute(Args &command, CommandReturnObject &result) override { 1360 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1361 1362 if (target == nullptr) { 1363 result.AppendError("Invalid target. No current target or breakpoints."); 1364 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1365 return true; 1366 } 1367 1368 const BreakpointList &breakpoints = 1369 target->GetBreakpointList(m_options.m_internal); 1370 std::unique_lock<std::recursive_mutex> lock; 1371 target->GetBreakpointList(m_options.m_internal).GetListMutex(lock); 1372 1373 size_t num_breakpoints = breakpoints.GetSize(); 1374 1375 if (num_breakpoints == 0) { 1376 result.AppendMessage("No breakpoints currently set."); 1377 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1378 return true; 1379 } 1380 1381 Stream &output_stream = result.GetOutputStream(); 1382 1383 if (command.GetArgumentCount() == 0) { 1384 // No breakpoint selected; show info about all currently set breakpoints. 1385 result.AppendMessage("Current breakpoints:"); 1386 for (size_t i = 0; i < num_breakpoints; ++i) { 1387 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get(); 1388 AddBreakpointDescription(&output_stream, breakpoint, m_options.m_level); 1389 } 1390 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1391 } else { 1392 // Particular breakpoints selected; show info about that breakpoint. 1393 BreakpointIDList valid_bp_ids; 1394 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1395 command, target, result, &valid_bp_ids); 1396 1397 if (result.Succeeded()) { 1398 for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) { 1399 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1400 Breakpoint *breakpoint = 1401 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1402 AddBreakpointDescription(&output_stream, breakpoint, 1403 m_options.m_level); 1404 } 1405 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1406 } else { 1407 result.AppendError("Invalid breakpoint ID."); 1408 result.SetStatus(eReturnStatusFailed); 1409 } 1410 } 1411 1412 return result.Succeeded(); 1413 } 1414 1415 private: 1416 CommandOptions m_options; 1417 }; 1418 1419 #pragma mark List::CommandOptions 1420 OptionDefinition CommandObjectBreakpointList::CommandOptions::g_option_table[] = 1421 { 1422 // clang-format off 1423 {LLDB_OPT_SET_ALL, false, "internal", 'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show debugger internal breakpoints" }, 1424 {LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a brief description of the breakpoint (no location info)."}, 1425 // FIXME: We need to add an "internal" command, and then add this sort of thing to it. 1426 // But I need to see it for now, and don't want to wait. 1427 {LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a full description of the breakpoint and its locations."}, 1428 {LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Explain everything we know about the breakpoint (for debugging debugger bugs)."}, 1429 {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."}, 1430 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 1431 // clang-format on 1432 }; 1433 1434 //------------------------------------------------------------------------- 1435 // CommandObjectBreakpointClear 1436 //------------------------------------------------------------------------- 1437 #pragma mark Clear 1438 1439 class CommandObjectBreakpointClear : public CommandObjectParsed { 1440 public: 1441 typedef enum BreakpointClearType { 1442 eClearTypeInvalid, 1443 eClearTypeFileAndLine 1444 } BreakpointClearType; 1445 1446 CommandObjectBreakpointClear(CommandInterpreter &interpreter) 1447 : CommandObjectParsed(interpreter, "breakpoint clear", 1448 "Delete or disable breakpoints matching the " 1449 "specified source file and line.", 1450 "breakpoint clear <cmd-options>"), 1451 m_options() {} 1452 1453 ~CommandObjectBreakpointClear() override = default; 1454 1455 Options *GetOptions() override { return &m_options; } 1456 1457 class CommandOptions : public Options { 1458 public: 1459 CommandOptions() : Options(), m_filename(), m_line_num(0) {} 1460 1461 ~CommandOptions() override = default; 1462 1463 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 1464 ExecutionContext *execution_context) override { 1465 Error error; 1466 const int short_option = m_getopt_table[option_idx].val; 1467 1468 switch (short_option) { 1469 case 'f': 1470 m_filename.assign(option_arg); 1471 break; 1472 1473 case 'l': 1474 m_line_num = StringConvert::ToUInt32(option_arg, 0); 1475 break; 1476 1477 default: 1478 error.SetErrorStringWithFormat("unrecognized option '%c'", 1479 short_option); 1480 break; 1481 } 1482 1483 return error; 1484 } 1485 1486 void OptionParsingStarting(ExecutionContext *execution_context) override { 1487 m_filename.clear(); 1488 m_line_num = 0; 1489 } 1490 1491 const OptionDefinition *GetDefinitions() override { return g_option_table; } 1492 1493 // Options table: Required for subclasses of Options. 1494 1495 static OptionDefinition g_option_table[]; 1496 1497 // Instance variables to hold the values for command options. 1498 1499 std::string m_filename; 1500 uint32_t m_line_num; 1501 }; 1502 1503 protected: 1504 bool DoExecute(Args &command, CommandReturnObject &result) override { 1505 Target *target = GetSelectedOrDummyTarget(); 1506 if (target == nullptr) { 1507 result.AppendError("Invalid target. No existing target or breakpoints."); 1508 result.SetStatus(eReturnStatusFailed); 1509 return false; 1510 } 1511 1512 // The following are the various types of breakpoints that could be cleared: 1513 // 1). -f -l (clearing breakpoint by source location) 1514 1515 BreakpointClearType break_type = eClearTypeInvalid; 1516 1517 if (m_options.m_line_num != 0) 1518 break_type = eClearTypeFileAndLine; 1519 1520 std::unique_lock<std::recursive_mutex> lock; 1521 target->GetBreakpointList().GetListMutex(lock); 1522 1523 BreakpointList &breakpoints = target->GetBreakpointList(); 1524 size_t num_breakpoints = breakpoints.GetSize(); 1525 1526 // Early return if there's no breakpoint at all. 1527 if (num_breakpoints == 0) { 1528 result.AppendError("Breakpoint clear: No breakpoint cleared."); 1529 result.SetStatus(eReturnStatusFailed); 1530 return result.Succeeded(); 1531 } 1532 1533 // Find matching breakpoints and delete them. 1534 1535 // First create a copy of all the IDs. 1536 std::vector<break_id_t> BreakIDs; 1537 for (size_t i = 0; i < num_breakpoints; ++i) 1538 BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID()); 1539 1540 int num_cleared = 0; 1541 StreamString ss; 1542 switch (break_type) { 1543 case eClearTypeFileAndLine: // Breakpoint by source position 1544 { 1545 const ConstString filename(m_options.m_filename.c_str()); 1546 BreakpointLocationCollection loc_coll; 1547 1548 for (size_t i = 0; i < num_breakpoints; ++i) { 1549 Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get(); 1550 1551 if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) { 1552 // If the collection size is 0, it's a full match and we can just 1553 // remove the breakpoint. 1554 if (loc_coll.GetSize() == 0) { 1555 bp->GetDescription(&ss, lldb::eDescriptionLevelBrief); 1556 ss.EOL(); 1557 target->RemoveBreakpointByID(bp->GetID()); 1558 ++num_cleared; 1559 } 1560 } 1561 } 1562 } break; 1563 1564 default: 1565 break; 1566 } 1567 1568 if (num_cleared > 0) { 1569 Stream &output_stream = result.GetOutputStream(); 1570 output_stream.Printf("%d breakpoints cleared:\n", num_cleared); 1571 output_stream << ss.GetData(); 1572 output_stream.EOL(); 1573 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1574 } else { 1575 result.AppendError("Breakpoint clear: No breakpoint cleared."); 1576 result.SetStatus(eReturnStatusFailed); 1577 } 1578 1579 return result.Succeeded(); 1580 } 1581 1582 private: 1583 CommandOptions m_options; 1584 }; 1585 1586 #pragma mark Clear::CommandOptions 1587 1588 OptionDefinition 1589 CommandObjectBreakpointClear::CommandOptions::g_option_table[] = { 1590 // clang-format off 1591 {LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specify the breakpoint by source location in this particular file."}, 1592 {LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "Specify the breakpoint by source location at this particular line."}, 1593 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 1594 // clang-format on 1595 }; 1596 1597 //------------------------------------------------------------------------- 1598 // CommandObjectBreakpointDelete 1599 //------------------------------------------------------------------------- 1600 #pragma mark Delete 1601 1602 class CommandObjectBreakpointDelete : public CommandObjectParsed { 1603 public: 1604 CommandObjectBreakpointDelete(CommandInterpreter &interpreter) 1605 : CommandObjectParsed(interpreter, "breakpoint delete", 1606 "Delete the specified breakpoint(s). If no " 1607 "breakpoints are specified, delete them all.", 1608 nullptr), 1609 m_options() { 1610 CommandArgumentEntry arg; 1611 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1612 eArgTypeBreakpointIDRange); 1613 // Add the entry for the first argument for this command to the object's 1614 // arguments vector. 1615 m_arguments.push_back(arg); 1616 } 1617 1618 ~CommandObjectBreakpointDelete() override = default; 1619 1620 Options *GetOptions() override { return &m_options; } 1621 1622 class CommandOptions : public Options { 1623 public: 1624 CommandOptions() : Options(), m_use_dummy(false), m_force(false) {} 1625 1626 ~CommandOptions() override = default; 1627 1628 Error SetOptionValue(uint32_t option_idx, const char *option_arg, 1629 ExecutionContext *execution_context) override { 1630 Error error; 1631 const int short_option = m_getopt_table[option_idx].val; 1632 1633 switch (short_option) { 1634 case 'f': 1635 m_force = true; 1636 break; 1637 1638 case 'D': 1639 m_use_dummy = true; 1640 break; 1641 1642 default: 1643 error.SetErrorStringWithFormat("unrecognized option '%c'", 1644 short_option); 1645 break; 1646 } 1647 1648 return error; 1649 } 1650 1651 void OptionParsingStarting(ExecutionContext *execution_context) override { 1652 m_use_dummy = false; 1653 m_force = false; 1654 } 1655 1656 const OptionDefinition *GetDefinitions() override { return g_option_table; } 1657 1658 // Options table: Required for subclasses of Options. 1659 1660 static OptionDefinition g_option_table[]; 1661 1662 // Instance variables to hold the values for command options. 1663 bool m_use_dummy; 1664 bool m_force; 1665 }; 1666 1667 protected: 1668 bool DoExecute(Args &command, CommandReturnObject &result) override { 1669 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1670 1671 if (target == nullptr) { 1672 result.AppendError("Invalid target. No existing target or breakpoints."); 1673 result.SetStatus(eReturnStatusFailed); 1674 return false; 1675 } 1676 1677 std::unique_lock<std::recursive_mutex> lock; 1678 target->GetBreakpointList().GetListMutex(lock); 1679 1680 const BreakpointList &breakpoints = target->GetBreakpointList(); 1681 1682 size_t num_breakpoints = breakpoints.GetSize(); 1683 1684 if (num_breakpoints == 0) { 1685 result.AppendError("No breakpoints exist to be deleted."); 1686 result.SetStatus(eReturnStatusFailed); 1687 return false; 1688 } 1689 1690 if (command.GetArgumentCount() == 0) { 1691 if (!m_options.m_force && 1692 !m_interpreter.Confirm( 1693 "About to delete all breakpoints, do you want to do that?", 1694 true)) { 1695 result.AppendMessage("Operation cancelled..."); 1696 } else { 1697 target->RemoveAllBreakpoints(); 1698 result.AppendMessageWithFormat( 1699 "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n", 1700 (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : ""); 1701 } 1702 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1703 } else { 1704 // Particular breakpoint selected; disable that breakpoint. 1705 BreakpointIDList valid_bp_ids; 1706 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1707 command, target, result, &valid_bp_ids); 1708 1709 if (result.Succeeded()) { 1710 int delete_count = 0; 1711 int disable_count = 0; 1712 const size_t count = valid_bp_ids.GetSize(); 1713 for (size_t i = 0; i < count; ++i) { 1714 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1715 1716 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1717 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1718 Breakpoint *breakpoint = 1719 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1720 BreakpointLocation *location = 1721 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1722 // It makes no sense to try to delete individual locations, so we 1723 // disable them instead. 1724 if (location) { 1725 location->SetEnabled(false); 1726 ++disable_count; 1727 } 1728 } else { 1729 target->RemoveBreakpointByID(cur_bp_id.GetBreakpointID()); 1730 ++delete_count; 1731 } 1732 } 1733 } 1734 result.AppendMessageWithFormat( 1735 "%d breakpoints deleted; %d breakpoint locations disabled.\n", 1736 delete_count, disable_count); 1737 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1738 } 1739 } 1740 return result.Succeeded(); 1741 } 1742 1743 private: 1744 CommandOptions m_options; 1745 }; 1746 1747 OptionDefinition 1748 CommandObjectBreakpointDelete::CommandOptions::g_option_table[] = { 1749 // clang-format off 1750 {LLDB_OPT_SET_1, false, "force", 'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete all breakpoints without querying for confirmation."}, 1751 {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."}, 1752 {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr} 1753 // clang-format on 1754 }; 1755 1756 //------------------------------------------------------------------------- 1757 // CommandObjectBreakpointName 1758 //------------------------------------------------------------------------- 1759 1760 static OptionDefinition g_breakpoint_name_options[] = { 1761 // clang-format off 1762 {LLDB_OPT_SET_1, false, "name", 'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."}, 1763 {LLDB_OPT_SET_2, false, "breakpoint-id", 'B', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointID, "Specify a breakpoint ID to use."}, 1764 {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."}, 1765 // clang-format on 1766 }; 1767 class BreakpointNameOptionGroup : public OptionGroup { 1768 public: 1769 BreakpointNameOptionGroup() 1770 : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) { 1771 } 1772 1773 ~BreakpointNameOptionGroup() override = default; 1774 1775 uint32_t GetNumDefinitions() override { 1776 return sizeof(g_breakpoint_name_options) / sizeof(OptionDefinition); 1777 } 1778 1779 const OptionDefinition *GetDefinitions() override { 1780 return g_breakpoint_name_options; 1781 } 1782 1783 Error SetOptionValue(uint32_t option_idx, const char *option_value, 1784 ExecutionContext *execution_context) override { 1785 Error error; 1786 const int short_option = g_breakpoint_name_options[option_idx].short_option; 1787 1788 switch (short_option) { 1789 case 'N': 1790 if (BreakpointID::StringIsBreakpointName(option_value, error) && 1791 error.Success()) 1792 m_name.SetValueFromString(option_value); 1793 break; 1794 1795 case 'B': 1796 if (m_breakpoint.SetValueFromString(option_value).Fail()) 1797 error.SetErrorStringWithFormat( 1798 "unrecognized value \"%s\" for breakpoint", option_value); 1799 break; 1800 case 'D': 1801 if (m_use_dummy.SetValueFromString(option_value).Fail()) 1802 error.SetErrorStringWithFormat( 1803 "unrecognized value \"%s\" for use-dummy", option_value); 1804 break; 1805 1806 default: 1807 error.SetErrorStringWithFormat("unrecognized short option '%c'", 1808 short_option); 1809 break; 1810 } 1811 return error; 1812 } 1813 1814 void OptionParsingStarting(ExecutionContext *execution_context) override { 1815 m_name.Clear(); 1816 m_breakpoint.Clear(); 1817 m_use_dummy.Clear(); 1818 m_use_dummy.SetDefaultValue(false); 1819 } 1820 1821 OptionValueString m_name; 1822 OptionValueUInt64 m_breakpoint; 1823 OptionValueBoolean m_use_dummy; 1824 }; 1825 1826 class CommandObjectBreakpointNameAdd : public CommandObjectParsed { 1827 public: 1828 CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter) 1829 : CommandObjectParsed( 1830 interpreter, "add", "Add a name to the breakpoints provided.", 1831 "breakpoint name add <command-options> <breakpoint-id-list>"), 1832 m_name_options(), m_option_group() { 1833 // Create the first variant for the first (and only) argument for this 1834 // command. 1835 CommandArgumentEntry arg1; 1836 CommandArgumentData id_arg; 1837 id_arg.arg_type = eArgTypeBreakpointID; 1838 id_arg.arg_repetition = eArgRepeatOptional; 1839 arg1.push_back(id_arg); 1840 m_arguments.push_back(arg1); 1841 1842 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 1843 m_option_group.Finalize(); 1844 } 1845 1846 ~CommandObjectBreakpointNameAdd() override = default; 1847 1848 Options *GetOptions() override { return &m_option_group; } 1849 1850 protected: 1851 bool DoExecute(Args &command, CommandReturnObject &result) override { 1852 if (!m_name_options.m_name.OptionWasSet()) { 1853 result.SetError("No name option provided."); 1854 return false; 1855 } 1856 1857 Target *target = 1858 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 1859 1860 if (target == nullptr) { 1861 result.AppendError("Invalid target. No existing target or breakpoints."); 1862 result.SetStatus(eReturnStatusFailed); 1863 return false; 1864 } 1865 1866 std::unique_lock<std::recursive_mutex> lock; 1867 target->GetBreakpointList().GetListMutex(lock); 1868 1869 const BreakpointList &breakpoints = target->GetBreakpointList(); 1870 1871 size_t num_breakpoints = breakpoints.GetSize(); 1872 if (num_breakpoints == 0) { 1873 result.SetError("No breakpoints, cannot add names."); 1874 result.SetStatus(eReturnStatusFailed); 1875 return false; 1876 } 1877 1878 // Particular breakpoint selected; disable that breakpoint. 1879 BreakpointIDList valid_bp_ids; 1880 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 1881 command, target, result, &valid_bp_ids); 1882 1883 if (result.Succeeded()) { 1884 if (valid_bp_ids.GetSize() == 0) { 1885 result.SetError("No breakpoints specified, cannot add names."); 1886 result.SetStatus(eReturnStatusFailed); 1887 return false; 1888 } 1889 size_t num_valid_ids = valid_bp_ids.GetSize(); 1890 for (size_t index = 0; index < num_valid_ids; index++) { 1891 lldb::break_id_t bp_id = 1892 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); 1893 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); 1894 Error error; // We don't need to check the error here, since the option 1895 // parser checked it... 1896 bp_sp->AddName(m_name_options.m_name.GetCurrentValue(), error); 1897 } 1898 } 1899 1900 return true; 1901 } 1902 1903 private: 1904 BreakpointNameOptionGroup m_name_options; 1905 OptionGroupOptions m_option_group; 1906 }; 1907 1908 class CommandObjectBreakpointNameDelete : public CommandObjectParsed { 1909 public: 1910 CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter) 1911 : CommandObjectParsed( 1912 interpreter, "delete", 1913 "Delete a name from the breakpoints provided.", 1914 "breakpoint name delete <command-options> <breakpoint-id-list>"), 1915 m_name_options(), m_option_group() { 1916 // Create the first variant for the first (and only) argument for this 1917 // command. 1918 CommandArgumentEntry arg1; 1919 CommandArgumentData id_arg; 1920 id_arg.arg_type = eArgTypeBreakpointID; 1921 id_arg.arg_repetition = eArgRepeatOptional; 1922 arg1.push_back(id_arg); 1923 m_arguments.push_back(arg1); 1924 1925 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 1926 m_option_group.Finalize(); 1927 } 1928 1929 ~CommandObjectBreakpointNameDelete() override = default; 1930 1931 Options *GetOptions() override { return &m_option_group; } 1932 1933 protected: 1934 bool DoExecute(Args &command, CommandReturnObject &result) override { 1935 if (!m_name_options.m_name.OptionWasSet()) { 1936 result.SetError("No name option provided."); 1937 return false; 1938 } 1939 1940 Target *target = 1941 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 1942 1943 if (target == nullptr) { 1944 result.AppendError("Invalid target. No existing target or breakpoints."); 1945 result.SetStatus(eReturnStatusFailed); 1946 return false; 1947 } 1948 1949 std::unique_lock<std::recursive_mutex> lock; 1950 target->GetBreakpointList().GetListMutex(lock); 1951 1952 const BreakpointList &breakpoints = target->GetBreakpointList(); 1953 1954 size_t num_breakpoints = breakpoints.GetSize(); 1955 if (num_breakpoints == 0) { 1956 result.SetError("No breakpoints, cannot delete names."); 1957 result.SetStatus(eReturnStatusFailed); 1958 return false; 1959 } 1960 1961 // Particular breakpoint selected; disable that breakpoint. 1962 BreakpointIDList valid_bp_ids; 1963 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 1964 command, target, result, &valid_bp_ids); 1965 1966 if (result.Succeeded()) { 1967 if (valid_bp_ids.GetSize() == 0) { 1968 result.SetError("No breakpoints specified, cannot delete names."); 1969 result.SetStatus(eReturnStatusFailed); 1970 return false; 1971 } 1972 size_t num_valid_ids = valid_bp_ids.GetSize(); 1973 for (size_t index = 0; index < num_valid_ids; index++) { 1974 lldb::break_id_t bp_id = 1975 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); 1976 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); 1977 bp_sp->RemoveName(m_name_options.m_name.GetCurrentValue()); 1978 } 1979 } 1980 1981 return true; 1982 } 1983 1984 private: 1985 BreakpointNameOptionGroup m_name_options; 1986 OptionGroupOptions m_option_group; 1987 }; 1988 1989 class CommandObjectBreakpointNameList : public CommandObjectParsed { 1990 public: 1991 CommandObjectBreakpointNameList(CommandInterpreter &interpreter) 1992 : CommandObjectParsed(interpreter, "list", 1993 "List either the names for a breakpoint or the " 1994 "breakpoints for a given name.", 1995 "breakpoint name list <command-options>"), 1996 m_name_options(), m_option_group() { 1997 m_option_group.Append(&m_name_options); 1998 m_option_group.Finalize(); 1999 } 2000 2001 ~CommandObjectBreakpointNameList() override = default; 2002 2003 Options *GetOptions() override { return &m_option_group; } 2004 2005 protected: 2006 bool DoExecute(Args &command, CommandReturnObject &result) override { 2007 Target *target = 2008 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 2009 2010 if (target == nullptr) { 2011 result.AppendError("Invalid target. No existing target or breakpoints."); 2012 result.SetStatus(eReturnStatusFailed); 2013 return false; 2014 } 2015 2016 if (m_name_options.m_name.OptionWasSet()) { 2017 const char *name = m_name_options.m_name.GetCurrentValue(); 2018 std::unique_lock<std::recursive_mutex> lock; 2019 target->GetBreakpointList().GetListMutex(lock); 2020 2021 BreakpointList &breakpoints = target->GetBreakpointList(); 2022 for (BreakpointSP bp_sp : breakpoints.Breakpoints()) { 2023 if (bp_sp->MatchesName(name)) { 2024 StreamString s; 2025 bp_sp->GetDescription(&s, eDescriptionLevelBrief); 2026 s.EOL(); 2027 result.AppendMessage(s.GetData()); 2028 } 2029 } 2030 2031 } else if (m_name_options.m_breakpoint.OptionWasSet()) { 2032 BreakpointSP bp_sp = target->GetBreakpointList().FindBreakpointByID( 2033 m_name_options.m_breakpoint.GetCurrentValue()); 2034 if (bp_sp) { 2035 std::vector<std::string> names; 2036 bp_sp->GetNames(names); 2037 result.AppendMessage("Names:"); 2038 for (auto name : names) 2039 result.AppendMessageWithFormat(" %s\n", name.c_str()); 2040 } else { 2041 result.AppendErrorWithFormat( 2042 "Could not find breakpoint %" PRId64 ".\n", 2043 m_name_options.m_breakpoint.GetCurrentValue()); 2044 result.SetStatus(eReturnStatusFailed); 2045 return false; 2046 } 2047 } else { 2048 result.SetError("Must specify -N or -B option to list."); 2049 result.SetStatus(eReturnStatusFailed); 2050 return false; 2051 } 2052 return true; 2053 } 2054 2055 private: 2056 BreakpointNameOptionGroup m_name_options; 2057 OptionGroupOptions m_option_group; 2058 }; 2059 2060 //------------------------------------------------------------------------- 2061 // CommandObjectMultiwordBreakpoint 2062 //------------------------------------------------------------------------- 2063 class CommandObjectBreakpointName : public CommandObjectMultiword { 2064 public: 2065 CommandObjectBreakpointName(CommandInterpreter &interpreter) 2066 : CommandObjectMultiword( 2067 interpreter, "name", "Commands to manage name tags for breakpoints", 2068 "breakpoint name <subcommand> [<command-options>]") { 2069 CommandObjectSP add_command_object( 2070 new CommandObjectBreakpointNameAdd(interpreter)); 2071 CommandObjectSP delete_command_object( 2072 new CommandObjectBreakpointNameDelete(interpreter)); 2073 CommandObjectSP list_command_object( 2074 new CommandObjectBreakpointNameList(interpreter)); 2075 2076 LoadSubCommand("add", add_command_object); 2077 LoadSubCommand("delete", delete_command_object); 2078 LoadSubCommand("list", list_command_object); 2079 } 2080 2081 ~CommandObjectBreakpointName() override = default; 2082 }; 2083 2084 //------------------------------------------------------------------------- 2085 // CommandObjectMultiwordBreakpoint 2086 //------------------------------------------------------------------------- 2087 #pragma mark MultiwordBreakpoint 2088 2089 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint( 2090 CommandInterpreter &interpreter) 2091 : CommandObjectMultiword( 2092 interpreter, "breakpoint", 2093 "Commands for operating on breakpoints (see 'help b' for shorthand.)", 2094 "breakpoint <subcommand> [<command-options>]") { 2095 CommandObjectSP list_command_object( 2096 new CommandObjectBreakpointList(interpreter)); 2097 CommandObjectSP enable_command_object( 2098 new CommandObjectBreakpointEnable(interpreter)); 2099 CommandObjectSP disable_command_object( 2100 new CommandObjectBreakpointDisable(interpreter)); 2101 CommandObjectSP clear_command_object( 2102 new CommandObjectBreakpointClear(interpreter)); 2103 CommandObjectSP delete_command_object( 2104 new CommandObjectBreakpointDelete(interpreter)); 2105 CommandObjectSP set_command_object( 2106 new CommandObjectBreakpointSet(interpreter)); 2107 CommandObjectSP command_command_object( 2108 new CommandObjectBreakpointCommand(interpreter)); 2109 CommandObjectSP modify_command_object( 2110 new CommandObjectBreakpointModify(interpreter)); 2111 CommandObjectSP name_command_object( 2112 new CommandObjectBreakpointName(interpreter)); 2113 2114 list_command_object->SetCommandName("breakpoint list"); 2115 enable_command_object->SetCommandName("breakpoint enable"); 2116 disable_command_object->SetCommandName("breakpoint disable"); 2117 clear_command_object->SetCommandName("breakpoint clear"); 2118 delete_command_object->SetCommandName("breakpoint delete"); 2119 set_command_object->SetCommandName("breakpoint set"); 2120 command_command_object->SetCommandName("breakpoint command"); 2121 modify_command_object->SetCommandName("breakpoint modify"); 2122 name_command_object->SetCommandName("breakpoint name"); 2123 2124 LoadSubCommand("list", list_command_object); 2125 LoadSubCommand("enable", enable_command_object); 2126 LoadSubCommand("disable", disable_command_object); 2127 LoadSubCommand("clear", clear_command_object); 2128 LoadSubCommand("delete", delete_command_object); 2129 LoadSubCommand("set", set_command_object); 2130 LoadSubCommand("command", command_command_object); 2131 LoadSubCommand("modify", modify_command_object); 2132 LoadSubCommand("name", name_command_object); 2133 } 2134 2135 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default; 2136 2137 void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target, 2138 bool allow_locations, 2139 CommandReturnObject &result, 2140 BreakpointIDList *valid_ids) { 2141 // args can be strings representing 1). integers (for breakpoint ids) 2142 // 2). the full breakpoint & location 2143 // canonical representation 2144 // 3). the word "to" or a hyphen, 2145 // representing a range (in which case there 2146 // had *better* be an entry both before & 2147 // after of one of the first two types. 2148 // 4). A breakpoint name 2149 // If args is empty, we will use the last created breakpoint (if there is 2150 // one.) 2151 2152 Args temp_args; 2153 2154 if (args.GetArgumentCount() == 0) { 2155 if (target->GetLastCreatedBreakpoint()) { 2156 valid_ids->AddBreakpointID(BreakpointID( 2157 target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID)); 2158 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2159 } else { 2160 result.AppendError( 2161 "No breakpoint specified and no last created breakpoint."); 2162 result.SetStatus(eReturnStatusFailed); 2163 } 2164 return; 2165 } 2166 2167 // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff 2168 // directly from the old ARGS to 2169 // the new TEMP_ARGS. Do not copy breakpoint id range strings over; instead 2170 // generate a list of strings for 2171 // all the breakpoint ids in the range, and shove all of those breakpoint id 2172 // strings into TEMP_ARGS. 2173 2174 BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations, 2175 result, temp_args); 2176 2177 // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual 2178 // BreakpointIDList: 2179 2180 valid_ids->InsertStringArray(temp_args.GetConstArgumentVector(), 2181 temp_args.GetArgumentCount(), result); 2182 2183 // At this point, all of the breakpoint ids that the user passed in have been 2184 // converted to breakpoint IDs 2185 // and put into valid_ids. 2186 2187 if (result.Succeeded()) { 2188 // Now that we've converted everything from args into a list of breakpoint 2189 // ids, go through our tentative list 2190 // of breakpoint id's and verify that they correspond to valid/currently set 2191 // breakpoints. 2192 2193 const size_t count = valid_ids->GetSize(); 2194 for (size_t i = 0; i < count; ++i) { 2195 BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i); 2196 Breakpoint *breakpoint = 2197 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 2198 if (breakpoint != nullptr) { 2199 const size_t num_locations = breakpoint->GetNumLocations(); 2200 if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) { 2201 StreamString id_str; 2202 BreakpointID::GetCanonicalReference( 2203 &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); 2204 i = valid_ids->GetSize() + 1; 2205 result.AppendErrorWithFormat( 2206 "'%s' is not a currently valid breakpoint/location id.\n", 2207 id_str.GetData()); 2208 result.SetStatus(eReturnStatusFailed); 2209 } 2210 } else { 2211 i = valid_ids->GetSize() + 1; 2212 result.AppendErrorWithFormat( 2213 "'%d' is not a currently valid breakpoint ID.\n", 2214 cur_bp_id.GetBreakpointID()); 2215 result.SetStatus(eReturnStatusFailed); 2216 } 2217 } 2218 } 2219 } 2220