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