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_column, 701 m_options.m_offset_addr, 702 check_inlines, 703 m_options.m_skip_prologue, 704 internal, 705 m_options.m_hardware, 706 m_options.m_move_to_nearest_code); 707 } break; 708 709 case eSetTypeAddress: // Breakpoint by address 710 { 711 // If a shared library has been specified, make an lldb_private::Address 712 // with the library, and use that. That way the address breakpoint 713 // will track the load location of the library. 714 size_t num_modules_specified = m_options.m_modules.GetSize(); 715 if (num_modules_specified == 1) { 716 const FileSpec *file_spec = 717 m_options.m_modules.GetFileSpecPointerAtIndex(0); 718 bp_sp = target->CreateAddressInModuleBreakpoint(m_options.m_load_addr, 719 internal, file_spec, 720 m_options.m_hardware); 721 } else if (num_modules_specified == 0) { 722 bp_sp = target->CreateBreakpoint(m_options.m_load_addr, internal, 723 m_options.m_hardware); 724 } else { 725 result.AppendError("Only one shared library can be specified for " 726 "address breakpoints."); 727 result.SetStatus(eReturnStatusFailed); 728 return false; 729 } 730 break; 731 } 732 case eSetTypeFunctionName: // Breakpoint by function name 733 { 734 uint32_t name_type_mask = m_options.m_func_name_type_mask; 735 736 if (name_type_mask == 0) 737 name_type_mask = eFunctionNameTypeAuto; 738 739 bp_sp = target->CreateBreakpoint(&(m_options.m_modules), 740 &(m_options.m_filenames), 741 m_options.m_func_names, 742 name_type_mask, 743 m_options.m_language, 744 m_options.m_offset_addr, 745 m_options.m_skip_prologue, 746 internal, 747 m_options.m_hardware); 748 } break; 749 750 case eSetTypeFunctionRegexp: // Breakpoint by regular expression function 751 // name 752 { 753 RegularExpression regexp(m_options.m_func_regexp); 754 if (!regexp.IsValid()) { 755 char err_str[1024]; 756 regexp.GetErrorAsCString(err_str, sizeof(err_str)); 757 result.AppendErrorWithFormat( 758 "Function name regular expression could not be compiled: \"%s\"", 759 err_str); 760 result.SetStatus(eReturnStatusFailed); 761 return false; 762 } 763 764 bp_sp = target->CreateFuncRegexBreakpoint(&(m_options.m_modules), 765 &(m_options.m_filenames), 766 regexp, 767 m_options.m_language, 768 m_options.m_skip_prologue, 769 internal, 770 m_options.m_hardware); 771 } 772 break; 773 case eSetTypeSourceRegexp: // Breakpoint by regexp on source text. 774 { 775 const size_t num_files = m_options.m_filenames.GetSize(); 776 777 if (num_files == 0 && !m_options.m_all_files) { 778 FileSpec file; 779 if (!GetDefaultFile(target, file, result)) { 780 result.AppendError( 781 "No files provided and could not find default file."); 782 result.SetStatus(eReturnStatusFailed); 783 return false; 784 } else { 785 m_options.m_filenames.Append(file); 786 } 787 } 788 789 RegularExpression regexp(m_options.m_source_text_regexp); 790 if (!regexp.IsValid()) { 791 char err_str[1024]; 792 regexp.GetErrorAsCString(err_str, sizeof(err_str)); 793 result.AppendErrorWithFormat( 794 "Source text regular expression could not be compiled: \"%s\"", 795 err_str); 796 result.SetStatus(eReturnStatusFailed); 797 return false; 798 } 799 bp_sp = 800 target->CreateSourceRegexBreakpoint(&(m_options.m_modules), 801 &(m_options.m_filenames), 802 m_options 803 .m_source_regex_func_names, 804 regexp, 805 internal, 806 m_options.m_hardware, 807 m_options.m_move_to_nearest_code); 808 } break; 809 case eSetTypeException: { 810 Status precond_error; 811 bp_sp = target->CreateExceptionBreakpoint(m_options.m_exception_language, 812 m_options.m_catch_bp, 813 m_options.m_throw_bp, 814 internal, 815 &m_options 816 .m_exception_extra_args, 817 &precond_error); 818 if (precond_error.Fail()) { 819 result.AppendErrorWithFormat( 820 "Error setting extra exception arguments: %s", 821 precond_error.AsCString()); 822 target->RemoveBreakpointByID(bp_sp->GetID()); 823 result.SetStatus(eReturnStatusFailed); 824 return false; 825 } 826 } break; 827 default: 828 break; 829 } 830 831 // Now set the various options that were passed in: 832 if (bp_sp) { 833 bp_sp->GetOptions()->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); 834 835 if (!m_options.m_breakpoint_names.empty()) { 836 Status name_error; 837 for (auto name : m_options.m_breakpoint_names) { 838 target->AddNameToBreakpoint(bp_sp, name.c_str(), name_error); 839 if (name_error.Fail()) { 840 result.AppendErrorWithFormat("Invalid breakpoint name: %s", 841 name.c_str()); 842 target->RemoveBreakpointByID(bp_sp->GetID()); 843 result.SetStatus(eReturnStatusFailed); 844 return false; 845 } 846 } 847 } 848 } 849 850 if (bp_sp) { 851 Stream &output_stream = result.GetOutputStream(); 852 const bool show_locations = false; 853 bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, 854 show_locations); 855 if (target == m_interpreter.GetDebugger().GetDummyTarget()) 856 output_stream.Printf("Breakpoint set in dummy target, will get copied " 857 "into future targets.\n"); 858 else { 859 // Don't print out this warning for exception breakpoints. They can 860 // get set before the target is set, but we won't know how to actually 861 // set the breakpoint till we run. 862 if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) { 863 output_stream.Printf("WARNING: Unable to resolve breakpoint to any " 864 "actual locations.\n"); 865 } 866 } 867 result.SetStatus(eReturnStatusSuccessFinishResult); 868 } else if (!bp_sp) { 869 result.AppendError("Breakpoint creation failed: No breakpoint created."); 870 result.SetStatus(eReturnStatusFailed); 871 } 872 873 return result.Succeeded(); 874 } 875 876 private: 877 bool GetDefaultFile(Target *target, FileSpec &file, 878 CommandReturnObject &result) { 879 uint32_t default_line; 880 // First use the Source Manager's default file. Then use the current stack 881 // frame's file. 882 if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line)) { 883 StackFrame *cur_frame = m_exe_ctx.GetFramePtr(); 884 if (cur_frame == nullptr) { 885 result.AppendError( 886 "No selected frame to use to find the default file."); 887 result.SetStatus(eReturnStatusFailed); 888 return false; 889 } else if (!cur_frame->HasDebugInformation()) { 890 result.AppendError("Cannot use the selected frame to find the default " 891 "file, it has no debug info."); 892 result.SetStatus(eReturnStatusFailed); 893 return false; 894 } else { 895 const SymbolContext &sc = 896 cur_frame->GetSymbolContext(eSymbolContextLineEntry); 897 if (sc.line_entry.file) { 898 file = sc.line_entry.file; 899 } else { 900 result.AppendError("Can't find the file for the selected frame to " 901 "use as the default file."); 902 result.SetStatus(eReturnStatusFailed); 903 return false; 904 } 905 } 906 } 907 return true; 908 } 909 910 BreakpointOptionGroup m_bp_opts; 911 BreakpointDummyOptionGroup m_dummy_options; 912 CommandOptions m_options; 913 OptionGroupOptions m_all_options; 914 }; 915 916 //------------------------------------------------------------------------- 917 // CommandObjectBreakpointModify 918 //------------------------------------------------------------------------- 919 #pragma mark Modify 920 921 class CommandObjectBreakpointModify : public CommandObjectParsed { 922 public: 923 CommandObjectBreakpointModify(CommandInterpreter &interpreter) 924 : CommandObjectParsed(interpreter, "breakpoint modify", 925 "Modify the options on a breakpoint or set of " 926 "breakpoints in the executable. " 927 "If no breakpoint is specified, acts on the last " 928 "created breakpoint. " 929 "With the exception of -e, -d and -i, passing an " 930 "empty argument clears the modification.", 931 nullptr), 932 m_options() { 933 CommandArgumentEntry arg; 934 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 935 eArgTypeBreakpointIDRange); 936 // Add the entry for the first argument for this command to the object's 937 // arguments vector. 938 m_arguments.push_back(arg); 939 940 m_options.Append(&m_bp_opts, 941 LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, 942 LLDB_OPT_SET_ALL); 943 m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 944 m_options.Finalize(); 945 } 946 947 ~CommandObjectBreakpointModify() override = default; 948 949 Options *GetOptions() override { return &m_options; } 950 951 protected: 952 bool DoExecute(Args &command, CommandReturnObject &result) override { 953 Target *target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy); 954 if (target == nullptr) { 955 result.AppendError("Invalid target. No existing target or breakpoints."); 956 result.SetStatus(eReturnStatusFailed); 957 return false; 958 } 959 960 std::unique_lock<std::recursive_mutex> lock; 961 target->GetBreakpointList().GetListMutex(lock); 962 963 BreakpointIDList valid_bp_ids; 964 965 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 966 command, target, result, &valid_bp_ids, 967 BreakpointName::Permissions::PermissionKinds::disablePerm); 968 969 if (result.Succeeded()) { 970 const size_t count = valid_bp_ids.GetSize(); 971 for (size_t i = 0; i < count; ++i) { 972 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 973 974 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 975 Breakpoint *bp = 976 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 977 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 978 BreakpointLocation *location = 979 bp->FindLocationByID(cur_bp_id.GetLocationID()).get(); 980 if (location) 981 location->GetLocationOptions() 982 ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); 983 } else { 984 bp->GetOptions() 985 ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions()); 986 } 987 } 988 } 989 } 990 991 return result.Succeeded(); 992 } 993 994 private: 995 BreakpointOptionGroup m_bp_opts; 996 BreakpointDummyOptionGroup m_dummy_opts; 997 OptionGroupOptions m_options; 998 }; 999 1000 //------------------------------------------------------------------------- 1001 // CommandObjectBreakpointEnable 1002 //------------------------------------------------------------------------- 1003 #pragma mark Enable 1004 1005 class CommandObjectBreakpointEnable : public CommandObjectParsed { 1006 public: 1007 CommandObjectBreakpointEnable(CommandInterpreter &interpreter) 1008 : CommandObjectParsed(interpreter, "enable", 1009 "Enable the specified disabled breakpoint(s). If " 1010 "no breakpoints are specified, enable all of them.", 1011 nullptr) { 1012 CommandArgumentEntry arg; 1013 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1014 eArgTypeBreakpointIDRange); 1015 // Add the entry for the first argument for this command to the object's 1016 // arguments vector. 1017 m_arguments.push_back(arg); 1018 } 1019 1020 ~CommandObjectBreakpointEnable() override = default; 1021 1022 protected: 1023 bool DoExecute(Args &command, CommandReturnObject &result) override { 1024 Target *target = GetSelectedOrDummyTarget(); 1025 if (target == nullptr) { 1026 result.AppendError("Invalid target. No existing target or breakpoints."); 1027 result.SetStatus(eReturnStatusFailed); 1028 return false; 1029 } 1030 1031 std::unique_lock<std::recursive_mutex> lock; 1032 target->GetBreakpointList().GetListMutex(lock); 1033 1034 const BreakpointList &breakpoints = target->GetBreakpointList(); 1035 1036 size_t num_breakpoints = breakpoints.GetSize(); 1037 1038 if (num_breakpoints == 0) { 1039 result.AppendError("No breakpoints exist to be enabled."); 1040 result.SetStatus(eReturnStatusFailed); 1041 return false; 1042 } 1043 1044 if (command.empty()) { 1045 // No breakpoint selected; enable all currently set breakpoints. 1046 target->EnableAllowedBreakpoints(); 1047 result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64 1048 " breakpoints)\n", 1049 (uint64_t)num_breakpoints); 1050 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1051 } else { 1052 // Particular breakpoint selected; enable that breakpoint. 1053 BreakpointIDList valid_bp_ids; 1054 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1055 command, target, result, &valid_bp_ids, 1056 BreakpointName::Permissions::PermissionKinds::disablePerm); 1057 1058 if (result.Succeeded()) { 1059 int enable_count = 0; 1060 int loc_count = 0; 1061 const size_t count = valid_bp_ids.GetSize(); 1062 for (size_t i = 0; i < count; ++i) { 1063 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1064 1065 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1066 Breakpoint *breakpoint = 1067 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1068 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1069 BreakpointLocation *location = 1070 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1071 if (location) { 1072 location->SetEnabled(true); 1073 ++loc_count; 1074 } 1075 } else { 1076 breakpoint->SetEnabled(true); 1077 ++enable_count; 1078 } 1079 } 1080 } 1081 result.AppendMessageWithFormat("%d breakpoints enabled.\n", 1082 enable_count + loc_count); 1083 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1084 } 1085 } 1086 1087 return result.Succeeded(); 1088 } 1089 }; 1090 1091 //------------------------------------------------------------------------- 1092 // CommandObjectBreakpointDisable 1093 //------------------------------------------------------------------------- 1094 #pragma mark Disable 1095 1096 class CommandObjectBreakpointDisable : public CommandObjectParsed { 1097 public: 1098 CommandObjectBreakpointDisable(CommandInterpreter &interpreter) 1099 : CommandObjectParsed( 1100 interpreter, "breakpoint disable", 1101 "Disable the specified breakpoint(s) without deleting " 1102 "them. If none are specified, disable all " 1103 "breakpoints.", 1104 nullptr) { 1105 SetHelpLong( 1106 "Disable the specified breakpoint(s) without deleting them. \ 1107 If none are specified, disable all breakpoints." 1108 R"( 1109 1110 )" 1111 "Note: disabling a breakpoint will cause none of its locations to be hit \ 1112 regardless of whether individual locations are enabled or disabled. After the sequence:" 1113 R"( 1114 1115 (lldb) break disable 1 1116 (lldb) break enable 1.1 1117 1118 execution will NOT stop at location 1.1. To achieve that, type: 1119 1120 (lldb) break disable 1.* 1121 (lldb) break enable 1.1 1122 1123 )" 1124 "The first command disables all locations for breakpoint 1, \ 1125 the second re-enables the first location."); 1126 1127 CommandArgumentEntry arg; 1128 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1129 eArgTypeBreakpointIDRange); 1130 // Add the entry for the first argument for this command to the object's 1131 // arguments vector. 1132 m_arguments.push_back(arg); 1133 } 1134 1135 ~CommandObjectBreakpointDisable() override = default; 1136 1137 protected: 1138 bool DoExecute(Args &command, CommandReturnObject &result) override { 1139 Target *target = GetSelectedOrDummyTarget(); 1140 if (target == nullptr) { 1141 result.AppendError("Invalid target. No existing target or breakpoints."); 1142 result.SetStatus(eReturnStatusFailed); 1143 return false; 1144 } 1145 1146 std::unique_lock<std::recursive_mutex> lock; 1147 target->GetBreakpointList().GetListMutex(lock); 1148 1149 const BreakpointList &breakpoints = target->GetBreakpointList(); 1150 size_t num_breakpoints = breakpoints.GetSize(); 1151 1152 if (num_breakpoints == 0) { 1153 result.AppendError("No breakpoints exist to be disabled."); 1154 result.SetStatus(eReturnStatusFailed); 1155 return false; 1156 } 1157 1158 if (command.empty()) { 1159 // No breakpoint selected; disable all currently set breakpoints. 1160 target->DisableAllowedBreakpoints(); 1161 result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64 1162 " breakpoints)\n", 1163 (uint64_t)num_breakpoints); 1164 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1165 } else { 1166 // Particular breakpoint selected; disable that breakpoint. 1167 BreakpointIDList valid_bp_ids; 1168 1169 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1170 command, target, result, &valid_bp_ids, 1171 BreakpointName::Permissions::PermissionKinds::disablePerm); 1172 1173 if (result.Succeeded()) { 1174 int disable_count = 0; 1175 int loc_count = 0; 1176 const size_t count = valid_bp_ids.GetSize(); 1177 for (size_t i = 0; i < count; ++i) { 1178 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1179 1180 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1181 Breakpoint *breakpoint = 1182 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1183 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1184 BreakpointLocation *location = 1185 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1186 if (location) { 1187 location->SetEnabled(false); 1188 ++loc_count; 1189 } 1190 } else { 1191 breakpoint->SetEnabled(false); 1192 ++disable_count; 1193 } 1194 } 1195 } 1196 result.AppendMessageWithFormat("%d breakpoints disabled.\n", 1197 disable_count + loc_count); 1198 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1199 } 1200 } 1201 1202 return result.Succeeded(); 1203 } 1204 }; 1205 1206 //------------------------------------------------------------------------- 1207 // CommandObjectBreakpointList 1208 //------------------------------------------------------------------------- 1209 1210 #pragma mark List::CommandOptions 1211 static OptionDefinition g_breakpoint_list_options[] = { 1212 // clang-format off 1213 { LLDB_OPT_SET_ALL, false, "internal", 'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show debugger internal breakpoints" }, 1214 { LLDB_OPT_SET_1, false, "brief", 'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a brief description of the breakpoint (no location info)." }, 1215 // FIXME: We need to add an "internal" command, and then add this sort of thing to it. 1216 // But I need to see it for now, and don't want to wait. 1217 { LLDB_OPT_SET_2, false, "full", 'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a full description of the breakpoint and its locations." }, 1218 { LLDB_OPT_SET_3, false, "verbose", 'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Explain everything we know about the breakpoint (for debugging debugger bugs)." }, 1219 { 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." }, 1220 // clang-format on 1221 }; 1222 1223 #pragma mark List 1224 1225 class CommandObjectBreakpointList : public CommandObjectParsed { 1226 public: 1227 CommandObjectBreakpointList(CommandInterpreter &interpreter) 1228 : CommandObjectParsed( 1229 interpreter, "breakpoint list", 1230 "List some or all breakpoints at configurable levels of detail.", 1231 nullptr), 1232 m_options() { 1233 CommandArgumentEntry arg; 1234 CommandArgumentData bp_id_arg; 1235 1236 // Define the first (and only) variant of this arg. 1237 bp_id_arg.arg_type = eArgTypeBreakpointID; 1238 bp_id_arg.arg_repetition = eArgRepeatOptional; 1239 1240 // There is only one variant this argument could be; put it into the 1241 // argument entry. 1242 arg.push_back(bp_id_arg); 1243 1244 // Push the data for the first argument into the m_arguments vector. 1245 m_arguments.push_back(arg); 1246 } 1247 1248 ~CommandObjectBreakpointList() override = default; 1249 1250 Options *GetOptions() override { return &m_options; } 1251 1252 class CommandOptions : public Options { 1253 public: 1254 CommandOptions() 1255 : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) { 1256 } 1257 1258 ~CommandOptions() override = default; 1259 1260 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1261 ExecutionContext *execution_context) override { 1262 Status error; 1263 const int short_option = m_getopt_table[option_idx].val; 1264 1265 switch (short_option) { 1266 case 'b': 1267 m_level = lldb::eDescriptionLevelBrief; 1268 break; 1269 case 'D': 1270 m_use_dummy = true; 1271 break; 1272 case 'f': 1273 m_level = lldb::eDescriptionLevelFull; 1274 break; 1275 case 'v': 1276 m_level = lldb::eDescriptionLevelVerbose; 1277 break; 1278 case 'i': 1279 m_internal = true; 1280 break; 1281 default: 1282 error.SetErrorStringWithFormat("unrecognized option '%c'", 1283 short_option); 1284 break; 1285 } 1286 1287 return error; 1288 } 1289 1290 void OptionParsingStarting(ExecutionContext *execution_context) override { 1291 m_level = lldb::eDescriptionLevelFull; 1292 m_internal = false; 1293 m_use_dummy = false; 1294 } 1295 1296 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1297 return llvm::makeArrayRef(g_breakpoint_list_options); 1298 } 1299 1300 // Instance variables to hold the values for command options. 1301 1302 lldb::DescriptionLevel m_level; 1303 1304 bool m_internal; 1305 bool m_use_dummy; 1306 }; 1307 1308 protected: 1309 bool DoExecute(Args &command, CommandReturnObject &result) override { 1310 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1311 1312 if (target == nullptr) { 1313 result.AppendError("Invalid target. No current target or breakpoints."); 1314 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1315 return true; 1316 } 1317 1318 const BreakpointList &breakpoints = 1319 target->GetBreakpointList(m_options.m_internal); 1320 std::unique_lock<std::recursive_mutex> lock; 1321 target->GetBreakpointList(m_options.m_internal).GetListMutex(lock); 1322 1323 size_t num_breakpoints = breakpoints.GetSize(); 1324 1325 if (num_breakpoints == 0) { 1326 result.AppendMessage("No breakpoints currently set."); 1327 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1328 return true; 1329 } 1330 1331 Stream &output_stream = result.GetOutputStream(); 1332 1333 if (command.empty()) { 1334 // No breakpoint selected; show info about all currently set breakpoints. 1335 result.AppendMessage("Current breakpoints:"); 1336 for (size_t i = 0; i < num_breakpoints; ++i) { 1337 Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get(); 1338 if (breakpoint->AllowList()) 1339 AddBreakpointDescription(&output_stream, breakpoint, 1340 m_options.m_level); 1341 } 1342 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1343 } else { 1344 // Particular breakpoints selected; show info about that breakpoint. 1345 BreakpointIDList valid_bp_ids; 1346 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1347 command, target, result, &valid_bp_ids, 1348 BreakpointName::Permissions::PermissionKinds::listPerm); 1349 1350 if (result.Succeeded()) { 1351 for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) { 1352 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1353 Breakpoint *breakpoint = 1354 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1355 AddBreakpointDescription(&output_stream, breakpoint, 1356 m_options.m_level); 1357 } 1358 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1359 } else { 1360 result.AppendError("Invalid breakpoint ID."); 1361 result.SetStatus(eReturnStatusFailed); 1362 } 1363 } 1364 1365 return result.Succeeded(); 1366 } 1367 1368 private: 1369 CommandOptions m_options; 1370 }; 1371 1372 //------------------------------------------------------------------------- 1373 // CommandObjectBreakpointClear 1374 //------------------------------------------------------------------------- 1375 #pragma mark Clear::CommandOptions 1376 1377 static OptionDefinition g_breakpoint_clear_options[] = { 1378 // clang-format off 1379 { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specify the breakpoint by source location in this particular file." }, 1380 { LLDB_OPT_SET_1, true, "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeLineNum, "Specify the breakpoint by source location at this particular line." } 1381 // clang-format on 1382 }; 1383 1384 #pragma mark Clear 1385 1386 class CommandObjectBreakpointClear : public CommandObjectParsed { 1387 public: 1388 typedef enum BreakpointClearType { 1389 eClearTypeInvalid, 1390 eClearTypeFileAndLine 1391 } BreakpointClearType; 1392 1393 CommandObjectBreakpointClear(CommandInterpreter &interpreter) 1394 : CommandObjectParsed(interpreter, "breakpoint clear", 1395 "Delete or disable breakpoints matching the " 1396 "specified source file and line.", 1397 "breakpoint clear <cmd-options>"), 1398 m_options() {} 1399 1400 ~CommandObjectBreakpointClear() override = default; 1401 1402 Options *GetOptions() override { return &m_options; } 1403 1404 class CommandOptions : public Options { 1405 public: 1406 CommandOptions() : Options(), m_filename(), m_line_num(0) {} 1407 1408 ~CommandOptions() override = default; 1409 1410 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1411 ExecutionContext *execution_context) override { 1412 Status error; 1413 const int short_option = m_getopt_table[option_idx].val; 1414 1415 switch (short_option) { 1416 case 'f': 1417 m_filename.assign(option_arg); 1418 break; 1419 1420 case 'l': 1421 option_arg.getAsInteger(0, m_line_num); 1422 break; 1423 1424 default: 1425 error.SetErrorStringWithFormat("unrecognized option '%c'", 1426 short_option); 1427 break; 1428 } 1429 1430 return error; 1431 } 1432 1433 void OptionParsingStarting(ExecutionContext *execution_context) override { 1434 m_filename.clear(); 1435 m_line_num = 0; 1436 } 1437 1438 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1439 return llvm::makeArrayRef(g_breakpoint_clear_options); 1440 } 1441 1442 // Instance variables to hold the values for command options. 1443 1444 std::string m_filename; 1445 uint32_t m_line_num; 1446 }; 1447 1448 protected: 1449 bool DoExecute(Args &command, CommandReturnObject &result) override { 1450 Target *target = GetSelectedOrDummyTarget(); 1451 if (target == nullptr) { 1452 result.AppendError("Invalid target. No existing target or breakpoints."); 1453 result.SetStatus(eReturnStatusFailed); 1454 return false; 1455 } 1456 1457 // The following are the various types of breakpoints that could be 1458 // cleared: 1459 // 1). -f -l (clearing breakpoint by source location) 1460 1461 BreakpointClearType break_type = eClearTypeInvalid; 1462 1463 if (m_options.m_line_num != 0) 1464 break_type = eClearTypeFileAndLine; 1465 1466 std::unique_lock<std::recursive_mutex> lock; 1467 target->GetBreakpointList().GetListMutex(lock); 1468 1469 BreakpointList &breakpoints = target->GetBreakpointList(); 1470 size_t num_breakpoints = breakpoints.GetSize(); 1471 1472 // Early return if there's no breakpoint at all. 1473 if (num_breakpoints == 0) { 1474 result.AppendError("Breakpoint clear: No breakpoint cleared."); 1475 result.SetStatus(eReturnStatusFailed); 1476 return result.Succeeded(); 1477 } 1478 1479 // Find matching breakpoints and delete them. 1480 1481 // First create a copy of all the IDs. 1482 std::vector<break_id_t> BreakIDs; 1483 for (size_t i = 0; i < num_breakpoints; ++i) 1484 BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID()); 1485 1486 int num_cleared = 0; 1487 StreamString ss; 1488 switch (break_type) { 1489 case eClearTypeFileAndLine: // Breakpoint by source position 1490 { 1491 const ConstString filename(m_options.m_filename.c_str()); 1492 BreakpointLocationCollection loc_coll; 1493 1494 for (size_t i = 0; i < num_breakpoints; ++i) { 1495 Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get(); 1496 1497 if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) { 1498 // If the collection size is 0, it's a full match and we can just 1499 // remove the breakpoint. 1500 if (loc_coll.GetSize() == 0) { 1501 bp->GetDescription(&ss, lldb::eDescriptionLevelBrief); 1502 ss.EOL(); 1503 target->RemoveBreakpointByID(bp->GetID()); 1504 ++num_cleared; 1505 } 1506 } 1507 } 1508 } break; 1509 1510 default: 1511 break; 1512 } 1513 1514 if (num_cleared > 0) { 1515 Stream &output_stream = result.GetOutputStream(); 1516 output_stream.Printf("%d breakpoints cleared:\n", num_cleared); 1517 output_stream << ss.GetString(); 1518 output_stream.EOL(); 1519 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1520 } else { 1521 result.AppendError("Breakpoint clear: No breakpoint cleared."); 1522 result.SetStatus(eReturnStatusFailed); 1523 } 1524 1525 return result.Succeeded(); 1526 } 1527 1528 private: 1529 CommandOptions m_options; 1530 }; 1531 1532 //------------------------------------------------------------------------- 1533 // CommandObjectBreakpointDelete 1534 //------------------------------------------------------------------------- 1535 static OptionDefinition g_breakpoint_delete_options[] = { 1536 // clang-format off 1537 { LLDB_OPT_SET_1, false, "force", 'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete all breakpoints without querying for confirmation." }, 1538 { 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." }, 1539 // clang-format on 1540 }; 1541 1542 #pragma mark Delete 1543 1544 class CommandObjectBreakpointDelete : public CommandObjectParsed { 1545 public: 1546 CommandObjectBreakpointDelete(CommandInterpreter &interpreter) 1547 : CommandObjectParsed(interpreter, "breakpoint delete", 1548 "Delete the specified breakpoint(s). If no " 1549 "breakpoints are specified, delete them all.", 1550 nullptr), 1551 m_options() { 1552 CommandArgumentEntry arg; 1553 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 1554 eArgTypeBreakpointIDRange); 1555 // Add the entry for the first argument for this command to the object's 1556 // arguments vector. 1557 m_arguments.push_back(arg); 1558 } 1559 1560 ~CommandObjectBreakpointDelete() override = default; 1561 1562 Options *GetOptions() override { return &m_options; } 1563 1564 class CommandOptions : public Options { 1565 public: 1566 CommandOptions() : Options(), m_use_dummy(false), m_force(false) {} 1567 1568 ~CommandOptions() override = default; 1569 1570 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1571 ExecutionContext *execution_context) override { 1572 Status error; 1573 const int short_option = m_getopt_table[option_idx].val; 1574 1575 switch (short_option) { 1576 case 'f': 1577 m_force = true; 1578 break; 1579 1580 case 'D': 1581 m_use_dummy = true; 1582 break; 1583 1584 default: 1585 error.SetErrorStringWithFormat("unrecognized option '%c'", 1586 short_option); 1587 break; 1588 } 1589 1590 return error; 1591 } 1592 1593 void OptionParsingStarting(ExecutionContext *execution_context) override { 1594 m_use_dummy = false; 1595 m_force = false; 1596 } 1597 1598 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1599 return llvm::makeArrayRef(g_breakpoint_delete_options); 1600 } 1601 1602 // Instance variables to hold the values for command options. 1603 bool m_use_dummy; 1604 bool m_force; 1605 }; 1606 1607 protected: 1608 bool DoExecute(Args &command, CommandReturnObject &result) override { 1609 Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy); 1610 1611 if (target == nullptr) { 1612 result.AppendError("Invalid target. No existing target or breakpoints."); 1613 result.SetStatus(eReturnStatusFailed); 1614 return false; 1615 } 1616 1617 std::unique_lock<std::recursive_mutex> lock; 1618 target->GetBreakpointList().GetListMutex(lock); 1619 1620 const BreakpointList &breakpoints = target->GetBreakpointList(); 1621 1622 size_t num_breakpoints = breakpoints.GetSize(); 1623 1624 if (num_breakpoints == 0) { 1625 result.AppendError("No breakpoints exist to be deleted."); 1626 result.SetStatus(eReturnStatusFailed); 1627 return false; 1628 } 1629 1630 if (command.empty()) { 1631 if (!m_options.m_force && 1632 !m_interpreter.Confirm( 1633 "About to delete all breakpoints, do you want to do that?", 1634 true)) { 1635 result.AppendMessage("Operation cancelled..."); 1636 } else { 1637 target->RemoveAllowedBreakpoints(); 1638 result.AppendMessageWithFormat( 1639 "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n", 1640 (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : ""); 1641 } 1642 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1643 } else { 1644 // Particular breakpoint selected; disable that breakpoint. 1645 BreakpointIDList valid_bp_ids; 1646 CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs( 1647 command, target, result, &valid_bp_ids, 1648 BreakpointName::Permissions::PermissionKinds::deletePerm); 1649 1650 if (result.Succeeded()) { 1651 int delete_count = 0; 1652 int disable_count = 0; 1653 const size_t count = valid_bp_ids.GetSize(); 1654 for (size_t i = 0; i < count; ++i) { 1655 BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i); 1656 1657 if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) { 1658 if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) { 1659 Breakpoint *breakpoint = 1660 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get(); 1661 BreakpointLocation *location = 1662 breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get(); 1663 // It makes no sense to try to delete individual locations, so we 1664 // disable them instead. 1665 if (location) { 1666 location->SetEnabled(false); 1667 ++disable_count; 1668 } 1669 } else { 1670 target->RemoveBreakpointByID(cur_bp_id.GetBreakpointID()); 1671 ++delete_count; 1672 } 1673 } 1674 } 1675 result.AppendMessageWithFormat( 1676 "%d breakpoints deleted; %d breakpoint locations disabled.\n", 1677 delete_count, disable_count); 1678 result.SetStatus(eReturnStatusSuccessFinishNoResult); 1679 } 1680 } 1681 return result.Succeeded(); 1682 } 1683 1684 private: 1685 CommandOptions m_options; 1686 }; 1687 1688 //------------------------------------------------------------------------- 1689 // CommandObjectBreakpointName 1690 //------------------------------------------------------------------------- 1691 1692 static OptionDefinition g_breakpoint_name_options[] = { 1693 // clang-format off 1694 {LLDB_OPT_SET_1, false, "name", 'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."}, 1695 {LLDB_OPT_SET_2, false, "breakpoint-id", 'B', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointID, "Specify a breakpoint ID to use."}, 1696 {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."}, 1697 {LLDB_OPT_SET_4, false, "help-string", 'H', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "A help string describing the purpose of this name."}, 1698 // clang-format on 1699 }; 1700 class BreakpointNameOptionGroup : public OptionGroup { 1701 public: 1702 BreakpointNameOptionGroup() 1703 : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) { 1704 } 1705 1706 ~BreakpointNameOptionGroup() override = default; 1707 1708 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1709 return llvm::makeArrayRef(g_breakpoint_name_options); 1710 } 1711 1712 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1713 ExecutionContext *execution_context) override { 1714 Status error; 1715 const int short_option = g_breakpoint_name_options[option_idx].short_option; 1716 1717 switch (short_option) { 1718 case 'N': 1719 if (BreakpointID::StringIsBreakpointName(option_arg, error) && 1720 error.Success()) 1721 m_name.SetValueFromString(option_arg); 1722 break; 1723 case 'B': 1724 if (m_breakpoint.SetValueFromString(option_arg).Fail()) 1725 error.SetErrorStringWithFormat( 1726 "unrecognized value \"%s\" for breakpoint", 1727 option_arg.str().c_str()); 1728 break; 1729 case 'D': 1730 if (m_use_dummy.SetValueFromString(option_arg).Fail()) 1731 error.SetErrorStringWithFormat( 1732 "unrecognized value \"%s\" for use-dummy", 1733 option_arg.str().c_str()); 1734 break; 1735 case 'H': 1736 m_help_string.SetValueFromString(option_arg); 1737 break; 1738 1739 default: 1740 error.SetErrorStringWithFormat("unrecognized short option '%c'", 1741 short_option); 1742 break; 1743 } 1744 return error; 1745 } 1746 1747 void OptionParsingStarting(ExecutionContext *execution_context) override { 1748 m_name.Clear(); 1749 m_breakpoint.Clear(); 1750 m_use_dummy.Clear(); 1751 m_use_dummy.SetDefaultValue(false); 1752 m_help_string.Clear(); 1753 } 1754 1755 OptionValueString m_name; 1756 OptionValueUInt64 m_breakpoint; 1757 OptionValueBoolean m_use_dummy; 1758 OptionValueString m_help_string; 1759 }; 1760 1761 static OptionDefinition g_breakpoint_access_options[] = { 1762 // clang-format off 1763 {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."}, 1764 {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."}, 1765 {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."}, 1766 // clang-format on 1767 }; 1768 1769 class BreakpointAccessOptionGroup : public OptionGroup 1770 { 1771 public: 1772 BreakpointAccessOptionGroup() : 1773 OptionGroup() 1774 {} 1775 1776 ~BreakpointAccessOptionGroup() override = default; 1777 1778 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 1779 return llvm::makeArrayRef(g_breakpoint_access_options); 1780 } 1781 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 1782 ExecutionContext *execution_context) override { 1783 Status error; 1784 const int short_option 1785 = g_breakpoint_access_options[option_idx].short_option; 1786 1787 switch (short_option) { 1788 case 'L': { 1789 bool value, success; 1790 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1791 if (success) { 1792 m_permissions.SetAllowList(value); 1793 } else 1794 error.SetErrorStringWithFormat( 1795 "invalid boolean value '%s' passed for -L option", 1796 option_arg.str().c_str()); 1797 } break; 1798 case 'A': { 1799 bool value, success; 1800 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1801 if (success) { 1802 m_permissions.SetAllowDisable(value); 1803 } else 1804 error.SetErrorStringWithFormat( 1805 "invalid boolean value '%s' passed for -L option", 1806 option_arg.str().c_str()); 1807 } break; 1808 case 'D': { 1809 bool value, success; 1810 value = OptionArgParser::ToBoolean(option_arg, false, &success); 1811 if (success) { 1812 m_permissions.SetAllowDelete(value); 1813 } else 1814 error.SetErrorStringWithFormat( 1815 "invalid boolean value '%s' passed for -L option", 1816 option_arg.str().c_str()); 1817 } break; 1818 1819 } 1820 1821 return error; 1822 } 1823 1824 void OptionParsingStarting(ExecutionContext *execution_context) override { 1825 } 1826 1827 const BreakpointName::Permissions &GetPermissions() const 1828 { 1829 return m_permissions; 1830 } 1831 BreakpointName::Permissions m_permissions; 1832 }; 1833 1834 class CommandObjectBreakpointNameConfigure : public CommandObjectParsed { 1835 public: 1836 CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter) 1837 : CommandObjectParsed( 1838 interpreter, "configure", "Configure the options for the breakpoint" 1839 " name provided. " 1840 "If you provide a breakpoint id, the options will be copied from " 1841 "the breakpoint, otherwise only the options specified will be set " 1842 "on the name.", 1843 "breakpoint name configure <command-options> " 1844 "<breakpoint-name-list>"), 1845 m_bp_opts(), m_option_group() { 1846 // Create the first variant for the first (and only) argument for this 1847 // command. 1848 CommandArgumentEntry arg1; 1849 CommandArgumentData id_arg; 1850 id_arg.arg_type = eArgTypeBreakpointName; 1851 id_arg.arg_repetition = eArgRepeatOptional; 1852 arg1.push_back(id_arg); 1853 m_arguments.push_back(arg1); 1854 1855 m_option_group.Append(&m_bp_opts, 1856 LLDB_OPT_SET_ALL, 1857 LLDB_OPT_SET_1); 1858 m_option_group.Append(&m_access_options, 1859 LLDB_OPT_SET_ALL, 1860 LLDB_OPT_SET_ALL); 1861 m_option_group.Append(&m_bp_id, 1862 LLDB_OPT_SET_2|LLDB_OPT_SET_4, 1863 LLDB_OPT_SET_ALL); 1864 m_option_group.Finalize(); 1865 } 1866 1867 ~CommandObjectBreakpointNameConfigure() override = default; 1868 1869 Options *GetOptions() override { return &m_option_group; } 1870 1871 protected: 1872 bool DoExecute(Args &command, CommandReturnObject &result) override { 1873 1874 const size_t argc = command.GetArgumentCount(); 1875 if (argc == 0) { 1876 result.AppendError("No names provided."); 1877 result.SetStatus(eReturnStatusFailed); 1878 return false; 1879 } 1880 1881 Target *target = 1882 GetSelectedOrDummyTarget(false); 1883 1884 if (target == nullptr) { 1885 result.AppendError("Invalid target. No existing target or breakpoints."); 1886 result.SetStatus(eReturnStatusFailed); 1887 return false; 1888 } 1889 1890 std::unique_lock<std::recursive_mutex> lock; 1891 target->GetBreakpointList().GetListMutex(lock); 1892 1893 // Make a pass through first to see that all the names are legal. 1894 for (auto &entry : command.entries()) { 1895 Status error; 1896 if (!BreakpointID::StringIsBreakpointName(entry.ref, error)) 1897 { 1898 result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s", 1899 entry.c_str(), error.AsCString()); 1900 result.SetStatus(eReturnStatusFailed); 1901 return false; 1902 } 1903 } 1904 // Now configure them, we already pre-checked the names so we don't need to 1905 // check the error: 1906 BreakpointSP bp_sp; 1907 if (m_bp_id.m_breakpoint.OptionWasSet()) 1908 { 1909 lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value(); 1910 bp_sp = target->GetBreakpointByID(bp_id); 1911 if (!bp_sp) 1912 { 1913 result.AppendErrorWithFormatv("Could not find specified breakpoint {0}", 1914 bp_id); 1915 result.SetStatus(eReturnStatusFailed); 1916 return false; 1917 } 1918 } 1919 1920 Status error; 1921 for (auto &entry : command.entries()) { 1922 ConstString name(entry.c_str()); 1923 BreakpointName *bp_name = target->FindBreakpointName(name, true, error); 1924 if (!bp_name) 1925 continue; 1926 if (m_bp_id.m_help_string.OptionWasSet()) 1927 bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str()); 1928 1929 if (bp_sp) 1930 target->ConfigureBreakpointName(*bp_name, 1931 *bp_sp->GetOptions(), 1932 m_access_options.GetPermissions()); 1933 else 1934 target->ConfigureBreakpointName(*bp_name, 1935 m_bp_opts.GetBreakpointOptions(), 1936 m_access_options.GetPermissions()); 1937 } 1938 return true; 1939 } 1940 1941 private: 1942 BreakpointNameOptionGroup m_bp_id; // Only using the id part of this. 1943 BreakpointOptionGroup m_bp_opts; 1944 BreakpointAccessOptionGroup m_access_options; 1945 OptionGroupOptions m_option_group; 1946 }; 1947 1948 class CommandObjectBreakpointNameAdd : public CommandObjectParsed { 1949 public: 1950 CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter) 1951 : CommandObjectParsed( 1952 interpreter, "add", "Add a name to the breakpoints provided.", 1953 "breakpoint name add <command-options> <breakpoint-id-list>"), 1954 m_name_options(), m_option_group() { 1955 // Create the first variant for the first (and only) argument for this 1956 // command. 1957 CommandArgumentEntry arg1; 1958 CommandArgumentData id_arg; 1959 id_arg.arg_type = eArgTypeBreakpointID; 1960 id_arg.arg_repetition = eArgRepeatOptional; 1961 arg1.push_back(id_arg); 1962 m_arguments.push_back(arg1); 1963 1964 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 1965 m_option_group.Finalize(); 1966 } 1967 1968 ~CommandObjectBreakpointNameAdd() override = default; 1969 1970 Options *GetOptions() override { return &m_option_group; } 1971 1972 protected: 1973 bool DoExecute(Args &command, CommandReturnObject &result) override { 1974 if (!m_name_options.m_name.OptionWasSet()) { 1975 result.SetError("No name option provided."); 1976 return false; 1977 } 1978 1979 Target *target = 1980 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 1981 1982 if (target == nullptr) { 1983 result.AppendError("Invalid target. No existing target or breakpoints."); 1984 result.SetStatus(eReturnStatusFailed); 1985 return false; 1986 } 1987 1988 std::unique_lock<std::recursive_mutex> lock; 1989 target->GetBreakpointList().GetListMutex(lock); 1990 1991 const BreakpointList &breakpoints = target->GetBreakpointList(); 1992 1993 size_t num_breakpoints = breakpoints.GetSize(); 1994 if (num_breakpoints == 0) { 1995 result.SetError("No breakpoints, cannot add names."); 1996 result.SetStatus(eReturnStatusFailed); 1997 return false; 1998 } 1999 2000 // Particular breakpoint selected; disable that breakpoint. 2001 BreakpointIDList valid_bp_ids; 2002 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 2003 command, target, result, &valid_bp_ids, 2004 BreakpointName::Permissions::PermissionKinds::listPerm); 2005 2006 if (result.Succeeded()) { 2007 if (valid_bp_ids.GetSize() == 0) { 2008 result.SetError("No breakpoints specified, cannot add names."); 2009 result.SetStatus(eReturnStatusFailed); 2010 return false; 2011 } 2012 size_t num_valid_ids = valid_bp_ids.GetSize(); 2013 const char *bp_name = m_name_options.m_name.GetCurrentValue(); 2014 Status error; // This error reports illegal names, but we've already 2015 // checked that, so we don't need to check it again here. 2016 for (size_t index = 0; index < num_valid_ids; index++) { 2017 lldb::break_id_t bp_id = 2018 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); 2019 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); 2020 target->AddNameToBreakpoint(bp_sp, bp_name, error); 2021 } 2022 } 2023 2024 return true; 2025 } 2026 2027 private: 2028 BreakpointNameOptionGroup m_name_options; 2029 OptionGroupOptions m_option_group; 2030 }; 2031 2032 class CommandObjectBreakpointNameDelete : public CommandObjectParsed { 2033 public: 2034 CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter) 2035 : CommandObjectParsed( 2036 interpreter, "delete", 2037 "Delete a name from the breakpoints provided.", 2038 "breakpoint name delete <command-options> <breakpoint-id-list>"), 2039 m_name_options(), m_option_group() { 2040 // Create the first variant for the first (and only) argument for this 2041 // command. 2042 CommandArgumentEntry arg1; 2043 CommandArgumentData id_arg; 2044 id_arg.arg_type = eArgTypeBreakpointID; 2045 id_arg.arg_repetition = eArgRepeatOptional; 2046 arg1.push_back(id_arg); 2047 m_arguments.push_back(arg1); 2048 2049 m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL); 2050 m_option_group.Finalize(); 2051 } 2052 2053 ~CommandObjectBreakpointNameDelete() override = default; 2054 2055 Options *GetOptions() override { return &m_option_group; } 2056 2057 protected: 2058 bool DoExecute(Args &command, CommandReturnObject &result) override { 2059 if (!m_name_options.m_name.OptionWasSet()) { 2060 result.SetError("No name option provided."); 2061 return false; 2062 } 2063 2064 Target *target = 2065 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 2066 2067 if (target == nullptr) { 2068 result.AppendError("Invalid target. No existing target or breakpoints."); 2069 result.SetStatus(eReturnStatusFailed); 2070 return false; 2071 } 2072 2073 std::unique_lock<std::recursive_mutex> lock; 2074 target->GetBreakpointList().GetListMutex(lock); 2075 2076 const BreakpointList &breakpoints = target->GetBreakpointList(); 2077 2078 size_t num_breakpoints = breakpoints.GetSize(); 2079 if (num_breakpoints == 0) { 2080 result.SetError("No breakpoints, cannot delete names."); 2081 result.SetStatus(eReturnStatusFailed); 2082 return false; 2083 } 2084 2085 // Particular breakpoint selected; disable that breakpoint. 2086 BreakpointIDList valid_bp_ids; 2087 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 2088 command, target, result, &valid_bp_ids, 2089 BreakpointName::Permissions::PermissionKinds::deletePerm); 2090 2091 if (result.Succeeded()) { 2092 if (valid_bp_ids.GetSize() == 0) { 2093 result.SetError("No breakpoints specified, cannot delete names."); 2094 result.SetStatus(eReturnStatusFailed); 2095 return false; 2096 } 2097 ConstString bp_name(m_name_options.m_name.GetCurrentValue()); 2098 size_t num_valid_ids = valid_bp_ids.GetSize(); 2099 for (size_t index = 0; index < num_valid_ids; index++) { 2100 lldb::break_id_t bp_id = 2101 valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID(); 2102 BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id); 2103 target->RemoveNameFromBreakpoint(bp_sp, bp_name); 2104 } 2105 } 2106 2107 return true; 2108 } 2109 2110 private: 2111 BreakpointNameOptionGroup m_name_options; 2112 OptionGroupOptions m_option_group; 2113 }; 2114 2115 class CommandObjectBreakpointNameList : public CommandObjectParsed { 2116 public: 2117 CommandObjectBreakpointNameList(CommandInterpreter &interpreter) 2118 : CommandObjectParsed(interpreter, "list", 2119 "List either the names for a breakpoint or info " 2120 "about a given name. With no arguments, lists all " 2121 "names", 2122 "breakpoint name list <command-options>"), 2123 m_name_options(), m_option_group() { 2124 m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL); 2125 m_option_group.Finalize(); 2126 } 2127 2128 ~CommandObjectBreakpointNameList() override = default; 2129 2130 Options *GetOptions() override { return &m_option_group; } 2131 2132 protected: 2133 bool DoExecute(Args &command, CommandReturnObject &result) override { 2134 Target *target = 2135 GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue()); 2136 2137 if (target == nullptr) { 2138 result.AppendError("Invalid target. No existing target or breakpoints."); 2139 result.SetStatus(eReturnStatusFailed); 2140 return false; 2141 } 2142 2143 2144 std::vector<std::string> name_list; 2145 if (command.empty()) { 2146 target->GetBreakpointNames(name_list); 2147 } else { 2148 for (const Args::ArgEntry &arg : command) 2149 { 2150 name_list.push_back(arg.c_str()); 2151 } 2152 } 2153 2154 if (name_list.empty()) { 2155 result.AppendMessage("No breakpoint names found."); 2156 } else { 2157 for (const std::string &name_str : name_list) { 2158 const char *name = name_str.c_str(); 2159 // First print out the options for the name: 2160 Status error; 2161 BreakpointName *bp_name = target->FindBreakpointName(ConstString(name), 2162 false, 2163 error); 2164 if (bp_name) 2165 { 2166 StreamString s; 2167 result.AppendMessageWithFormat("Name: %s\n", name); 2168 if (bp_name->GetDescription(&s, eDescriptionLevelFull)) 2169 { 2170 result.AppendMessage(s.GetString()); 2171 } 2172 2173 std::unique_lock<std::recursive_mutex> lock; 2174 target->GetBreakpointList().GetListMutex(lock); 2175 2176 BreakpointList &breakpoints = target->GetBreakpointList(); 2177 bool any_set = false; 2178 for (BreakpointSP bp_sp : breakpoints.Breakpoints()) { 2179 if (bp_sp->MatchesName(name)) { 2180 StreamString s; 2181 any_set = true; 2182 bp_sp->GetDescription(&s, eDescriptionLevelBrief); 2183 s.EOL(); 2184 result.AppendMessage(s.GetString()); 2185 } 2186 } 2187 if (!any_set) 2188 result.AppendMessage("No breakpoints using this name."); 2189 } else { 2190 result.AppendMessageWithFormat("Name: %s not found.\n", name); 2191 } 2192 } 2193 } 2194 return true; 2195 } 2196 2197 private: 2198 BreakpointNameOptionGroup m_name_options; 2199 OptionGroupOptions m_option_group; 2200 }; 2201 2202 //------------------------------------------------------------------------- 2203 // CommandObjectBreakpointName 2204 //------------------------------------------------------------------------- 2205 class CommandObjectBreakpointName : public CommandObjectMultiword { 2206 public: 2207 CommandObjectBreakpointName(CommandInterpreter &interpreter) 2208 : CommandObjectMultiword( 2209 interpreter, "name", "Commands to manage name tags for breakpoints", 2210 "breakpoint name <subcommand> [<command-options>]") { 2211 CommandObjectSP add_command_object( 2212 new CommandObjectBreakpointNameAdd(interpreter)); 2213 CommandObjectSP delete_command_object( 2214 new CommandObjectBreakpointNameDelete(interpreter)); 2215 CommandObjectSP list_command_object( 2216 new CommandObjectBreakpointNameList(interpreter)); 2217 CommandObjectSP configure_command_object( 2218 new CommandObjectBreakpointNameConfigure(interpreter)); 2219 2220 LoadSubCommand("add", add_command_object); 2221 LoadSubCommand("delete", delete_command_object); 2222 LoadSubCommand("list", list_command_object); 2223 LoadSubCommand("configure", configure_command_object); 2224 } 2225 2226 ~CommandObjectBreakpointName() override = default; 2227 }; 2228 2229 //------------------------------------------------------------------------- 2230 // CommandObjectBreakpointRead 2231 //------------------------------------------------------------------------- 2232 #pragma mark Read::CommandOptions 2233 static OptionDefinition g_breakpoint_read_options[] = { 2234 // clang-format off 2235 { LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file from which to read the breakpoints." }, 2236 {LLDB_OPT_SET_ALL, false, "breakpoint-name", 'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Only read in breakpoints with this name."}, 2237 // clang-format on 2238 }; 2239 2240 #pragma mark Read 2241 2242 class CommandObjectBreakpointRead : public CommandObjectParsed { 2243 public: 2244 CommandObjectBreakpointRead(CommandInterpreter &interpreter) 2245 : CommandObjectParsed(interpreter, "breakpoint read", 2246 "Read and set the breakpoints previously saved to " 2247 "a file with \"breakpoint write\". ", 2248 nullptr), 2249 m_options() { 2250 CommandArgumentEntry arg; 2251 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 2252 eArgTypeBreakpointIDRange); 2253 // Add the entry for the first argument for this command to the object's 2254 // arguments vector. 2255 m_arguments.push_back(arg); 2256 } 2257 2258 ~CommandObjectBreakpointRead() override = default; 2259 2260 Options *GetOptions() override { return &m_options; } 2261 2262 class CommandOptions : public Options { 2263 public: 2264 CommandOptions() : Options() {} 2265 2266 ~CommandOptions() override = default; 2267 2268 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2269 ExecutionContext *execution_context) override { 2270 Status error; 2271 const int short_option = m_getopt_table[option_idx].val; 2272 2273 switch (short_option) { 2274 case 'f': 2275 m_filename.assign(option_arg); 2276 break; 2277 case 'N': { 2278 Status name_error; 2279 if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg), 2280 name_error)) { 2281 error.SetErrorStringWithFormat("Invalid breakpoint name: %s", 2282 name_error.AsCString()); 2283 } 2284 m_names.push_back(option_arg); 2285 break; 2286 } 2287 default: 2288 error.SetErrorStringWithFormat("unrecognized option '%c'", 2289 short_option); 2290 break; 2291 } 2292 2293 return error; 2294 } 2295 2296 void OptionParsingStarting(ExecutionContext *execution_context) override { 2297 m_filename.clear(); 2298 m_names.clear(); 2299 } 2300 2301 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2302 return llvm::makeArrayRef(g_breakpoint_read_options); 2303 } 2304 2305 // Instance variables to hold the values for command options. 2306 2307 std::string m_filename; 2308 std::vector<std::string> m_names; 2309 }; 2310 2311 protected: 2312 bool DoExecute(Args &command, CommandReturnObject &result) override { 2313 Target *target = GetSelectedOrDummyTarget(); 2314 if (target == nullptr) { 2315 result.AppendError("Invalid target. No existing target or breakpoints."); 2316 result.SetStatus(eReturnStatusFailed); 2317 return false; 2318 } 2319 2320 std::unique_lock<std::recursive_mutex> lock; 2321 target->GetBreakpointList().GetListMutex(lock); 2322 2323 FileSpec input_spec(m_options.m_filename, true); 2324 BreakpointIDList new_bps; 2325 Status error = target->CreateBreakpointsFromFile( 2326 input_spec, m_options.m_names, new_bps); 2327 2328 if (!error.Success()) { 2329 result.AppendError(error.AsCString()); 2330 result.SetStatus(eReturnStatusFailed); 2331 return false; 2332 } 2333 2334 Stream &output_stream = result.GetOutputStream(); 2335 2336 size_t num_breakpoints = new_bps.GetSize(); 2337 if (num_breakpoints == 0) { 2338 result.AppendMessage("No breakpoints added."); 2339 } else { 2340 // No breakpoint selected; show info about all currently set breakpoints. 2341 result.AppendMessage("New breakpoints:"); 2342 for (size_t i = 0; i < num_breakpoints; ++i) { 2343 BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i); 2344 Breakpoint *bp = target->GetBreakpointList() 2345 .FindBreakpointByID(bp_id.GetBreakpointID()) 2346 .get(); 2347 if (bp) 2348 bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial, 2349 false); 2350 } 2351 } 2352 return result.Succeeded(); 2353 } 2354 2355 private: 2356 CommandOptions m_options; 2357 }; 2358 2359 //------------------------------------------------------------------------- 2360 // CommandObjectBreakpointWrite 2361 //------------------------------------------------------------------------- 2362 #pragma mark Write::CommandOptions 2363 static OptionDefinition g_breakpoint_write_options[] = { 2364 // clang-format off 2365 { LLDB_OPT_SET_ALL, true, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename, "The file into which to write the breakpoints." }, 2366 { LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Append to saved breakpoints file if it exists."}, 2367 // clang-format on 2368 }; 2369 2370 #pragma mark Write 2371 class CommandObjectBreakpointWrite : public CommandObjectParsed { 2372 public: 2373 CommandObjectBreakpointWrite(CommandInterpreter &interpreter) 2374 : CommandObjectParsed(interpreter, "breakpoint write", 2375 "Write the breakpoints listed to a file that can " 2376 "be read in with \"breakpoint read\". " 2377 "If given no arguments, writes all breakpoints.", 2378 nullptr), 2379 m_options() { 2380 CommandArgumentEntry arg; 2381 CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID, 2382 eArgTypeBreakpointIDRange); 2383 // Add the entry for the first argument for this command to the object's 2384 // arguments vector. 2385 m_arguments.push_back(arg); 2386 } 2387 2388 ~CommandObjectBreakpointWrite() override = default; 2389 2390 Options *GetOptions() override { return &m_options; } 2391 2392 class CommandOptions : public Options { 2393 public: 2394 CommandOptions() : Options() {} 2395 2396 ~CommandOptions() override = default; 2397 2398 Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg, 2399 ExecutionContext *execution_context) override { 2400 Status error; 2401 const int short_option = m_getopt_table[option_idx].val; 2402 2403 switch (short_option) { 2404 case 'f': 2405 m_filename.assign(option_arg); 2406 break; 2407 case 'a': 2408 m_append = true; 2409 break; 2410 default: 2411 error.SetErrorStringWithFormat("unrecognized option '%c'", 2412 short_option); 2413 break; 2414 } 2415 2416 return error; 2417 } 2418 2419 void OptionParsingStarting(ExecutionContext *execution_context) override { 2420 m_filename.clear(); 2421 m_append = false; 2422 } 2423 2424 llvm::ArrayRef<OptionDefinition> GetDefinitions() override { 2425 return llvm::makeArrayRef(g_breakpoint_write_options); 2426 } 2427 2428 // Instance variables to hold the values for command options. 2429 2430 std::string m_filename; 2431 bool m_append = false; 2432 }; 2433 2434 protected: 2435 bool DoExecute(Args &command, CommandReturnObject &result) override { 2436 Target *target = GetSelectedOrDummyTarget(); 2437 if (target == nullptr) { 2438 result.AppendError("Invalid target. No existing target or breakpoints."); 2439 result.SetStatus(eReturnStatusFailed); 2440 return false; 2441 } 2442 2443 std::unique_lock<std::recursive_mutex> lock; 2444 target->GetBreakpointList().GetListMutex(lock); 2445 2446 BreakpointIDList valid_bp_ids; 2447 if (!command.empty()) { 2448 CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs( 2449 command, target, result, &valid_bp_ids, 2450 BreakpointName::Permissions::PermissionKinds::listPerm); 2451 2452 if (!result.Succeeded()) { 2453 result.SetStatus(eReturnStatusFailed); 2454 return false; 2455 } 2456 } 2457 Status error = target->SerializeBreakpointsToFile( 2458 FileSpec(m_options.m_filename, true), valid_bp_ids, m_options.m_append); 2459 if (!error.Success()) { 2460 result.AppendErrorWithFormat("error serializing breakpoints: %s.", 2461 error.AsCString()); 2462 result.SetStatus(eReturnStatusFailed); 2463 } 2464 return result.Succeeded(); 2465 } 2466 2467 private: 2468 CommandOptions m_options; 2469 }; 2470 2471 //------------------------------------------------------------------------- 2472 // CommandObjectMultiwordBreakpoint 2473 //------------------------------------------------------------------------- 2474 #pragma mark MultiwordBreakpoint 2475 2476 CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint( 2477 CommandInterpreter &interpreter) 2478 : CommandObjectMultiword( 2479 interpreter, "breakpoint", 2480 "Commands for operating on breakpoints (see 'help b' for shorthand.)", 2481 "breakpoint <subcommand> [<command-options>]") { 2482 CommandObjectSP list_command_object( 2483 new CommandObjectBreakpointList(interpreter)); 2484 CommandObjectSP enable_command_object( 2485 new CommandObjectBreakpointEnable(interpreter)); 2486 CommandObjectSP disable_command_object( 2487 new CommandObjectBreakpointDisable(interpreter)); 2488 CommandObjectSP clear_command_object( 2489 new CommandObjectBreakpointClear(interpreter)); 2490 CommandObjectSP delete_command_object( 2491 new CommandObjectBreakpointDelete(interpreter)); 2492 CommandObjectSP set_command_object( 2493 new CommandObjectBreakpointSet(interpreter)); 2494 CommandObjectSP command_command_object( 2495 new CommandObjectBreakpointCommand(interpreter)); 2496 CommandObjectSP modify_command_object( 2497 new CommandObjectBreakpointModify(interpreter)); 2498 CommandObjectSP name_command_object( 2499 new CommandObjectBreakpointName(interpreter)); 2500 CommandObjectSP write_command_object( 2501 new CommandObjectBreakpointWrite(interpreter)); 2502 CommandObjectSP read_command_object( 2503 new CommandObjectBreakpointRead(interpreter)); 2504 2505 list_command_object->SetCommandName("breakpoint list"); 2506 enable_command_object->SetCommandName("breakpoint enable"); 2507 disable_command_object->SetCommandName("breakpoint disable"); 2508 clear_command_object->SetCommandName("breakpoint clear"); 2509 delete_command_object->SetCommandName("breakpoint delete"); 2510 set_command_object->SetCommandName("breakpoint set"); 2511 command_command_object->SetCommandName("breakpoint command"); 2512 modify_command_object->SetCommandName("breakpoint modify"); 2513 name_command_object->SetCommandName("breakpoint name"); 2514 write_command_object->SetCommandName("breakpoint write"); 2515 read_command_object->SetCommandName("breakpoint read"); 2516 2517 LoadSubCommand("list", list_command_object); 2518 LoadSubCommand("enable", enable_command_object); 2519 LoadSubCommand("disable", disable_command_object); 2520 LoadSubCommand("clear", clear_command_object); 2521 LoadSubCommand("delete", delete_command_object); 2522 LoadSubCommand("set", set_command_object); 2523 LoadSubCommand("command", command_command_object); 2524 LoadSubCommand("modify", modify_command_object); 2525 LoadSubCommand("name", name_command_object); 2526 LoadSubCommand("write", write_command_object); 2527 LoadSubCommand("read", read_command_object); 2528 } 2529 2530 CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default; 2531 2532 void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target, 2533 bool allow_locations, 2534 CommandReturnObject &result, 2535 BreakpointIDList *valid_ids, 2536 BreakpointName::Permissions 2537 ::PermissionKinds 2538 purpose) { 2539 // args can be strings representing 1). integers (for breakpoint ids) 2540 // 2). the full breakpoint & location 2541 // canonical representation 2542 // 3). the word "to" or a hyphen, 2543 // representing a range (in which case there 2544 // had *better* be an entry both before & 2545 // after of one of the first two types. 2546 // 4). A breakpoint name 2547 // If args is empty, we will use the last created breakpoint (if there is 2548 // one.) 2549 2550 Args temp_args; 2551 2552 if (args.empty()) { 2553 if (target->GetLastCreatedBreakpoint()) { 2554 valid_ids->AddBreakpointID(BreakpointID( 2555 target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID)); 2556 result.SetStatus(eReturnStatusSuccessFinishNoResult); 2557 } else { 2558 result.AppendError( 2559 "No breakpoint specified and no last created breakpoint."); 2560 result.SetStatus(eReturnStatusFailed); 2561 } 2562 return; 2563 } 2564 2565 // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff 2566 // directly from the old ARGS to the new TEMP_ARGS. Do not copy breakpoint 2567 // id range strings over; instead generate a list of strings for all the 2568 // breakpoint ids in the range, and shove all of those breakpoint id strings 2569 // into TEMP_ARGS. 2570 2571 BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations, 2572 purpose, result, temp_args); 2573 2574 // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual 2575 // BreakpointIDList: 2576 2577 valid_ids->InsertStringArray(temp_args.GetArgumentArrayRef(), 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