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