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