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