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