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 // clang-format off 1250 { LLDB_OPT_SET_ALL, false, "internal", 'i', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Show debugger internal breakpoints" }, 1251 { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Give a brief description of the breakpoint (no location info)." }, 1252 // FIXME: We need to add an "internal" command, and then add this sort of thing to it. 1253 // But I need to see it for now, and don't want to wait. 1254 { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Give a full description of the breakpoint and its locations." }, 1255 { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Explain everything we know about the breakpoint (for debugging debugger bugs)." }, 1256 { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "List Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." }, 1257 // clang-format on 1258 }; 1259 1260 #pragma mark List 1261 1262 class CommandObjectBreakpointList : public CommandObjectParsed { 1263 public: 1264 CommandObjectBreakpointList(CommandInterpreter &interpreter) 1265 : CommandObjectParsed( 1266 interpreter, "breakpoint list", 1267 "List some or all breakpoints at configurable levels of detail.", 1268 nullptr), 1269 m_options() { 1270 CommandArgumentEntry arg; 1271 CommandArgumentData bp_id_arg; 1272 1273 // Define the first (and only) variant of this arg. 1274 bp_id_arg.arg_type = eArgTypeBreakpointID; 1275 bp_id_arg.arg_repetition = eArgRepeatOptional; 1276 1277 // There is only one variant this argument could be; put it into the 1278 // argument entry. 1279 arg.push_back(bp_id_arg); 1280 1281 // Push the data for the first argument into the m_arguments vector. 1282 m_arguments.push_back(arg); 1283 } 1284 1285 ~CommandObjectBreakpointList() override = default; 1286 1287 Options *GetOptions() override { return &m_options; } 1288 1289 class CommandOptions : public Options { 1290 public: 1291 CommandOptions() 1292 : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) { 1293 } 1294 1295 ~CommandOptions() override = default; 1296 1297 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1298 ExecutionContext *execution_context) override { 1299 Status error; 1300 const int short_option = m_getopt_table[option_idx].val; 1301 1302 switch (short_option) { 1303 case 'b': 1304 m_level = lldb::eDescriptionLevelBrief; 1305 break; 1306 case 'D': 1307 m_use_dummy = true; 1308 break; 1309 case 'f': 1310 m_level = lldb::eDescriptionLevelFull; 1311 break; 1312 case 'v': 1313 m_level = lldb::eDescriptionLevelVerbose; 1314 break; 1315 case 'i': 1316 m_internal = true; 1317 break; 1318 default: 1319 error.SetErrorStringWithFormat("unrecognized option '%c'", 1320 short_option); 1321 break; 1322 } 1323 1324 return error; 1325 } 1326 1327 void OptionParsingStarting(ExecutionContext *execution_context) override { 1328 m_level = lldb::eDescriptionLevelFull; 1329 m_internal = false; 1330 m_use_dummy = false; 1331 } 1332 1333 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1334 return llvm::makeArrayRef(g_breakpoint_list_options); 1335 } 1336 1337 // Instance variables to hold the values for command options. 1338 1339 lldb::DescriptionLevel m_level; 1340 1341 bool m_internal; 1342 bool m_use_dummy; 1343 }; 1344 1345 protected: 1346 bool DoExecute(Args &command, CommandReturnObject &result) override { 1347 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1348 1349 if (target == nullptr) { 1350 result.AppendError("Invalid target. No current target or breakpoints."); 1351 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1352 return true; 1353 } 1354 1355 const BreakpointList &breakpoints = 1356 target->GetBreakpointList(m_options.m_internal); 1357 std::unique_lock<std::recursive_mutex> lock; 1358 target->GetBreakpointList(m_options.m_internal).GetListMutex(lock); 1359 1360 size_t num_breakpoints = breakpoints.GetSize(); 1361 1362 if (num_breakpoints == 0) { 1363 result.AppendMessage("No breakpoints currently set."); 1364 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1365 return true; 1366 } 1367 1368 Stream &output_stream = result.GetOutputStream(); 1369 1370 if (command.empty()) { 1371 // No breakpoint selected; show info about all currently set breakpoints. 1372 result.AppendMessage("Current breakpoints:"); 1373 for (size_t i = 0; i < num_breakpoints; ++i) { 1374 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get(); 1375 if (breakpoint->AllowList()) 1376 AddBreakpointDescription(&output_stream, breakpoint, 1377 m_options.m_level); 1378 } 1379 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1380 } else { 1381 // Particular breakpoints selected; show info about that breakpoint. 1382 BreakpointIDList valid_bp_ids; 1383 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1384 command, target, result, &valid_bp_ids, 1385 BreakpointName::Permissions::PermissionKinds::listPerm); 1386 1387 if (result.Succeeded()) { 1388 for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) { 1389 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1390 Breakpoint *breakpoint = 1391 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1392 AddBreakpointDescription(&output_stream, breakpoint, 1393 m_options.m_level); 1394 } 1395 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1396 } else { 1397 result.AppendError("Invalid breakpoint ID."); 1398 result.SetStatus(eReturnStatusFailed); 1399 } 1400 } 1401 1402 return result.Succeeded(); 1403 } 1404 1405 private: 1406 CommandOptions m_options; 1407 }; 1408 1409 // CommandObjectBreakpointClear 1410 #pragma mark Clear::CommandOptions 1411 1412 static constexpr OptionDefinition g_breakpoint_clear_options[] = { 1413 // clang-format off 1414 { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specify the breakpoint by source location in this particular file." }, 1415 { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeLineNum, "Specify the breakpoint by source location at this particular line." } 1416 // clang-format on 1417 }; 1418 1419 #pragma mark Clear 1420 1421 class CommandObjectBreakpointClear : public CommandObjectParsed { 1422 public: 1423 enum BreakpointClearType { eClearTypeInvalid, eClearTypeFileAndLine }; 1424 1425 CommandObjectBreakpointClear(CommandInterpreter &interpreter) 1426 : CommandObjectParsed(interpreter, "breakpoint clear", 1427 "Delete or disable breakpoints matching the " 1428 "specified source file and line.", 1429 "breakpoint clear <cmd-options>"), 1430 m_options() {} 1431 1432 ~CommandObjectBreakpointClear() override = default; 1433 1434 Options *GetOptions() override { return &m_options; } 1435 1436 class CommandOptions : public Options { 1437 public: 1438 CommandOptions() : Options(), m_filename(), m_line_num(0) {} 1439 1440 ~CommandOptions() override = default; 1441 1442 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1443 ExecutionContext *execution_context) override { 1444 Status error; 1445 const int short_option = m_getopt_table[option_idx].val; 1446 1447 switch (short_option) { 1448 case 'f': 1449 m_filename.assign(option_arg); 1450 break; 1451 1452 case 'l': 1453 option_arg.getAsInteger(0, m_line_num); 1454 break; 1455 1456 default: 1457 error.SetErrorStringWithFormat("unrecognized option '%c'", 1458 short_option); 1459 break; 1460 } 1461 1462 return error; 1463 } 1464 1465 void OptionParsingStarting(ExecutionContext *execution_context) override { 1466 m_filename.clear(); 1467 m_line_num = 0; 1468 } 1469 1470 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1471 return llvm::makeArrayRef(g_breakpoint_clear_options); 1472 } 1473 1474 // Instance variables to hold the values for command options. 1475 1476 std::string m_filename; 1477 uint32_t m_line_num; 1478 }; 1479 1480 protected: 1481 bool DoExecute(Args &command, CommandReturnObject &result) override { 1482 Target *target = GetSelectedOrDummyTarget(); 1483 if (target == nullptr) { 1484 result.AppendError("Invalid target. No existing target or breakpoints."); 1485 result.SetStatus(eReturnStatusFailed); 1486 return false; 1487 } 1488 1489 // The following are the various types of breakpoints that could be 1490 // cleared: 1491 // 1). -f -l (clearing breakpoint by source location) 1492 1493 BreakpointClearType break_type = eClearTypeInvalid; 1494 1495 if (m_options.m_line_num != 0) 1496 break_type = eClearTypeFileAndLine; 1497 1498 std::unique_lock<std::recursive_mutex> lock; 1499 target->GetBreakpointList().GetListMutex(lock); 1500 1501 BreakpointList &breakpoints = target->GetBreakpointList(); 1502 size_t num_breakpoints = breakpoints.GetSize(); 1503 1504 // Early return if there's no breakpoint at all. 1505 if (num_breakpoints == 0) { 1506 result.AppendError("Breakpoint clear: No breakpoint cleared."); 1507 result.SetStatus(eReturnStatusFailed); 1508 return result.Succeeded(); 1509 } 1510 1511 // Find matching breakpoints and delete them. 1512 1513 // First create a copy of all the IDs. 1514 std::vector<break_id_t> BreakIDs; 1515 for (size_t i = 0; i < num_breakpoints; ++i) 1516 BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID()); 1517 1518 int num_cleared = 0; 1519 StreamString ss; 1520 switch (break_type) { 1521 case eClearTypeFileAndLine: // Breakpoint by source position 1522 { 1523 const ConstString filename(m_options.m_filename.c_str()); 1524 BreakpointLocationCollection loc_coll; 1525 1526 for (size_t i = 0; i < num_breakpoints; ++i) { 1527 Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get(); 1528 1529 if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) { 1530 // If the collection size is 0, it's a full match and we can just 1531 // remove the breakpoint. 1532 if (loc_coll.GetSize() == 0) { 1533 bp->GetDescription(&ss, lldb::eDescriptionLevelBrief); 1534 ss.EOL(); 1535 target->RemoveBreakpointByID(bp->GetID()); 1536 ++num_cleared; 1537 } 1538 } 1539 } 1540 } break; 1541 1542 default: 1543 break; 1544 } 1545 1546 if (num_cleared > 0) { 1547 Stream &output_stream = result.GetOutputStream(); 1548 output_stream.Printf("%d breakpoints cleared:\n", num_cleared); 1549 output_stream << ss.GetString(); 1550 output_stream.EOL(); 1551 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1552 } else { 1553 result.AppendError("Breakpoint clear: No breakpoint cleared."); 1554 result.SetStatus(eReturnStatusFailed); 1555 } 1556 1557 return result.Succeeded(); 1558 } 1559 1560 private: 1561 CommandOptions m_options; 1562 }; 1563 1564 // CommandObjectBreakpointDelete 1565 static constexpr OptionDefinition g_breakpoint_delete_options[] = { 1566 // clang-format off 1567 { LLDB_OPT_SET_1, false, "force", 'f', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Delete all breakpoints without querying for confirmation." }, 1568 { 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." }, 1569 // clang-format on 1570 }; 1571 1572 #pragma mark Delete 1573 1574 class CommandObjectBreakpointDelete : public CommandObjectParsed { 1575 public: 1576 CommandObjectBreakpointDelete(CommandInterpreter &interpreter) 1577 : CommandObjectParsed(interpreter, "breakpoint delete", 1578 "Delete the specified breakpoint(s). If no " 1579 "breakpoints are specified, delete them all.", 1580 nullptr), 1581 m_options() { 1582 CommandArgumentEntry arg; 1583 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1584 eArgTypeBreakpointIDRange); 1585 // Add the entry for the first argument for this command to the object's 1586 // arguments vector. 1587 m_arguments.push_back(arg); 1588 } 1589 1590 ~CommandObjectBreakpointDelete() override = default; 1591 1592 Options *GetOptions() override { return &m_options; } 1593 1594 class CommandOptions : public Options { 1595 public: 1596 CommandOptions() : Options(), m_use_dummy(false), m_force(false) {} 1597 1598 ~CommandOptions() override = default; 1599 1600 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1601 ExecutionContext *execution_context) override { 1602 Status error; 1603 const int short_option = m_getopt_table[option_idx].val; 1604 1605 switch (short_option) { 1606 case 'f': 1607 m_force = true; 1608 break; 1609 1610 case 'D': 1611 m_use_dummy = true; 1612 break; 1613 1614 default: 1615 error.SetErrorStringWithFormat("unrecognized option '%c'", 1616 short_option); 1617 break; 1618 } 1619 1620 return error; 1621 } 1622 1623 void OptionParsingStarting(ExecutionContext *execution_context) override { 1624 m_use_dummy = false; 1625 m_force = false; 1626 } 1627 1628 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1629 return llvm::makeArrayRef(g_breakpoint_delete_options); 1630 } 1631 1632 // Instance variables to hold the values for command options. 1633 bool m_use_dummy; 1634 bool m_force; 1635 }; 1636 1637 protected: 1638 bool DoExecute(Args &command, CommandReturnObject &result) override { 1639 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1640 1641 if (target == nullptr) { 1642 result.AppendError("Invalid target. No existing target or breakpoints."); 1643 result.SetStatus(eReturnStatusFailed); 1644 return false; 1645 } 1646 1647 std::unique_lock<std::recursive_mutex> lock; 1648 target->GetBreakpointList().GetListMutex(lock); 1649 1650 const BreakpointList &breakpoints = target->GetBreakpointList(); 1651 1652 size_t num_breakpoints = breakpoints.GetSize(); 1653 1654 if (num_breakpoints == 0) { 1655 result.AppendError("No breakpoints exist to be deleted."); 1656 result.SetStatus(eReturnStatusFailed); 1657 return false; 1658 } 1659 1660 if (command.empty()) { 1661 if (!m_options.m_force && 1662 !m_interpreter.Confirm( 1663 "About to delete all breakpoints, do you want to do that?", 1664 true)) { 1665 result.AppendMessage("Operation cancelled..."); 1666 } else { 1667 target->RemoveAllowedBreakpoints(); 1668 result.AppendMessageWithFormat( 1669 "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n", 1670 (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : ""); 1671 } 1672 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1673 } else { 1674 // Particular breakpoint selected; disable that breakpoint. 1675 BreakpointIDList valid_bp_ids; 1676 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1677 command, target, result, &valid_bp_ids, 1678 BreakpointName::Permissions::PermissionKinds::deletePerm); 1679 1680 if (result.Succeeded()) { 1681 int delete_count = 0; 1682 int disable_count = 0; 1683 const size_t count = valid_bp_ids.GetSize(); 1684 for (size_t i = 0; i < count; ++i) { 1685 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1686 1687 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1688 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1689 Breakpoint *breakpoint = 1690 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1691 BreakpointLocation *location = 1692 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1693 // It makes no sense to try to delete individual locations, so we 1694 // disable them instead. 1695 if (location) { 1696 location->SetEnabled(false); 1697 ++disable_count; 1698 } 1699 } else { 1700 target->RemoveBreakpointByID(cur_bp_id.GetBreakpointID()); 1701 ++delete_count; 1702 } 1703 } 1704 } 1705 result.AppendMessageWithFormat( 1706 "%d breakpoints deleted; %d breakpoint locations disabled.\n", 1707 delete_count, disable_count); 1708 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1709 } 1710 } 1711 return result.Succeeded(); 1712 } 1713 1714 private: 1715 CommandOptions m_options; 1716 }; 1717 1718 // CommandObjectBreakpointName 1719 1720 static constexpr OptionDefinition g_breakpoint_name_options[] = { 1721 // clang-format off 1722 {LLDB_OPT_SET_1, false, "name", 'N', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."}, 1723 {LLDB_OPT_SET_2, false, "breakpoint-id", 'B', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBreakpointID, "Specify a breakpoint ID to use."}, 1724 {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."}, 1725 {LLDB_OPT_SET_4, false, "help-string", 'H', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNone, "A help string describing the purpose of this name."}, 1726 // clang-format on 1727 }; 1728 class BreakpointNameOptionGroup : public OptionGroup { 1729 public: 1730 BreakpointNameOptionGroup() 1731 : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) { 1732 } 1733 1734 ~BreakpointNameOptionGroup() override = default; 1735 1736 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1737 return llvm::makeArrayRef(g_breakpoint_name_options); 1738 } 1739 1740 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1741 ExecutionContext *execution_context) override { 1742 Status error; 1743 const int short_option = g_breakpoint_name_options[option_idx].short_option; 1744 1745 switch (short_option) { 1746 case 'N': 1747 if (BreakpointID::StringIsBreakpointName(option_arg, error) && 1748 error.Success()) 1749 m_name.SetValueFromString(option_arg); 1750 break; 1751 case 'B': 1752 if (m_breakpoint.SetValueFromString(option_arg).Fail()) 1753 error.SetErrorStringWithFormat( 1754 "unrecognized value \"%s\" for breakpoint", 1755 option_arg.str().c_str()); 1756 break; 1757 case 'D': 1758 if (m_use_dummy.SetValueFromString(option_arg).Fail()) 1759 error.SetErrorStringWithFormat( 1760 "unrecognized value \"%s\" for use-dummy", 1761 option_arg.str().c_str()); 1762 break; 1763 case 'H': 1764 m_help_string.SetValueFromString(option_arg); 1765 break; 1766 1767 default: 1768 error.SetErrorStringWithFormat("unrecognized short option '%c'", 1769 short_option); 1770 break; 1771 } 1772 return error; 1773 } 1774 1775 void OptionParsingStarting(ExecutionContext *execution_context) override { 1776 m_name.Clear(); 1777 m_breakpoint.Clear(); 1778 m_use_dummy.Clear(); 1779 m_use_dummy.SetDefaultValue(false); 1780 m_help_string.Clear(); 1781 } 1782 1783 OptionValueString m_name; 1784 OptionValueUInt64 m_breakpoint; 1785 OptionValueBoolean m_use_dummy; 1786 OptionValueString m_help_string; 1787 }; 1788 1789 static constexpr OptionDefinition g_breakpoint_access_options[] = { 1790 // clang-format off 1791 {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."}, 1792 {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."}, 1793 {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."}, 1794 // clang-format on 1795 }; 1796 1797 class BreakpointAccessOptionGroup : public OptionGroup { 1798 public: 1799 BreakpointAccessOptionGroup() : OptionGroup() {} 1800 1801 ~BreakpointAccessOptionGroup() override = default; 1802 1803 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1804 return llvm::makeArrayRef(g_breakpoint_access_options); 1805 } 1806 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1807 ExecutionContext *execution_context) override { 1808 Status error; 1809 const int short_option 1810 = g_breakpoint_access_options[option_idx].short_option; 1811 1812 switch (short_option) { 1813 case 'L': { 1814 bool value, success; 1815 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1816 if (success) { 1817 m_permissions.SetAllowList(value); 1818 } else 1819 error.SetErrorStringWithFormat( 1820 "invalid boolean value '%s' passed for -L option", 1821 option_arg.str().c_str()); 1822 } break; 1823 case 'A': { 1824 bool value, success; 1825 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1826 if (success) { 1827 m_permissions.SetAllowDisable(value); 1828 } else 1829 error.SetErrorStringWithFormat( 1830 "invalid boolean value '%s' passed for -L option", 1831 option_arg.str().c_str()); 1832 } break; 1833 case 'D': { 1834 bool value, success; 1835 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1836 if (success) { 1837 m_permissions.SetAllowDelete(value); 1838 } else 1839 error.SetErrorStringWithFormat( 1840 "invalid boolean value '%s' passed for -L option", 1841 option_arg.str().c_str()); 1842 } break; 1843 1844 } 1845 1846 return error; 1847 } 1848 1849 void OptionParsingStarting(ExecutionContext *execution_context) override { 1850 } 1851 1852 const BreakpointName::Permissions &GetPermissions() const 1853 { 1854 return m_permissions; 1855 } 1856 BreakpointName::Permissions m_permissions; 1857 }; 1858 1859 class CommandObjectBreakpointNameConfigure : public CommandObjectParsed { 1860 public: 1861 CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter) 1862 : CommandObjectParsed( 1863 interpreter, "configure", "Configure the options for the breakpoint" 1864 " name provided. " 1865 "If you provide a breakpoint id, the options will be copied from " 1866 "the breakpoint, otherwise only the options specified will be set " 1867 "on the name.", 1868 "breakpoint name configure <command-options> " 1869 "<breakpoint-name-list>"), 1870 m_bp_opts(), m_option_group() { 1871 // Create the first variant for the first (and only) argument for this 1872 // command. 1873 CommandArgumentEntry arg1; 1874 CommandArgumentData id_arg; 1875 id_arg.arg_type = eArgTypeBreakpointName; 1876 id_arg.arg_repetition = eArgRepeatOptional; 1877 arg1.push_back(id_arg); 1878 m_arguments.push_back(arg1); 1879 1880 m_option_group.Append(&m_bp_opts, 1881 LLDB_OPT_SET_ALL, 1882 LLDB_OPT_SET_1); 1883 m_option_group.Append(&m_access_options, 1884 LLDB_OPT_SET_ALL, 1885 LLDB_OPT_SET_ALL); 1886 m_option_group.Append(&m_bp_id, 1887 LLDB_OPT_SET_2|LLDB_OPT_SET_4, 1888 LLDB_OPT_SET_ALL); 1889 m_option_group.Finalize(); 1890 } 1891 1892 ~CommandObjectBreakpointNameConfigure() override = default; 1893 1894 Options *GetOptions() override { return &m_option_group; } 1895 1896 protected: 1897 bool DoExecute(Args &command, CommandReturnObject &result) override { 1898 1899 const size_t argc = command.GetArgumentCount(); 1900 if (argc == 0) { 1901 result.AppendError("No names provided."); 1902 result.SetStatus(eReturnStatusFailed); 1903 return false; 1904 } 1905 1906 Target *target = 1907 GetSelectedOrDummyTarget(false); 1908 1909 if (target == nullptr) { 1910 result.AppendError("Invalid target. No existing target or breakpoints."); 1911 result.SetStatus(eReturnStatusFailed); 1912 return false; 1913 } 1914 1915 std::unique_lock<std::recursive_mutex> lock; 1916 target->GetBreakpointList().GetListMutex(lock); 1917 1918 // Make a pass through first to see that all the names are legal. 1919 for (auto &entry : command.entries()) { 1920 Status error; 1921 if (!BreakpointID::StringIsBreakpointName(entry.ref, error)) 1922 { 1923 result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s", 1924 entry.c_str(), error.AsCString()); 1925 result.SetStatus(eReturnStatusFailed); 1926 return false; 1927 } 1928 } 1929 // Now configure them, we already pre-checked the names so we don't need to 1930 // check the error: 1931 BreakpointSP bp_sp; 1932 if (m_bp_id.m_breakpoint.OptionWasSet()) 1933 { 1934 lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value(); 1935 bp_sp = target->GetBreakpointByID(bp_id); 1936 if (!bp_sp) 1937 { 1938 result.AppendErrorWithFormatv("Could not find specified breakpoint {0}", 1939 bp_id); 1940 result.SetStatus(eReturnStatusFailed); 1941 return false; 1942 } 1943 } 1944 1945 Status error; 1946 for (auto &entry : command.entries()) { 1947 ConstString name(entry.c_str()); 1948 BreakpointName *bp_name = target->FindBreakpointName(name, true, error); 1949 if (!bp_name) 1950 continue; 1951 if (m_bp_id.m_help_string.OptionWasSet()) 1952 bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str()); 1953 1954 if (bp_sp) 1955 target->ConfigureBreakpointName(*bp_name, 1956 *bp_sp->GetOptions(), 1957 m_access_options.GetPermissions()); 1958 else 1959 target->ConfigureBreakpointName(*bp_name, 1960 m_bp_opts.GetBreakpointOptions(), 1961 m_access_options.GetPermissions()); 1962 } 1963 return true; 1964 } 1965 1966 private: 1967 BreakpointNameOptionGroup m_bp_id; // Only using the id part of this. 1968 BreakpointOptionGroup m_bp_opts; 1969 BreakpointAccessOptionGroup m_access_options; 1970 OptionGroupOptions m_option_group; 1971 }; 1972 1973 class CommandObjectBreakpointNameAdd : public CommandObjectParsed { 1974 public: 1975 CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter) 1976 : CommandObjectParsed( 1977 interpreter, "add", "Add a name to the breakpoints provided.", 1978 "breakpoint name add <command-options> <breakpoint-id-list>"), 1979 m_name_options(), m_option_group() { 1980 // Create the first variant for the first (and only) argument for this 1981 // command. 1982 CommandArgumentEntry arg1; 1983 CommandArgumentData id_arg; 1984 id_arg.arg_type = eArgTypeBreakpointID; 1985 id_arg.arg_repetition = eArgRepeatOptional; 1986 arg1.push_back(id_arg); 1987 m_arguments.push_back(arg1); 1988 1989 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 1990 m_option_group.Finalize(); 1991 } 1992 1993 ~CommandObjectBreakpointNameAdd() override = default; 1994 1995 Options *GetOptions() override { return &m_option_group; } 1996 1997 protected: 1998 bool DoExecute(Args &command, CommandReturnObject &result) override { 1999 if (!m_name_options.m_name.OptionWasSet()) { 2000 result.SetError("No name option provided."); 2001 return false; 2002 } 2003 2004 Target *target = 2005 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 2006 2007 if (target == nullptr) { 2008 result.AppendError("Invalid target. No existing target or breakpoints."); 2009 result.SetStatus(eReturnStatusFailed); 2010 return false; 2011 } 2012 2013 std::unique_lock<std::recursive_mutex> lock; 2014 target->GetBreakpointList().GetListMutex(lock); 2015 2016 const BreakpointList &breakpoints = target->GetBreakpointList(); 2017 2018 size_t num_breakpoints = breakpoints.GetSize(); 2019 if (num_breakpoints == 0) { 2020 result.SetError("No breakpoints, cannot add names."); 2021 result.SetStatus(eReturnStatusFailed); 2022 return false; 2023 } 2024 2025 // Particular breakpoint selected; disable that breakpoint. 2026 BreakpointIDList valid_bp_ids; 2027 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 2028 command, target, result, &valid_bp_ids, 2029 BreakpointName::Permissions::PermissionKinds::listPerm); 2030 2031 if (result.Succeeded()) { 2032 if (valid_bp_ids.GetSize() == 0) { 2033 result.SetError("No breakpoints specified, cannot add names."); 2034 result.SetStatus(eReturnStatusFailed); 2035 return false; 2036 } 2037 size_t num_valid_ids = valid_bp_ids.GetSize(); 2038 const char *bp_name = m_name_options.m_name.GetCurrentValue(); 2039 Status error; // This error reports illegal names, but we've already 2040 // checked that, so we don't need to check it again here. 2041 for (size_t index = 0; index < num_valid_ids; index++) { 2042 lldb::break_id_t bp_id = 2043 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); 2044 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); 2045 target->AddNameToBreakpoint(bp_sp, bp_name, error); 2046 } 2047 } 2048 2049 return true; 2050 } 2051 2052 private: 2053 BreakpointNameOptionGroup m_name_options; 2054 OptionGroupOptions m_option_group; 2055 }; 2056 2057 class CommandObjectBreakpointNameDelete : public CommandObjectParsed { 2058 public: 2059 CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter) 2060 : CommandObjectParsed( 2061 interpreter, "delete", 2062 "Delete a name from the breakpoints provided.", 2063 "breakpoint name delete <command-options> <breakpoint-id-list>"), 2064 m_name_options(), m_option_group() { 2065 // Create the first variant for the first (and only) argument for this 2066 // command. 2067 CommandArgumentEntry arg1; 2068 CommandArgumentData id_arg; 2069 id_arg.arg_type = eArgTypeBreakpointID; 2070 id_arg.arg_repetition = eArgRepeatOptional; 2071 arg1.push_back(id_arg); 2072 m_arguments.push_back(arg1); 2073 2074 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 2075 m_option_group.Finalize(); 2076 } 2077 2078 ~CommandObjectBreakpointNameDelete() override = default; 2079 2080 Options *GetOptions() override { return &m_option_group; } 2081 2082 protected: 2083 bool DoExecute(Args &command, CommandReturnObject &result) override { 2084 if (!m_name_options.m_name.OptionWasSet()) { 2085 result.SetError("No name option provided."); 2086 return false; 2087 } 2088 2089 Target *target = 2090 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 2091 2092 if (target == nullptr) { 2093 result.AppendError("Invalid target. No existing target or breakpoints."); 2094 result.SetStatus(eReturnStatusFailed); 2095 return false; 2096 } 2097 2098 std::unique_lock<std::recursive_mutex> lock; 2099 target->GetBreakpointList().GetListMutex(lock); 2100 2101 const BreakpointList &breakpoints = target->GetBreakpointList(); 2102 2103 size_t num_breakpoints = breakpoints.GetSize(); 2104 if (num_breakpoints == 0) { 2105 result.SetError("No breakpoints, cannot delete names."); 2106 result.SetStatus(eReturnStatusFailed); 2107 return false; 2108 } 2109 2110 // Particular breakpoint selected; disable that breakpoint. 2111 BreakpointIDList valid_bp_ids; 2112 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 2113 command, target, result, &valid_bp_ids, 2114 BreakpointName::Permissions::PermissionKinds::deletePerm); 2115 2116 if (result.Succeeded()) { 2117 if (valid_bp_ids.GetSize() == 0) { 2118 result.SetError("No breakpoints specified, cannot delete names."); 2119 result.SetStatus(eReturnStatusFailed); 2120 return false; 2121 } 2122 ConstString bp_name(m_name_options.m_name.GetCurrentValue()); 2123 size_t num_valid_ids = valid_bp_ids.GetSize(); 2124 for (size_t index = 0; index < num_valid_ids; index++) { 2125 lldb::break_id_t bp_id = 2126 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); 2127 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); 2128 target->RemoveNameFromBreakpoint(bp_sp, bp_name); 2129 } 2130 } 2131 2132 return true; 2133 } 2134 2135 private: 2136 BreakpointNameOptionGroup m_name_options; 2137 OptionGroupOptions m_option_group; 2138 }; 2139 2140 class CommandObjectBreakpointNameList : public CommandObjectParsed { 2141 public: 2142 CommandObjectBreakpointNameList(CommandInterpreter &interpreter) 2143 : CommandObjectParsed(interpreter, "list", 2144 "List either the names for a breakpoint or info " 2145 "about a given name. With no arguments, lists all " 2146 "names", 2147 "breakpoint name list <command-options>"), 2148 m_name_options(), m_option_group() { 2149 m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL); 2150 m_option_group.Finalize(); 2151 } 2152 2153 ~CommandObjectBreakpointNameList() override = default; 2154 2155 Options *GetOptions() override { return &m_option_group; } 2156 2157 protected: 2158 bool DoExecute(Args &command, CommandReturnObject &result) override { 2159 Target *target = 2160 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 2161 2162 if (target == nullptr) { 2163 result.AppendError("Invalid target. No existing target or breakpoints."); 2164 result.SetStatus(eReturnStatusFailed); 2165 return false; 2166 } 2167 2168 2169 std::vector<std::string> name_list; 2170 if (command.empty()) { 2171 target->GetBreakpointNames(name_list); 2172 } else { 2173 for (const Args::ArgEntry &arg : command) 2174 { 2175 name_list.push_back(arg.c_str()); 2176 } 2177 } 2178 2179 if (name_list.empty()) { 2180 result.AppendMessage("No breakpoint names found."); 2181 } else { 2182 for (const std::string &name_str : name_list) { 2183 const char *name = name_str.c_str(); 2184 // First print out the options for the name: 2185 Status error; 2186 BreakpointName *bp_name = target->FindBreakpointName(ConstString(name), 2187 false, 2188 error); 2189 if (bp_name) 2190 { 2191 StreamString s; 2192 result.AppendMessageWithFormat("Name: %s\n", name); 2193 if (bp_name->GetDescription(&s, eDescriptionLevelFull)) 2194 { 2195 result.AppendMessage(s.GetString()); 2196 } 2197 2198 std::unique_lock<std::recursive_mutex> lock; 2199 target->GetBreakpointList().GetListMutex(lock); 2200 2201 BreakpointList &breakpoints = target->GetBreakpointList(); 2202 bool any_set = false; 2203 for (BreakpointSP bp_sp : breakpoints.Breakpoints()) { 2204 if (bp_sp->MatchesName(name)) { 2205 StreamString s; 2206 any_set = true; 2207 bp_sp->GetDescription(&s, eDescriptionLevelBrief); 2208 s.EOL(); 2209 result.AppendMessage(s.GetString()); 2210 } 2211 } 2212 if (!any_set) 2213 result.AppendMessage("No breakpoints using this name."); 2214 } else { 2215 result.AppendMessageWithFormat("Name: %s not found.\n", name); 2216 } 2217 } 2218 } 2219 return true; 2220 } 2221 2222 private: 2223 BreakpointNameOptionGroup m_name_options; 2224 OptionGroupOptions m_option_group; 2225 }; 2226 2227 // CommandObjectBreakpointName 2228 class CommandObjectBreakpointName : public CommandObjectMultiword { 2229 public: 2230 CommandObjectBreakpointName(CommandInterpreter &interpreter) 2231 : CommandObjectMultiword( 2232 interpreter, "name", "Commands to manage name tags for breakpoints", 2233 "breakpoint name <subcommand> [<command-options>]") { 2234 CommandObjectSP add_command_object( 2235 new CommandObjectBreakpointNameAdd(interpreter)); 2236 CommandObjectSP delete_command_object( 2237 new CommandObjectBreakpointNameDelete(interpreter)); 2238 CommandObjectSP list_command_object( 2239 new CommandObjectBreakpointNameList(interpreter)); 2240 CommandObjectSP configure_command_object( 2241 new CommandObjectBreakpointNameConfigure(interpreter)); 2242 2243 LoadSubCommand("add", add_command_object); 2244 LoadSubCommand("delete", delete_command_object); 2245 LoadSubCommand("list", list_command_object); 2246 LoadSubCommand("configure", configure_command_object); 2247 } 2248 2249 ~CommandObjectBreakpointName() override = default; 2250 }; 2251 2252 // CommandObjectBreakpointRead 2253 #pragma mark Read::CommandOptions 2254 static constexpr OptionDefinition g_breakpoint_read_options[] = { 2255 // clang-format off 2256 {LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file from which to read the breakpoints." }, 2257 {LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBreakpointName, "Only read in breakpoints with this name."}, 2258 // clang-format on 2259 }; 2260 2261 #pragma mark Read 2262 2263 class CommandObjectBreakpointRead : public CommandObjectParsed { 2264 public: 2265 CommandObjectBreakpointRead(CommandInterpreter &interpreter) 2266 : CommandObjectParsed(interpreter, "breakpoint read", 2267 "Read and set the breakpoints previously saved to " 2268 "a file with \"breakpoint write\". ", 2269 nullptr), 2270 m_options() { 2271 CommandArgumentEntry arg; 2272 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 2273 eArgTypeBreakpointIDRange); 2274 // Add the entry for the first argument for this command to the object's 2275 // arguments vector. 2276 m_arguments.push_back(arg); 2277 } 2278 2279 ~CommandObjectBreakpointRead() override = default; 2280 2281 Options *GetOptions() override { return &m_options; } 2282 2283 class CommandOptions : public Options { 2284 public: 2285 CommandOptions() : Options() {} 2286 2287 ~CommandOptions() override = default; 2288 2289 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2290 ExecutionContext *execution_context) override { 2291 Status error; 2292 const int short_option = m_getopt_table[option_idx].val; 2293 2294 switch (short_option) { 2295 case 'f': 2296 m_filename.assign(option_arg); 2297 break; 2298 case 'N': { 2299 Status name_error; 2300 if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg), 2301 name_error)) { 2302 error.SetErrorStringWithFormat("Invalid breakpoint name: %s", 2303 name_error.AsCString()); 2304 } 2305 m_names.push_back(option_arg); 2306 break; 2307 } 2308 default: 2309 error.SetErrorStringWithFormat("unrecognized option '%c'", 2310 short_option); 2311 break; 2312 } 2313 2314 return error; 2315 } 2316 2317 void OptionParsingStarting(ExecutionContext *execution_context) override { 2318 m_filename.clear(); 2319 m_names.clear(); 2320 } 2321 2322 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2323 return llvm::makeArrayRef(g_breakpoint_read_options); 2324 } 2325 2326 // Instance variables to hold the values for command options. 2327 2328 std::string m_filename; 2329 std::vector<std::string> m_names; 2330 }; 2331 2332 protected: 2333 bool DoExecute(Args &command, CommandReturnObject &result) override { 2334 Target *target = GetSelectedOrDummyTarget(); 2335 if (target == nullptr) { 2336 result.AppendError("Invalid target. No existing target or breakpoints."); 2337 result.SetStatus(eReturnStatusFailed); 2338 return false; 2339 } 2340 2341 std::unique_lock<std::recursive_mutex> lock; 2342 target->GetBreakpointList().GetListMutex(lock); 2343 2344 FileSpec input_spec(m_options.m_filename); 2345 FileSystem::Instance().Resolve(input_spec); 2346 BreakpointIDList new_bps; 2347 Status error = target->CreateBreakpointsFromFile( 2348 input_spec, m_options.m_names, new_bps); 2349 2350 if (!error.Success()) { 2351 result.AppendError(error.AsCString()); 2352 result.SetStatus(eReturnStatusFailed); 2353 return false; 2354 } 2355 2356 Stream &output_stream = result.GetOutputStream(); 2357 2358 size_t num_breakpoints = new_bps.GetSize(); 2359 if (num_breakpoints == 0) { 2360 result.AppendMessage("No breakpoints added."); 2361 } else { 2362 // No breakpoint selected; show info about all currently set breakpoints. 2363 result.AppendMessage("New breakpoints:"); 2364 for (size_t i = 0; i < num_breakpoints; ++i) { 2365 BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i); 2366 Breakpoint *bp = target->GetBreakpointList() 2367 .FindBreakpointByID(bp_id.GetBreakpointID()) 2368 .get(); 2369 if (bp) 2370 bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, 2371 false); 2372 } 2373 } 2374 return result.Succeeded(); 2375 } 2376 2377 private: 2378 CommandOptions m_options; 2379 }; 2380 2381 // CommandObjectBreakpointWrite 2382 #pragma mark Write::CommandOptions 2383 static constexpr OptionDefinition g_breakpoint_write_options[] = { 2384 // clang-format off 2385 { LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file into which to write the breakpoints." }, 2386 { LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Append to saved breakpoints file if it exists."}, 2387 // clang-format on 2388 }; 2389 2390 #pragma mark Write 2391 class CommandObjectBreakpointWrite : public CommandObjectParsed { 2392 public: 2393 CommandObjectBreakpointWrite(CommandInterpreter &interpreter) 2394 : CommandObjectParsed(interpreter, "breakpoint write", 2395 "Write the breakpoints listed to a file that can " 2396 "be read in with \"breakpoint read\". " 2397 "If given no arguments, writes all breakpoints.", 2398 nullptr), 2399 m_options() { 2400 CommandArgumentEntry arg; 2401 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 2402 eArgTypeBreakpointIDRange); 2403 // Add the entry for the first argument for this command to the object's 2404 // arguments vector. 2405 m_arguments.push_back(arg); 2406 } 2407 2408 ~CommandObjectBreakpointWrite() override = default; 2409 2410 Options *GetOptions() override { return &m_options; } 2411 2412 class CommandOptions : public Options { 2413 public: 2414 CommandOptions() : Options() {} 2415 2416 ~CommandOptions() override = default; 2417 2418 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2419 ExecutionContext *execution_context) override { 2420 Status error; 2421 const int short_option = m_getopt_table[option_idx].val; 2422 2423 switch (short_option) { 2424 case 'f': 2425 m_filename.assign(option_arg); 2426 break; 2427 case 'a': 2428 m_append = true; 2429 break; 2430 default: 2431 error.SetErrorStringWithFormat("unrecognized option '%c'", 2432 short_option); 2433 break; 2434 } 2435 2436 return error; 2437 } 2438 2439 void OptionParsingStarting(ExecutionContext *execution_context) override { 2440 m_filename.clear(); 2441 m_append = false; 2442 } 2443 2444 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2445 return llvm::makeArrayRef(g_breakpoint_write_options); 2446 } 2447 2448 // Instance variables to hold the values for command options. 2449 2450 std::string m_filename; 2451 bool m_append = false; 2452 }; 2453 2454 protected: 2455 bool DoExecute(Args &command, CommandReturnObject &result) override { 2456 Target *target = GetSelectedOrDummyTarget(); 2457 if (target == nullptr) { 2458 result.AppendError("Invalid target. No existing target or breakpoints."); 2459 result.SetStatus(eReturnStatusFailed); 2460 return false; 2461 } 2462 2463 std::unique_lock<std::recursive_mutex> lock; 2464 target->GetBreakpointList().GetListMutex(lock); 2465 2466 BreakpointIDList valid_bp_ids; 2467 if (!command.empty()) { 2468 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 2469 command, target, result, &valid_bp_ids, 2470 BreakpointName::Permissions::PermissionKinds::listPerm); 2471 2472 if (!result.Succeeded()) { 2473 result.SetStatus(eReturnStatusFailed); 2474 return false; 2475 } 2476 } 2477 FileSpec file_spec(m_options.m_filename); 2478 FileSystem::Instance().Resolve(file_spec); 2479 Status error = target->SerializeBreakpointsToFile(file_spec, valid_bp_ids, 2480 m_options.m_append); 2481 if (!error.Success()) { 2482 result.AppendErrorWithFormat("error serializing breakpoints: %s.", 2483 error.AsCString()); 2484 result.SetStatus(eReturnStatusFailed); 2485 } 2486 return result.Succeeded(); 2487 } 2488 2489 private: 2490 CommandOptions m_options; 2491 }; 2492 2493 // CommandObjectMultiwordBreakpoint 2494 #pragma mark MultiwordBreakpoint 2495 2496 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint( 2497 CommandInterpreter &interpreter) 2498 : CommandObjectMultiword( 2499 interpreter, "breakpoint", 2500 "Commands for operating on breakpoints (see 'help b' for shorthand.)", 2501 "breakpoint <subcommand> [<command-options>]") { 2502 CommandObjectSP list_command_object( 2503 new CommandObjectBreakpointList(interpreter)); 2504 CommandObjectSP enable_command_object( 2505 new CommandObjectBreakpointEnable(interpreter)); 2506 CommandObjectSP disable_command_object( 2507 new CommandObjectBreakpointDisable(interpreter)); 2508 CommandObjectSP clear_command_object( 2509 new CommandObjectBreakpointClear(interpreter)); 2510 CommandObjectSP delete_command_object( 2511 new CommandObjectBreakpointDelete(interpreter)); 2512 CommandObjectSP set_command_object( 2513 new CommandObjectBreakpointSet(interpreter)); 2514 CommandObjectSP command_command_object( 2515 new CommandObjectBreakpointCommand(interpreter)); 2516 CommandObjectSP modify_command_object( 2517 new CommandObjectBreakpointModify(interpreter)); 2518 CommandObjectSP name_command_object( 2519 new CommandObjectBreakpointName(interpreter)); 2520 CommandObjectSP write_command_object( 2521 new CommandObjectBreakpointWrite(interpreter)); 2522 CommandObjectSP read_command_object( 2523 new CommandObjectBreakpointRead(interpreter)); 2524 2525 list_command_object->SetCommandName("breakpoint list"); 2526 enable_command_object->SetCommandName("breakpoint enable"); 2527 disable_command_object->SetCommandName("breakpoint disable"); 2528 clear_command_object->SetCommandName("breakpoint clear"); 2529 delete_command_object->SetCommandName("breakpoint delete"); 2530 set_command_object->SetCommandName("breakpoint set"); 2531 command_command_object->SetCommandName("breakpoint command"); 2532 modify_command_object->SetCommandName("breakpoint modify"); 2533 name_command_object->SetCommandName("breakpoint name"); 2534 write_command_object->SetCommandName("breakpoint write"); 2535 read_command_object->SetCommandName("breakpoint read"); 2536 2537 LoadSubCommand("list", list_command_object); 2538 LoadSubCommand("enable", enable_command_object); 2539 LoadSubCommand("disable", disable_command_object); 2540 LoadSubCommand("clear", clear_command_object); 2541 LoadSubCommand("delete", delete_command_object); 2542 LoadSubCommand("set", set_command_object); 2543 LoadSubCommand("command", command_command_object); 2544 LoadSubCommand("modify", modify_command_object); 2545 LoadSubCommand("name", name_command_object); 2546 LoadSubCommand("write", write_command_object); 2547 LoadSubCommand("read", read_command_object); 2548 } 2549 2550 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default; 2551 2552 void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target, 2553 bool allow_locations, 2554 CommandReturnObject &result, 2555 BreakpointIDList *valid_ids, 2556 BreakpointName::Permissions 2557 ::PermissionKinds 2558 purpose) { 2559 // args can be strings representing 1). integers (for breakpoint ids) 2560 // 2). the full breakpoint & location 2561 // canonical representation 2562 // 3). the word "to" or a hyphen, 2563 // representing a range (in which case there 2564 // had *better* be an entry both before & 2565 // after of one of the first two types. 2566 // 4). A breakpoint name 2567 // If args is empty, we will use the last created breakpoint (if there is 2568 // one.) 2569 2570 Args temp_args; 2571 2572 if (args.empty()) { 2573 if (target->GetLastCreatedBreakpoint()) { 2574 valid_ids->AddBreakpointID(BreakpointID( 2575 target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID)); 2576 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2577 } else { 2578 result.AppendError( 2579 "No breakpoint specified and no last created breakpoint."); 2580 result.SetStatus(eReturnStatusFailed); 2581 } 2582 return; 2583 } 2584 2585 // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff 2586 // directly from the old ARGS to the new TEMP_ARGS. Do not copy breakpoint 2587 // id range strings over; instead generate a list of strings for all the 2588 // breakpoint ids in the range, and shove all of those breakpoint id strings 2589 // into TEMP_ARGS. 2590 2591 BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations, 2592 purpose, result, temp_args); 2593 2594 // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual 2595 // BreakpointIDList: 2596 2597 valid_ids->InsertStringArray(temp_args.GetArgumentArrayRef(), result); 2598 2599 // At this point, all of the breakpoint ids that the user passed in have 2600 // been converted to breakpoint IDs and put into valid_ids. 2601 2602 if (result.Succeeded()) { 2603 // Now that we've converted everything from args into a list of breakpoint 2604 // ids, go through our tentative list of breakpoint id's and verify that 2605 // they correspond to valid/currently set breakpoints. 2606 2607 const size_t count = valid_ids->GetSize(); 2608 for (size_t i = 0; i < count; ++i) { 2609 BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i); 2610 Breakpoint *breakpoint = 2611 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 2612 if (breakpoint != nullptr) { 2613 const size_t num_locations = breakpoint->GetNumLocations(); 2614 if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) { 2615 StreamString id_str; 2616 BreakpointID::GetCanonicalReference( 2617 &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID()); 2618 i = valid_ids->GetSize() + 1; 2619 result.AppendErrorWithFormat( 2620 "'%s' is not a currently valid breakpoint/location id.\n", 2621 id_str.GetData()); 2622 result.SetStatus(eReturnStatusFailed); 2623 } 2624 } else { 2625 i = valid_ids->GetSize() + 1; 2626 result.AppendErrorWithFormat( 2627 "'%d' is not a currently valid breakpoint ID.\n", 2628 cur_bp_id.GetBreakpointID()); 2629 result.SetStatus(eReturnStatusFailed); 2630 } 2631 } 2632 } 2633 } 2634