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