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