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