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