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