1dda28197Spatrick //===-- CommandObjectBreakpoint.cpp ---------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "CommandObjectBreakpoint.h"
10061da546Spatrick #include "CommandObjectBreakpointCommand.h"
11061da546Spatrick #include "lldb/Breakpoint/Breakpoint.h"
12061da546Spatrick #include "lldb/Breakpoint/BreakpointIDList.h"
13061da546Spatrick #include "lldb/Breakpoint/BreakpointLocation.h"
14061da546Spatrick #include "lldb/Host/OptionParser.h"
15061da546Spatrick #include "lldb/Interpreter/CommandInterpreter.h"
16*f6aab3d8Srobert #include "lldb/Interpreter/CommandOptionArgumentTable.h"
17061da546Spatrick #include "lldb/Interpreter/CommandReturnObject.h"
18061da546Spatrick #include "lldb/Interpreter/OptionArgParser.h"
19061da546Spatrick #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
20061da546Spatrick #include "lldb/Interpreter/OptionValueBoolean.h"
21be691f3bSpatrick #include "lldb/Interpreter/OptionValueFileColonLine.h"
22061da546Spatrick #include "lldb/Interpreter/OptionValueString.h"
23061da546Spatrick #include "lldb/Interpreter/OptionValueUInt64.h"
24061da546Spatrick #include "lldb/Interpreter/Options.h"
25061da546Spatrick #include "lldb/Target/Language.h"
26061da546Spatrick #include "lldb/Target/StackFrame.h"
27061da546Spatrick #include "lldb/Target/Target.h"
28061da546Spatrick #include "lldb/Target/ThreadSpec.h"
29061da546Spatrick #include "lldb/Utility/RegularExpression.h"
30061da546Spatrick #include "lldb/Utility/StreamString.h"
31061da546Spatrick
32061da546Spatrick #include <memory>
33*f6aab3d8Srobert #include <optional>
34061da546Spatrick #include <vector>
35061da546Spatrick
36061da546Spatrick using namespace lldb;
37061da546Spatrick using namespace lldb_private;
38061da546Spatrick
AddBreakpointDescription(Stream * s,Breakpoint * bp,lldb::DescriptionLevel level)39061da546Spatrick static void AddBreakpointDescription(Stream *s, Breakpoint *bp,
40061da546Spatrick lldb::DescriptionLevel level) {
41061da546Spatrick s->IndentMore();
42061da546Spatrick bp->GetDescription(s, level, true);
43061da546Spatrick s->IndentLess();
44061da546Spatrick s->EOL();
45061da546Spatrick }
46061da546Spatrick
47061da546Spatrick // Modifiable Breakpoint Options
48061da546Spatrick #pragma mark Modify::CommandOptions
49061da546Spatrick #define LLDB_OPTIONS_breakpoint_modify
50061da546Spatrick #include "CommandOptions.inc"
51061da546Spatrick
52061da546Spatrick class lldb_private::BreakpointOptionGroup : public OptionGroup {
53061da546Spatrick public:
BreakpointOptionGroup()54*f6aab3d8Srobert BreakpointOptionGroup() : m_bp_opts(false) {}
55061da546Spatrick
56061da546Spatrick ~BreakpointOptionGroup() override = default;
57061da546Spatrick
GetDefinitions()58061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
59*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_modify_options);
60061da546Spatrick }
61061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)62061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
63061da546Spatrick ExecutionContext *execution_context) override {
64061da546Spatrick Status error;
65061da546Spatrick const int short_option =
66061da546Spatrick g_breakpoint_modify_options[option_idx].short_option;
67061da546Spatrick
68061da546Spatrick switch (short_option) {
69061da546Spatrick case 'c':
70061da546Spatrick // Normally an empty breakpoint condition marks is as unset. But we need
71061da546Spatrick // to say it was passed in.
72061da546Spatrick m_bp_opts.SetCondition(option_arg.str().c_str());
73061da546Spatrick m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition);
74061da546Spatrick break;
75061da546Spatrick case 'C':
76dda28197Spatrick m_commands.push_back(std::string(option_arg));
77061da546Spatrick break;
78061da546Spatrick case 'd':
79061da546Spatrick m_bp_opts.SetEnabled(false);
80061da546Spatrick break;
81061da546Spatrick case 'e':
82061da546Spatrick m_bp_opts.SetEnabled(true);
83061da546Spatrick break;
84061da546Spatrick case 'G': {
85061da546Spatrick bool value, success;
86061da546Spatrick value = OptionArgParser::ToBoolean(option_arg, false, &success);
87061da546Spatrick if (success) {
88061da546Spatrick m_bp_opts.SetAutoContinue(value);
89061da546Spatrick } else
90061da546Spatrick error.SetErrorStringWithFormat(
91061da546Spatrick "invalid boolean value '%s' passed for -G option",
92061da546Spatrick option_arg.str().c_str());
93061da546Spatrick } break;
94061da546Spatrick case 'i': {
95061da546Spatrick uint32_t ignore_count;
96061da546Spatrick if (option_arg.getAsInteger(0, ignore_count))
97061da546Spatrick error.SetErrorStringWithFormat("invalid ignore count '%s'",
98061da546Spatrick option_arg.str().c_str());
99061da546Spatrick else
100061da546Spatrick m_bp_opts.SetIgnoreCount(ignore_count);
101061da546Spatrick } break;
102061da546Spatrick case 'o': {
103061da546Spatrick bool value, success;
104061da546Spatrick value = OptionArgParser::ToBoolean(option_arg, false, &success);
105061da546Spatrick if (success) {
106061da546Spatrick m_bp_opts.SetOneShot(value);
107061da546Spatrick } else
108061da546Spatrick error.SetErrorStringWithFormat(
109061da546Spatrick "invalid boolean value '%s' passed for -o option",
110061da546Spatrick option_arg.str().c_str());
111061da546Spatrick } break;
112061da546Spatrick case 't': {
113061da546Spatrick lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID;
114*f6aab3d8Srobert if (option_arg == "current") {
115*f6aab3d8Srobert if (!execution_context) {
116*f6aab3d8Srobert error.SetErrorStringWithFormat("No context to determine current "
117*f6aab3d8Srobert "thread");
118*f6aab3d8Srobert } else {
119*f6aab3d8Srobert ThreadSP ctx_thread_sp = execution_context->GetThreadSP();
120*f6aab3d8Srobert if (!ctx_thread_sp || !ctx_thread_sp->IsValid()) {
121*f6aab3d8Srobert error.SetErrorStringWithFormat("No currently selected thread");
122*f6aab3d8Srobert } else {
123*f6aab3d8Srobert thread_id = ctx_thread_sp->GetID();
124*f6aab3d8Srobert }
125*f6aab3d8Srobert }
126*f6aab3d8Srobert } else if (option_arg.getAsInteger(0, thread_id)) {
127061da546Spatrick error.SetErrorStringWithFormat("invalid thread id string '%s'",
128061da546Spatrick option_arg.str().c_str());
129061da546Spatrick }
130*f6aab3d8Srobert if (thread_id != LLDB_INVALID_THREAD_ID)
131061da546Spatrick m_bp_opts.SetThreadID(thread_id);
132061da546Spatrick } break;
133061da546Spatrick case 'T':
134061da546Spatrick m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str());
135061da546Spatrick break;
136061da546Spatrick case 'q':
137061da546Spatrick m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str());
138061da546Spatrick break;
139061da546Spatrick case 'x': {
140061da546Spatrick uint32_t thread_index = UINT32_MAX;
141*f6aab3d8Srobert if (option_arg.getAsInteger(0, thread_index)) {
142061da546Spatrick error.SetErrorStringWithFormat("invalid thread index string '%s'",
143061da546Spatrick option_arg.str().c_str());
144*f6aab3d8Srobert } else {
145061da546Spatrick m_bp_opts.GetThreadSpec()->SetIndex(thread_index);
146*f6aab3d8Srobert }
147061da546Spatrick } break;
148061da546Spatrick default:
149061da546Spatrick llvm_unreachable("Unimplemented option");
150061da546Spatrick }
151061da546Spatrick
152061da546Spatrick return error;
153061da546Spatrick }
154061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)155061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
156061da546Spatrick m_bp_opts.Clear();
157061da546Spatrick m_commands.clear();
158061da546Spatrick }
159061da546Spatrick
OptionParsingFinished(ExecutionContext * execution_context)160061da546Spatrick Status OptionParsingFinished(ExecutionContext *execution_context) override {
161061da546Spatrick if (!m_commands.empty()) {
162061da546Spatrick auto cmd_data = std::make_unique<BreakpointOptions::CommandData>();
163061da546Spatrick
164061da546Spatrick for (std::string &str : m_commands)
165061da546Spatrick cmd_data->user_source.AppendString(str);
166061da546Spatrick
167061da546Spatrick cmd_data->stop_on_error = true;
168061da546Spatrick m_bp_opts.SetCommandDataCallback(cmd_data);
169061da546Spatrick }
170061da546Spatrick return Status();
171061da546Spatrick }
172061da546Spatrick
GetBreakpointOptions()173061da546Spatrick const BreakpointOptions &GetBreakpointOptions() { return m_bp_opts; }
174061da546Spatrick
175061da546Spatrick std::vector<std::string> m_commands;
176061da546Spatrick BreakpointOptions m_bp_opts;
177061da546Spatrick };
178061da546Spatrick
179061da546Spatrick #define LLDB_OPTIONS_breakpoint_dummy
180061da546Spatrick #include "CommandOptions.inc"
181061da546Spatrick
182061da546Spatrick class BreakpointDummyOptionGroup : public OptionGroup {
183061da546Spatrick public:
184*f6aab3d8Srobert BreakpointDummyOptionGroup() = default;
185061da546Spatrick
186061da546Spatrick ~BreakpointDummyOptionGroup() override = default;
187061da546Spatrick
GetDefinitions()188061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
189*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_dummy_options);
190061da546Spatrick }
191061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)192061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
193061da546Spatrick ExecutionContext *execution_context) override {
194061da546Spatrick Status error;
195061da546Spatrick const int short_option =
196061da546Spatrick g_breakpoint_dummy_options[option_idx].short_option;
197061da546Spatrick
198061da546Spatrick switch (short_option) {
199061da546Spatrick case 'D':
200061da546Spatrick m_use_dummy = true;
201061da546Spatrick break;
202061da546Spatrick default:
203061da546Spatrick llvm_unreachable("Unimplemented option");
204061da546Spatrick }
205061da546Spatrick
206061da546Spatrick return error;
207061da546Spatrick }
208061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)209061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
210061da546Spatrick m_use_dummy = false;
211061da546Spatrick }
212061da546Spatrick
213061da546Spatrick bool m_use_dummy;
214061da546Spatrick };
215061da546Spatrick
216061da546Spatrick #define LLDB_OPTIONS_breakpoint_set
217061da546Spatrick #include "CommandOptions.inc"
218061da546Spatrick
219061da546Spatrick // CommandObjectBreakpointSet
220061da546Spatrick
221061da546Spatrick class CommandObjectBreakpointSet : public CommandObjectParsed {
222061da546Spatrick public:
223061da546Spatrick enum BreakpointSetType {
224061da546Spatrick eSetTypeInvalid,
225061da546Spatrick eSetTypeFileAndLine,
226061da546Spatrick eSetTypeAddress,
227061da546Spatrick eSetTypeFunctionName,
228061da546Spatrick eSetTypeFunctionRegexp,
229061da546Spatrick eSetTypeSourceRegexp,
230061da546Spatrick eSetTypeException,
231061da546Spatrick eSetTypeScripted,
232061da546Spatrick };
233061da546Spatrick
CommandObjectBreakpointSet(CommandInterpreter & interpreter)234061da546Spatrick CommandObjectBreakpointSet(CommandInterpreter &interpreter)
235061da546Spatrick : CommandObjectParsed(
236061da546Spatrick interpreter, "breakpoint set",
237061da546Spatrick "Sets a breakpoint or set of breakpoints in the executable.",
238061da546Spatrick "breakpoint set <cmd-options>"),
239*f6aab3d8Srobert m_python_class_options("scripted breakpoint", true, 'P') {
240061da546Spatrick // We're picking up all the normal options, commands and disable.
241061da546Spatrick m_all_options.Append(&m_python_class_options,
242061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_2, LLDB_OPT_SET_11);
243061da546Spatrick m_all_options.Append(&m_bp_opts,
244061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4,
245061da546Spatrick LLDB_OPT_SET_ALL);
246061da546Spatrick m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
247061da546Spatrick m_all_options.Append(&m_options);
248061da546Spatrick m_all_options.Finalize();
249061da546Spatrick }
250061da546Spatrick
251061da546Spatrick ~CommandObjectBreakpointSet() override = default;
252061da546Spatrick
GetOptions()253061da546Spatrick Options *GetOptions() override { return &m_all_options; }
254061da546Spatrick
255061da546Spatrick class CommandOptions : public OptionGroup {
256061da546Spatrick public:
257*f6aab3d8Srobert CommandOptions() = default;
258061da546Spatrick
259061da546Spatrick ~CommandOptions() override = default;
260061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)261061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
262061da546Spatrick ExecutionContext *execution_context) override {
263061da546Spatrick Status error;
264061da546Spatrick const int short_option =
265061da546Spatrick g_breakpoint_set_options[option_idx].short_option;
266061da546Spatrick
267061da546Spatrick switch (short_option) {
268061da546Spatrick case 'a': {
269061da546Spatrick m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
270061da546Spatrick LLDB_INVALID_ADDRESS, &error);
271061da546Spatrick } break;
272061da546Spatrick
273061da546Spatrick case 'A':
274061da546Spatrick m_all_files = true;
275061da546Spatrick break;
276061da546Spatrick
277061da546Spatrick case 'b':
278dda28197Spatrick m_func_names.push_back(std::string(option_arg));
279061da546Spatrick m_func_name_type_mask |= eFunctionNameTypeBase;
280061da546Spatrick break;
281061da546Spatrick
282dda28197Spatrick case 'u':
283061da546Spatrick if (option_arg.getAsInteger(0, m_column))
284061da546Spatrick error.SetErrorStringWithFormat("invalid column number: %s",
285061da546Spatrick option_arg.str().c_str());
286061da546Spatrick break;
287061da546Spatrick
288061da546Spatrick case 'E': {
289061da546Spatrick LanguageType language = Language::GetLanguageTypeFromString(option_arg);
290061da546Spatrick
291061da546Spatrick switch (language) {
292061da546Spatrick case eLanguageTypeC89:
293061da546Spatrick case eLanguageTypeC:
294061da546Spatrick case eLanguageTypeC99:
295061da546Spatrick case eLanguageTypeC11:
296061da546Spatrick m_exception_language = eLanguageTypeC;
297061da546Spatrick break;
298061da546Spatrick case eLanguageTypeC_plus_plus:
299061da546Spatrick case eLanguageTypeC_plus_plus_03:
300061da546Spatrick case eLanguageTypeC_plus_plus_11:
301061da546Spatrick case eLanguageTypeC_plus_plus_14:
302061da546Spatrick m_exception_language = eLanguageTypeC_plus_plus;
303061da546Spatrick break;
304061da546Spatrick case eLanguageTypeObjC:
305061da546Spatrick m_exception_language = eLanguageTypeObjC;
306061da546Spatrick break;
307061da546Spatrick case eLanguageTypeObjC_plus_plus:
308061da546Spatrick error.SetErrorStringWithFormat(
309061da546Spatrick "Set exception breakpoints separately for c++ and objective-c");
310061da546Spatrick break;
311061da546Spatrick case eLanguageTypeUnknown:
312061da546Spatrick error.SetErrorStringWithFormat(
313061da546Spatrick "Unknown language type: '%s' for exception breakpoint",
314061da546Spatrick option_arg.str().c_str());
315061da546Spatrick break;
316061da546Spatrick default:
317061da546Spatrick error.SetErrorStringWithFormat(
318061da546Spatrick "Unsupported language type: '%s' for exception breakpoint",
319061da546Spatrick option_arg.str().c_str());
320061da546Spatrick }
321061da546Spatrick } break;
322061da546Spatrick
323061da546Spatrick case 'f':
324061da546Spatrick m_filenames.AppendIfUnique(FileSpec(option_arg));
325061da546Spatrick break;
326061da546Spatrick
327061da546Spatrick case 'F':
328dda28197Spatrick m_func_names.push_back(std::string(option_arg));
329061da546Spatrick m_func_name_type_mask |= eFunctionNameTypeFull;
330061da546Spatrick break;
331061da546Spatrick
332061da546Spatrick case 'h': {
333061da546Spatrick bool success;
334061da546Spatrick m_catch_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
335061da546Spatrick if (!success)
336061da546Spatrick error.SetErrorStringWithFormat(
337061da546Spatrick "Invalid boolean value for on-catch option: '%s'",
338061da546Spatrick option_arg.str().c_str());
339061da546Spatrick } break;
340061da546Spatrick
341061da546Spatrick case 'H':
342061da546Spatrick m_hardware = true;
343061da546Spatrick break;
344061da546Spatrick
345061da546Spatrick case 'K': {
346061da546Spatrick bool success;
347061da546Spatrick bool value;
348061da546Spatrick value = OptionArgParser::ToBoolean(option_arg, true, &success);
349061da546Spatrick if (value)
350061da546Spatrick m_skip_prologue = eLazyBoolYes;
351061da546Spatrick else
352061da546Spatrick m_skip_prologue = eLazyBoolNo;
353061da546Spatrick
354061da546Spatrick if (!success)
355061da546Spatrick error.SetErrorStringWithFormat(
356061da546Spatrick "Invalid boolean value for skip prologue option: '%s'",
357061da546Spatrick option_arg.str().c_str());
358061da546Spatrick } break;
359061da546Spatrick
360061da546Spatrick case 'l':
361061da546Spatrick if (option_arg.getAsInteger(0, m_line_num))
362061da546Spatrick error.SetErrorStringWithFormat("invalid line number: %s.",
363061da546Spatrick option_arg.str().c_str());
364061da546Spatrick break;
365061da546Spatrick
366061da546Spatrick case 'L':
367061da546Spatrick m_language = Language::GetLanguageTypeFromString(option_arg);
368061da546Spatrick if (m_language == eLanguageTypeUnknown)
369061da546Spatrick error.SetErrorStringWithFormat(
370061da546Spatrick "Unknown language type: '%s' for breakpoint",
371061da546Spatrick option_arg.str().c_str());
372061da546Spatrick break;
373061da546Spatrick
374061da546Spatrick case 'm': {
375061da546Spatrick bool success;
376061da546Spatrick bool value;
377061da546Spatrick value = OptionArgParser::ToBoolean(option_arg, true, &success);
378061da546Spatrick if (value)
379061da546Spatrick m_move_to_nearest_code = eLazyBoolYes;
380061da546Spatrick else
381061da546Spatrick m_move_to_nearest_code = eLazyBoolNo;
382061da546Spatrick
383061da546Spatrick if (!success)
384061da546Spatrick error.SetErrorStringWithFormat(
385061da546Spatrick "Invalid boolean value for move-to-nearest-code option: '%s'",
386061da546Spatrick option_arg.str().c_str());
387061da546Spatrick break;
388061da546Spatrick }
389061da546Spatrick
390061da546Spatrick case 'M':
391dda28197Spatrick m_func_names.push_back(std::string(option_arg));
392061da546Spatrick m_func_name_type_mask |= eFunctionNameTypeMethod;
393061da546Spatrick break;
394061da546Spatrick
395061da546Spatrick case 'n':
396dda28197Spatrick m_func_names.push_back(std::string(option_arg));
397061da546Spatrick m_func_name_type_mask |= eFunctionNameTypeAuto;
398061da546Spatrick break;
399061da546Spatrick
400061da546Spatrick case 'N': {
401061da546Spatrick if (BreakpointID::StringIsBreakpointName(option_arg, error))
402dda28197Spatrick m_breakpoint_names.push_back(std::string(option_arg));
403061da546Spatrick else
404061da546Spatrick error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
405061da546Spatrick option_arg.str().c_str());
406061da546Spatrick break;
407061da546Spatrick }
408061da546Spatrick
409061da546Spatrick case 'R': {
410061da546Spatrick lldb::addr_t tmp_offset_addr;
411061da546Spatrick tmp_offset_addr = OptionArgParser::ToAddress(execution_context,
412061da546Spatrick option_arg, 0, &error);
413061da546Spatrick if (error.Success())
414061da546Spatrick m_offset_addr = tmp_offset_addr;
415061da546Spatrick } break;
416061da546Spatrick
417061da546Spatrick case 'O':
418061da546Spatrick m_exception_extra_args.AppendArgument("-O");
419061da546Spatrick m_exception_extra_args.AppendArgument(option_arg);
420061da546Spatrick break;
421061da546Spatrick
422061da546Spatrick case 'p':
423dda28197Spatrick m_source_text_regexp.assign(std::string(option_arg));
424061da546Spatrick break;
425061da546Spatrick
426061da546Spatrick case 'r':
427dda28197Spatrick m_func_regexp.assign(std::string(option_arg));
428061da546Spatrick break;
429061da546Spatrick
430061da546Spatrick case 's':
431061da546Spatrick m_modules.AppendIfUnique(FileSpec(option_arg));
432061da546Spatrick break;
433061da546Spatrick
434061da546Spatrick case 'S':
435dda28197Spatrick m_func_names.push_back(std::string(option_arg));
436061da546Spatrick m_func_name_type_mask |= eFunctionNameTypeSelector;
437061da546Spatrick break;
438061da546Spatrick
439061da546Spatrick case 'w': {
440061da546Spatrick bool success;
441061da546Spatrick m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
442061da546Spatrick if (!success)
443061da546Spatrick error.SetErrorStringWithFormat(
444061da546Spatrick "Invalid boolean value for on-throw option: '%s'",
445061da546Spatrick option_arg.str().c_str());
446061da546Spatrick } break;
447061da546Spatrick
448061da546Spatrick case 'X':
449dda28197Spatrick m_source_regex_func_names.insert(std::string(option_arg));
450061da546Spatrick break;
451061da546Spatrick
452be691f3bSpatrick case 'y':
453be691f3bSpatrick {
454be691f3bSpatrick OptionValueFileColonLine value;
455be691f3bSpatrick Status fcl_err = value.SetValueFromString(option_arg);
456be691f3bSpatrick if (!fcl_err.Success()) {
457be691f3bSpatrick error.SetErrorStringWithFormat(
458be691f3bSpatrick "Invalid value for file:line specifier: %s",
459be691f3bSpatrick fcl_err.AsCString());
460be691f3bSpatrick } else {
461be691f3bSpatrick m_filenames.AppendIfUnique(value.GetFileSpec());
462be691f3bSpatrick m_line_num = value.GetLineNumber();
463be691f3bSpatrick m_column = value.GetColumnNumber();
464be691f3bSpatrick }
465be691f3bSpatrick } break;
466be691f3bSpatrick
467061da546Spatrick default:
468061da546Spatrick llvm_unreachable("Unimplemented option");
469061da546Spatrick }
470061da546Spatrick
471061da546Spatrick return error;
472061da546Spatrick }
473061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)474061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
475061da546Spatrick m_filenames.Clear();
476061da546Spatrick m_line_num = 0;
477061da546Spatrick m_column = 0;
478061da546Spatrick m_func_names.clear();
479061da546Spatrick m_func_name_type_mask = eFunctionNameTypeNone;
480061da546Spatrick m_func_regexp.clear();
481061da546Spatrick m_source_text_regexp.clear();
482061da546Spatrick m_modules.Clear();
483061da546Spatrick m_load_addr = LLDB_INVALID_ADDRESS;
484061da546Spatrick m_offset_addr = 0;
485061da546Spatrick m_catch_bp = false;
486061da546Spatrick m_throw_bp = true;
487061da546Spatrick m_hardware = false;
488061da546Spatrick m_exception_language = eLanguageTypeUnknown;
489061da546Spatrick m_language = lldb::eLanguageTypeUnknown;
490061da546Spatrick m_skip_prologue = eLazyBoolCalculate;
491061da546Spatrick m_breakpoint_names.clear();
492061da546Spatrick m_all_files = false;
493061da546Spatrick m_exception_extra_args.Clear();
494061da546Spatrick m_move_to_nearest_code = eLazyBoolCalculate;
495061da546Spatrick m_source_regex_func_names.clear();
496061da546Spatrick m_current_key.clear();
497061da546Spatrick }
498061da546Spatrick
GetDefinitions()499061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
500*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_set_options);
501061da546Spatrick }
502061da546Spatrick
503061da546Spatrick // Instance variables to hold the values for command options.
504061da546Spatrick
505061da546Spatrick std::string m_condition;
506061da546Spatrick FileSpecList m_filenames;
507be691f3bSpatrick uint32_t m_line_num = 0;
508be691f3bSpatrick uint32_t m_column = 0;
509061da546Spatrick std::vector<std::string> m_func_names;
510061da546Spatrick std::vector<std::string> m_breakpoint_names;
511be691f3bSpatrick lldb::FunctionNameType m_func_name_type_mask = eFunctionNameTypeNone;
512061da546Spatrick std::string m_func_regexp;
513061da546Spatrick std::string m_source_text_regexp;
514061da546Spatrick FileSpecList m_modules;
515be691f3bSpatrick lldb::addr_t m_load_addr = 0;
516061da546Spatrick lldb::addr_t m_offset_addr;
517be691f3bSpatrick bool m_catch_bp = false;
518be691f3bSpatrick bool m_throw_bp = true;
519be691f3bSpatrick bool m_hardware = false; // Request to use hardware breakpoints
520be691f3bSpatrick lldb::LanguageType m_exception_language = eLanguageTypeUnknown;
521be691f3bSpatrick lldb::LanguageType m_language = lldb::eLanguageTypeUnknown;
522be691f3bSpatrick LazyBool m_skip_prologue = eLazyBoolCalculate;
523be691f3bSpatrick bool m_all_files = false;
524061da546Spatrick Args m_exception_extra_args;
525be691f3bSpatrick LazyBool m_move_to_nearest_code = eLazyBoolCalculate;
526061da546Spatrick std::unordered_set<std::string> m_source_regex_func_names;
527061da546Spatrick std::string m_current_key;
528061da546Spatrick };
529061da546Spatrick
530061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)531061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
532061da546Spatrick Target &target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy);
533061da546Spatrick
534061da546Spatrick // The following are the various types of breakpoints that could be set:
535061da546Spatrick // 1). -f -l -p [-s -g] (setting breakpoint by source location)
536061da546Spatrick // 2). -a [-s -g] (setting breakpoint by address)
537061da546Spatrick // 3). -n [-s -g] (setting breakpoint by function name)
538061da546Spatrick // 4). -r [-s -g] (setting breakpoint by function name regular
539061da546Spatrick // expression)
540061da546Spatrick // 5). -p -f (setting a breakpoint by comparing a reg-exp
541061da546Spatrick // to source text)
542061da546Spatrick // 6). -E [-w -h] (setting a breakpoint for exceptions for a
543061da546Spatrick // given language.)
544061da546Spatrick
545061da546Spatrick BreakpointSetType break_type = eSetTypeInvalid;
546061da546Spatrick
547061da546Spatrick if (!m_python_class_options.GetName().empty())
548061da546Spatrick break_type = eSetTypeScripted;
549061da546Spatrick else if (m_options.m_line_num != 0)
550061da546Spatrick break_type = eSetTypeFileAndLine;
551061da546Spatrick else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
552061da546Spatrick break_type = eSetTypeAddress;
553061da546Spatrick else if (!m_options.m_func_names.empty())
554061da546Spatrick break_type = eSetTypeFunctionName;
555061da546Spatrick else if (!m_options.m_func_regexp.empty())
556061da546Spatrick break_type = eSetTypeFunctionRegexp;
557061da546Spatrick else if (!m_options.m_source_text_regexp.empty())
558061da546Spatrick break_type = eSetTypeSourceRegexp;
559061da546Spatrick else if (m_options.m_exception_language != eLanguageTypeUnknown)
560061da546Spatrick break_type = eSetTypeException;
561061da546Spatrick
562061da546Spatrick BreakpointSP bp_sp = nullptr;
563061da546Spatrick FileSpec module_spec;
564061da546Spatrick const bool internal = false;
565061da546Spatrick
566061da546Spatrick // If the user didn't specify skip-prologue, having an offset should turn
567061da546Spatrick // that off.
568061da546Spatrick if (m_options.m_offset_addr != 0 &&
569061da546Spatrick m_options.m_skip_prologue == eLazyBoolCalculate)
570061da546Spatrick m_options.m_skip_prologue = eLazyBoolNo;
571061da546Spatrick
572061da546Spatrick switch (break_type) {
573061da546Spatrick case eSetTypeFileAndLine: // Breakpoint by source position
574061da546Spatrick {
575061da546Spatrick FileSpec file;
576061da546Spatrick const size_t num_files = m_options.m_filenames.GetSize();
577061da546Spatrick if (num_files == 0) {
578061da546Spatrick if (!GetDefaultFile(target, file, result)) {
579061da546Spatrick result.AppendError("No file supplied and no default file available.");
580061da546Spatrick return false;
581061da546Spatrick }
582061da546Spatrick } else if (num_files > 1) {
583061da546Spatrick result.AppendError("Only one file at a time is allowed for file and "
584061da546Spatrick "line breakpoints.");
585061da546Spatrick return false;
586061da546Spatrick } else
587061da546Spatrick file = m_options.m_filenames.GetFileSpecAtIndex(0);
588061da546Spatrick
589061da546Spatrick // Only check for inline functions if
590061da546Spatrick LazyBool check_inlines = eLazyBoolCalculate;
591061da546Spatrick
592061da546Spatrick bp_sp = target.CreateBreakpoint(
593061da546Spatrick &(m_options.m_modules), file, m_options.m_line_num,
594061da546Spatrick m_options.m_column, m_options.m_offset_addr, check_inlines,
595061da546Spatrick m_options.m_skip_prologue, internal, m_options.m_hardware,
596061da546Spatrick m_options.m_move_to_nearest_code);
597061da546Spatrick } break;
598061da546Spatrick
599061da546Spatrick case eSetTypeAddress: // Breakpoint by address
600061da546Spatrick {
601061da546Spatrick // If a shared library has been specified, make an lldb_private::Address
602061da546Spatrick // with the library, and use that. That way the address breakpoint
603061da546Spatrick // will track the load location of the library.
604061da546Spatrick size_t num_modules_specified = m_options.m_modules.GetSize();
605061da546Spatrick if (num_modules_specified == 1) {
606061da546Spatrick const FileSpec *file_spec =
607061da546Spatrick m_options.m_modules.GetFileSpecPointerAtIndex(0);
608061da546Spatrick bp_sp = target.CreateAddressInModuleBreakpoint(
609061da546Spatrick m_options.m_load_addr, internal, file_spec, m_options.m_hardware);
610061da546Spatrick } else if (num_modules_specified == 0) {
611061da546Spatrick bp_sp = target.CreateBreakpoint(m_options.m_load_addr, internal,
612061da546Spatrick m_options.m_hardware);
613061da546Spatrick } else {
614061da546Spatrick result.AppendError("Only one shared library can be specified for "
615061da546Spatrick "address breakpoints.");
616061da546Spatrick return false;
617061da546Spatrick }
618061da546Spatrick break;
619061da546Spatrick }
620061da546Spatrick case eSetTypeFunctionName: // Breakpoint by function name
621061da546Spatrick {
622061da546Spatrick FunctionNameType name_type_mask = m_options.m_func_name_type_mask;
623061da546Spatrick
624061da546Spatrick if (name_type_mask == 0)
625061da546Spatrick name_type_mask = eFunctionNameTypeAuto;
626061da546Spatrick
627061da546Spatrick bp_sp = target.CreateBreakpoint(
628061da546Spatrick &(m_options.m_modules), &(m_options.m_filenames),
629061da546Spatrick m_options.m_func_names, name_type_mask, m_options.m_language,
630061da546Spatrick m_options.m_offset_addr, m_options.m_skip_prologue, internal,
631061da546Spatrick m_options.m_hardware);
632061da546Spatrick } break;
633061da546Spatrick
634061da546Spatrick case eSetTypeFunctionRegexp: // Breakpoint by regular expression function
635061da546Spatrick // name
636061da546Spatrick {
637061da546Spatrick RegularExpression regexp(m_options.m_func_regexp);
638061da546Spatrick if (llvm::Error err = regexp.GetError()) {
639061da546Spatrick result.AppendErrorWithFormat(
640dda28197Spatrick "Function name regular expression could not be compiled: %s",
641061da546Spatrick llvm::toString(std::move(err)).c_str());
642dda28197Spatrick // Check if the incorrect regex looks like a globbing expression and
643dda28197Spatrick // warn the user about it.
644dda28197Spatrick if (!m_options.m_func_regexp.empty()) {
645dda28197Spatrick if (m_options.m_func_regexp[0] == '*' ||
646dda28197Spatrick m_options.m_func_regexp[0] == '?')
647dda28197Spatrick result.AppendWarning(
648dda28197Spatrick "Function name regex does not accept glob patterns.");
649dda28197Spatrick }
650061da546Spatrick return false;
651061da546Spatrick }
652061da546Spatrick
653061da546Spatrick bp_sp = target.CreateFuncRegexBreakpoint(
654061da546Spatrick &(m_options.m_modules), &(m_options.m_filenames), std::move(regexp),
655061da546Spatrick m_options.m_language, m_options.m_skip_prologue, internal,
656061da546Spatrick m_options.m_hardware);
657061da546Spatrick } break;
658061da546Spatrick case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
659061da546Spatrick {
660061da546Spatrick const size_t num_files = m_options.m_filenames.GetSize();
661061da546Spatrick
662061da546Spatrick if (num_files == 0 && !m_options.m_all_files) {
663061da546Spatrick FileSpec file;
664061da546Spatrick if (!GetDefaultFile(target, file, result)) {
665061da546Spatrick result.AppendError(
666061da546Spatrick "No files provided and could not find default file.");
667061da546Spatrick return false;
668061da546Spatrick } else {
669061da546Spatrick m_options.m_filenames.Append(file);
670061da546Spatrick }
671061da546Spatrick }
672061da546Spatrick
673061da546Spatrick RegularExpression regexp(m_options.m_source_text_regexp);
674061da546Spatrick if (llvm::Error err = regexp.GetError()) {
675061da546Spatrick result.AppendErrorWithFormat(
676061da546Spatrick "Source text regular expression could not be compiled: \"%s\"",
677061da546Spatrick llvm::toString(std::move(err)).c_str());
678061da546Spatrick return false;
679061da546Spatrick }
680061da546Spatrick bp_sp = target.CreateSourceRegexBreakpoint(
681061da546Spatrick &(m_options.m_modules), &(m_options.m_filenames),
682061da546Spatrick m_options.m_source_regex_func_names, std::move(regexp), internal,
683061da546Spatrick m_options.m_hardware, m_options.m_move_to_nearest_code);
684061da546Spatrick } break;
685061da546Spatrick case eSetTypeException: {
686061da546Spatrick Status precond_error;
687061da546Spatrick bp_sp = target.CreateExceptionBreakpoint(
688061da546Spatrick m_options.m_exception_language, m_options.m_catch_bp,
689061da546Spatrick m_options.m_throw_bp, internal, &m_options.m_exception_extra_args,
690061da546Spatrick &precond_error);
691061da546Spatrick if (precond_error.Fail()) {
692061da546Spatrick result.AppendErrorWithFormat(
693061da546Spatrick "Error setting extra exception arguments: %s",
694061da546Spatrick precond_error.AsCString());
695061da546Spatrick target.RemoveBreakpointByID(bp_sp->GetID());
696061da546Spatrick return false;
697061da546Spatrick }
698061da546Spatrick } break;
699061da546Spatrick case eSetTypeScripted: {
700061da546Spatrick
701061da546Spatrick Status error;
702061da546Spatrick bp_sp = target.CreateScriptedBreakpoint(
703061da546Spatrick m_python_class_options.GetName().c_str(), &(m_options.m_modules),
704061da546Spatrick &(m_options.m_filenames), false, m_options.m_hardware,
705061da546Spatrick m_python_class_options.GetStructuredData(), &error);
706061da546Spatrick if (error.Fail()) {
707061da546Spatrick result.AppendErrorWithFormat(
708061da546Spatrick "Error setting extra exception arguments: %s", error.AsCString());
709061da546Spatrick target.RemoveBreakpointByID(bp_sp->GetID());
710061da546Spatrick return false;
711061da546Spatrick }
712061da546Spatrick } break;
713061da546Spatrick default:
714061da546Spatrick break;
715061da546Spatrick }
716061da546Spatrick
717061da546Spatrick // Now set the various options that were passed in:
718061da546Spatrick if (bp_sp) {
719be691f3bSpatrick bp_sp->GetOptions().CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
720061da546Spatrick
721061da546Spatrick if (!m_options.m_breakpoint_names.empty()) {
722061da546Spatrick Status name_error;
723061da546Spatrick for (auto name : m_options.m_breakpoint_names) {
724061da546Spatrick target.AddNameToBreakpoint(bp_sp, name.c_str(), name_error);
725061da546Spatrick if (name_error.Fail()) {
726061da546Spatrick result.AppendErrorWithFormat("Invalid breakpoint name: %s",
727061da546Spatrick name.c_str());
728061da546Spatrick target.RemoveBreakpointByID(bp_sp->GetID());
729061da546Spatrick return false;
730061da546Spatrick }
731061da546Spatrick }
732061da546Spatrick }
733061da546Spatrick }
734061da546Spatrick
735061da546Spatrick if (bp_sp) {
736061da546Spatrick Stream &output_stream = result.GetOutputStream();
737061da546Spatrick const bool show_locations = false;
738061da546Spatrick bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
739061da546Spatrick show_locations);
740061da546Spatrick if (&target == &GetDummyTarget())
741061da546Spatrick output_stream.Printf("Breakpoint set in dummy target, will get copied "
742061da546Spatrick "into future targets.\n");
743061da546Spatrick else {
744061da546Spatrick // Don't print out this warning for exception breakpoints. They can
745061da546Spatrick // get set before the target is set, but we won't know how to actually
746061da546Spatrick // set the breakpoint till we run.
747061da546Spatrick if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) {
748061da546Spatrick output_stream.Printf("WARNING: Unable to resolve breakpoint to any "
749061da546Spatrick "actual locations.\n");
750061da546Spatrick }
751061da546Spatrick }
752061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishResult);
753061da546Spatrick } else if (!bp_sp) {
754061da546Spatrick result.AppendError("Breakpoint creation failed: No breakpoint created.");
755061da546Spatrick }
756061da546Spatrick
757061da546Spatrick return result.Succeeded();
758061da546Spatrick }
759061da546Spatrick
760061da546Spatrick private:
GetDefaultFile(Target & target,FileSpec & file,CommandReturnObject & result)761061da546Spatrick bool GetDefaultFile(Target &target, FileSpec &file,
762061da546Spatrick CommandReturnObject &result) {
763061da546Spatrick uint32_t default_line;
764061da546Spatrick // First use the Source Manager's default file. Then use the current stack
765061da546Spatrick // frame's file.
766061da546Spatrick if (!target.GetSourceManager().GetDefaultFileAndLine(file, default_line)) {
767061da546Spatrick StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
768061da546Spatrick if (cur_frame == nullptr) {
769061da546Spatrick result.AppendError(
770061da546Spatrick "No selected frame to use to find the default file.");
771061da546Spatrick return false;
772061da546Spatrick } else if (!cur_frame->HasDebugInformation()) {
773061da546Spatrick result.AppendError("Cannot use the selected frame to find the default "
774061da546Spatrick "file, it has no debug info.");
775061da546Spatrick return false;
776061da546Spatrick } else {
777061da546Spatrick const SymbolContext &sc =
778061da546Spatrick cur_frame->GetSymbolContext(eSymbolContextLineEntry);
779061da546Spatrick if (sc.line_entry.file) {
780061da546Spatrick file = sc.line_entry.file;
781061da546Spatrick } else {
782061da546Spatrick result.AppendError("Can't find the file for the selected frame to "
783061da546Spatrick "use as the default file.");
784061da546Spatrick return false;
785061da546Spatrick }
786061da546Spatrick }
787061da546Spatrick }
788061da546Spatrick return true;
789061da546Spatrick }
790061da546Spatrick
791061da546Spatrick BreakpointOptionGroup m_bp_opts;
792061da546Spatrick BreakpointDummyOptionGroup m_dummy_options;
793061da546Spatrick OptionGroupPythonClassWithDict m_python_class_options;
794061da546Spatrick CommandOptions m_options;
795061da546Spatrick OptionGroupOptions m_all_options;
796061da546Spatrick };
797061da546Spatrick
798061da546Spatrick // CommandObjectBreakpointModify
799061da546Spatrick #pragma mark Modify
800061da546Spatrick
801061da546Spatrick class CommandObjectBreakpointModify : public CommandObjectParsed {
802061da546Spatrick public:
CommandObjectBreakpointModify(CommandInterpreter & interpreter)803061da546Spatrick CommandObjectBreakpointModify(CommandInterpreter &interpreter)
804061da546Spatrick : CommandObjectParsed(interpreter, "breakpoint modify",
805061da546Spatrick "Modify the options on a breakpoint or set of "
806061da546Spatrick "breakpoints in the executable. "
807061da546Spatrick "If no breakpoint is specified, acts on the last "
808061da546Spatrick "created breakpoint. "
809061da546Spatrick "With the exception of -e, -d and -i, passing an "
810061da546Spatrick "empty argument clears the modification.",
811*f6aab3d8Srobert nullptr) {
812061da546Spatrick CommandArgumentEntry arg;
813061da546Spatrick CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
814061da546Spatrick eArgTypeBreakpointIDRange);
815061da546Spatrick // Add the entry for the first argument for this command to the object's
816061da546Spatrick // arguments vector.
817061da546Spatrick m_arguments.push_back(arg);
818061da546Spatrick
819061da546Spatrick m_options.Append(&m_bp_opts,
820061da546Spatrick LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3,
821061da546Spatrick LLDB_OPT_SET_ALL);
822061da546Spatrick m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
823061da546Spatrick m_options.Finalize();
824061da546Spatrick }
825061da546Spatrick
826061da546Spatrick ~CommandObjectBreakpointModify() override = default;
827061da546Spatrick
828dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)829dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
830dda28197Spatrick OptionElementVector &opt_element_vector) override {
831dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
832dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
833dda28197Spatrick request, nullptr);
834dda28197Spatrick }
835dda28197Spatrick
GetOptions()836061da546Spatrick Options *GetOptions() override { return &m_options; }
837061da546Spatrick
838061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)839061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
840061da546Spatrick Target &target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy);
841061da546Spatrick
842061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
843061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
844061da546Spatrick
845061da546Spatrick BreakpointIDList valid_bp_ids;
846061da546Spatrick
847061da546Spatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
848061da546Spatrick command, &target, result, &valid_bp_ids,
849061da546Spatrick BreakpointName::Permissions::PermissionKinds::disablePerm);
850061da546Spatrick
851061da546Spatrick if (result.Succeeded()) {
852061da546Spatrick const size_t count = valid_bp_ids.GetSize();
853061da546Spatrick for (size_t i = 0; i < count; ++i) {
854061da546Spatrick BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
855061da546Spatrick
856061da546Spatrick if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
857061da546Spatrick Breakpoint *bp =
858061da546Spatrick target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
859061da546Spatrick if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
860061da546Spatrick BreakpointLocation *location =
861061da546Spatrick bp->FindLocationByID(cur_bp_id.GetLocationID()).get();
862061da546Spatrick if (location)
863be691f3bSpatrick location->GetLocationOptions().CopyOverSetOptions(
864061da546Spatrick m_bp_opts.GetBreakpointOptions());
865061da546Spatrick } else {
866be691f3bSpatrick bp->GetOptions().CopyOverSetOptions(
867061da546Spatrick m_bp_opts.GetBreakpointOptions());
868061da546Spatrick }
869061da546Spatrick }
870061da546Spatrick }
871061da546Spatrick }
872061da546Spatrick
873061da546Spatrick return result.Succeeded();
874061da546Spatrick }
875061da546Spatrick
876061da546Spatrick private:
877061da546Spatrick BreakpointOptionGroup m_bp_opts;
878061da546Spatrick BreakpointDummyOptionGroup m_dummy_opts;
879061da546Spatrick OptionGroupOptions m_options;
880061da546Spatrick };
881061da546Spatrick
882061da546Spatrick // CommandObjectBreakpointEnable
883061da546Spatrick #pragma mark Enable
884061da546Spatrick
885061da546Spatrick class CommandObjectBreakpointEnable : public CommandObjectParsed {
886061da546Spatrick public:
CommandObjectBreakpointEnable(CommandInterpreter & interpreter)887061da546Spatrick CommandObjectBreakpointEnable(CommandInterpreter &interpreter)
888061da546Spatrick : CommandObjectParsed(interpreter, "enable",
889061da546Spatrick "Enable the specified disabled breakpoint(s). If "
890061da546Spatrick "no breakpoints are specified, enable all of them.",
891061da546Spatrick nullptr) {
892061da546Spatrick CommandArgumentEntry arg;
893061da546Spatrick CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
894061da546Spatrick eArgTypeBreakpointIDRange);
895061da546Spatrick // Add the entry for the first argument for this command to the object's
896061da546Spatrick // arguments vector.
897061da546Spatrick m_arguments.push_back(arg);
898061da546Spatrick }
899061da546Spatrick
900061da546Spatrick ~CommandObjectBreakpointEnable() override = default;
901061da546Spatrick
902dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)903dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
904dda28197Spatrick OptionElementVector &opt_element_vector) override {
905dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
906dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
907dda28197Spatrick request, nullptr);
908dda28197Spatrick }
909dda28197Spatrick
910061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)911061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
912061da546Spatrick Target &target = GetSelectedOrDummyTarget();
913061da546Spatrick
914061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
915061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
916061da546Spatrick
917061da546Spatrick const BreakpointList &breakpoints = target.GetBreakpointList();
918061da546Spatrick
919061da546Spatrick size_t num_breakpoints = breakpoints.GetSize();
920061da546Spatrick
921061da546Spatrick if (num_breakpoints == 0) {
922061da546Spatrick result.AppendError("No breakpoints exist to be enabled.");
923061da546Spatrick return false;
924061da546Spatrick }
925061da546Spatrick
926061da546Spatrick if (command.empty()) {
927061da546Spatrick // No breakpoint selected; enable all currently set breakpoints.
928061da546Spatrick target.EnableAllowedBreakpoints();
929061da546Spatrick result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64
930061da546Spatrick " breakpoints)\n",
931061da546Spatrick (uint64_t)num_breakpoints);
932061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
933061da546Spatrick } else {
934061da546Spatrick // Particular breakpoint selected; enable that breakpoint.
935061da546Spatrick BreakpointIDList valid_bp_ids;
936061da546Spatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
937061da546Spatrick command, &target, result, &valid_bp_ids,
938061da546Spatrick BreakpointName::Permissions::PermissionKinds::disablePerm);
939061da546Spatrick
940061da546Spatrick if (result.Succeeded()) {
941061da546Spatrick int enable_count = 0;
942061da546Spatrick int loc_count = 0;
943061da546Spatrick const size_t count = valid_bp_ids.GetSize();
944061da546Spatrick for (size_t i = 0; i < count; ++i) {
945061da546Spatrick BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
946061da546Spatrick
947061da546Spatrick if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
948061da546Spatrick Breakpoint *breakpoint =
949061da546Spatrick target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
950061da546Spatrick if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
951061da546Spatrick BreakpointLocation *location =
952061da546Spatrick breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
953061da546Spatrick if (location) {
954061da546Spatrick location->SetEnabled(true);
955061da546Spatrick ++loc_count;
956061da546Spatrick }
957061da546Spatrick } else {
958061da546Spatrick breakpoint->SetEnabled(true);
959061da546Spatrick ++enable_count;
960061da546Spatrick }
961061da546Spatrick }
962061da546Spatrick }
963061da546Spatrick result.AppendMessageWithFormat("%d breakpoints enabled.\n",
964061da546Spatrick enable_count + loc_count);
965061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
966061da546Spatrick }
967061da546Spatrick }
968061da546Spatrick
969061da546Spatrick return result.Succeeded();
970061da546Spatrick }
971061da546Spatrick };
972061da546Spatrick
973061da546Spatrick // CommandObjectBreakpointDisable
974061da546Spatrick #pragma mark Disable
975061da546Spatrick
976061da546Spatrick class CommandObjectBreakpointDisable : public CommandObjectParsed {
977061da546Spatrick public:
CommandObjectBreakpointDisable(CommandInterpreter & interpreter)978061da546Spatrick CommandObjectBreakpointDisable(CommandInterpreter &interpreter)
979061da546Spatrick : CommandObjectParsed(
980061da546Spatrick interpreter, "breakpoint disable",
981061da546Spatrick "Disable the specified breakpoint(s) without deleting "
982061da546Spatrick "them. If none are specified, disable all "
983061da546Spatrick "breakpoints.",
984061da546Spatrick nullptr) {
985061da546Spatrick SetHelpLong(
986061da546Spatrick "Disable the specified breakpoint(s) without deleting them. \
987061da546Spatrick If none are specified, disable all breakpoints."
988061da546Spatrick R"(
989061da546Spatrick
990061da546Spatrick )"
991061da546Spatrick "Note: disabling a breakpoint will cause none of its locations to be hit \
992061da546Spatrick regardless of whether individual locations are enabled or disabled. After the sequence:"
993061da546Spatrick R"(
994061da546Spatrick
995061da546Spatrick (lldb) break disable 1
996061da546Spatrick (lldb) break enable 1.1
997061da546Spatrick
998061da546Spatrick execution will NOT stop at location 1.1. To achieve that, type:
999061da546Spatrick
1000061da546Spatrick (lldb) break disable 1.*
1001061da546Spatrick (lldb) break enable 1.1
1002061da546Spatrick
1003061da546Spatrick )"
1004061da546Spatrick "The first command disables all locations for breakpoint 1, \
1005061da546Spatrick the second re-enables the first location.");
1006061da546Spatrick
1007061da546Spatrick CommandArgumentEntry arg;
1008061da546Spatrick CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1009061da546Spatrick eArgTypeBreakpointIDRange);
1010061da546Spatrick // Add the entry for the first argument for this command to the object's
1011061da546Spatrick // arguments vector.
1012061da546Spatrick m_arguments.push_back(arg);
1013061da546Spatrick }
1014061da546Spatrick
1015061da546Spatrick ~CommandObjectBreakpointDisable() override = default;
1016061da546Spatrick
1017dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1018dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
1019dda28197Spatrick OptionElementVector &opt_element_vector) override {
1020dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1021dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
1022dda28197Spatrick request, nullptr);
1023dda28197Spatrick }
1024dda28197Spatrick
1025061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1026061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1027061da546Spatrick Target &target = GetSelectedOrDummyTarget();
1028061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
1029061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
1030061da546Spatrick
1031061da546Spatrick const BreakpointList &breakpoints = target.GetBreakpointList();
1032061da546Spatrick size_t num_breakpoints = breakpoints.GetSize();
1033061da546Spatrick
1034061da546Spatrick if (num_breakpoints == 0) {
1035061da546Spatrick result.AppendError("No breakpoints exist to be disabled.");
1036061da546Spatrick return false;
1037061da546Spatrick }
1038061da546Spatrick
1039061da546Spatrick if (command.empty()) {
1040061da546Spatrick // No breakpoint selected; disable all currently set breakpoints.
1041061da546Spatrick target.DisableAllowedBreakpoints();
1042061da546Spatrick result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64
1043061da546Spatrick " breakpoints)\n",
1044061da546Spatrick (uint64_t)num_breakpoints);
1045061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1046061da546Spatrick } else {
1047061da546Spatrick // Particular breakpoint selected; disable that breakpoint.
1048061da546Spatrick BreakpointIDList valid_bp_ids;
1049061da546Spatrick
1050061da546Spatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1051061da546Spatrick command, &target, result, &valid_bp_ids,
1052061da546Spatrick BreakpointName::Permissions::PermissionKinds::disablePerm);
1053061da546Spatrick
1054061da546Spatrick if (result.Succeeded()) {
1055061da546Spatrick int disable_count = 0;
1056061da546Spatrick int loc_count = 0;
1057061da546Spatrick const size_t count = valid_bp_ids.GetSize();
1058061da546Spatrick for (size_t i = 0; i < count; ++i) {
1059061da546Spatrick BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1060061da546Spatrick
1061061da546Spatrick if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1062061da546Spatrick Breakpoint *breakpoint =
1063061da546Spatrick target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1064061da546Spatrick if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1065061da546Spatrick BreakpointLocation *location =
1066061da546Spatrick breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1067061da546Spatrick if (location) {
1068061da546Spatrick location->SetEnabled(false);
1069061da546Spatrick ++loc_count;
1070061da546Spatrick }
1071061da546Spatrick } else {
1072061da546Spatrick breakpoint->SetEnabled(false);
1073061da546Spatrick ++disable_count;
1074061da546Spatrick }
1075061da546Spatrick }
1076061da546Spatrick }
1077061da546Spatrick result.AppendMessageWithFormat("%d breakpoints disabled.\n",
1078061da546Spatrick disable_count + loc_count);
1079061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1080061da546Spatrick }
1081061da546Spatrick }
1082061da546Spatrick
1083061da546Spatrick return result.Succeeded();
1084061da546Spatrick }
1085061da546Spatrick };
1086061da546Spatrick
1087061da546Spatrick // CommandObjectBreakpointList
1088061da546Spatrick
1089061da546Spatrick #pragma mark List::CommandOptions
1090061da546Spatrick #define LLDB_OPTIONS_breakpoint_list
1091061da546Spatrick #include "CommandOptions.inc"
1092061da546Spatrick
1093061da546Spatrick #pragma mark List
1094061da546Spatrick
1095061da546Spatrick class CommandObjectBreakpointList : public CommandObjectParsed {
1096061da546Spatrick public:
CommandObjectBreakpointList(CommandInterpreter & interpreter)1097061da546Spatrick CommandObjectBreakpointList(CommandInterpreter &interpreter)
1098061da546Spatrick : CommandObjectParsed(
1099061da546Spatrick interpreter, "breakpoint list",
1100061da546Spatrick "List some or all breakpoints at configurable levels of detail.",
1101*f6aab3d8Srobert nullptr) {
1102061da546Spatrick CommandArgumentEntry arg;
1103061da546Spatrick CommandArgumentData bp_id_arg;
1104061da546Spatrick
1105061da546Spatrick // Define the first (and only) variant of this arg.
1106061da546Spatrick bp_id_arg.arg_type = eArgTypeBreakpointID;
1107061da546Spatrick bp_id_arg.arg_repetition = eArgRepeatOptional;
1108061da546Spatrick
1109061da546Spatrick // There is only one variant this argument could be; put it into the
1110061da546Spatrick // argument entry.
1111061da546Spatrick arg.push_back(bp_id_arg);
1112061da546Spatrick
1113061da546Spatrick // Push the data for the first argument into the m_arguments vector.
1114061da546Spatrick m_arguments.push_back(arg);
1115061da546Spatrick }
1116061da546Spatrick
1117061da546Spatrick ~CommandObjectBreakpointList() override = default;
1118061da546Spatrick
GetOptions()1119061da546Spatrick Options *GetOptions() override { return &m_options; }
1120061da546Spatrick
1121061da546Spatrick class CommandOptions : public Options {
1122061da546Spatrick public:
1123*f6aab3d8Srobert CommandOptions() = default;
1124061da546Spatrick
1125061da546Spatrick ~CommandOptions() override = default;
1126061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1127061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1128061da546Spatrick ExecutionContext *execution_context) override {
1129061da546Spatrick Status error;
1130061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1131061da546Spatrick
1132061da546Spatrick switch (short_option) {
1133061da546Spatrick case 'b':
1134061da546Spatrick m_level = lldb::eDescriptionLevelBrief;
1135061da546Spatrick break;
1136061da546Spatrick case 'D':
1137061da546Spatrick m_use_dummy = true;
1138061da546Spatrick break;
1139061da546Spatrick case 'f':
1140061da546Spatrick m_level = lldb::eDescriptionLevelFull;
1141061da546Spatrick break;
1142061da546Spatrick case 'v':
1143061da546Spatrick m_level = lldb::eDescriptionLevelVerbose;
1144061da546Spatrick break;
1145061da546Spatrick case 'i':
1146061da546Spatrick m_internal = true;
1147061da546Spatrick break;
1148061da546Spatrick default:
1149061da546Spatrick llvm_unreachable("Unimplemented option");
1150061da546Spatrick }
1151061da546Spatrick
1152061da546Spatrick return error;
1153061da546Spatrick }
1154061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1155061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1156061da546Spatrick m_level = lldb::eDescriptionLevelFull;
1157061da546Spatrick m_internal = false;
1158061da546Spatrick m_use_dummy = false;
1159061da546Spatrick }
1160061da546Spatrick
GetDefinitions()1161061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1162*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_list_options);
1163061da546Spatrick }
1164061da546Spatrick
1165061da546Spatrick // Instance variables to hold the values for command options.
1166061da546Spatrick
1167be691f3bSpatrick lldb::DescriptionLevel m_level = lldb::eDescriptionLevelBrief;
1168061da546Spatrick
1169061da546Spatrick bool m_internal;
1170be691f3bSpatrick bool m_use_dummy = false;
1171061da546Spatrick };
1172061da546Spatrick
1173061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1174061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1175061da546Spatrick Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1176061da546Spatrick
1177061da546Spatrick const BreakpointList &breakpoints =
1178061da546Spatrick target.GetBreakpointList(m_options.m_internal);
1179061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
1180061da546Spatrick target.GetBreakpointList(m_options.m_internal).GetListMutex(lock);
1181061da546Spatrick
1182061da546Spatrick size_t num_breakpoints = breakpoints.GetSize();
1183061da546Spatrick
1184061da546Spatrick if (num_breakpoints == 0) {
1185061da546Spatrick result.AppendMessage("No breakpoints currently set.");
1186061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1187061da546Spatrick return true;
1188061da546Spatrick }
1189061da546Spatrick
1190061da546Spatrick Stream &output_stream = result.GetOutputStream();
1191061da546Spatrick
1192061da546Spatrick if (command.empty()) {
1193061da546Spatrick // No breakpoint selected; show info about all currently set breakpoints.
1194061da546Spatrick result.AppendMessage("Current breakpoints:");
1195061da546Spatrick for (size_t i = 0; i < num_breakpoints; ++i) {
1196061da546Spatrick Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get();
1197061da546Spatrick if (breakpoint->AllowList())
1198061da546Spatrick AddBreakpointDescription(&output_stream, breakpoint,
1199061da546Spatrick m_options.m_level);
1200061da546Spatrick }
1201061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1202061da546Spatrick } else {
1203061da546Spatrick // Particular breakpoints selected; show info about that breakpoint.
1204061da546Spatrick BreakpointIDList valid_bp_ids;
1205061da546Spatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1206061da546Spatrick command, &target, result, &valid_bp_ids,
1207061da546Spatrick BreakpointName::Permissions::PermissionKinds::listPerm);
1208061da546Spatrick
1209061da546Spatrick if (result.Succeeded()) {
1210061da546Spatrick for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) {
1211061da546Spatrick BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1212061da546Spatrick Breakpoint *breakpoint =
1213061da546Spatrick target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1214061da546Spatrick AddBreakpointDescription(&output_stream, breakpoint,
1215061da546Spatrick m_options.m_level);
1216061da546Spatrick }
1217061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1218061da546Spatrick } else {
1219061da546Spatrick result.AppendError("Invalid breakpoint ID.");
1220061da546Spatrick }
1221061da546Spatrick }
1222061da546Spatrick
1223061da546Spatrick return result.Succeeded();
1224061da546Spatrick }
1225061da546Spatrick
1226061da546Spatrick private:
1227061da546Spatrick CommandOptions m_options;
1228061da546Spatrick };
1229061da546Spatrick
1230061da546Spatrick // CommandObjectBreakpointClear
1231061da546Spatrick #pragma mark Clear::CommandOptions
1232061da546Spatrick
1233061da546Spatrick #define LLDB_OPTIONS_breakpoint_clear
1234061da546Spatrick #include "CommandOptions.inc"
1235061da546Spatrick
1236061da546Spatrick #pragma mark Clear
1237061da546Spatrick
1238061da546Spatrick class CommandObjectBreakpointClear : public CommandObjectParsed {
1239061da546Spatrick public:
1240061da546Spatrick enum BreakpointClearType { eClearTypeInvalid, eClearTypeFileAndLine };
1241061da546Spatrick
CommandObjectBreakpointClear(CommandInterpreter & interpreter)1242061da546Spatrick CommandObjectBreakpointClear(CommandInterpreter &interpreter)
1243061da546Spatrick : CommandObjectParsed(interpreter, "breakpoint clear",
1244061da546Spatrick "Delete or disable breakpoints matching the "
1245061da546Spatrick "specified source file and line.",
1246*f6aab3d8Srobert "breakpoint clear <cmd-options>") {}
1247061da546Spatrick
1248061da546Spatrick ~CommandObjectBreakpointClear() override = default;
1249061da546Spatrick
GetOptions()1250061da546Spatrick Options *GetOptions() override { return &m_options; }
1251061da546Spatrick
1252061da546Spatrick class CommandOptions : public Options {
1253061da546Spatrick public:
1254*f6aab3d8Srobert CommandOptions() = default;
1255061da546Spatrick
1256061da546Spatrick ~CommandOptions() override = default;
1257061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1258061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1259061da546Spatrick ExecutionContext *execution_context) override {
1260061da546Spatrick Status error;
1261061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1262061da546Spatrick
1263061da546Spatrick switch (short_option) {
1264061da546Spatrick case 'f':
1265dda28197Spatrick m_filename.assign(std::string(option_arg));
1266061da546Spatrick break;
1267061da546Spatrick
1268061da546Spatrick case 'l':
1269061da546Spatrick option_arg.getAsInteger(0, m_line_num);
1270061da546Spatrick break;
1271061da546Spatrick
1272061da546Spatrick default:
1273061da546Spatrick llvm_unreachable("Unimplemented option");
1274061da546Spatrick }
1275061da546Spatrick
1276061da546Spatrick return error;
1277061da546Spatrick }
1278061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1279061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1280061da546Spatrick m_filename.clear();
1281061da546Spatrick m_line_num = 0;
1282061da546Spatrick }
1283061da546Spatrick
GetDefinitions()1284061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1285*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_clear_options);
1286061da546Spatrick }
1287061da546Spatrick
1288061da546Spatrick // Instance variables to hold the values for command options.
1289061da546Spatrick
1290061da546Spatrick std::string m_filename;
1291be691f3bSpatrick uint32_t m_line_num = 0;
1292061da546Spatrick };
1293061da546Spatrick
1294061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1295061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1296061da546Spatrick Target &target = GetSelectedOrDummyTarget();
1297061da546Spatrick
1298061da546Spatrick // The following are the various types of breakpoints that could be
1299061da546Spatrick // cleared:
1300061da546Spatrick // 1). -f -l (clearing breakpoint by source location)
1301061da546Spatrick
1302061da546Spatrick BreakpointClearType break_type = eClearTypeInvalid;
1303061da546Spatrick
1304061da546Spatrick if (m_options.m_line_num != 0)
1305061da546Spatrick break_type = eClearTypeFileAndLine;
1306061da546Spatrick
1307061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
1308061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
1309061da546Spatrick
1310061da546Spatrick BreakpointList &breakpoints = target.GetBreakpointList();
1311061da546Spatrick size_t num_breakpoints = breakpoints.GetSize();
1312061da546Spatrick
1313061da546Spatrick // Early return if there's no breakpoint at all.
1314061da546Spatrick if (num_breakpoints == 0) {
1315061da546Spatrick result.AppendError("Breakpoint clear: No breakpoint cleared.");
1316061da546Spatrick return result.Succeeded();
1317061da546Spatrick }
1318061da546Spatrick
1319061da546Spatrick // Find matching breakpoints and delete them.
1320061da546Spatrick
1321061da546Spatrick // First create a copy of all the IDs.
1322061da546Spatrick std::vector<break_id_t> BreakIDs;
1323061da546Spatrick for (size_t i = 0; i < num_breakpoints; ++i)
1324061da546Spatrick BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID());
1325061da546Spatrick
1326061da546Spatrick int num_cleared = 0;
1327061da546Spatrick StreamString ss;
1328061da546Spatrick switch (break_type) {
1329061da546Spatrick case eClearTypeFileAndLine: // Breakpoint by source position
1330061da546Spatrick {
1331061da546Spatrick const ConstString filename(m_options.m_filename.c_str());
1332061da546Spatrick BreakpointLocationCollection loc_coll;
1333061da546Spatrick
1334061da546Spatrick for (size_t i = 0; i < num_breakpoints; ++i) {
1335061da546Spatrick Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
1336061da546Spatrick
1337061da546Spatrick if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) {
1338061da546Spatrick // If the collection size is 0, it's a full match and we can just
1339061da546Spatrick // remove the breakpoint.
1340061da546Spatrick if (loc_coll.GetSize() == 0) {
1341061da546Spatrick bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
1342061da546Spatrick ss.EOL();
1343061da546Spatrick target.RemoveBreakpointByID(bp->GetID());
1344061da546Spatrick ++num_cleared;
1345061da546Spatrick }
1346061da546Spatrick }
1347061da546Spatrick }
1348061da546Spatrick } break;
1349061da546Spatrick
1350061da546Spatrick default:
1351061da546Spatrick break;
1352061da546Spatrick }
1353061da546Spatrick
1354061da546Spatrick if (num_cleared > 0) {
1355061da546Spatrick Stream &output_stream = result.GetOutputStream();
1356061da546Spatrick output_stream.Printf("%d breakpoints cleared:\n", num_cleared);
1357061da546Spatrick output_stream << ss.GetString();
1358061da546Spatrick output_stream.EOL();
1359061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1360061da546Spatrick } else {
1361061da546Spatrick result.AppendError("Breakpoint clear: No breakpoint cleared.");
1362061da546Spatrick }
1363061da546Spatrick
1364061da546Spatrick return result.Succeeded();
1365061da546Spatrick }
1366061da546Spatrick
1367061da546Spatrick private:
1368061da546Spatrick CommandOptions m_options;
1369061da546Spatrick };
1370061da546Spatrick
1371061da546Spatrick // CommandObjectBreakpointDelete
1372061da546Spatrick #define LLDB_OPTIONS_breakpoint_delete
1373061da546Spatrick #include "CommandOptions.inc"
1374061da546Spatrick
1375061da546Spatrick #pragma mark Delete
1376061da546Spatrick
1377061da546Spatrick class CommandObjectBreakpointDelete : public CommandObjectParsed {
1378061da546Spatrick public:
CommandObjectBreakpointDelete(CommandInterpreter & interpreter)1379061da546Spatrick CommandObjectBreakpointDelete(CommandInterpreter &interpreter)
1380061da546Spatrick : CommandObjectParsed(interpreter, "breakpoint delete",
1381061da546Spatrick "Delete the specified breakpoint(s). If no "
1382061da546Spatrick "breakpoints are specified, delete them all.",
1383*f6aab3d8Srobert nullptr) {
1384061da546Spatrick CommandArgumentEntry arg;
1385061da546Spatrick CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1386061da546Spatrick eArgTypeBreakpointIDRange);
1387061da546Spatrick // Add the entry for the first argument for this command to the object's
1388061da546Spatrick // arguments vector.
1389061da546Spatrick m_arguments.push_back(arg);
1390061da546Spatrick }
1391061da546Spatrick
1392061da546Spatrick ~CommandObjectBreakpointDelete() override = default;
1393061da546Spatrick
1394dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1395dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
1396dda28197Spatrick OptionElementVector &opt_element_vector) override {
1397dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1398dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
1399dda28197Spatrick request, nullptr);
1400dda28197Spatrick }
1401dda28197Spatrick
GetOptions()1402061da546Spatrick Options *GetOptions() override { return &m_options; }
1403061da546Spatrick
1404061da546Spatrick class CommandOptions : public Options {
1405061da546Spatrick public:
1406*f6aab3d8Srobert CommandOptions() = default;
1407061da546Spatrick
1408061da546Spatrick ~CommandOptions() override = default;
1409061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1410061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1411061da546Spatrick ExecutionContext *execution_context) override {
1412061da546Spatrick Status error;
1413061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
1414061da546Spatrick
1415061da546Spatrick switch (short_option) {
1416061da546Spatrick case 'f':
1417061da546Spatrick m_force = true;
1418061da546Spatrick break;
1419061da546Spatrick
1420061da546Spatrick case 'D':
1421061da546Spatrick m_use_dummy = true;
1422061da546Spatrick break;
1423061da546Spatrick
1424be691f3bSpatrick case 'd':
1425be691f3bSpatrick m_delete_disabled = true;
1426be691f3bSpatrick break;
1427be691f3bSpatrick
1428061da546Spatrick default:
1429061da546Spatrick llvm_unreachable("Unimplemented option");
1430061da546Spatrick }
1431061da546Spatrick
1432061da546Spatrick return error;
1433061da546Spatrick }
1434061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1435061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1436061da546Spatrick m_use_dummy = false;
1437061da546Spatrick m_force = false;
1438be691f3bSpatrick m_delete_disabled = false;
1439061da546Spatrick }
1440061da546Spatrick
GetDefinitions()1441061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1442*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_delete_options);
1443061da546Spatrick }
1444061da546Spatrick
1445061da546Spatrick // Instance variables to hold the values for command options.
1446be691f3bSpatrick bool m_use_dummy = false;
1447be691f3bSpatrick bool m_force = false;
1448be691f3bSpatrick bool m_delete_disabled = false;
1449061da546Spatrick };
1450061da546Spatrick
1451061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1452061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1453061da546Spatrick Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
1454be691f3bSpatrick result.Clear();
1455061da546Spatrick
1456061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
1457061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
1458061da546Spatrick
1459be691f3bSpatrick BreakpointList &breakpoints = target.GetBreakpointList();
1460061da546Spatrick
1461061da546Spatrick size_t num_breakpoints = breakpoints.GetSize();
1462061da546Spatrick
1463061da546Spatrick if (num_breakpoints == 0) {
1464061da546Spatrick result.AppendError("No breakpoints exist to be deleted.");
1465061da546Spatrick return false;
1466061da546Spatrick }
1467061da546Spatrick
1468be691f3bSpatrick // Handle the delete all breakpoints case:
1469be691f3bSpatrick if (command.empty() && !m_options.m_delete_disabled) {
1470061da546Spatrick if (!m_options.m_force &&
1471061da546Spatrick !m_interpreter.Confirm(
1472061da546Spatrick "About to delete all breakpoints, do you want to do that?",
1473061da546Spatrick true)) {
1474061da546Spatrick result.AppendMessage("Operation cancelled...");
1475061da546Spatrick } else {
1476061da546Spatrick target.RemoveAllowedBreakpoints();
1477061da546Spatrick result.AppendMessageWithFormat(
1478061da546Spatrick "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n",
1479061da546Spatrick (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");
1480061da546Spatrick }
1481061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1482be691f3bSpatrick return result.Succeeded();
1483be691f3bSpatrick }
1484be691f3bSpatrick
1485be691f3bSpatrick // Either we have some kind of breakpoint specification(s),
1486be691f3bSpatrick // or we are handling "break disable --deleted". Gather the list
1487be691f3bSpatrick // of breakpoints to delete here, the we'll delete them below.
1488061da546Spatrick BreakpointIDList valid_bp_ids;
1489be691f3bSpatrick
1490be691f3bSpatrick if (m_options.m_delete_disabled) {
1491be691f3bSpatrick BreakpointIDList excluded_bp_ids;
1492be691f3bSpatrick
1493be691f3bSpatrick if (!command.empty()) {
1494be691f3bSpatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1495be691f3bSpatrick command, &target, result, &excluded_bp_ids,
1496be691f3bSpatrick BreakpointName::Permissions::PermissionKinds::deletePerm);
1497be691f3bSpatrick if (!result.Succeeded())
1498be691f3bSpatrick return false;
1499be691f3bSpatrick }
1500be691f3bSpatrick
1501be691f3bSpatrick for (auto breakpoint_sp : breakpoints.Breakpoints()) {
1502be691f3bSpatrick if (!breakpoint_sp->IsEnabled() && breakpoint_sp->AllowDelete()) {
1503be691f3bSpatrick BreakpointID bp_id(breakpoint_sp->GetID());
1504be691f3bSpatrick size_t pos = 0;
1505be691f3bSpatrick if (!excluded_bp_ids.FindBreakpointID(bp_id, &pos))
1506be691f3bSpatrick valid_bp_ids.AddBreakpointID(breakpoint_sp->GetID());
1507be691f3bSpatrick }
1508be691f3bSpatrick }
1509be691f3bSpatrick if (valid_bp_ids.GetSize() == 0) {
1510be691f3bSpatrick result.AppendError("No disabled breakpoints.");
1511be691f3bSpatrick return false;
1512be691f3bSpatrick }
1513be691f3bSpatrick } else {
1514061da546Spatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1515061da546Spatrick command, &target, result, &valid_bp_ids,
1516061da546Spatrick BreakpointName::Permissions::PermissionKinds::deletePerm);
1517be691f3bSpatrick if (!result.Succeeded())
1518be691f3bSpatrick return false;
1519be691f3bSpatrick }
1520061da546Spatrick
1521061da546Spatrick int delete_count = 0;
1522061da546Spatrick int disable_count = 0;
1523061da546Spatrick const size_t count = valid_bp_ids.GetSize();
1524061da546Spatrick for (size_t i = 0; i < count; ++i) {
1525061da546Spatrick BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1526061da546Spatrick
1527061da546Spatrick if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1528061da546Spatrick if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1529061da546Spatrick Breakpoint *breakpoint =
1530061da546Spatrick target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1531061da546Spatrick BreakpointLocation *location =
1532061da546Spatrick breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1533061da546Spatrick // It makes no sense to try to delete individual locations, so we
1534061da546Spatrick // disable them instead.
1535061da546Spatrick if (location) {
1536061da546Spatrick location->SetEnabled(false);
1537061da546Spatrick ++disable_count;
1538061da546Spatrick }
1539061da546Spatrick } else {
1540061da546Spatrick target.RemoveBreakpointByID(cur_bp_id.GetBreakpointID());
1541061da546Spatrick ++delete_count;
1542061da546Spatrick }
1543061da546Spatrick }
1544061da546Spatrick }
1545061da546Spatrick result.AppendMessageWithFormat(
1546061da546Spatrick "%d breakpoints deleted; %d breakpoint locations disabled.\n",
1547061da546Spatrick delete_count, disable_count);
1548061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
1549061da546Spatrick return result.Succeeded();
1550061da546Spatrick }
1551061da546Spatrick
1552061da546Spatrick private:
1553061da546Spatrick CommandOptions m_options;
1554061da546Spatrick };
1555061da546Spatrick
1556061da546Spatrick // CommandObjectBreakpointName
1557061da546Spatrick #define LLDB_OPTIONS_breakpoint_name
1558061da546Spatrick #include "CommandOptions.inc"
1559061da546Spatrick
1560061da546Spatrick class BreakpointNameOptionGroup : public OptionGroup {
1561061da546Spatrick public:
BreakpointNameOptionGroup()1562061da546Spatrick BreakpointNameOptionGroup()
1563*f6aab3d8Srobert : m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) {}
1564061da546Spatrick
1565061da546Spatrick ~BreakpointNameOptionGroup() override = default;
1566061da546Spatrick
GetDefinitions()1567061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1568*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_name_options);
1569061da546Spatrick }
1570061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1571061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1572061da546Spatrick ExecutionContext *execution_context) override {
1573061da546Spatrick Status error;
1574061da546Spatrick const int short_option = g_breakpoint_name_options[option_idx].short_option;
1575061da546Spatrick
1576061da546Spatrick switch (short_option) {
1577061da546Spatrick case 'N':
1578061da546Spatrick if (BreakpointID::StringIsBreakpointName(option_arg, error) &&
1579061da546Spatrick error.Success())
1580061da546Spatrick m_name.SetValueFromString(option_arg);
1581061da546Spatrick break;
1582061da546Spatrick case 'B':
1583061da546Spatrick if (m_breakpoint.SetValueFromString(option_arg).Fail())
1584061da546Spatrick error.SetErrorStringWithFormat(
1585061da546Spatrick "unrecognized value \"%s\" for breakpoint",
1586061da546Spatrick option_arg.str().c_str());
1587061da546Spatrick break;
1588061da546Spatrick case 'D':
1589061da546Spatrick if (m_use_dummy.SetValueFromString(option_arg).Fail())
1590061da546Spatrick error.SetErrorStringWithFormat(
1591061da546Spatrick "unrecognized value \"%s\" for use-dummy",
1592061da546Spatrick option_arg.str().c_str());
1593061da546Spatrick break;
1594061da546Spatrick case 'H':
1595061da546Spatrick m_help_string.SetValueFromString(option_arg);
1596061da546Spatrick break;
1597061da546Spatrick
1598061da546Spatrick default:
1599061da546Spatrick llvm_unreachable("Unimplemented option");
1600061da546Spatrick }
1601061da546Spatrick return error;
1602061da546Spatrick }
1603061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1604061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
1605061da546Spatrick m_name.Clear();
1606061da546Spatrick m_breakpoint.Clear();
1607061da546Spatrick m_use_dummy.Clear();
1608061da546Spatrick m_use_dummy.SetDefaultValue(false);
1609061da546Spatrick m_help_string.Clear();
1610061da546Spatrick }
1611061da546Spatrick
1612061da546Spatrick OptionValueString m_name;
1613061da546Spatrick OptionValueUInt64 m_breakpoint;
1614061da546Spatrick OptionValueBoolean m_use_dummy;
1615061da546Spatrick OptionValueString m_help_string;
1616061da546Spatrick };
1617061da546Spatrick
1618061da546Spatrick #define LLDB_OPTIONS_breakpoint_access
1619061da546Spatrick #include "CommandOptions.inc"
1620061da546Spatrick
1621061da546Spatrick class BreakpointAccessOptionGroup : public OptionGroup {
1622061da546Spatrick public:
1623*f6aab3d8Srobert BreakpointAccessOptionGroup() = default;
1624061da546Spatrick
1625061da546Spatrick ~BreakpointAccessOptionGroup() override = default;
1626061da546Spatrick
GetDefinitions()1627061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1628*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_access_options);
1629061da546Spatrick }
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)1630061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1631061da546Spatrick ExecutionContext *execution_context) override {
1632061da546Spatrick Status error;
1633061da546Spatrick const int short_option =
1634061da546Spatrick g_breakpoint_access_options[option_idx].short_option;
1635061da546Spatrick
1636061da546Spatrick switch (short_option) {
1637061da546Spatrick case 'L': {
1638061da546Spatrick bool value, success;
1639061da546Spatrick value = OptionArgParser::ToBoolean(option_arg, false, &success);
1640061da546Spatrick if (success) {
1641061da546Spatrick m_permissions.SetAllowList(value);
1642061da546Spatrick } else
1643061da546Spatrick error.SetErrorStringWithFormat(
1644061da546Spatrick "invalid boolean value '%s' passed for -L option",
1645061da546Spatrick option_arg.str().c_str());
1646061da546Spatrick } break;
1647061da546Spatrick case 'A': {
1648061da546Spatrick bool value, success;
1649061da546Spatrick value = OptionArgParser::ToBoolean(option_arg, false, &success);
1650061da546Spatrick if (success) {
1651061da546Spatrick m_permissions.SetAllowDisable(value);
1652061da546Spatrick } else
1653061da546Spatrick error.SetErrorStringWithFormat(
1654061da546Spatrick "invalid boolean value '%s' passed for -L option",
1655061da546Spatrick option_arg.str().c_str());
1656061da546Spatrick } break;
1657061da546Spatrick case 'D': {
1658061da546Spatrick bool value, success;
1659061da546Spatrick value = OptionArgParser::ToBoolean(option_arg, false, &success);
1660061da546Spatrick if (success) {
1661061da546Spatrick m_permissions.SetAllowDelete(value);
1662061da546Spatrick } else
1663061da546Spatrick error.SetErrorStringWithFormat(
1664061da546Spatrick "invalid boolean value '%s' passed for -L option",
1665061da546Spatrick option_arg.str().c_str());
1666061da546Spatrick } break;
1667061da546Spatrick default:
1668061da546Spatrick llvm_unreachable("Unimplemented option");
1669061da546Spatrick }
1670061da546Spatrick
1671061da546Spatrick return error;
1672061da546Spatrick }
1673061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)1674061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {}
1675061da546Spatrick
GetPermissions() const1676061da546Spatrick const BreakpointName::Permissions &GetPermissions() const {
1677061da546Spatrick return m_permissions;
1678061da546Spatrick }
1679061da546Spatrick BreakpointName::Permissions m_permissions;
1680061da546Spatrick };
1681061da546Spatrick
1682061da546Spatrick class CommandObjectBreakpointNameConfigure : public CommandObjectParsed {
1683061da546Spatrick public:
CommandObjectBreakpointNameConfigure(CommandInterpreter & interpreter)1684061da546Spatrick CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter)
1685061da546Spatrick : CommandObjectParsed(
1686061da546Spatrick interpreter, "configure",
1687061da546Spatrick "Configure the options for the breakpoint"
1688061da546Spatrick " name provided. "
1689061da546Spatrick "If you provide a breakpoint id, the options will be copied from "
1690061da546Spatrick "the breakpoint, otherwise only the options specified will be set "
1691061da546Spatrick "on the name.",
1692061da546Spatrick "breakpoint name configure <command-options> "
1693*f6aab3d8Srobert "<breakpoint-name-list>") {
1694061da546Spatrick // Create the first variant for the first (and only) argument for this
1695061da546Spatrick // command.
1696061da546Spatrick CommandArgumentEntry arg1;
1697061da546Spatrick CommandArgumentData id_arg;
1698061da546Spatrick id_arg.arg_type = eArgTypeBreakpointName;
1699061da546Spatrick id_arg.arg_repetition = eArgRepeatOptional;
1700061da546Spatrick arg1.push_back(id_arg);
1701061da546Spatrick m_arguments.push_back(arg1);
1702061da546Spatrick
1703061da546Spatrick m_option_group.Append(&m_bp_opts, LLDB_OPT_SET_ALL, LLDB_OPT_SET_1);
1704061da546Spatrick m_option_group.Append(&m_access_options, LLDB_OPT_SET_ALL,
1705061da546Spatrick LLDB_OPT_SET_ALL);
1706061da546Spatrick m_option_group.Append(&m_bp_id, LLDB_OPT_SET_2 | LLDB_OPT_SET_4,
1707061da546Spatrick LLDB_OPT_SET_ALL);
1708061da546Spatrick m_option_group.Finalize();
1709061da546Spatrick }
1710061da546Spatrick
1711061da546Spatrick ~CommandObjectBreakpointNameConfigure() override = default;
1712061da546Spatrick
GetOptions()1713061da546Spatrick Options *GetOptions() override { return &m_option_group; }
1714061da546Spatrick
1715061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1716061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1717061da546Spatrick
1718061da546Spatrick const size_t argc = command.GetArgumentCount();
1719061da546Spatrick if (argc == 0) {
1720061da546Spatrick result.AppendError("No names provided.");
1721061da546Spatrick return false;
1722061da546Spatrick }
1723061da546Spatrick
1724061da546Spatrick Target &target = GetSelectedOrDummyTarget(false);
1725061da546Spatrick
1726061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
1727061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
1728061da546Spatrick
1729061da546Spatrick // Make a pass through first to see that all the names are legal.
1730061da546Spatrick for (auto &entry : command.entries()) {
1731061da546Spatrick Status error;
1732061da546Spatrick if (!BreakpointID::StringIsBreakpointName(entry.ref(), error)) {
1733061da546Spatrick result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s",
1734061da546Spatrick entry.c_str(), error.AsCString());
1735061da546Spatrick return false;
1736061da546Spatrick }
1737061da546Spatrick }
1738061da546Spatrick // Now configure them, we already pre-checked the names so we don't need to
1739061da546Spatrick // check the error:
1740061da546Spatrick BreakpointSP bp_sp;
1741061da546Spatrick if (m_bp_id.m_breakpoint.OptionWasSet()) {
1742061da546Spatrick lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value();
1743061da546Spatrick bp_sp = target.GetBreakpointByID(bp_id);
1744061da546Spatrick if (!bp_sp) {
1745061da546Spatrick result.AppendErrorWithFormatv("Could not find specified breakpoint {0}",
1746061da546Spatrick bp_id);
1747061da546Spatrick return false;
1748061da546Spatrick }
1749061da546Spatrick }
1750061da546Spatrick
1751061da546Spatrick Status error;
1752061da546Spatrick for (auto &entry : command.entries()) {
1753061da546Spatrick ConstString name(entry.c_str());
1754061da546Spatrick BreakpointName *bp_name = target.FindBreakpointName(name, true, error);
1755061da546Spatrick if (!bp_name)
1756061da546Spatrick continue;
1757061da546Spatrick if (m_bp_id.m_help_string.OptionWasSet())
1758061da546Spatrick bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str());
1759061da546Spatrick
1760061da546Spatrick if (bp_sp)
1761be691f3bSpatrick target.ConfigureBreakpointName(*bp_name, bp_sp->GetOptions(),
1762061da546Spatrick m_access_options.GetPermissions());
1763061da546Spatrick else
1764061da546Spatrick target.ConfigureBreakpointName(*bp_name,
1765061da546Spatrick m_bp_opts.GetBreakpointOptions(),
1766061da546Spatrick m_access_options.GetPermissions());
1767061da546Spatrick }
1768061da546Spatrick return true;
1769061da546Spatrick }
1770061da546Spatrick
1771061da546Spatrick private:
1772061da546Spatrick BreakpointNameOptionGroup m_bp_id; // Only using the id part of this.
1773061da546Spatrick BreakpointOptionGroup m_bp_opts;
1774061da546Spatrick BreakpointAccessOptionGroup m_access_options;
1775061da546Spatrick OptionGroupOptions m_option_group;
1776061da546Spatrick };
1777061da546Spatrick
1778061da546Spatrick class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
1779061da546Spatrick public:
CommandObjectBreakpointNameAdd(CommandInterpreter & interpreter)1780061da546Spatrick CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter)
1781061da546Spatrick : CommandObjectParsed(
1782061da546Spatrick interpreter, "add", "Add a name to the breakpoints provided.",
1783*f6aab3d8Srobert "breakpoint name add <command-options> <breakpoint-id-list>") {
1784061da546Spatrick // Create the first variant for the first (and only) argument for this
1785061da546Spatrick // command.
1786061da546Spatrick CommandArgumentEntry arg1;
1787061da546Spatrick CommandArgumentData id_arg;
1788061da546Spatrick id_arg.arg_type = eArgTypeBreakpointID;
1789061da546Spatrick id_arg.arg_repetition = eArgRepeatOptional;
1790061da546Spatrick arg1.push_back(id_arg);
1791061da546Spatrick m_arguments.push_back(arg1);
1792061da546Spatrick
1793061da546Spatrick m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1794061da546Spatrick m_option_group.Finalize();
1795061da546Spatrick }
1796061da546Spatrick
1797061da546Spatrick ~CommandObjectBreakpointNameAdd() override = default;
1798061da546Spatrick
1799dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1800dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
1801dda28197Spatrick OptionElementVector &opt_element_vector) override {
1802dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1803dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
1804dda28197Spatrick request, nullptr);
1805dda28197Spatrick }
1806dda28197Spatrick
GetOptions()1807061da546Spatrick Options *GetOptions() override { return &m_option_group; }
1808061da546Spatrick
1809061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1810061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1811061da546Spatrick if (!m_name_options.m_name.OptionWasSet()) {
1812be691f3bSpatrick result.AppendError("No name option provided.");
1813061da546Spatrick return false;
1814061da546Spatrick }
1815061da546Spatrick
1816061da546Spatrick Target &target =
1817061da546Spatrick GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1818061da546Spatrick
1819061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
1820061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
1821061da546Spatrick
1822061da546Spatrick const BreakpointList &breakpoints = target.GetBreakpointList();
1823061da546Spatrick
1824061da546Spatrick size_t num_breakpoints = breakpoints.GetSize();
1825061da546Spatrick if (num_breakpoints == 0) {
1826be691f3bSpatrick result.AppendError("No breakpoints, cannot add names.");
1827061da546Spatrick return false;
1828061da546Spatrick }
1829061da546Spatrick
1830061da546Spatrick // Particular breakpoint selected; disable that breakpoint.
1831061da546Spatrick BreakpointIDList valid_bp_ids;
1832061da546Spatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1833061da546Spatrick command, &target, result, &valid_bp_ids,
1834061da546Spatrick BreakpointName::Permissions::PermissionKinds::listPerm);
1835061da546Spatrick
1836061da546Spatrick if (result.Succeeded()) {
1837061da546Spatrick if (valid_bp_ids.GetSize() == 0) {
1838be691f3bSpatrick result.AppendError("No breakpoints specified, cannot add names.");
1839061da546Spatrick return false;
1840061da546Spatrick }
1841061da546Spatrick size_t num_valid_ids = valid_bp_ids.GetSize();
1842061da546Spatrick const char *bp_name = m_name_options.m_name.GetCurrentValue();
1843061da546Spatrick Status error; // This error reports illegal names, but we've already
1844061da546Spatrick // checked that, so we don't need to check it again here.
1845061da546Spatrick for (size_t index = 0; index < num_valid_ids; index++) {
1846061da546Spatrick lldb::break_id_t bp_id =
1847061da546Spatrick valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
1848061da546Spatrick BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
1849061da546Spatrick target.AddNameToBreakpoint(bp_sp, bp_name, error);
1850061da546Spatrick }
1851061da546Spatrick }
1852061da546Spatrick
1853061da546Spatrick return true;
1854061da546Spatrick }
1855061da546Spatrick
1856061da546Spatrick private:
1857061da546Spatrick BreakpointNameOptionGroup m_name_options;
1858061da546Spatrick OptionGroupOptions m_option_group;
1859061da546Spatrick };
1860061da546Spatrick
1861061da546Spatrick class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
1862061da546Spatrick public:
CommandObjectBreakpointNameDelete(CommandInterpreter & interpreter)1863061da546Spatrick CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter)
1864061da546Spatrick : CommandObjectParsed(
1865061da546Spatrick interpreter, "delete",
1866061da546Spatrick "Delete a name from the breakpoints provided.",
1867*f6aab3d8Srobert "breakpoint name delete <command-options> <breakpoint-id-list>") {
1868061da546Spatrick // Create the first variant for the first (and only) argument for this
1869061da546Spatrick // command.
1870061da546Spatrick CommandArgumentEntry arg1;
1871061da546Spatrick CommandArgumentData id_arg;
1872061da546Spatrick id_arg.arg_type = eArgTypeBreakpointID;
1873061da546Spatrick id_arg.arg_repetition = eArgRepeatOptional;
1874061da546Spatrick arg1.push_back(id_arg);
1875061da546Spatrick m_arguments.push_back(arg1);
1876061da546Spatrick
1877061da546Spatrick m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
1878061da546Spatrick m_option_group.Finalize();
1879061da546Spatrick }
1880061da546Spatrick
1881061da546Spatrick ~CommandObjectBreakpointNameDelete() override = default;
1882061da546Spatrick
1883dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)1884dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
1885dda28197Spatrick OptionElementVector &opt_element_vector) override {
1886dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
1887dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
1888dda28197Spatrick request, nullptr);
1889dda28197Spatrick }
1890dda28197Spatrick
GetOptions()1891061da546Spatrick Options *GetOptions() override { return &m_option_group; }
1892061da546Spatrick
1893061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1894061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1895061da546Spatrick if (!m_name_options.m_name.OptionWasSet()) {
1896be691f3bSpatrick result.AppendError("No name option provided.");
1897061da546Spatrick return false;
1898061da546Spatrick }
1899061da546Spatrick
1900061da546Spatrick Target &target =
1901061da546Spatrick GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1902061da546Spatrick
1903061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
1904061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
1905061da546Spatrick
1906061da546Spatrick const BreakpointList &breakpoints = target.GetBreakpointList();
1907061da546Spatrick
1908061da546Spatrick size_t num_breakpoints = breakpoints.GetSize();
1909061da546Spatrick if (num_breakpoints == 0) {
1910be691f3bSpatrick result.AppendError("No breakpoints, cannot delete names.");
1911061da546Spatrick return false;
1912061da546Spatrick }
1913061da546Spatrick
1914061da546Spatrick // Particular breakpoint selected; disable that breakpoint.
1915061da546Spatrick BreakpointIDList valid_bp_ids;
1916061da546Spatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1917061da546Spatrick command, &target, result, &valid_bp_ids,
1918061da546Spatrick BreakpointName::Permissions::PermissionKinds::deletePerm);
1919061da546Spatrick
1920061da546Spatrick if (result.Succeeded()) {
1921061da546Spatrick if (valid_bp_ids.GetSize() == 0) {
1922be691f3bSpatrick result.AppendError("No breakpoints specified, cannot delete names.");
1923061da546Spatrick return false;
1924061da546Spatrick }
1925061da546Spatrick ConstString bp_name(m_name_options.m_name.GetCurrentValue());
1926061da546Spatrick size_t num_valid_ids = valid_bp_ids.GetSize();
1927061da546Spatrick for (size_t index = 0; index < num_valid_ids; index++) {
1928061da546Spatrick lldb::break_id_t bp_id =
1929061da546Spatrick valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
1930061da546Spatrick BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
1931061da546Spatrick target.RemoveNameFromBreakpoint(bp_sp, bp_name);
1932061da546Spatrick }
1933061da546Spatrick }
1934061da546Spatrick
1935061da546Spatrick return true;
1936061da546Spatrick }
1937061da546Spatrick
1938061da546Spatrick private:
1939061da546Spatrick BreakpointNameOptionGroup m_name_options;
1940061da546Spatrick OptionGroupOptions m_option_group;
1941061da546Spatrick };
1942061da546Spatrick
1943061da546Spatrick class CommandObjectBreakpointNameList : public CommandObjectParsed {
1944061da546Spatrick public:
CommandObjectBreakpointNameList(CommandInterpreter & interpreter)1945061da546Spatrick CommandObjectBreakpointNameList(CommandInterpreter &interpreter)
1946061da546Spatrick : CommandObjectParsed(interpreter, "list",
1947061da546Spatrick "List either the names for a breakpoint or info "
1948061da546Spatrick "about a given name. With no arguments, lists all "
1949061da546Spatrick "names",
1950*f6aab3d8Srobert "breakpoint name list <command-options>") {
1951061da546Spatrick m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL);
1952061da546Spatrick m_option_group.Finalize();
1953061da546Spatrick }
1954061da546Spatrick
1955061da546Spatrick ~CommandObjectBreakpointNameList() override = default;
1956061da546Spatrick
GetOptions()1957061da546Spatrick Options *GetOptions() override { return &m_option_group; }
1958061da546Spatrick
1959061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)1960061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
1961061da546Spatrick Target &target =
1962061da546Spatrick GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
1963061da546Spatrick
1964061da546Spatrick std::vector<std::string> name_list;
1965061da546Spatrick if (command.empty()) {
1966061da546Spatrick target.GetBreakpointNames(name_list);
1967061da546Spatrick } else {
1968061da546Spatrick for (const Args::ArgEntry &arg : command) {
1969061da546Spatrick name_list.push_back(arg.c_str());
1970061da546Spatrick }
1971061da546Spatrick }
1972061da546Spatrick
1973061da546Spatrick if (name_list.empty()) {
1974061da546Spatrick result.AppendMessage("No breakpoint names found.");
1975061da546Spatrick } else {
1976061da546Spatrick for (const std::string &name_str : name_list) {
1977061da546Spatrick const char *name = name_str.c_str();
1978061da546Spatrick // First print out the options for the name:
1979061da546Spatrick Status error;
1980061da546Spatrick BreakpointName *bp_name =
1981061da546Spatrick target.FindBreakpointName(ConstString(name), false, error);
1982061da546Spatrick if (bp_name) {
1983061da546Spatrick StreamString s;
1984061da546Spatrick result.AppendMessageWithFormat("Name: %s\n", name);
1985061da546Spatrick if (bp_name->GetDescription(&s, eDescriptionLevelFull)) {
1986061da546Spatrick result.AppendMessage(s.GetString());
1987061da546Spatrick }
1988061da546Spatrick
1989061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
1990061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
1991061da546Spatrick
1992061da546Spatrick BreakpointList &breakpoints = target.GetBreakpointList();
1993061da546Spatrick bool any_set = false;
1994061da546Spatrick for (BreakpointSP bp_sp : breakpoints.Breakpoints()) {
1995061da546Spatrick if (bp_sp->MatchesName(name)) {
1996061da546Spatrick StreamString s;
1997061da546Spatrick any_set = true;
1998061da546Spatrick bp_sp->GetDescription(&s, eDescriptionLevelBrief);
1999061da546Spatrick s.EOL();
2000061da546Spatrick result.AppendMessage(s.GetString());
2001061da546Spatrick }
2002061da546Spatrick }
2003061da546Spatrick if (!any_set)
2004061da546Spatrick result.AppendMessage("No breakpoints using this name.");
2005061da546Spatrick } else {
2006061da546Spatrick result.AppendMessageWithFormat("Name: %s not found.\n", name);
2007061da546Spatrick }
2008061da546Spatrick }
2009061da546Spatrick }
2010061da546Spatrick return true;
2011061da546Spatrick }
2012061da546Spatrick
2013061da546Spatrick private:
2014061da546Spatrick BreakpointNameOptionGroup m_name_options;
2015061da546Spatrick OptionGroupOptions m_option_group;
2016061da546Spatrick };
2017061da546Spatrick
2018061da546Spatrick // CommandObjectBreakpointName
2019061da546Spatrick class CommandObjectBreakpointName : public CommandObjectMultiword {
2020061da546Spatrick public:
CommandObjectBreakpointName(CommandInterpreter & interpreter)2021061da546Spatrick CommandObjectBreakpointName(CommandInterpreter &interpreter)
2022061da546Spatrick : CommandObjectMultiword(
2023*f6aab3d8Srobert interpreter, "name", "Commands to manage breakpoint names") {
2024*f6aab3d8Srobert
2025*f6aab3d8Srobert
2026*f6aab3d8Srobert SetHelpLong(
2027*f6aab3d8Srobert R"(
2028*f6aab3d8Srobert Breakpoint names provide a general tagging mechanism for breakpoints. Each
2029*f6aab3d8Srobert breakpoint name can be added to any number of breakpoints, and each breakpoint
2030*f6aab3d8Srobert can have any number of breakpoint names attached to it. For instance:
2031*f6aab3d8Srobert
2032*f6aab3d8Srobert (lldb) break name add -N MyName 1-10
2033*f6aab3d8Srobert
2034*f6aab3d8Srobert adds the name MyName to breakpoints 1-10, and:
2035*f6aab3d8Srobert
2036*f6aab3d8Srobert (lldb) break set -n myFunc -N Name1 -N Name2
2037*f6aab3d8Srobert
2038*f6aab3d8Srobert adds two names to the breakpoint set at myFunc.
2039*f6aab3d8Srobert
2040*f6aab3d8Srobert They have a number of interrelated uses:
2041*f6aab3d8Srobert
2042*f6aab3d8Srobert 1) They provide a stable way to refer to a breakpoint (e.g. in another
2043*f6aab3d8Srobert breakpoint's action). Using the breakpoint ID for this purpose is fragile, since
2044*f6aab3d8Srobert it depends on the order of breakpoint creation. Giving a name to the breakpoint
2045*f6aab3d8Srobert you want to act on, and then referring to it by name, is more robust:
2046*f6aab3d8Srobert
2047*f6aab3d8Srobert (lldb) break set -n myFunc -N BKPT1
2048*f6aab3d8Srobert (lldb) break set -n myOtherFunc -C "break disable BKPT1"
2049*f6aab3d8Srobert
2050*f6aab3d8Srobert 2) This is actually just a specific use of a more general feature of breakpoint
2051*f6aab3d8Srobert names. The <breakpt-id-list> argument type used to specify one or more
2052*f6aab3d8Srobert breakpoints in most of the commands that deal with breakpoints also accepts
2053*f6aab3d8Srobert breakpoint names. That allows you to refer to one breakpoint in a stable
2054*f6aab3d8Srobert manner, but also makes them a convenient grouping mechanism, allowing you to
2055*f6aab3d8Srobert easily act on a group of breakpoints by using their name, for instance disabling
2056*f6aab3d8Srobert them all in one action:
2057*f6aab3d8Srobert
2058*f6aab3d8Srobert (lldb) break set -n myFunc -N Group1
2059*f6aab3d8Srobert (lldb) break set -n myOtherFunc -N Group1
2060*f6aab3d8Srobert (lldb) break disable Group1
2061*f6aab3d8Srobert
2062*f6aab3d8Srobert 3) But breakpoint names are also entities in their own right, and can be
2063*f6aab3d8Srobert configured with all the modifiable attributes of a breakpoint. Then when you
2064*f6aab3d8Srobert add a breakpoint name to a breakpoint, the breakpoint will be configured to
2065*f6aab3d8Srobert match the state of the breakpoint name. The link between the name and the
2066*f6aab3d8Srobert breakpoints sharing it remains live, so if you change the configuration on the
2067*f6aab3d8Srobert name, it will also change the configurations on the breakpoints:
2068*f6aab3d8Srobert
2069*f6aab3d8Srobert (lldb) break name configure -i 10 IgnoreSome
2070*f6aab3d8Srobert (lldb) break set -n myFunc -N IgnoreSome
2071*f6aab3d8Srobert (lldb) break list IgnoreSome
2072*f6aab3d8Srobert 2: name = 'myFunc', locations = 0 (pending) Options: ignore: 10 enabled
2073*f6aab3d8Srobert Names:
2074*f6aab3d8Srobert IgnoreSome
2075*f6aab3d8Srobert (lldb) break name configure -i 5 IgnoreSome
2076*f6aab3d8Srobert (lldb) break list IgnoreSome
2077*f6aab3d8Srobert 2: name = 'myFunc', locations = 0 (pending) Options: ignore: 5 enabled
2078*f6aab3d8Srobert Names:
2079*f6aab3d8Srobert IgnoreSome
2080*f6aab3d8Srobert
2081*f6aab3d8Srobert Options that are not configured on a breakpoint name don't affect the value of
2082*f6aab3d8Srobert those options on the breakpoints they are added to. So for instance, if Name1
2083*f6aab3d8Srobert has the -i option configured and Name2 the -c option, adding both names to a
2084*f6aab3d8Srobert breakpoint will set the -i option from Name1 and the -c option from Name2, and
2085*f6aab3d8Srobert the other options will be unaltered.
2086*f6aab3d8Srobert
2087*f6aab3d8Srobert If you add multiple names to a breakpoint which have configured values for
2088*f6aab3d8Srobert the same option, the last name added's value wins.
2089*f6aab3d8Srobert
2090*f6aab3d8Srobert The "liveness" of these settings is one way, from name to breakpoint.
2091*f6aab3d8Srobert If you use "break modify" to change an option that is also configured on a name
2092*f6aab3d8Srobert which that breakpoint has, the "break modify" command will override the setting
2093*f6aab3d8Srobert for that breakpoint, but won't change the value configured in the name or on the
2094*f6aab3d8Srobert other breakpoints sharing that name.
2095*f6aab3d8Srobert
2096*f6aab3d8Srobert 4) Breakpoint names are also a convenient way to copy option sets from one
2097*f6aab3d8Srobert breakpoint to another. Using the -B option to "breakpoint name configure" makes
2098*f6aab3d8Srobert a name configured with all the options of the original breakpoint. Then
2099*f6aab3d8Srobert adding that name to another breakpoint copies over all the values from the
2100*f6aab3d8Srobert original breakpoint to the new one.
2101*f6aab3d8Srobert
2102*f6aab3d8Srobert 5) You can also use breakpoint names to hide breakpoints from the breakpoint
2103*f6aab3d8Srobert operations that act on all breakpoints: "break delete", "break disable" and
2104*f6aab3d8Srobert "break list". You do that by specifying a "false" value for the
2105*f6aab3d8Srobert --allow-{list,delete,disable} options to "breakpoint name configure" and then
2106*f6aab3d8Srobert adding that name to a breakpoint.
2107*f6aab3d8Srobert
2108*f6aab3d8Srobert This won't keep the breakpoint from being deleted or disabled if you refer to it
2109*f6aab3d8Srobert specifically by ID. The point of the feature is to make sure users don't
2110*f6aab3d8Srobert inadvertently delete or disable useful breakpoints (e.g. ones an IDE is using
2111*f6aab3d8Srobert for its own purposes) as part of a "delete all" or "disable all" operation. The
2112*f6aab3d8Srobert list hiding is because it's confusing for people to see breakpoints they
2113*f6aab3d8Srobert didn't set.
2114*f6aab3d8Srobert
2115*f6aab3d8Srobert )");
2116061da546Spatrick CommandObjectSP add_command_object(
2117061da546Spatrick new CommandObjectBreakpointNameAdd(interpreter));
2118061da546Spatrick CommandObjectSP delete_command_object(
2119061da546Spatrick new CommandObjectBreakpointNameDelete(interpreter));
2120061da546Spatrick CommandObjectSP list_command_object(
2121061da546Spatrick new CommandObjectBreakpointNameList(interpreter));
2122061da546Spatrick CommandObjectSP configure_command_object(
2123061da546Spatrick new CommandObjectBreakpointNameConfigure(interpreter));
2124061da546Spatrick
2125061da546Spatrick LoadSubCommand("add", add_command_object);
2126061da546Spatrick LoadSubCommand("delete", delete_command_object);
2127061da546Spatrick LoadSubCommand("list", list_command_object);
2128061da546Spatrick LoadSubCommand("configure", configure_command_object);
2129061da546Spatrick }
2130061da546Spatrick
2131061da546Spatrick ~CommandObjectBreakpointName() override = default;
2132061da546Spatrick };
2133061da546Spatrick
2134061da546Spatrick // CommandObjectBreakpointRead
2135061da546Spatrick #pragma mark Read::CommandOptions
2136061da546Spatrick #define LLDB_OPTIONS_breakpoint_read
2137061da546Spatrick #include "CommandOptions.inc"
2138061da546Spatrick
2139061da546Spatrick #pragma mark Read
2140061da546Spatrick
2141061da546Spatrick class CommandObjectBreakpointRead : public CommandObjectParsed {
2142061da546Spatrick public:
CommandObjectBreakpointRead(CommandInterpreter & interpreter)2143061da546Spatrick CommandObjectBreakpointRead(CommandInterpreter &interpreter)
2144061da546Spatrick : CommandObjectParsed(interpreter, "breakpoint read",
2145061da546Spatrick "Read and set the breakpoints previously saved to "
2146061da546Spatrick "a file with \"breakpoint write\". ",
2147*f6aab3d8Srobert nullptr) {}
2148061da546Spatrick
2149061da546Spatrick ~CommandObjectBreakpointRead() override = default;
2150061da546Spatrick
GetOptions()2151061da546Spatrick Options *GetOptions() override { return &m_options; }
2152061da546Spatrick
2153061da546Spatrick class CommandOptions : public Options {
2154061da546Spatrick public:
2155*f6aab3d8Srobert CommandOptions() = default;
2156061da546Spatrick
2157061da546Spatrick ~CommandOptions() override = default;
2158061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2159061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2160061da546Spatrick ExecutionContext *execution_context) override {
2161061da546Spatrick Status error;
2162061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
2163061da546Spatrick
2164061da546Spatrick switch (short_option) {
2165061da546Spatrick case 'f':
2166dda28197Spatrick m_filename.assign(std::string(option_arg));
2167061da546Spatrick break;
2168061da546Spatrick case 'N': {
2169061da546Spatrick Status name_error;
2170061da546Spatrick if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg),
2171061da546Spatrick name_error)) {
2172061da546Spatrick error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
2173061da546Spatrick name_error.AsCString());
2174061da546Spatrick }
2175dda28197Spatrick m_names.push_back(std::string(option_arg));
2176061da546Spatrick break;
2177061da546Spatrick }
2178061da546Spatrick default:
2179061da546Spatrick llvm_unreachable("Unimplemented option");
2180061da546Spatrick }
2181061da546Spatrick
2182061da546Spatrick return error;
2183061da546Spatrick }
2184061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)2185061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
2186061da546Spatrick m_filename.clear();
2187061da546Spatrick m_names.clear();
2188061da546Spatrick }
2189061da546Spatrick
GetDefinitions()2190061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2191*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_read_options);
2192061da546Spatrick }
2193061da546Spatrick
HandleOptionArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector,int opt_element_index,CommandInterpreter & interpreter)2194be691f3bSpatrick void HandleOptionArgumentCompletion(
2195be691f3bSpatrick CompletionRequest &request, OptionElementVector &opt_element_vector,
2196be691f3bSpatrick int opt_element_index, CommandInterpreter &interpreter) override {
2197be691f3bSpatrick int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
2198be691f3bSpatrick int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
2199be691f3bSpatrick
2200be691f3bSpatrick switch (GetDefinitions()[opt_defs_index].short_option) {
2201be691f3bSpatrick case 'f':
2202be691f3bSpatrick CommandCompletions::InvokeCommonCompletionCallbacks(
2203be691f3bSpatrick interpreter, CommandCompletions::eDiskFileCompletion, request,
2204be691f3bSpatrick nullptr);
2205be691f3bSpatrick break;
2206be691f3bSpatrick
2207be691f3bSpatrick case 'N':
2208*f6aab3d8Srobert std::optional<FileSpec> file_spec;
2209be691f3bSpatrick const llvm::StringRef dash_f("-f");
2210be691f3bSpatrick for (int arg_idx = 0; arg_idx < opt_arg_pos; arg_idx++) {
2211be691f3bSpatrick if (dash_f == request.GetParsedLine().GetArgumentAtIndex(arg_idx)) {
2212be691f3bSpatrick file_spec.emplace(
2213be691f3bSpatrick request.GetParsedLine().GetArgumentAtIndex(arg_idx + 1));
2214be691f3bSpatrick break;
2215be691f3bSpatrick }
2216be691f3bSpatrick }
2217be691f3bSpatrick if (!file_spec)
2218be691f3bSpatrick return;
2219be691f3bSpatrick
2220be691f3bSpatrick FileSystem::Instance().Resolve(*file_spec);
2221be691f3bSpatrick Status error;
2222be691f3bSpatrick StructuredData::ObjectSP input_data_sp =
2223be691f3bSpatrick StructuredData::ParseJSONFromFile(*file_spec, error);
2224be691f3bSpatrick if (!error.Success())
2225be691f3bSpatrick return;
2226be691f3bSpatrick
2227be691f3bSpatrick StructuredData::Array *bkpt_array = input_data_sp->GetAsArray();
2228be691f3bSpatrick if (!bkpt_array)
2229be691f3bSpatrick return;
2230be691f3bSpatrick
2231be691f3bSpatrick const size_t num_bkpts = bkpt_array->GetSize();
2232be691f3bSpatrick for (size_t i = 0; i < num_bkpts; i++) {
2233be691f3bSpatrick StructuredData::ObjectSP bkpt_object_sp =
2234be691f3bSpatrick bkpt_array->GetItemAtIndex(i);
2235be691f3bSpatrick if (!bkpt_object_sp)
2236be691f3bSpatrick return;
2237be691f3bSpatrick
2238be691f3bSpatrick StructuredData::Dictionary *bkpt_dict =
2239be691f3bSpatrick bkpt_object_sp->GetAsDictionary();
2240be691f3bSpatrick if (!bkpt_dict)
2241be691f3bSpatrick return;
2242be691f3bSpatrick
2243be691f3bSpatrick StructuredData::ObjectSP bkpt_data_sp =
2244be691f3bSpatrick bkpt_dict->GetValueForKey(Breakpoint::GetSerializationKey());
2245be691f3bSpatrick if (!bkpt_data_sp)
2246be691f3bSpatrick return;
2247be691f3bSpatrick
2248be691f3bSpatrick bkpt_dict = bkpt_data_sp->GetAsDictionary();
2249be691f3bSpatrick if (!bkpt_dict)
2250be691f3bSpatrick return;
2251be691f3bSpatrick
2252be691f3bSpatrick StructuredData::Array *names_array;
2253be691f3bSpatrick
2254be691f3bSpatrick if (!bkpt_dict->GetValueForKeyAsArray("Names", names_array))
2255be691f3bSpatrick return;
2256be691f3bSpatrick
2257be691f3bSpatrick size_t num_names = names_array->GetSize();
2258be691f3bSpatrick
2259be691f3bSpatrick for (size_t i = 0; i < num_names; i++) {
2260be691f3bSpatrick llvm::StringRef name;
2261be691f3bSpatrick if (names_array->GetItemAtIndexAsString(i, name))
2262be691f3bSpatrick request.TryCompleteCurrentArg(name);
2263be691f3bSpatrick }
2264be691f3bSpatrick }
2265be691f3bSpatrick }
2266be691f3bSpatrick }
2267061da546Spatrick
2268061da546Spatrick std::string m_filename;
2269061da546Spatrick std::vector<std::string> m_names;
2270061da546Spatrick };
2271061da546Spatrick
2272061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)2273061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
2274061da546Spatrick Target &target = GetSelectedOrDummyTarget();
2275061da546Spatrick
2276061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
2277061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
2278061da546Spatrick
2279061da546Spatrick FileSpec input_spec(m_options.m_filename);
2280061da546Spatrick FileSystem::Instance().Resolve(input_spec);
2281061da546Spatrick BreakpointIDList new_bps;
2282061da546Spatrick Status error = target.CreateBreakpointsFromFile(input_spec,
2283061da546Spatrick m_options.m_names, new_bps);
2284061da546Spatrick
2285061da546Spatrick if (!error.Success()) {
2286061da546Spatrick result.AppendError(error.AsCString());
2287061da546Spatrick return false;
2288061da546Spatrick }
2289061da546Spatrick
2290061da546Spatrick Stream &output_stream = result.GetOutputStream();
2291061da546Spatrick
2292061da546Spatrick size_t num_breakpoints = new_bps.GetSize();
2293061da546Spatrick if (num_breakpoints == 0) {
2294061da546Spatrick result.AppendMessage("No breakpoints added.");
2295061da546Spatrick } else {
2296061da546Spatrick // No breakpoint selected; show info about all currently set breakpoints.
2297061da546Spatrick result.AppendMessage("New breakpoints:");
2298061da546Spatrick for (size_t i = 0; i < num_breakpoints; ++i) {
2299061da546Spatrick BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i);
2300061da546Spatrick Breakpoint *bp = target.GetBreakpointList()
2301061da546Spatrick .FindBreakpointByID(bp_id.GetBreakpointID())
2302061da546Spatrick .get();
2303061da546Spatrick if (bp)
2304061da546Spatrick bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
2305061da546Spatrick false);
2306061da546Spatrick }
2307061da546Spatrick }
2308061da546Spatrick return result.Succeeded();
2309061da546Spatrick }
2310061da546Spatrick
2311061da546Spatrick private:
2312061da546Spatrick CommandOptions m_options;
2313061da546Spatrick };
2314061da546Spatrick
2315061da546Spatrick // CommandObjectBreakpointWrite
2316061da546Spatrick #pragma mark Write::CommandOptions
2317061da546Spatrick #define LLDB_OPTIONS_breakpoint_write
2318061da546Spatrick #include "CommandOptions.inc"
2319061da546Spatrick
2320061da546Spatrick #pragma mark Write
2321061da546Spatrick class CommandObjectBreakpointWrite : public CommandObjectParsed {
2322061da546Spatrick public:
CommandObjectBreakpointWrite(CommandInterpreter & interpreter)2323061da546Spatrick CommandObjectBreakpointWrite(CommandInterpreter &interpreter)
2324061da546Spatrick : CommandObjectParsed(interpreter, "breakpoint write",
2325061da546Spatrick "Write the breakpoints listed to a file that can "
2326061da546Spatrick "be read in with \"breakpoint read\". "
2327061da546Spatrick "If given no arguments, writes all breakpoints.",
2328*f6aab3d8Srobert nullptr) {
2329061da546Spatrick CommandArgumentEntry arg;
2330061da546Spatrick CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2331061da546Spatrick eArgTypeBreakpointIDRange);
2332061da546Spatrick // Add the entry for the first argument for this command to the object's
2333061da546Spatrick // arguments vector.
2334061da546Spatrick m_arguments.push_back(arg);
2335061da546Spatrick }
2336061da546Spatrick
2337061da546Spatrick ~CommandObjectBreakpointWrite() override = default;
2338061da546Spatrick
2339dda28197Spatrick void
HandleArgumentCompletion(CompletionRequest & request,OptionElementVector & opt_element_vector)2340dda28197Spatrick HandleArgumentCompletion(CompletionRequest &request,
2341dda28197Spatrick OptionElementVector &opt_element_vector) override {
2342dda28197Spatrick CommandCompletions::InvokeCommonCompletionCallbacks(
2343dda28197Spatrick GetCommandInterpreter(), CommandCompletions::eBreakpointCompletion,
2344dda28197Spatrick request, nullptr);
2345dda28197Spatrick }
2346dda28197Spatrick
GetOptions()2347061da546Spatrick Options *GetOptions() override { return &m_options; }
2348061da546Spatrick
2349061da546Spatrick class CommandOptions : public Options {
2350061da546Spatrick public:
2351*f6aab3d8Srobert CommandOptions() = default;
2352061da546Spatrick
2353061da546Spatrick ~CommandOptions() override = default;
2354061da546Spatrick
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)2355061da546Spatrick Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2356061da546Spatrick ExecutionContext *execution_context) override {
2357061da546Spatrick Status error;
2358061da546Spatrick const int short_option = m_getopt_table[option_idx].val;
2359061da546Spatrick
2360061da546Spatrick switch (short_option) {
2361061da546Spatrick case 'f':
2362dda28197Spatrick m_filename.assign(std::string(option_arg));
2363061da546Spatrick break;
2364061da546Spatrick case 'a':
2365061da546Spatrick m_append = true;
2366061da546Spatrick break;
2367061da546Spatrick default:
2368061da546Spatrick llvm_unreachable("Unimplemented option");
2369061da546Spatrick }
2370061da546Spatrick
2371061da546Spatrick return error;
2372061da546Spatrick }
2373061da546Spatrick
OptionParsingStarting(ExecutionContext * execution_context)2374061da546Spatrick void OptionParsingStarting(ExecutionContext *execution_context) override {
2375061da546Spatrick m_filename.clear();
2376061da546Spatrick m_append = false;
2377061da546Spatrick }
2378061da546Spatrick
GetDefinitions()2379061da546Spatrick llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
2380*f6aab3d8Srobert return llvm::ArrayRef(g_breakpoint_write_options);
2381061da546Spatrick }
2382061da546Spatrick
2383061da546Spatrick // Instance variables to hold the values for command options.
2384061da546Spatrick
2385061da546Spatrick std::string m_filename;
2386061da546Spatrick bool m_append = false;
2387061da546Spatrick };
2388061da546Spatrick
2389061da546Spatrick protected:
DoExecute(Args & command,CommandReturnObject & result)2390061da546Spatrick bool DoExecute(Args &command, CommandReturnObject &result) override {
2391061da546Spatrick Target &target = GetSelectedOrDummyTarget();
2392061da546Spatrick
2393061da546Spatrick std::unique_lock<std::recursive_mutex> lock;
2394061da546Spatrick target.GetBreakpointList().GetListMutex(lock);
2395061da546Spatrick
2396061da546Spatrick BreakpointIDList valid_bp_ids;
2397061da546Spatrick if (!command.empty()) {
2398061da546Spatrick CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2399061da546Spatrick command, &target, result, &valid_bp_ids,
2400061da546Spatrick BreakpointName::Permissions::PermissionKinds::listPerm);
2401061da546Spatrick
2402061da546Spatrick if (!result.Succeeded()) {
2403061da546Spatrick result.SetStatus(eReturnStatusFailed);
2404061da546Spatrick return false;
2405061da546Spatrick }
2406061da546Spatrick }
2407061da546Spatrick FileSpec file_spec(m_options.m_filename);
2408061da546Spatrick FileSystem::Instance().Resolve(file_spec);
2409061da546Spatrick Status error = target.SerializeBreakpointsToFile(file_spec, valid_bp_ids,
2410061da546Spatrick m_options.m_append);
2411061da546Spatrick if (!error.Success()) {
2412061da546Spatrick result.AppendErrorWithFormat("error serializing breakpoints: %s.",
2413061da546Spatrick error.AsCString());
2414061da546Spatrick }
2415061da546Spatrick return result.Succeeded();
2416061da546Spatrick }
2417061da546Spatrick
2418061da546Spatrick private:
2419061da546Spatrick CommandOptions m_options;
2420061da546Spatrick };
2421061da546Spatrick
2422061da546Spatrick // CommandObjectMultiwordBreakpoint
2423061da546Spatrick #pragma mark MultiwordBreakpoint
2424061da546Spatrick
CommandObjectMultiwordBreakpoint(CommandInterpreter & interpreter)2425061da546Spatrick CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
2426061da546Spatrick CommandInterpreter &interpreter)
2427061da546Spatrick : CommandObjectMultiword(
2428061da546Spatrick interpreter, "breakpoint",
2429061da546Spatrick "Commands for operating on breakpoints (see 'help b' for shorthand.)",
2430061da546Spatrick "breakpoint <subcommand> [<command-options>]") {
2431061da546Spatrick CommandObjectSP list_command_object(
2432061da546Spatrick new CommandObjectBreakpointList(interpreter));
2433061da546Spatrick CommandObjectSP enable_command_object(
2434061da546Spatrick new CommandObjectBreakpointEnable(interpreter));
2435061da546Spatrick CommandObjectSP disable_command_object(
2436061da546Spatrick new CommandObjectBreakpointDisable(interpreter));
2437061da546Spatrick CommandObjectSP clear_command_object(
2438061da546Spatrick new CommandObjectBreakpointClear(interpreter));
2439061da546Spatrick CommandObjectSP delete_command_object(
2440061da546Spatrick new CommandObjectBreakpointDelete(interpreter));
2441061da546Spatrick CommandObjectSP set_command_object(
2442061da546Spatrick new CommandObjectBreakpointSet(interpreter));
2443061da546Spatrick CommandObjectSP command_command_object(
2444061da546Spatrick new CommandObjectBreakpointCommand(interpreter));
2445061da546Spatrick CommandObjectSP modify_command_object(
2446061da546Spatrick new CommandObjectBreakpointModify(interpreter));
2447061da546Spatrick CommandObjectSP name_command_object(
2448061da546Spatrick new CommandObjectBreakpointName(interpreter));
2449061da546Spatrick CommandObjectSP write_command_object(
2450061da546Spatrick new CommandObjectBreakpointWrite(interpreter));
2451061da546Spatrick CommandObjectSP read_command_object(
2452061da546Spatrick new CommandObjectBreakpointRead(interpreter));
2453061da546Spatrick
2454061da546Spatrick list_command_object->SetCommandName("breakpoint list");
2455061da546Spatrick enable_command_object->SetCommandName("breakpoint enable");
2456061da546Spatrick disable_command_object->SetCommandName("breakpoint disable");
2457061da546Spatrick clear_command_object->SetCommandName("breakpoint clear");
2458061da546Spatrick delete_command_object->SetCommandName("breakpoint delete");
2459061da546Spatrick set_command_object->SetCommandName("breakpoint set");
2460061da546Spatrick command_command_object->SetCommandName("breakpoint command");
2461061da546Spatrick modify_command_object->SetCommandName("breakpoint modify");
2462061da546Spatrick name_command_object->SetCommandName("breakpoint name");
2463061da546Spatrick write_command_object->SetCommandName("breakpoint write");
2464061da546Spatrick read_command_object->SetCommandName("breakpoint read");
2465061da546Spatrick
2466061da546Spatrick LoadSubCommand("list", list_command_object);
2467061da546Spatrick LoadSubCommand("enable", enable_command_object);
2468061da546Spatrick LoadSubCommand("disable", disable_command_object);
2469061da546Spatrick LoadSubCommand("clear", clear_command_object);
2470061da546Spatrick LoadSubCommand("delete", delete_command_object);
2471061da546Spatrick LoadSubCommand("set", set_command_object);
2472061da546Spatrick LoadSubCommand("command", command_command_object);
2473061da546Spatrick LoadSubCommand("modify", modify_command_object);
2474061da546Spatrick LoadSubCommand("name", name_command_object);
2475061da546Spatrick LoadSubCommand("write", write_command_object);
2476061da546Spatrick LoadSubCommand("read", read_command_object);
2477061da546Spatrick }
2478061da546Spatrick
2479061da546Spatrick CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
2480061da546Spatrick
VerifyIDs(Args & args,Target * target,bool allow_locations,CommandReturnObject & result,BreakpointIDList * valid_ids,BreakpointName::Permissions::PermissionKinds purpose)2481061da546Spatrick void CommandObjectMultiwordBreakpoint::VerifyIDs(
2482061da546Spatrick Args &args, Target *target, bool allow_locations,
2483061da546Spatrick CommandReturnObject &result, BreakpointIDList *valid_ids,
2484061da546Spatrick BreakpointName::Permissions ::PermissionKinds purpose) {
2485061da546Spatrick // args can be strings representing 1). integers (for breakpoint ids)
2486061da546Spatrick // 2). the full breakpoint & location
2487061da546Spatrick // canonical representation
2488061da546Spatrick // 3). the word "to" or a hyphen,
2489061da546Spatrick // representing a range (in which case there
2490061da546Spatrick // had *better* be an entry both before &
2491061da546Spatrick // after of one of the first two types.
2492061da546Spatrick // 4). A breakpoint name
2493061da546Spatrick // If args is empty, we will use the last created breakpoint (if there is
2494061da546Spatrick // one.)
2495061da546Spatrick
2496061da546Spatrick Args temp_args;
2497061da546Spatrick
2498061da546Spatrick if (args.empty()) {
2499061da546Spatrick if (target->GetLastCreatedBreakpoint()) {
2500061da546Spatrick valid_ids->AddBreakpointID(BreakpointID(
2501061da546Spatrick target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
2502061da546Spatrick result.SetStatus(eReturnStatusSuccessFinishNoResult);
2503061da546Spatrick } else {
2504061da546Spatrick result.AppendError(
2505061da546Spatrick "No breakpoint specified and no last created breakpoint.");
2506061da546Spatrick }
2507061da546Spatrick return;
2508061da546Spatrick }
2509061da546Spatrick
2510061da546Spatrick // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff
2511061da546Spatrick // directly from the old ARGS to the new TEMP_ARGS. Do not copy breakpoint
2512061da546Spatrick // id range strings over; instead generate a list of strings for all the
2513061da546Spatrick // breakpoint ids in the range, and shove all of those breakpoint id strings
2514061da546Spatrick // into TEMP_ARGS.
2515061da546Spatrick
2516061da546Spatrick BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations,
2517061da546Spatrick purpose, result, temp_args);
2518061da546Spatrick
2519061da546Spatrick // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual
2520061da546Spatrick // BreakpointIDList:
2521061da546Spatrick
2522061da546Spatrick valid_ids->InsertStringArray(temp_args.GetArgumentArrayRef(), result);
2523061da546Spatrick
2524061da546Spatrick // At this point, all of the breakpoint ids that the user passed in have
2525061da546Spatrick // been converted to breakpoint IDs and put into valid_ids.
2526061da546Spatrick
2527061da546Spatrick if (result.Succeeded()) {
2528061da546Spatrick // Now that we've converted everything from args into a list of breakpoint
2529061da546Spatrick // ids, go through our tentative list of breakpoint id's and verify that
2530061da546Spatrick // they correspond to valid/currently set breakpoints.
2531061da546Spatrick
2532061da546Spatrick const size_t count = valid_ids->GetSize();
2533061da546Spatrick for (size_t i = 0; i < count; ++i) {
2534061da546Spatrick BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i);
2535061da546Spatrick Breakpoint *breakpoint =
2536061da546Spatrick target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
2537061da546Spatrick if (breakpoint != nullptr) {
2538061da546Spatrick const size_t num_locations = breakpoint->GetNumLocations();
2539061da546Spatrick if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {
2540061da546Spatrick StreamString id_str;
2541061da546Spatrick BreakpointID::GetCanonicalReference(
2542061da546Spatrick &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
2543061da546Spatrick i = valid_ids->GetSize() + 1;
2544061da546Spatrick result.AppendErrorWithFormat(
2545061da546Spatrick "'%s' is not a currently valid breakpoint/location id.\n",
2546061da546Spatrick id_str.GetData());
2547061da546Spatrick }
2548061da546Spatrick } else {
2549061da546Spatrick i = valid_ids->GetSize() + 1;
2550061da546Spatrick result.AppendErrorWithFormat(
2551061da546Spatrick "'%d' is not a currently valid breakpoint ID.\n",
2552061da546Spatrick cur_bp_id.GetBreakpointID());
2553061da546Spatrick }
2554061da546Spatrick }
2555061da546Spatrick }
2556061da546Spatrick }
2557