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