130fdc8d8SChris Lattner //===-- CommandObjectBreakpoint.cpp -----------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
630fdc8d8SChris Lattner //
730fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
830fdc8d8SChris Lattner 
99e85e5a8SEugene Zelenko #include <vector>
109e85e5a8SEugene Zelenko 
119e85e5a8SEugene Zelenko #include "CommandObjectBreakpoint.h"
129e85e5a8SEugene Zelenko #include "CommandObjectBreakpointCommand.h"
1330fdc8d8SChris Lattner #include "lldb/Breakpoint/Breakpoint.h"
1430fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointIDList.h"
1530fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointLocation.h"
163eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
17b9c1b51eSKate Stone #include "lldb/Interpreter/CommandCompletions.h"
18b9c1b51eSKate Stone #include "lldb/Interpreter/CommandInterpreter.h"
19b9c1b51eSKate Stone #include "lldb/Interpreter/CommandReturnObject.h"
2047cbf4a0SPavel Labath #include "lldb/Interpreter/OptionArgParser.h"
2132abc6edSZachary Turner #include "lldb/Interpreter/OptionValueBoolean.h"
225e09c8c3SJim Ingham #include "lldb/Interpreter/OptionValueString.h"
235e09c8c3SJim Ingham #include "lldb/Interpreter/OptionValueUInt64.h"
24b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
250e0984eeSJim Ingham #include "lldb/Target/Language.h"
26b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
27b9c1b51eSKate Stone #include "lldb/Target/Target.h"
281b54c88cSJim Ingham #include "lldb/Target/Thread.h"
291b54c88cSJim Ingham #include "lldb/Target/ThreadSpec.h"
30bf9a7730SZachary Turner #include "lldb/Utility/RegularExpression.h"
31bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
3230fdc8d8SChris Lattner 
3330fdc8d8SChris Lattner using namespace lldb;
3430fdc8d8SChris Lattner using namespace lldb_private;
3530fdc8d8SChris Lattner 
36b9c1b51eSKate Stone static void AddBreakpointDescription(Stream *s, Breakpoint *bp,
37b9c1b51eSKate Stone                                      lldb::DescriptionLevel level) {
3830fdc8d8SChris Lattner   s->IndentMore();
3930fdc8d8SChris Lattner   bp->GetDescription(s, level, true);
4030fdc8d8SChris Lattner   s->IndentLess();
4130fdc8d8SChris Lattner   s->EOL();
4230fdc8d8SChris Lattner }
4330fdc8d8SChris Lattner 
44b842f2ecSJim Ingham //-------------------------------------------------------------------------
45b842f2ecSJim Ingham // Modifiable Breakpoint Options
46b842f2ecSJim Ingham //-------------------------------------------------------------------------
47b842f2ecSJim Ingham #pragma mark Modify::CommandOptions
488fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_modify_options[] = {
49b842f2ecSJim Ingham     // clang-format off
508fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCount,       "Set the number of times this breakpoint is skipped before stopping." },
518fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "one-shot",     'o', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean,     "The breakpoint is deleted the first time it stop causes a stop." },
528fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "thread-index", 'x', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument." },
538fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "thread-id",    't', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeThreadID,    "The breakpoint stops only for the thread whose TID matches this argument." },
548fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "thread-name",  'T', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeThreadName,  "The breakpoint stops only for the thread whose thread name matches this argument." },
558fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "queue-name",   'q', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeQueueName,   "The breakpoint stops only for threads in the queue whose name is given by this argument." },
568fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "condition",    'c', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeExpression,  "The breakpoint stops only if this condition expression evaluates to true." },
578fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "auto-continue",'G', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean,     "The breakpoint will auto-continue after running its commands." },
588fe53c49STatyana Krasnukha   { LLDB_OPT_SET_2, false, "enable",       'e', OptionParser::eNoArgument,       nullptr, {}, 0, eArgTypeNone,        "Enable the breakpoint." },
598fe53c49STatyana Krasnukha   { LLDB_OPT_SET_3, false, "disable",      'd', OptionParser::eNoArgument,       nullptr, {}, 0, eArgTypeNone,        "Disable the breakpoint." },
608fe53c49STatyana Krasnukha   { LLDB_OPT_SET_4, false, "command",      'C', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeCommand,     "A command to run when the breakpoint is hit, can be provided more than once, the commands will get run in order left to right." },
61b842f2ecSJim Ingham     // clang-format on
62b842f2ecSJim Ingham };
63b842f2ecSJim Ingham class lldb_private::BreakpointOptionGroup : public OptionGroup
64b842f2ecSJim Ingham {
65b842f2ecSJim Ingham public:
66b842f2ecSJim Ingham   BreakpointOptionGroup() :
67b842f2ecSJim Ingham           OptionGroup(),
68b842f2ecSJim Ingham           m_bp_opts(false) {}
69b842f2ecSJim Ingham 
70b842f2ecSJim Ingham   ~BreakpointOptionGroup() override = default;
71b842f2ecSJim Ingham 
72b842f2ecSJim Ingham   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
73b842f2ecSJim Ingham     return llvm::makeArrayRef(g_breakpoint_modify_options);
74b842f2ecSJim Ingham   }
75b842f2ecSJim Ingham 
76b842f2ecSJim Ingham   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
77b842f2ecSJim Ingham                           ExecutionContext *execution_context) override {
78b842f2ecSJim Ingham     Status error;
79b842f2ecSJim Ingham     const int short_option = g_breakpoint_modify_options[option_idx].short_option;
80b842f2ecSJim Ingham 
81b842f2ecSJim Ingham     switch (short_option) {
82b842f2ecSJim Ingham     case 'c':
8305097246SAdrian Prantl       // Normally an empty breakpoint condition marks is as unset. But we need
8405097246SAdrian Prantl       // to say it was passed in.
85b842f2ecSJim Ingham       m_bp_opts.SetCondition(option_arg.str().c_str());
86b842f2ecSJim Ingham       m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition);
87b842f2ecSJim Ingham       break;
88b842f2ecSJim Ingham     case 'C':
89b842f2ecSJim Ingham       m_commands.push_back(option_arg);
90b842f2ecSJim Ingham       break;
91b842f2ecSJim Ingham     case 'd':
92b842f2ecSJim Ingham       m_bp_opts.SetEnabled(false);
93b842f2ecSJim Ingham       break;
94b842f2ecSJim Ingham     case 'e':
95b842f2ecSJim Ingham       m_bp_opts.SetEnabled(true);
96b842f2ecSJim Ingham       break;
97b842f2ecSJim Ingham     case 'G': {
98b842f2ecSJim Ingham       bool value, success;
9947cbf4a0SPavel Labath       value = OptionArgParser::ToBoolean(option_arg, false, &success);
100b842f2ecSJim Ingham       if (success) {
101b842f2ecSJim Ingham         m_bp_opts.SetAutoContinue(value);
102b842f2ecSJim Ingham       } else
103b842f2ecSJim Ingham         error.SetErrorStringWithFormat(
104b842f2ecSJim Ingham             "invalid boolean value '%s' passed for -G option",
105b842f2ecSJim Ingham             option_arg.str().c_str());
106b842f2ecSJim Ingham     }
107b842f2ecSJim Ingham     break;
108b842f2ecSJim Ingham     case 'i':
109b842f2ecSJim Ingham     {
110b842f2ecSJim Ingham       uint32_t ignore_count;
111b842f2ecSJim Ingham       if (option_arg.getAsInteger(0, ignore_count))
112b842f2ecSJim Ingham         error.SetErrorStringWithFormat("invalid ignore count '%s'",
113b842f2ecSJim Ingham                                        option_arg.str().c_str());
114b842f2ecSJim Ingham       else
115b842f2ecSJim Ingham         m_bp_opts.SetIgnoreCount(ignore_count);
116b842f2ecSJim Ingham     }
117b842f2ecSJim Ingham     break;
118b842f2ecSJim Ingham     case 'o': {
119b842f2ecSJim Ingham       bool value, success;
12047cbf4a0SPavel Labath       value = OptionArgParser::ToBoolean(option_arg, false, &success);
121b842f2ecSJim Ingham       if (success) {
122b842f2ecSJim Ingham         m_bp_opts.SetOneShot(value);
123b842f2ecSJim Ingham       } else
124b842f2ecSJim Ingham         error.SetErrorStringWithFormat(
125b842f2ecSJim Ingham             "invalid boolean value '%s' passed for -o option",
126b842f2ecSJim Ingham             option_arg.str().c_str());
127b842f2ecSJim Ingham     } break;
128b842f2ecSJim Ingham     case 't':
129b842f2ecSJim Ingham     {
130b842f2ecSJim Ingham       lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID;
131b842f2ecSJim Ingham       if (option_arg[0] != '\0') {
132b842f2ecSJim Ingham         if (option_arg.getAsInteger(0, thread_id))
133b842f2ecSJim Ingham           error.SetErrorStringWithFormat("invalid thread id string '%s'",
134b842f2ecSJim Ingham                                          option_arg.str().c_str());
135b842f2ecSJim Ingham       }
136b842f2ecSJim Ingham       m_bp_opts.SetThreadID(thread_id);
137b842f2ecSJim Ingham     }
138b842f2ecSJim Ingham     break;
139b842f2ecSJim Ingham     case 'T':
140b842f2ecSJim Ingham       m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str());
141b842f2ecSJim Ingham       break;
142b842f2ecSJim Ingham     case 'q':
143b842f2ecSJim Ingham       m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str());
144b842f2ecSJim Ingham       break;
145b842f2ecSJim Ingham     case 'x':
146b842f2ecSJim Ingham     {
147b842f2ecSJim Ingham       uint32_t thread_index = UINT32_MAX;
148b842f2ecSJim Ingham       if (option_arg[0] != '\n') {
149b842f2ecSJim Ingham         if (option_arg.getAsInteger(0, thread_index))
150b842f2ecSJim Ingham           error.SetErrorStringWithFormat("invalid thread index string '%s'",
151b842f2ecSJim Ingham                                          option_arg.str().c_str());
152b842f2ecSJim Ingham       }
153b842f2ecSJim Ingham       m_bp_opts.GetThreadSpec()->SetIndex(thread_index);
154b842f2ecSJim Ingham     }
155b842f2ecSJim Ingham     break;
156b842f2ecSJim Ingham     default:
157b842f2ecSJim Ingham       error.SetErrorStringWithFormat("unrecognized option '%c'",
158b842f2ecSJim Ingham                                      short_option);
159b842f2ecSJim Ingham       break;
160b842f2ecSJim Ingham     }
161b842f2ecSJim Ingham 
162b842f2ecSJim Ingham     return error;
163b842f2ecSJim Ingham   }
164b842f2ecSJim Ingham 
165b842f2ecSJim Ingham   void OptionParsingStarting(ExecutionContext *execution_context) override {
166b842f2ecSJim Ingham     m_bp_opts.Clear();
167b842f2ecSJim Ingham     m_commands.clear();
168b842f2ecSJim Ingham   }
169b842f2ecSJim Ingham 
170b842f2ecSJim Ingham   Status OptionParsingFinished(ExecutionContext *execution_context) override {
171b842f2ecSJim Ingham     if (!m_commands.empty())
172b842f2ecSJim Ingham     {
173b842f2ecSJim Ingham       if (!m_commands.empty())
174b842f2ecSJim Ingham       {
175b842f2ecSJim Ingham           auto cmd_data = llvm::make_unique<BreakpointOptions::CommandData>();
176b842f2ecSJim Ingham 
177b842f2ecSJim Ingham           for (std::string &str : m_commands)
178b842f2ecSJim Ingham             cmd_data->user_source.AppendString(str);
179b842f2ecSJim Ingham 
180b842f2ecSJim Ingham           cmd_data->stop_on_error = true;
181b842f2ecSJim Ingham           m_bp_opts.SetCommandDataCallback(cmd_data);
182b842f2ecSJim Ingham       }
183b842f2ecSJim Ingham     }
184b842f2ecSJim Ingham     return Status();
185b842f2ecSJim Ingham   }
186b842f2ecSJim Ingham 
187b842f2ecSJim Ingham   const BreakpointOptions &GetBreakpointOptions()
188b842f2ecSJim Ingham   {
189b842f2ecSJim Ingham     return m_bp_opts;
190b842f2ecSJim Ingham   }
191b842f2ecSJim Ingham 
192b842f2ecSJim Ingham   std::vector<std::string> m_commands;
193b842f2ecSJim Ingham   BreakpointOptions m_bp_opts;
194b842f2ecSJim Ingham 
195b842f2ecSJim Ingham };
1968fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_dummy_options[] = {
197b842f2ecSJim Ingham     // clang-format off
1988fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Act on Dummy breakpoints - i.e. breakpoints set before a file is provided, "
199b842f2ecSJim Ingham   "which prime new targets." },
200b842f2ecSJim Ingham     // clang-format on
201b842f2ecSJim Ingham };
202b842f2ecSJim Ingham 
203b842f2ecSJim Ingham class BreakpointDummyOptionGroup : public OptionGroup
204b842f2ecSJim Ingham {
205b842f2ecSJim Ingham public:
206b842f2ecSJim Ingham   BreakpointDummyOptionGroup() :
207b842f2ecSJim Ingham           OptionGroup() {}
208b842f2ecSJim Ingham 
209b842f2ecSJim Ingham   ~BreakpointDummyOptionGroup() override = default;
210b842f2ecSJim Ingham 
211b842f2ecSJim Ingham   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
212b842f2ecSJim Ingham     return llvm::makeArrayRef(g_breakpoint_dummy_options);
213b842f2ecSJim Ingham   }
214b842f2ecSJim Ingham 
215b842f2ecSJim Ingham   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
216b842f2ecSJim Ingham                           ExecutionContext *execution_context) override {
217b842f2ecSJim Ingham     Status error;
218b842f2ecSJim Ingham     const int short_option = g_breakpoint_modify_options[option_idx].short_option;
219b842f2ecSJim Ingham 
220b842f2ecSJim Ingham     switch (short_option) {
221b842f2ecSJim Ingham       case 'D':
222b842f2ecSJim Ingham         m_use_dummy = true;
223b842f2ecSJim Ingham         break;
224b842f2ecSJim Ingham     default:
225b842f2ecSJim Ingham       error.SetErrorStringWithFormat("unrecognized option '%c'",
226b842f2ecSJim Ingham                                      short_option);
227b842f2ecSJim Ingham       break;
228b842f2ecSJim Ingham     }
229b842f2ecSJim Ingham 
230b842f2ecSJim Ingham     return error;
231b842f2ecSJim Ingham   }
232b842f2ecSJim Ingham 
233b842f2ecSJim Ingham   void OptionParsingStarting(ExecutionContext *execution_context) override {
234b842f2ecSJim Ingham     m_use_dummy = false;
235b842f2ecSJim Ingham   }
236b842f2ecSJim Ingham 
237b842f2ecSJim Ingham   bool m_use_dummy;
238b842f2ecSJim Ingham 
239b842f2ecSJim Ingham };
240b842f2ecSJim Ingham 
2411f0f5b5bSZachary Turner // If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
2421f0f5b5bSZachary Turner // update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
2433815e702SJim Ingham #define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 11) & ~LLDB_OPT_SET_10)
2441f0f5b5bSZachary Turner #define LLDB_OPT_SKIP_PROLOGUE (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
2453815e702SJim Ingham #define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 11) & ~LLDB_OPT_SET_2 & ~LLDB_OPT_SET_10)
2463815e702SJim Ingham #define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_FROM_TO(1, 8) & ~LLDB_OPT_SET_2)
2471f0f5b5bSZachary Turner #define LLDB_OPT_MOVE_TO_NEAREST_CODE (LLDB_OPT_SET_1 | LLDB_OPT_SET_9)
2481f0f5b5bSZachary Turner #define LLDB_OPT_EXPR_LANGUAGE (LLDB_OPT_SET_FROM_TO(3, 8))
2491f0f5b5bSZachary Turner 
2508fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_set_options[] = {
2511f0f5b5bSZachary Turner     // clang-format off
2528fe53c49STatyana Krasnukha   { LLDB_OPT_NOT_10,               false, "shlib",                  's', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eModuleCompletion,     eArgTypeShlibName,           "Set the breakpoint only in this shared library.  Can repeat this option "
2531f0f5b5bSZachary Turner   "multiple times to specify multiple shared libraries." },
2548fe53c49STatyana Krasnukha   { LLDB_OPT_SET_ALL,              false, "hardware",               'H', OptionParser::eNoArgument,       nullptr, {}, 0,                                         eArgTypeNone,                "Require the breakpoint to use hardware breakpoints." },
2558fe53c49STatyana Krasnukha   { LLDB_OPT_FILE,                 false, "file",                   'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,            "Specifies the source file in which to set this breakpoint.  Note, by default "
2561f0f5b5bSZachary Turner   "lldb only looks for files that are #included if they use the standard include "
2571f0f5b5bSZachary Turner   "file extensions.  To set breakpoints on .c/.cpp/.m/.mm files that are "
2581f0f5b5bSZachary Turner   "#included, set target.inline-breakpoint-strategy to \"always\"." },
2598fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1,                true,  "line",                   'l', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeLineNum,             "Specifies the line number on which to set this breakpoint." },
2601f0f5b5bSZachary Turner 
26105097246SAdrian Prantl   // Comment out this option for the moment, as we don't actually use it, but
26205097246SAdrian Prantl   // will in the future. This way users won't see it, but the infrastructure is
26305097246SAdrian Prantl   // left in place.
2641f0f5b5bSZachary Turner   //    { 0, false, "column",     'C', OptionParser::eRequiredArgument, nullptr, "<column>",
2651f0f5b5bSZachary Turner   //    "Set the breakpoint by source location at this particular column."},
2661f0f5b5bSZachary Turner 
2678fe53c49STatyana Krasnukha   { LLDB_OPT_SET_2,                true,  "address",                'a', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeAddressOrExpression, "Set the breakpoint at the specified address.  If the address maps uniquely to "
2681f0f5b5bSZachary Turner   "a particular binary, then the address will be converted to a \"file\" "
2691f0f5b5bSZachary Turner   "address, so that the breakpoint will track that binary+offset no matter where "
2701f0f5b5bSZachary Turner   "the binary eventually loads.  Alternately, if you also specify the module - "
2711f0f5b5bSZachary Turner   "with the -s option - then the address will be treated as a file address in "
2721f0f5b5bSZachary Turner   "that module, and resolved accordingly.  Again, this will allow lldb to track "
2731f0f5b5bSZachary Turner   "that offset on subsequent reloads.  The module need not have been loaded at "
2741f0f5b5bSZachary Turner   "the time you specify this breakpoint, and will get resolved when the module "
2751f0f5b5bSZachary Turner   "is loaded." },
2768fe53c49STatyana Krasnukha   { LLDB_OPT_SET_3,                true,  "name",                   'n', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "Set the breakpoint by function name.  Can be repeated multiple times to make "
2771f0f5b5bSZachary Turner   "one breakpoint for multiple names" },
2788fe53c49STatyana Krasnukha   { LLDB_OPT_SET_9,                false, "source-regexp-function", 'X', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "When used with '-p' limits the source regex to source contained in the named "
2791f0f5b5bSZachary Turner   "functions.  Can be repeated multiple times." },
2808fe53c49STatyana Krasnukha   { LLDB_OPT_SET_4,                true,  "fullname",               'F', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion,     eArgTypeFullName,            "Set the breakpoint by fully qualified function names. For C++ this means "
2814e8be2c9SAdrian Prantl   "namespaces and all arguments, and for Objective-C this means a full function "
2821f0f5b5bSZachary Turner   "prototype with class and selector.  Can be repeated multiple times to make "
2831f0f5b5bSZachary Turner   "one breakpoint for multiple names." },
2848fe53c49STatyana Krasnukha   { LLDB_OPT_SET_5,                true,  "selector",               'S', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeSelector,            "Set the breakpoint by ObjC selector name. Can be repeated multiple times to "
2851f0f5b5bSZachary Turner   "make one breakpoint for multiple Selectors." },
2868fe53c49STatyana Krasnukha   { LLDB_OPT_SET_6,                true,  "method",                 'M', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeMethod,              "Set the breakpoint by C++ method names.  Can be repeated multiple times to "
2871f0f5b5bSZachary Turner   "make one breakpoint for multiple methods." },
2888fe53c49STatyana Krasnukha   { LLDB_OPT_SET_7,                true,  "func-regex",             'r', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeRegularExpression,   "Set the breakpoint by function name, evaluating a regular-expression to find "
2891f0f5b5bSZachary Turner   "the function name(s)." },
2908fe53c49STatyana Krasnukha   { LLDB_OPT_SET_8,                true,  "basename",               'b', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "Set the breakpoint by function basename (C++ namespaces and arguments will be "
2911f0f5b5bSZachary Turner   "ignored).  Can be repeated multiple times to make one breakpoint for multiple "
2921f0f5b5bSZachary Turner   "symbols." },
2938fe53c49STatyana Krasnukha   { LLDB_OPT_SET_9,                true,  "source-pattern-regexp",  'p', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeRegularExpression,   "Set the breakpoint by specifying a regular expression which is matched "
2941f0f5b5bSZachary Turner   "against the source text in a source file or files specified with the -f "
2951f0f5b5bSZachary Turner   "option.  The -f option can be specified more than once.  If no source files "
2961f0f5b5bSZachary Turner   "are specified, uses the current \"default source file\".  If you want to "
2971f0f5b5bSZachary Turner   "match against all source files, pass the \"--all-files\" option." },
2988fe53c49STatyana Krasnukha   { LLDB_OPT_SET_9,                false, "all-files",              'A', OptionParser::eNoArgument,       nullptr, {}, 0,                                         eArgTypeNone,                "All files are searched for source pattern matches." },
2998fe53c49STatyana Krasnukha   { LLDB_OPT_SET_11,               true, "python-class",            'P', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypePythonClass,       "The name of the class that implement a scripted breakpoint." },
3008fe53c49STatyana Krasnukha   { LLDB_OPT_SET_11,               false, "python-class-key",       'k', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeNone,                "The key for a key/value pair passed to the class that implements a scripted breakpoint.  Can be specified more than once." },
3018fe53c49STatyana Krasnukha   { LLDB_OPT_SET_11,               false, "python-class-value",     'v', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeNone,                "The value for the previous key in the pair passed to the class that implements a scripted breakpoint.    Can be specified more than once." },
3028fe53c49STatyana Krasnukha   { LLDB_OPT_SET_10,               true,  "language-exception",     'E', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeLanguage,            "Set the breakpoint on exceptions thrown by the specified language (without "
3031f0f5b5bSZachary Turner   "options, on throw but not catch.)" },
3048fe53c49STatyana Krasnukha   { LLDB_OPT_SET_10,               false, "on-throw",               'w', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeBoolean,             "Set the breakpoint on exception throW." },
3058fe53c49STatyana Krasnukha   { LLDB_OPT_SET_10,               false, "on-catch",               'h', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeBoolean,             "Set the breakpoint on exception catcH." },
3061f0f5b5bSZachary Turner 
3071f0f5b5bSZachary Turner   //  Don't add this option till it actually does something useful...
3081f0f5b5bSZachary Turner   //    { LLDB_OPT_SET_10, false, "exception-typename", 'O', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeTypeName,
3091f0f5b5bSZachary Turner   //        "The breakpoint will only stop if an exception Object of this type is thrown.  Can be repeated multiple times to stop for multiple object types" },
3101f0f5b5bSZachary Turner 
3118fe53c49STatyana Krasnukha   { LLDB_OPT_EXPR_LANGUAGE,        false, "language",               'L', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeLanguage,            "Specifies the Language to use when interpreting the breakpoint's expression "
3121f0f5b5bSZachary Turner   "(note: currently only implemented for setting breakpoints on identifiers).  "
3131f0f5b5bSZachary Turner   "If not set the target.language setting is used." },
3148fe53c49STatyana Krasnukha   { LLDB_OPT_SKIP_PROLOGUE,        false, "skip-prologue",          'K', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeBoolean,             "sKip the prologue if the breakpoint is at the beginning of a function.  "
3151f0f5b5bSZachary Turner   "If not set the target.skip-prologue setting is used." },
3168fe53c49STatyana Krasnukha   { LLDB_OPT_SET_ALL,              false, "breakpoint-name",        'N', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeBreakpointName,      "Adds this to the list of names for this breakpoint." },
3178fe53c49STatyana Krasnukha   { LLDB_OPT_OFFSET_APPLIES,       false, "address-slide",          'R', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeAddress,             "Add the specified offset to whatever address(es) the breakpoint resolves to.  "
3181f0f5b5bSZachary Turner   "At present this applies the offset directly as given, and doesn't try to align it to instruction boundaries." },
3198fe53c49STatyana Krasnukha   { LLDB_OPT_MOVE_TO_NEAREST_CODE, false, "move-to-nearest-code", 'm', OptionParser::eRequiredArgument,   nullptr, {}, 0,                                         eArgTypeBoolean,             "Move breakpoints to nearest code. If not set the target.move-to-nearest-code "
3201f0f5b5bSZachary Turner   "setting is used." },
3211f0f5b5bSZachary Turner     // clang-format on
3221f0f5b5bSZachary Turner };
3231f0f5b5bSZachary Turner 
32430fdc8d8SChris Lattner //-------------------------------------------------------------------------
3255a988416SJim Ingham // CommandObjectBreakpointSet
32630fdc8d8SChris Lattner //-------------------------------------------------------------------------
32730fdc8d8SChris Lattner 
328b9c1b51eSKate Stone class CommandObjectBreakpointSet : public CommandObjectParsed {
3295a988416SJim Ingham public:
330b9c1b51eSKate Stone   typedef enum BreakpointSetType {
3315a988416SJim Ingham     eSetTypeInvalid,
3325a988416SJim Ingham     eSetTypeFileAndLine,
3335a988416SJim Ingham     eSetTypeAddress,
3345a988416SJim Ingham     eSetTypeFunctionName,
3355a988416SJim Ingham     eSetTypeFunctionRegexp,
3365a988416SJim Ingham     eSetTypeSourceRegexp,
3373815e702SJim Ingham     eSetTypeException,
3383815e702SJim Ingham     eSetTypeScripted,
3395a988416SJim Ingham   } BreakpointSetType;
3405a988416SJim Ingham 
341b9c1b51eSKate Stone   CommandObjectBreakpointSet(CommandInterpreter &interpreter)
342b9c1b51eSKate Stone       : CommandObjectParsed(
343b9c1b51eSKate Stone             interpreter, "breakpoint set",
3445a988416SJim Ingham             "Sets a breakpoint or set of breakpoints in the executable.",
3455a988416SJim Ingham             "breakpoint set <cmd-options>"),
346b842f2ecSJim Ingham         m_bp_opts(), m_options() {
347b842f2ecSJim Ingham           // We're picking up all the normal options, commands and disable.
348b842f2ecSJim Ingham           m_all_options.Append(&m_bp_opts,
349b842f2ecSJim Ingham                                LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4,
350b842f2ecSJim Ingham                                LLDB_OPT_SET_ALL);
351b842f2ecSJim Ingham           m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
352b842f2ecSJim Ingham           m_all_options.Append(&m_options);
353b842f2ecSJim Ingham           m_all_options.Finalize();
354b842f2ecSJim Ingham         }
3555a988416SJim Ingham 
3569e85e5a8SEugene Zelenko   ~CommandObjectBreakpointSet() override = default;
3575a988416SJim Ingham 
358b842f2ecSJim Ingham   Options *GetOptions() override { return &m_all_options; }
3595a988416SJim Ingham 
360b842f2ecSJim Ingham   class CommandOptions : public OptionGroup {
3615a988416SJim Ingham   public:
362b9c1b51eSKate Stone     CommandOptions()
363b842f2ecSJim Ingham         : OptionGroup(), m_condition(), m_filenames(), m_line_num(0), m_column(0),
364b9c1b51eSKate Stone           m_func_names(), m_func_name_type_mask(eFunctionNameTypeNone),
365b9c1b51eSKate Stone           m_func_regexp(), m_source_text_regexp(), m_modules(), m_load_addr(),
366b9c1b51eSKate Stone           m_catch_bp(false), m_throw_bp(true), m_hardware(false),
367a72b31c7SJim Ingham           m_exception_language(eLanguageTypeUnknown),
36823b1decbSDawn Perchik           m_language(lldb::eLanguageTypeUnknown),
369b842f2ecSJim Ingham           m_skip_prologue(eLazyBoolCalculate),
370b9c1b51eSKate Stone           m_all_files(false), m_move_to_nearest_code(eLazyBoolCalculate) {}
37130fdc8d8SChris Lattner 
3729e85e5a8SEugene Zelenko     ~CommandOptions() override = default;
37387df91b8SJim Ingham 
37497206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
375b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
37697206d57SZachary Turner       Status error;
377b842f2ecSJim Ingham       const int short_option = g_breakpoint_set_options[option_idx].short_option;
37830fdc8d8SChris Lattner 
379b9c1b51eSKate Stone       switch (short_option) {
380b9c1b51eSKate Stone       case 'a': {
38147cbf4a0SPavel Labath         m_load_addr = OptionArgParser::ToAddress(execution_context, option_arg,
382e1cfbc79STodd Fiala                                                  LLDB_INVALID_ADDRESS, &error);
383b9c1b51eSKate Stone       } break;
38430fdc8d8SChris Lattner 
385e732052fSJim Ingham       case 'A':
386e732052fSJim Ingham         m_all_files = true;
387e732052fSJim Ingham         break;
388e732052fSJim Ingham 
389ca36cd16SJim Ingham       case 'b':
390ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
391ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeBase;
392ca36cd16SJim Ingham         break;
393ca36cd16SJim Ingham 
394fe11483bSZachary Turner       case 'C':
395fe11483bSZachary Turner         if (option_arg.getAsInteger(0, m_column))
396b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid column number: %s",
397fe11483bSZachary Turner                                          option_arg.str().c_str());
39830fdc8d8SChris Lattner         break;
3999e85e5a8SEugene Zelenko 
400b9c1b51eSKate Stone       case 'E': {
401fe11483bSZachary Turner         LanguageType language = Language::GetLanguageTypeFromString(option_arg);
402fab10e89SJim Ingham 
403b9c1b51eSKate Stone         switch (language) {
404fab10e89SJim Ingham         case eLanguageTypeC89:
405fab10e89SJim Ingham         case eLanguageTypeC:
406fab10e89SJim Ingham         case eLanguageTypeC99:
4071d0089faSBruce Mitchener         case eLanguageTypeC11:
408a72b31c7SJim Ingham           m_exception_language = eLanguageTypeC;
409fab10e89SJim Ingham           break;
410fab10e89SJim Ingham         case eLanguageTypeC_plus_plus:
4111d0089faSBruce Mitchener         case eLanguageTypeC_plus_plus_03:
4121d0089faSBruce Mitchener         case eLanguageTypeC_plus_plus_11:
4132ba84a6aSBruce Mitchener         case eLanguageTypeC_plus_plus_14:
414a72b31c7SJim Ingham           m_exception_language = eLanguageTypeC_plus_plus;
415fab10e89SJim Ingham           break;
416fab10e89SJim Ingham         case eLanguageTypeObjC:
417a72b31c7SJim Ingham           m_exception_language = eLanguageTypeObjC;
418fab10e89SJim Ingham           break;
419fab10e89SJim Ingham         case eLanguageTypeObjC_plus_plus:
420b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
421b9c1b51eSKate Stone               "Set exception breakpoints separately for c++ and objective-c");
422fab10e89SJim Ingham           break;
423fab10e89SJim Ingham         case eLanguageTypeUnknown:
424b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
425b9c1b51eSKate Stone               "Unknown language type: '%s' for exception breakpoint",
426fe11483bSZachary Turner               option_arg.str().c_str());
427fab10e89SJim Ingham           break;
428fab10e89SJim Ingham         default:
429b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
430b9c1b51eSKate Stone               "Unsupported language type: '%s' for exception breakpoint",
431fe11483bSZachary Turner               option_arg.str().c_str());
432fab10e89SJim Ingham         }
433b9c1b51eSKate Stone       } break;
434ca36cd16SJim Ingham 
435ca36cd16SJim Ingham       case 'f':
4368f3be7a3SJonas Devlieghere         m_filenames.AppendIfUnique(FileSpec(option_arg));
437fab10e89SJim Ingham         break;
438ca36cd16SJim Ingham 
439ca36cd16SJim Ingham       case 'F':
440ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
441ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeFull;
442ca36cd16SJim Ingham         break;
443ca36cd16SJim Ingham 
444b9c1b51eSKate Stone       case 'h': {
445fab10e89SJim Ingham         bool success;
44647cbf4a0SPavel Labath         m_catch_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
447fab10e89SJim Ingham         if (!success)
448b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
449fe11483bSZachary Turner               "Invalid boolean value for on-catch option: '%s'",
450fe11483bSZachary Turner               option_arg.str().c_str());
451b9c1b51eSKate Stone       } break;
452eb023e75SGreg Clayton 
453eb023e75SGreg Clayton       case 'H':
454eb023e75SGreg Clayton         m_hardware = true;
455eb023e75SGreg Clayton         break;
456eb023e75SGreg Clayton 
4573815e702SJim Ingham       case 'k': {
4583815e702SJim Ingham           if (m_current_key.empty())
4593815e702SJim Ingham             m_current_key.assign(option_arg);
4603815e702SJim Ingham           else
4613815e702SJim Ingham             error.SetErrorStringWithFormat("Key: %s missing value.",
4623815e702SJim Ingham                                             m_current_key.c_str());
4633815e702SJim Ingham 
4643815e702SJim Ingham       } break;
465b9c1b51eSKate Stone       case 'K': {
466a8558b62SJim Ingham         bool success;
467a8558b62SJim Ingham         bool value;
46847cbf4a0SPavel Labath         value = OptionArgParser::ToBoolean(option_arg, true, &success);
469a8558b62SJim Ingham         if (value)
470a8558b62SJim Ingham           m_skip_prologue = eLazyBoolYes;
471a8558b62SJim Ingham         else
472a8558b62SJim Ingham           m_skip_prologue = eLazyBoolNo;
473a8558b62SJim Ingham 
474a8558b62SJim Ingham         if (!success)
475b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
476b9c1b51eSKate Stone               "Invalid boolean value for skip prologue option: '%s'",
477fe11483bSZachary Turner               option_arg.str().c_str());
478b9c1b51eSKate Stone       } break;
479ca36cd16SJim Ingham 
480fe11483bSZachary Turner       case 'l':
481fe11483bSZachary Turner         if (option_arg.getAsInteger(0, m_line_num))
482b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid line number: %s.",
483fe11483bSZachary Turner                                          option_arg.str().c_str());
484ca36cd16SJim Ingham         break;
485055ad9beSIlia K 
48623b1decbSDawn Perchik       case 'L':
487fe11483bSZachary Turner         m_language = Language::GetLanguageTypeFromString(option_arg);
48823b1decbSDawn Perchik         if (m_language == eLanguageTypeUnknown)
489b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
490fe11483bSZachary Turner               "Unknown language type: '%s' for breakpoint",
491fe11483bSZachary Turner               option_arg.str().c_str());
49223b1decbSDawn Perchik         break;
49323b1decbSDawn Perchik 
494b9c1b51eSKate Stone       case 'm': {
495055ad9beSIlia K         bool success;
496055ad9beSIlia K         bool value;
49747cbf4a0SPavel Labath         value = OptionArgParser::ToBoolean(option_arg, true, &success);
498055ad9beSIlia K         if (value)
499055ad9beSIlia K           m_move_to_nearest_code = eLazyBoolYes;
500055ad9beSIlia K         else
501055ad9beSIlia K           m_move_to_nearest_code = eLazyBoolNo;
502055ad9beSIlia K 
503055ad9beSIlia K         if (!success)
504b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
505b9c1b51eSKate Stone               "Invalid boolean value for move-to-nearest-code option: '%s'",
506fe11483bSZachary Turner               option_arg.str().c_str());
507055ad9beSIlia K         break;
508055ad9beSIlia K       }
509055ad9beSIlia K 
510ca36cd16SJim Ingham       case 'M':
511ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
512ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeMethod;
513ca36cd16SJim Ingham         break;
514ca36cd16SJim Ingham 
515ca36cd16SJim Ingham       case 'n':
516ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
517ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeAuto;
518ca36cd16SJim Ingham         break;
519ca36cd16SJim Ingham 
5206fa7681bSZachary Turner       case 'N': {
521fe11483bSZachary Turner         if (BreakpointID::StringIsBreakpointName(option_arg, error))
5225e09c8c3SJim Ingham           m_breakpoint_names.push_back(option_arg);
523ff9a91eaSJim Ingham         else
524ff9a91eaSJim Ingham           error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
525fe11483bSZachary Turner                                          option_arg.str().c_str());
5265e09c8c3SJim Ingham         break;
5276fa7681bSZachary Turner       }
5285e09c8c3SJim Ingham 
529b9c1b51eSKate Stone       case 'R': {
5302411167fSJim Ingham         lldb::addr_t tmp_offset_addr;
53147cbf4a0SPavel Labath         tmp_offset_addr = OptionArgParser::ToAddress(execution_context,
53247cbf4a0SPavel Labath                                                      option_arg, 0, &error);
5332411167fSJim Ingham         if (error.Success())
5342411167fSJim Ingham           m_offset_addr = tmp_offset_addr;
535b9c1b51eSKate Stone       } break;
5362411167fSJim Ingham 
537a72b31c7SJim Ingham       case 'O':
538fe11483bSZachary Turner         m_exception_extra_args.AppendArgument("-O");
539fe11483bSZachary Turner         m_exception_extra_args.AppendArgument(option_arg);
540a72b31c7SJim Ingham         break;
541a72b31c7SJim Ingham 
542ca36cd16SJim Ingham       case 'p':
543ca36cd16SJim Ingham         m_source_text_regexp.assign(option_arg);
544ca36cd16SJim Ingham         break;
545ca36cd16SJim Ingham 
5463815e702SJim Ingham       case 'P':
5473815e702SJim Ingham         m_python_class.assign(option_arg);
5483815e702SJim Ingham         break;
5493815e702SJim Ingham 
550ca36cd16SJim Ingham       case 'r':
551ca36cd16SJim Ingham         m_func_regexp.assign(option_arg);
552ca36cd16SJim Ingham         break;
553ca36cd16SJim Ingham 
554ca36cd16SJim Ingham       case 's':
5558f3be7a3SJonas Devlieghere         m_modules.AppendIfUnique(FileSpec(option_arg));
556ca36cd16SJim Ingham         break;
557ca36cd16SJim Ingham 
558ca36cd16SJim Ingham       case 'S':
559ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
560ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeSelector;
561ca36cd16SJim Ingham         break;
562ca36cd16SJim Ingham 
5633815e702SJim Ingham       case 'v': {
5643815e702SJim Ingham           if (!m_current_key.empty()) {
5653815e702SJim Ingham               m_extra_args_sp->AddStringItem(m_current_key, option_arg);
5663815e702SJim Ingham               m_current_key.clear();
5673815e702SJim Ingham           }
5683815e702SJim Ingham           else
5693815e702SJim Ingham             error.SetErrorStringWithFormat("Value \"%s\" missing matching key.",
5703815e702SJim Ingham                                            option_arg.str().c_str());
5713815e702SJim Ingham       } break;
5723815e702SJim Ingham 
573b9c1b51eSKate Stone       case 'w': {
574ca36cd16SJim Ingham         bool success;
57547cbf4a0SPavel Labath         m_throw_bp = OptionArgParser::ToBoolean(option_arg, true, &success);
576ca36cd16SJim Ingham         if (!success)
577b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
578fe11483bSZachary Turner               "Invalid boolean value for on-throw option: '%s'",
579fe11483bSZachary Turner               option_arg.str().c_str());
580b9c1b51eSKate Stone       } break;
581ca36cd16SJim Ingham 
58276bb8d67SJim Ingham       case 'X':
58376bb8d67SJim Ingham         m_source_regex_func_names.insert(option_arg);
58476bb8d67SJim Ingham         break;
58576bb8d67SJim Ingham 
58630fdc8d8SChris Lattner       default:
587b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
588b9c1b51eSKate Stone                                        short_option);
58930fdc8d8SChris Lattner         break;
59030fdc8d8SChris Lattner       }
59130fdc8d8SChris Lattner 
59230fdc8d8SChris Lattner       return error;
59330fdc8d8SChris Lattner     }
5949e85e5a8SEugene Zelenko 
595b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
59687df91b8SJim Ingham       m_filenames.Clear();
59730fdc8d8SChris Lattner       m_line_num = 0;
59830fdc8d8SChris Lattner       m_column = 0;
599fab10e89SJim Ingham       m_func_names.clear();
6001f746071SGreg Clayton       m_func_name_type_mask = eFunctionNameTypeNone;
60130fdc8d8SChris Lattner       m_func_regexp.clear();
6021f746071SGreg Clayton       m_source_text_regexp.clear();
60387df91b8SJim Ingham       m_modules.Clear();
6041f746071SGreg Clayton       m_load_addr = LLDB_INVALID_ADDRESS;
6052411167fSJim Ingham       m_offset_addr = 0;
606fab10e89SJim Ingham       m_catch_bp = false;
607fab10e89SJim Ingham       m_throw_bp = true;
608eb023e75SGreg Clayton       m_hardware = false;
609a72b31c7SJim Ingham       m_exception_language = eLanguageTypeUnknown;
61023b1decbSDawn Perchik       m_language = lldb::eLanguageTypeUnknown;
611a8558b62SJim Ingham       m_skip_prologue = eLazyBoolCalculate;
6125e09c8c3SJim Ingham       m_breakpoint_names.clear();
613e732052fSJim Ingham       m_all_files = false;
614a72b31c7SJim Ingham       m_exception_extra_args.Clear();
615055ad9beSIlia K       m_move_to_nearest_code = eLazyBoolCalculate;
61676bb8d67SJim Ingham       m_source_regex_func_names.clear();
6173815e702SJim Ingham       m_python_class.clear();
6183815e702SJim Ingham       m_extra_args_sp.reset(new StructuredData::Dictionary());
6193815e702SJim Ingham       m_current_key.clear();
62030fdc8d8SChris Lattner     }
62130fdc8d8SChris Lattner 
6221f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
62370602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_set_options);
6241f0f5b5bSZachary Turner     }
62530fdc8d8SChris Lattner 
6265a988416SJim Ingham     // Instance variables to hold the values for command options.
627969795f1SJim Ingham 
6285a988416SJim Ingham     std::string m_condition;
6295a988416SJim Ingham     FileSpecList m_filenames;
6305a988416SJim Ingham     uint32_t m_line_num;
6315a988416SJim Ingham     uint32_t m_column;
6325a988416SJim Ingham     std::vector<std::string> m_func_names;
6335e09c8c3SJim Ingham     std::vector<std::string> m_breakpoint_names;
634117b1fa1SZachary Turner     lldb::FunctionNameType m_func_name_type_mask;
6355a988416SJim Ingham     std::string m_func_regexp;
6365a988416SJim Ingham     std::string m_source_text_regexp;
6375a988416SJim Ingham     FileSpecList m_modules;
6385a988416SJim Ingham     lldb::addr_t m_load_addr;
6392411167fSJim Ingham     lldb::addr_t m_offset_addr;
6405a988416SJim Ingham     bool m_catch_bp;
6415a988416SJim Ingham     bool m_throw_bp;
642eb023e75SGreg Clayton     bool m_hardware; // Request to use hardware breakpoints
643a72b31c7SJim Ingham     lldb::LanguageType m_exception_language;
64423b1decbSDawn Perchik     lldb::LanguageType m_language;
6455a988416SJim Ingham     LazyBool m_skip_prologue;
646e732052fSJim Ingham     bool m_all_files;
647a72b31c7SJim Ingham     Args m_exception_extra_args;
648055ad9beSIlia K     LazyBool m_move_to_nearest_code;
64976bb8d67SJim Ingham     std::unordered_set<std::string> m_source_regex_func_names;
6503815e702SJim Ingham     std::string m_python_class;
6513815e702SJim Ingham     StructuredData::DictionarySP m_extra_args_sp;
6523815e702SJim Ingham     std::string m_current_key;
6535a988416SJim Ingham   };
6545a988416SJim Ingham 
6555a988416SJim Ingham protected:
656b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
657b842f2ecSJim Ingham     Target *target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy);
65833df7cd3SJim Ingham 
659b9c1b51eSKate Stone     if (target == nullptr) {
660b9c1b51eSKate Stone       result.AppendError("Invalid target.  Must set target before setting "
661b9c1b51eSKate Stone                          "breakpoints (see 'target create' command).");
66230fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
66330fdc8d8SChris Lattner       return false;
66430fdc8d8SChris Lattner     }
66530fdc8d8SChris Lattner 
66630fdc8d8SChris Lattner     // The following are the various types of breakpoints that could be set:
66730fdc8d8SChris Lattner     //   1).  -f -l -p  [-s -g]   (setting breakpoint by source location)
66830fdc8d8SChris Lattner     //   2).  -a  [-s -g]         (setting breakpoint by address)
66930fdc8d8SChris Lattner     //   3).  -n  [-s -g]         (setting breakpoint by function name)
670b9c1b51eSKate Stone     //   4).  -r  [-s -g]         (setting breakpoint by function name regular
671b9c1b51eSKate Stone     //   expression)
672b9c1b51eSKate Stone     //   5).  -p -f               (setting a breakpoint by comparing a reg-exp
673b9c1b51eSKate Stone     //   to source text)
674b9c1b51eSKate Stone     //   6).  -E [-w -h]          (setting a breakpoint for exceptions for a
675b9c1b51eSKate Stone     //   given language.)
67630fdc8d8SChris Lattner 
67730fdc8d8SChris Lattner     BreakpointSetType break_type = eSetTypeInvalid;
67830fdc8d8SChris Lattner 
6793815e702SJim Ingham     if (!m_options.m_python_class.empty())
6803815e702SJim Ingham       break_type = eSetTypeScripted;
6813815e702SJim Ingham     else if (m_options.m_line_num != 0)
68230fdc8d8SChris Lattner       break_type = eSetTypeFileAndLine;
68330fdc8d8SChris Lattner     else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
68430fdc8d8SChris Lattner       break_type = eSetTypeAddress;
685fab10e89SJim Ingham     else if (!m_options.m_func_names.empty())
68630fdc8d8SChris Lattner       break_type = eSetTypeFunctionName;
68730fdc8d8SChris Lattner     else if (!m_options.m_func_regexp.empty())
68830fdc8d8SChris Lattner       break_type = eSetTypeFunctionRegexp;
689969795f1SJim Ingham     else if (!m_options.m_source_text_regexp.empty())
690969795f1SJim Ingham       break_type = eSetTypeSourceRegexp;
691a72b31c7SJim Ingham     else if (m_options.m_exception_language != eLanguageTypeUnknown)
692fab10e89SJim Ingham       break_type = eSetTypeException;
69330fdc8d8SChris Lattner 
694b842f2ecSJim Ingham     BreakpointSP bp_sp = nullptr;
695274060b6SGreg Clayton     FileSpec module_spec;
696a8558b62SJim Ingham     const bool internal = false;
697a8558b62SJim Ingham 
698b9c1b51eSKate Stone     // If the user didn't specify skip-prologue, having an offset should turn
699b9c1b51eSKate Stone     // that off.
700b9c1b51eSKate Stone     if (m_options.m_offset_addr != 0 &&
701b9c1b51eSKate Stone         m_options.m_skip_prologue == eLazyBoolCalculate)
7022411167fSJim Ingham       m_options.m_skip_prologue = eLazyBoolNo;
7032411167fSJim Ingham 
704b9c1b51eSKate Stone     switch (break_type) {
70530fdc8d8SChris Lattner     case eSetTypeFileAndLine: // Breakpoint by source position
70630fdc8d8SChris Lattner     {
70730fdc8d8SChris Lattner       FileSpec file;
708c7bece56SGreg Clayton       const size_t num_files = m_options.m_filenames.GetSize();
709b9c1b51eSKate Stone       if (num_files == 0) {
710b9c1b51eSKate Stone         if (!GetDefaultFile(target, file, result)) {
71187df91b8SJim Ingham           result.AppendError("No file supplied and no default file available.");
71287df91b8SJim Ingham           result.SetStatus(eReturnStatusFailed);
71387df91b8SJim Ingham           return false;
71487df91b8SJim Ingham         }
715b9c1b51eSKate Stone       } else if (num_files > 1) {
716b9c1b51eSKate Stone         result.AppendError("Only one file at a time is allowed for file and "
717b9c1b51eSKate Stone                            "line breakpoints.");
71887df91b8SJim Ingham         result.SetStatus(eReturnStatusFailed);
71987df91b8SJim Ingham         return false;
720b9c1b51eSKate Stone       } else
72187df91b8SJim Ingham         file = m_options.m_filenames.GetFileSpecAtIndex(0);
72230fdc8d8SChris Lattner 
7231f746071SGreg Clayton       // Only check for inline functions if
7241f746071SGreg Clayton       LazyBool check_inlines = eLazyBoolCalculate;
7251f746071SGreg Clayton 
726b842f2ecSJim Ingham       bp_sp = target->CreateBreakpoint(&(m_options.m_modules),
727b842f2ecSJim Ingham                                        file,
728b842f2ecSJim Ingham                                        m_options.m_line_num,
729431b1584SAdrian Prantl                                        m_options.m_column,
730b842f2ecSJim Ingham                                        m_options.m_offset_addr,
731b842f2ecSJim Ingham                                        check_inlines,
732b842f2ecSJim Ingham                                        m_options.m_skip_prologue,
733b842f2ecSJim Ingham                                        internal,
734b842f2ecSJim Ingham                                        m_options.m_hardware,
735b842f2ecSJim Ingham                                        m_options.m_move_to_nearest_code);
736b9c1b51eSKate Stone     } break;
7376eee5aa0SGreg Clayton 
73830fdc8d8SChris Lattner     case eSetTypeAddress: // Breakpoint by address
739055a08a4SJim Ingham     {
740b9c1b51eSKate Stone       // If a shared library has been specified, make an lldb_private::Address
741b842f2ecSJim Ingham       // with the library, and use that.  That way the address breakpoint
742b842f2ecSJim Ingham       //  will track the load location of the library.
743055a08a4SJim Ingham       size_t num_modules_specified = m_options.m_modules.GetSize();
744b9c1b51eSKate Stone       if (num_modules_specified == 1) {
745b9c1b51eSKate Stone         const FileSpec *file_spec =
746b9c1b51eSKate Stone             m_options.m_modules.GetFileSpecPointerAtIndex(0);
747b842f2ecSJim Ingham         bp_sp = target->CreateAddressInModuleBreakpoint(m_options.m_load_addr,
748b9c1b51eSKate Stone                                                         internal, file_spec,
749b842f2ecSJim Ingham                                                         m_options.m_hardware);
750b9c1b51eSKate Stone       } else if (num_modules_specified == 0) {
751b842f2ecSJim Ingham         bp_sp = target->CreateBreakpoint(m_options.m_load_addr, internal,
752b842f2ecSJim Ingham                                          m_options.m_hardware);
753b9c1b51eSKate Stone       } else {
754b9c1b51eSKate Stone         result.AppendError("Only one shared library can be specified for "
755b9c1b51eSKate Stone                            "address breakpoints.");
756055a08a4SJim Ingham         result.SetStatus(eReturnStatusFailed);
757055a08a4SJim Ingham         return false;
758055a08a4SJim Ingham       }
75930fdc8d8SChris Lattner       break;
760055a08a4SJim Ingham     }
76130fdc8d8SChris Lattner     case eSetTypeFunctionName: // Breakpoint by function name
7620c5cd90dSGreg Clayton     {
763117b1fa1SZachary Turner       FunctionNameType name_type_mask = m_options.m_func_name_type_mask;
7640c5cd90dSGreg Clayton 
7650c5cd90dSGreg Clayton       if (name_type_mask == 0)
766e02b8504SGreg Clayton         name_type_mask = eFunctionNameTypeAuto;
7670c5cd90dSGreg Clayton 
768b842f2ecSJim Ingham       bp_sp = target->CreateBreakpoint(&(m_options.m_modules),
769b842f2ecSJim Ingham                                        &(m_options.m_filenames),
770b842f2ecSJim Ingham                                        m_options.m_func_names,
771b842f2ecSJim Ingham                                        name_type_mask,
772b842f2ecSJim Ingham                                        m_options.m_language,
773b842f2ecSJim Ingham                                        m_options.m_offset_addr,
774b842f2ecSJim Ingham                                        m_options.m_skip_prologue,
775b842f2ecSJim Ingham                                        internal,
776b842f2ecSJim Ingham                                        m_options.m_hardware);
777b9c1b51eSKate Stone     } break;
7780c5cd90dSGreg Clayton 
779b9c1b51eSKate Stone     case eSetTypeFunctionRegexp: // Breakpoint by regular expression function
780b9c1b51eSKate Stone                                  // name
78130fdc8d8SChris Lattner       {
78295eae423SZachary Turner         RegularExpression regexp(m_options.m_func_regexp);
783b9c1b51eSKate Stone         if (!regexp.IsValid()) {
784969795f1SJim Ingham           char err_str[1024];
785969795f1SJim Ingham           regexp.GetErrorAsCString(err_str, sizeof(err_str));
786b9c1b51eSKate Stone           result.AppendErrorWithFormat(
787b9c1b51eSKate Stone               "Function name regular expression could not be compiled: \"%s\"",
788969795f1SJim Ingham               err_str);
78930fdc8d8SChris Lattner           result.SetStatus(eReturnStatusFailed);
790969795f1SJim Ingham           return false;
79130fdc8d8SChris Lattner         }
79287df91b8SJim Ingham 
793b842f2ecSJim Ingham         bp_sp = target->CreateFuncRegexBreakpoint(&(m_options.m_modules),
794b842f2ecSJim Ingham                                                   &(m_options.m_filenames),
795b842f2ecSJim Ingham                                                   regexp,
796b842f2ecSJim Ingham                                                   m_options.m_language,
797b842f2ecSJim Ingham                                                   m_options.m_skip_prologue,
798b842f2ecSJim Ingham                                                   internal,
799b842f2ecSJim Ingham                                                   m_options.m_hardware);
800e14dc268SJim Ingham       }
801e14dc268SJim Ingham       break;
802969795f1SJim Ingham     case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
803969795f1SJim Ingham     {
804c7bece56SGreg Clayton       const size_t num_files = m_options.m_filenames.GetSize();
80587df91b8SJim Ingham 
806b9c1b51eSKate Stone       if (num_files == 0 && !m_options.m_all_files) {
807969795f1SJim Ingham         FileSpec file;
808b9c1b51eSKate Stone         if (!GetDefaultFile(target, file, result)) {
809b9c1b51eSKate Stone           result.AppendError(
810b9c1b51eSKate Stone               "No files provided and could not find default file.");
81187df91b8SJim Ingham           result.SetStatus(eReturnStatusFailed);
81287df91b8SJim Ingham           return false;
813b9c1b51eSKate Stone         } else {
81487df91b8SJim Ingham           m_options.m_filenames.Append(file);
81587df91b8SJim Ingham         }
81687df91b8SJim Ingham       }
8170c5cd90dSGreg Clayton 
81895eae423SZachary Turner       RegularExpression regexp(m_options.m_source_text_regexp);
819b9c1b51eSKate Stone       if (!regexp.IsValid()) {
820969795f1SJim Ingham         char err_str[1024];
821969795f1SJim Ingham         regexp.GetErrorAsCString(err_str, sizeof(err_str));
822b9c1b51eSKate Stone         result.AppendErrorWithFormat(
823b9c1b51eSKate Stone             "Source text regular expression could not be compiled: \"%s\"",
824969795f1SJim Ingham             err_str);
825969795f1SJim Ingham         result.SetStatus(eReturnStatusFailed);
826969795f1SJim Ingham         return false;
827969795f1SJim Ingham       }
828b842f2ecSJim Ingham       bp_sp =
829b842f2ecSJim Ingham           target->CreateSourceRegexBreakpoint(&(m_options.m_modules),
830b842f2ecSJim Ingham                                               &(m_options.m_filenames),
831b842f2ecSJim Ingham                                               m_options
832b842f2ecSJim Ingham                                                   .m_source_regex_func_names,
833b842f2ecSJim Ingham                                               regexp,
834b842f2ecSJim Ingham                                               internal,
835b842f2ecSJim Ingham                                               m_options.m_hardware,
836b842f2ecSJim Ingham                                               m_options.m_move_to_nearest_code);
837b9c1b51eSKate Stone     } break;
838b9c1b51eSKate Stone     case eSetTypeException: {
83997206d57SZachary Turner       Status precond_error;
840b842f2ecSJim Ingham       bp_sp = target->CreateExceptionBreakpoint(m_options.m_exception_language,
841b842f2ecSJim Ingham                                                 m_options.m_catch_bp,
842b842f2ecSJim Ingham                                                 m_options.m_throw_bp,
843b842f2ecSJim Ingham                                                 internal,
844b842f2ecSJim Ingham                                                 &m_options
845b842f2ecSJim Ingham                                                     .m_exception_extra_args,
846b842f2ecSJim Ingham                                                 &precond_error);
847b9c1b51eSKate Stone       if (precond_error.Fail()) {
848b9c1b51eSKate Stone         result.AppendErrorWithFormat(
849b9c1b51eSKate Stone             "Error setting extra exception arguments: %s",
850a72b31c7SJim Ingham             precond_error.AsCString());
851b842f2ecSJim Ingham         target->RemoveBreakpointByID(bp_sp->GetID());
852a72b31c7SJim Ingham         result.SetStatus(eReturnStatusFailed);
853a72b31c7SJim Ingham         return false;
854a72b31c7SJim Ingham       }
855b9c1b51eSKate Stone     } break;
8563815e702SJim Ingham     case eSetTypeScripted: {
8573815e702SJim Ingham 
8583815e702SJim Ingham       Status error;
8593815e702SJim Ingham       bp_sp = target->CreateScriptedBreakpoint(m_options.m_python_class,
8603815e702SJim Ingham                                                &(m_options.m_modules),
8613815e702SJim Ingham                                                &(m_options.m_filenames),
8623815e702SJim Ingham                                                false,
8633815e702SJim Ingham                                                m_options.m_hardware,
8643815e702SJim Ingham                                                m_options.m_extra_args_sp,
8653815e702SJim Ingham                                                &error);
8663815e702SJim Ingham       if (error.Fail()) {
8673815e702SJim Ingham         result.AppendErrorWithFormat(
8683815e702SJim Ingham             "Error setting extra exception arguments: %s",
8693815e702SJim Ingham             error.AsCString());
8703815e702SJim Ingham         target->RemoveBreakpointByID(bp_sp->GetID());
8713815e702SJim Ingham         result.SetStatus(eReturnStatusFailed);
8723815e702SJim Ingham         return false;
8733815e702SJim Ingham       }
8743815e702SJim Ingham     } break;
87530fdc8d8SChris Lattner     default:
87630fdc8d8SChris Lattner       break;
87730fdc8d8SChris Lattner     }
87830fdc8d8SChris Lattner 
8791b54c88cSJim Ingham     // Now set the various options that were passed in:
880b842f2ecSJim Ingham     if (bp_sp) {
881b842f2ecSJim Ingham       bp_sp->GetOptions()->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
882ca36cd16SJim Ingham 
883b9c1b51eSKate Stone       if (!m_options.m_breakpoint_names.empty()) {
88497206d57SZachary Turner         Status name_error;
885ff9a91eaSJim Ingham         for (auto name : m_options.m_breakpoint_names) {
886b842f2ecSJim Ingham           target->AddNameToBreakpoint(bp_sp, name.c_str(), name_error);
887ff9a91eaSJim Ingham           if (name_error.Fail()) {
888ff9a91eaSJim Ingham             result.AppendErrorWithFormat("Invalid breakpoint name: %s",
889ff9a91eaSJim Ingham                                          name.c_str());
890b842f2ecSJim Ingham             target->RemoveBreakpointByID(bp_sp->GetID());
891ff9a91eaSJim Ingham             result.SetStatus(eReturnStatusFailed);
892ff9a91eaSJim Ingham             return false;
893ff9a91eaSJim Ingham           }
894ff9a91eaSJim Ingham         }
8955e09c8c3SJim Ingham       }
8961b54c88cSJim Ingham     }
8971b54c88cSJim Ingham 
898b842f2ecSJim Ingham     if (bp_sp) {
89985e8b814SJim Ingham       Stream &output_stream = result.GetOutputStream();
9001391cc7dSJim Ingham       const bool show_locations = false;
901b842f2ecSJim Ingham       bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
902b9c1b51eSKate Stone                          show_locations);
9034aeb1989SJim Ingham       if (target == m_interpreter.GetDebugger().GetDummyTarget())
904b9c1b51eSKate Stone         output_stream.Printf("Breakpoint set in dummy target, will get copied "
905b9c1b51eSKate Stone                              "into future targets.\n");
906b9c1b51eSKate Stone       else {
90705097246SAdrian Prantl         // Don't print out this warning for exception breakpoints.  They can
90805097246SAdrian Prantl         // get set before the target is set, but we won't know how to actually
90905097246SAdrian Prantl         // set the breakpoint till we run.
910b842f2ecSJim Ingham         if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) {
911b9c1b51eSKate Stone           output_stream.Printf("WARNING:  Unable to resolve breakpoint to any "
912b9c1b51eSKate Stone                                "actual locations.\n");
9134aeb1989SJim Ingham         }
9144aeb1989SJim Ingham       }
91530fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
916b842f2ecSJim Ingham     } else if (!bp_sp) {
91730fdc8d8SChris Lattner       result.AppendError("Breakpoint creation failed: No breakpoint created.");
91830fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
91930fdc8d8SChris Lattner     }
92030fdc8d8SChris Lattner 
92130fdc8d8SChris Lattner     return result.Succeeded();
92230fdc8d8SChris Lattner   }
92330fdc8d8SChris Lattner 
9245a988416SJim Ingham private:
925b9c1b51eSKate Stone   bool GetDefaultFile(Target *target, FileSpec &file,
926b9c1b51eSKate Stone                       CommandReturnObject &result) {
9275a988416SJim Ingham     uint32_t default_line;
92805097246SAdrian Prantl     // First use the Source Manager's default file. Then use the current stack
92905097246SAdrian Prantl     // frame's file.
930b9c1b51eSKate Stone     if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line)) {
931b57e4a1bSJason Molenda       StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
932b9c1b51eSKate Stone       if (cur_frame == nullptr) {
933b9c1b51eSKate Stone         result.AppendError(
934b9c1b51eSKate Stone             "No selected frame to use to find the default file.");
9355a988416SJim Ingham         result.SetStatus(eReturnStatusFailed);
9365a988416SJim Ingham         return false;
937b9c1b51eSKate Stone       } else if (!cur_frame->HasDebugInformation()) {
938b9c1b51eSKate Stone         result.AppendError("Cannot use the selected frame to find the default "
939b9c1b51eSKate Stone                            "file, it has no debug info.");
9405a988416SJim Ingham         result.SetStatus(eReturnStatusFailed);
9415a988416SJim Ingham         return false;
942b9c1b51eSKate Stone       } else {
943b9c1b51eSKate Stone         const SymbolContext &sc =
944b9c1b51eSKate Stone             cur_frame->GetSymbolContext(eSymbolContextLineEntry);
945b9c1b51eSKate Stone         if (sc.line_entry.file) {
9465a988416SJim Ingham           file = sc.line_entry.file;
947b9c1b51eSKate Stone         } else {
948b9c1b51eSKate Stone           result.AppendError("Can't find the file for the selected frame to "
949b9c1b51eSKate Stone                              "use as the default file.");
9505a988416SJim Ingham           result.SetStatus(eReturnStatusFailed);
9515a988416SJim Ingham           return false;
9525a988416SJim Ingham         }
9535a988416SJim Ingham       }
9545a988416SJim Ingham     }
9555a988416SJim Ingham     return true;
9565a988416SJim Ingham   }
9575a988416SJim Ingham 
958b842f2ecSJim Ingham   BreakpointOptionGroup m_bp_opts;
959b842f2ecSJim Ingham   BreakpointDummyOptionGroup m_dummy_options;
9605a988416SJim Ingham   CommandOptions m_options;
961b842f2ecSJim Ingham   OptionGroupOptions m_all_options;
9625a988416SJim Ingham };
9639e85e5a8SEugene Zelenko 
9645a988416SJim Ingham //-------------------------------------------------------------------------
9655a988416SJim Ingham // CommandObjectBreakpointModify
9665a988416SJim Ingham //-------------------------------------------------------------------------
9675a988416SJim Ingham #pragma mark Modify
9685a988416SJim Ingham 
969b9c1b51eSKate Stone class CommandObjectBreakpointModify : public CommandObjectParsed {
9705a988416SJim Ingham public:
971b9c1b51eSKate Stone   CommandObjectBreakpointModify(CommandInterpreter &interpreter)
972b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "breakpoint modify",
973b9c1b51eSKate Stone                             "Modify the options on a breakpoint or set of "
974b9c1b51eSKate Stone                             "breakpoints in the executable.  "
975b9c1b51eSKate Stone                             "If no breakpoint is specified, acts on the last "
976b9c1b51eSKate Stone                             "created breakpoint.  "
977b9c1b51eSKate Stone                             "With the exception of -e, -d and -i, passing an "
978b9c1b51eSKate Stone                             "empty argument clears the modification.",
9799e85e5a8SEugene Zelenko                             nullptr),
980b9c1b51eSKate Stone         m_options() {
9815a988416SJim Ingham     CommandArgumentEntry arg;
982b9c1b51eSKate Stone     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
983b9c1b51eSKate Stone                                       eArgTypeBreakpointIDRange);
984b9c1b51eSKate Stone     // Add the entry for the first argument for this command to the object's
985b9c1b51eSKate Stone     // arguments vector.
9865a988416SJim Ingham     m_arguments.push_back(arg);
987b842f2ecSJim Ingham 
988b842f2ecSJim Ingham     m_options.Append(&m_bp_opts,
989b842f2ecSJim Ingham                      LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3,
990b842f2ecSJim Ingham                      LLDB_OPT_SET_ALL);
991b842f2ecSJim Ingham     m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
992b842f2ecSJim Ingham     m_options.Finalize();
9935a988416SJim Ingham   }
9945a988416SJim Ingham 
9959e85e5a8SEugene Zelenko   ~CommandObjectBreakpointModify() override = default;
9965a988416SJim Ingham 
997b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
9985a988416SJim Ingham 
9995a988416SJim Ingham protected:
1000b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1001b842f2ecSJim Ingham     Target *target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy);
1002b9c1b51eSKate Stone     if (target == nullptr) {
10035a988416SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
10045a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
10055a988416SJim Ingham       return false;
10065a988416SJim Ingham     }
10075a988416SJim Ingham 
1008bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1009bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
10105a988416SJim Ingham 
10115a988416SJim Ingham     BreakpointIDList valid_bp_ids;
10125a988416SJim Ingham 
1013b9c1b51eSKate Stone     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1014b842f2ecSJim Ingham         command, target, result, &valid_bp_ids,
1015b842f2ecSJim Ingham         BreakpointName::Permissions::PermissionKinds::disablePerm);
10165a988416SJim Ingham 
1017b9c1b51eSKate Stone     if (result.Succeeded()) {
10185a988416SJim Ingham       const size_t count = valid_bp_ids.GetSize();
1019b9c1b51eSKate Stone       for (size_t i = 0; i < count; ++i) {
10205a988416SJim Ingham         BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
10215a988416SJim Ingham 
1022b9c1b51eSKate Stone         if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1023b9c1b51eSKate Stone           Breakpoint *bp =
1024b9c1b51eSKate Stone               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1025b9c1b51eSKate Stone           if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1026b9c1b51eSKate Stone             BreakpointLocation *location =
1027b9c1b51eSKate Stone                 bp->FindLocationByID(cur_bp_id.GetLocationID()).get();
1028b842f2ecSJim Ingham             if (location)
1029b842f2ecSJim Ingham               location->GetLocationOptions()
1030b842f2ecSJim Ingham                   ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
1031b9c1b51eSKate Stone           } else {
1032b842f2ecSJim Ingham             bp->GetOptions()
1033b842f2ecSJim Ingham                 ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
10345a988416SJim Ingham           }
10355a988416SJim Ingham         }
10365a988416SJim Ingham       }
10375a988416SJim Ingham     }
10385a988416SJim Ingham 
10395a988416SJim Ingham     return result.Succeeded();
10405a988416SJim Ingham   }
10415a988416SJim Ingham 
10425a988416SJim Ingham private:
1043b842f2ecSJim Ingham   BreakpointOptionGroup m_bp_opts;
1044b842f2ecSJim Ingham   BreakpointDummyOptionGroup m_dummy_opts;
1045b842f2ecSJim Ingham   OptionGroupOptions m_options;
10465a988416SJim Ingham };
10475a988416SJim Ingham 
10485a988416SJim Ingham //-------------------------------------------------------------------------
10495a988416SJim Ingham // CommandObjectBreakpointEnable
10505a988416SJim Ingham //-------------------------------------------------------------------------
10515a988416SJim Ingham #pragma mark Enable
10525a988416SJim Ingham 
1053b9c1b51eSKate Stone class CommandObjectBreakpointEnable : public CommandObjectParsed {
10545a988416SJim Ingham public:
1055b9c1b51eSKate Stone   CommandObjectBreakpointEnable(CommandInterpreter &interpreter)
1056b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "enable",
1057b9c1b51eSKate Stone                             "Enable the specified disabled breakpoint(s). If "
1058b9c1b51eSKate Stone                             "no breakpoints are specified, enable all of them.",
1059b9c1b51eSKate Stone                             nullptr) {
10605a988416SJim Ingham     CommandArgumentEntry arg;
1061b9c1b51eSKate Stone     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1062b9c1b51eSKate Stone                                       eArgTypeBreakpointIDRange);
1063b9c1b51eSKate Stone     // Add the entry for the first argument for this command to the object's
1064b9c1b51eSKate Stone     // arguments vector.
10655a988416SJim Ingham     m_arguments.push_back(arg);
10665a988416SJim Ingham   }
10675a988416SJim Ingham 
10689e85e5a8SEugene Zelenko   ~CommandObjectBreakpointEnable() override = default;
10695a988416SJim Ingham 
10705a988416SJim Ingham protected:
1071b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1072893c932aSJim Ingham     Target *target = GetSelectedOrDummyTarget();
1073b9c1b51eSKate Stone     if (target == nullptr) {
10745a988416SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
10755a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
10765a988416SJim Ingham       return false;
10775a988416SJim Ingham     }
10785a988416SJim Ingham 
1079bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1080bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
10815a988416SJim Ingham 
10825a988416SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
10835a988416SJim Ingham 
10845a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
10855a988416SJim Ingham 
1086b9c1b51eSKate Stone     if (num_breakpoints == 0) {
10875a988416SJim Ingham       result.AppendError("No breakpoints exist to be enabled.");
10885a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
10895a988416SJim Ingham       return false;
10905a988416SJim Ingham     }
10915a988416SJim Ingham 
109211eb9c64SZachary Turner     if (command.empty()) {
10935a988416SJim Ingham       // No breakpoint selected; enable all currently set breakpoints.
1094b842f2ecSJim Ingham       target->EnableAllowedBreakpoints();
1095b9c1b51eSKate Stone       result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64
1096b9c1b51eSKate Stone                                      " breakpoints)\n",
1097b9c1b51eSKate Stone                                      (uint64_t)num_breakpoints);
10985a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1099b9c1b51eSKate Stone     } else {
11005a988416SJim Ingham       // Particular breakpoint selected; enable that breakpoint.
11015a988416SJim Ingham       BreakpointIDList valid_bp_ids;
1102b9c1b51eSKate Stone       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1103b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
1104b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::disablePerm);
11055a988416SJim Ingham 
1106b9c1b51eSKate Stone       if (result.Succeeded()) {
11075a988416SJim Ingham         int enable_count = 0;
11085a988416SJim Ingham         int loc_count = 0;
11095a988416SJim Ingham         const size_t count = valid_bp_ids.GetSize();
1110b9c1b51eSKate Stone         for (size_t i = 0; i < count; ++i) {
11115a988416SJim Ingham           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
11125a988416SJim Ingham 
1113b9c1b51eSKate Stone           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1114b9c1b51eSKate Stone             Breakpoint *breakpoint =
1115b9c1b51eSKate Stone                 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1116b9c1b51eSKate Stone             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1117b9c1b51eSKate Stone               BreakpointLocation *location =
1118b9c1b51eSKate Stone                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1119b9c1b51eSKate Stone               if (location) {
11205a988416SJim Ingham                 location->SetEnabled(true);
11215a988416SJim Ingham                 ++loc_count;
11225a988416SJim Ingham               }
1123b9c1b51eSKate Stone             } else {
11245a988416SJim Ingham               breakpoint->SetEnabled(true);
11255a988416SJim Ingham               ++enable_count;
11265a988416SJim Ingham             }
11275a988416SJim Ingham           }
11285a988416SJim Ingham         }
1129b9c1b51eSKate Stone         result.AppendMessageWithFormat("%d breakpoints enabled.\n",
1130b9c1b51eSKate Stone                                        enable_count + loc_count);
11315a988416SJim Ingham         result.SetStatus(eReturnStatusSuccessFinishNoResult);
11325a988416SJim Ingham       }
11335a988416SJim Ingham     }
11345a988416SJim Ingham 
11355a988416SJim Ingham     return result.Succeeded();
11365a988416SJim Ingham   }
11375a988416SJim Ingham };
11385a988416SJim Ingham 
11395a988416SJim Ingham //-------------------------------------------------------------------------
11405a988416SJim Ingham // CommandObjectBreakpointDisable
11415a988416SJim Ingham //-------------------------------------------------------------------------
11425a988416SJim Ingham #pragma mark Disable
11435a988416SJim Ingham 
1144b9c1b51eSKate Stone class CommandObjectBreakpointDisable : public CommandObjectParsed {
11455a988416SJim Ingham public:
11467428a18cSKate Stone   CommandObjectBreakpointDisable(CommandInterpreter &interpreter)
1147b9c1b51eSKate Stone       : CommandObjectParsed(
1148b9c1b51eSKate Stone             interpreter, "breakpoint disable",
1149b9c1b51eSKate Stone             "Disable the specified breakpoint(s) without deleting "
11507428a18cSKate Stone             "them.  If none are specified, disable all "
11517428a18cSKate Stone             "breakpoints.",
1152b9c1b51eSKate Stone             nullptr) {
1153b9c1b51eSKate Stone     SetHelpLong(
1154b9c1b51eSKate Stone         "Disable the specified breakpoint(s) without deleting them.  \
11557428a18cSKate Stone If none are specified, disable all breakpoints."
11567428a18cSKate Stone         R"(
1157ea671fbdSKate Stone 
11587428a18cSKate Stone )"
11597428a18cSKate Stone         "Note: disabling a breakpoint will cause none of its locations to be hit \
11607428a18cSKate Stone regardless of whether individual locations are enabled or disabled.  After the sequence:"
11617428a18cSKate Stone         R"(
1162ea671fbdSKate Stone 
1163ea671fbdSKate Stone     (lldb) break disable 1
1164ea671fbdSKate Stone     (lldb) break enable 1.1
1165ea671fbdSKate Stone 
1166ea671fbdSKate Stone execution will NOT stop at location 1.1.  To achieve that, type:
1167ea671fbdSKate Stone 
1168ea671fbdSKate Stone     (lldb) break disable 1.*
1169ea671fbdSKate Stone     (lldb) break enable 1.1
1170ea671fbdSKate Stone 
11717428a18cSKate Stone )"
11727428a18cSKate Stone         "The first command disables all locations for breakpoint 1, \
11737428a18cSKate Stone the second re-enables the first location.");
1174b0fac509SJim Ingham 
11755a988416SJim Ingham     CommandArgumentEntry arg;
1176b9c1b51eSKate Stone     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1177b9c1b51eSKate Stone                                       eArgTypeBreakpointIDRange);
1178b9c1b51eSKate Stone     // Add the entry for the first argument for this command to the object's
1179b9c1b51eSKate Stone     // arguments vector.
11805a988416SJim Ingham     m_arguments.push_back(arg);
11815a988416SJim Ingham   }
11825a988416SJim Ingham 
11839e85e5a8SEugene Zelenko   ~CommandObjectBreakpointDisable() override = default;
11845a988416SJim Ingham 
11855a988416SJim Ingham protected:
1186b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1187893c932aSJim Ingham     Target *target = GetSelectedOrDummyTarget();
1188b9c1b51eSKate Stone     if (target == nullptr) {
11895a988416SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
11905a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
11915a988416SJim Ingham       return false;
11925a988416SJim Ingham     }
11935a988416SJim Ingham 
1194bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1195bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
11965a988416SJim Ingham 
11975a988416SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
11985a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
11995a988416SJim Ingham 
1200b9c1b51eSKate Stone     if (num_breakpoints == 0) {
12015a988416SJim Ingham       result.AppendError("No breakpoints exist to be disabled.");
12025a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
12035a988416SJim Ingham       return false;
12045a988416SJim Ingham     }
12055a988416SJim Ingham 
120611eb9c64SZachary Turner     if (command.empty()) {
12075a988416SJim Ingham       // No breakpoint selected; disable all currently set breakpoints.
1208b842f2ecSJim Ingham       target->DisableAllowedBreakpoints();
1209b9c1b51eSKate Stone       result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64
1210b9c1b51eSKate Stone                                      " breakpoints)\n",
1211b9c1b51eSKate Stone                                      (uint64_t)num_breakpoints);
12125a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1213b9c1b51eSKate Stone     } else {
12145a988416SJim Ingham       // Particular breakpoint selected; disable that breakpoint.
12155a988416SJim Ingham       BreakpointIDList valid_bp_ids;
12165a988416SJim Ingham 
1217b9c1b51eSKate Stone       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1218b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
1219b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::disablePerm);
12205a988416SJim Ingham 
1221b9c1b51eSKate Stone       if (result.Succeeded()) {
12225a988416SJim Ingham         int disable_count = 0;
12235a988416SJim Ingham         int loc_count = 0;
12245a988416SJim Ingham         const size_t count = valid_bp_ids.GetSize();
1225b9c1b51eSKate Stone         for (size_t i = 0; i < count; ++i) {
12265a988416SJim Ingham           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
12275a988416SJim Ingham 
1228b9c1b51eSKate Stone           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1229b9c1b51eSKate Stone             Breakpoint *breakpoint =
1230b9c1b51eSKate Stone                 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1231b9c1b51eSKate Stone             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1232b9c1b51eSKate Stone               BreakpointLocation *location =
1233b9c1b51eSKate Stone                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1234b9c1b51eSKate Stone               if (location) {
12355a988416SJim Ingham                 location->SetEnabled(false);
12365a988416SJim Ingham                 ++loc_count;
12375a988416SJim Ingham               }
1238b9c1b51eSKate Stone             } else {
12395a988416SJim Ingham               breakpoint->SetEnabled(false);
12405a988416SJim Ingham               ++disable_count;
12415a988416SJim Ingham             }
12425a988416SJim Ingham           }
12435a988416SJim Ingham         }
1244b9c1b51eSKate Stone         result.AppendMessageWithFormat("%d breakpoints disabled.\n",
1245b9c1b51eSKate Stone                                        disable_count + loc_count);
12465a988416SJim Ingham         result.SetStatus(eReturnStatusSuccessFinishNoResult);
12475a988416SJim Ingham       }
12485a988416SJim Ingham     }
12495a988416SJim Ingham 
12505a988416SJim Ingham     return result.Succeeded();
12515a988416SJim Ingham   }
12525a988416SJim Ingham };
12535a988416SJim Ingham 
12545a988416SJim Ingham //-------------------------------------------------------------------------
12555a988416SJim Ingham // CommandObjectBreakpointList
12565a988416SJim Ingham //-------------------------------------------------------------------------
12571f0f5b5bSZachary Turner 
12581f0f5b5bSZachary Turner #pragma mark List::CommandOptions
12598fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_list_options[] = {
12601f0f5b5bSZachary Turner     // clang-format off
12618fe53c49STatyana Krasnukha   { LLDB_OPT_SET_ALL, false, "internal",          'i', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Show debugger internal breakpoints" },
12628fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1,   false, "brief",             'b', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Give a brief description of the breakpoint (no location info)." },
12631f0f5b5bSZachary Turner   // FIXME: We need to add an "internal" command, and then add this sort of thing to it.
12641f0f5b5bSZachary Turner   // But I need to see it for now, and don't want to wait.
12658fe53c49STatyana Krasnukha   { LLDB_OPT_SET_2,   false, "full",              'f', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Give a full description of the breakpoint and its locations." },
12668fe53c49STatyana Krasnukha   { LLDB_OPT_SET_3,   false, "verbose",           'v', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Explain everything we know about the breakpoint (for debugging debugger bugs)." },
12678fe53c49STatyana Krasnukha   { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "List Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." },
12681f0f5b5bSZachary Turner     // clang-format on
12691f0f5b5bSZachary Turner };
12701f0f5b5bSZachary Turner 
12715a988416SJim Ingham #pragma mark List
12725a988416SJim Ingham 
1273b9c1b51eSKate Stone class CommandObjectBreakpointList : public CommandObjectParsed {
12745a988416SJim Ingham public:
1275b9c1b51eSKate Stone   CommandObjectBreakpointList(CommandInterpreter &interpreter)
1276b9c1b51eSKate Stone       : CommandObjectParsed(
1277b9c1b51eSKate Stone             interpreter, "breakpoint list",
12785a988416SJim Ingham             "List some or all breakpoints at configurable levels of detail.",
12799e85e5a8SEugene Zelenko             nullptr),
1280b9c1b51eSKate Stone         m_options() {
12815a988416SJim Ingham     CommandArgumentEntry arg;
12825a988416SJim Ingham     CommandArgumentData bp_id_arg;
12835a988416SJim Ingham 
12845a988416SJim Ingham     // Define the first (and only) variant of this arg.
12855a988416SJim Ingham     bp_id_arg.arg_type = eArgTypeBreakpointID;
12865a988416SJim Ingham     bp_id_arg.arg_repetition = eArgRepeatOptional;
12875a988416SJim Ingham 
1288b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
1289b9c1b51eSKate Stone     // argument entry.
12905a988416SJim Ingham     arg.push_back(bp_id_arg);
12915a988416SJim Ingham 
12925a988416SJim Ingham     // Push the data for the first argument into the m_arguments vector.
12935a988416SJim Ingham     m_arguments.push_back(arg);
12945a988416SJim Ingham   }
12955a988416SJim Ingham 
12969e85e5a8SEugene Zelenko   ~CommandObjectBreakpointList() override = default;
12975a988416SJim Ingham 
1298b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
12995a988416SJim Ingham 
1300b9c1b51eSKate Stone   class CommandOptions : public Options {
13015a988416SJim Ingham   public:
1302b9c1b51eSKate Stone     CommandOptions()
1303b9c1b51eSKate Stone         : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) {
13045a988416SJim Ingham     }
13055a988416SJim Ingham 
13069e85e5a8SEugene Zelenko     ~CommandOptions() override = default;
13075a988416SJim Ingham 
130897206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1309b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
131097206d57SZachary Turner       Status error;
13113bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
13125a988416SJim Ingham 
1313b9c1b51eSKate Stone       switch (short_option) {
13145a988416SJim Ingham       case 'b':
13155a988416SJim Ingham         m_level = lldb::eDescriptionLevelBrief;
13165a988416SJim Ingham         break;
131733df7cd3SJim Ingham       case 'D':
131833df7cd3SJim Ingham         m_use_dummy = true;
131933df7cd3SJim Ingham         break;
13205a988416SJim Ingham       case 'f':
13215a988416SJim Ingham         m_level = lldb::eDescriptionLevelFull;
13225a988416SJim Ingham         break;
13235a988416SJim Ingham       case 'v':
13245a988416SJim Ingham         m_level = lldb::eDescriptionLevelVerbose;
13255a988416SJim Ingham         break;
13265a988416SJim Ingham       case 'i':
13275a988416SJim Ingham         m_internal = true;
13285a988416SJim Ingham         break;
13295a988416SJim Ingham       default:
1330b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
1331b9c1b51eSKate Stone                                        short_option);
13325a988416SJim Ingham         break;
13335a988416SJim Ingham       }
13345a988416SJim Ingham 
13355a988416SJim Ingham       return error;
13365a988416SJim Ingham     }
13375a988416SJim Ingham 
1338b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
13395a988416SJim Ingham       m_level = lldb::eDescriptionLevelFull;
13405a988416SJim Ingham       m_internal = false;
134133df7cd3SJim Ingham       m_use_dummy = false;
13425a988416SJim Ingham     }
13435a988416SJim Ingham 
13441f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
134570602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_list_options);
13461f0f5b5bSZachary Turner     }
13475a988416SJim Ingham 
13485a988416SJim Ingham     // Instance variables to hold the values for command options.
13495a988416SJim Ingham 
13505a988416SJim Ingham     lldb::DescriptionLevel m_level;
13515a988416SJim Ingham 
13525a988416SJim Ingham     bool m_internal;
135333df7cd3SJim Ingham     bool m_use_dummy;
13545a988416SJim Ingham   };
13555a988416SJim Ingham 
13565a988416SJim Ingham protected:
1357b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
135833df7cd3SJim Ingham     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
135933df7cd3SJim Ingham 
1360b9c1b51eSKate Stone     if (target == nullptr) {
13615a988416SJim Ingham       result.AppendError("Invalid target. No current target or breakpoints.");
13625a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
13635a988416SJim Ingham       return true;
13645a988416SJim Ingham     }
13655a988416SJim Ingham 
1366b9c1b51eSKate Stone     const BreakpointList &breakpoints =
1367b9c1b51eSKate Stone         target->GetBreakpointList(m_options.m_internal);
1368bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1369bb19a13cSSaleem Abdulrasool     target->GetBreakpointList(m_options.m_internal).GetListMutex(lock);
13705a988416SJim Ingham 
13715a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
13725a988416SJim Ingham 
1373b9c1b51eSKate Stone     if (num_breakpoints == 0) {
13745a988416SJim Ingham       result.AppendMessage("No breakpoints currently set.");
13755a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
13765a988416SJim Ingham       return true;
13775a988416SJim Ingham     }
13785a988416SJim Ingham 
13795a988416SJim Ingham     Stream &output_stream = result.GetOutputStream();
13805a988416SJim Ingham 
138111eb9c64SZachary Turner     if (command.empty()) {
13825a988416SJim Ingham       // No breakpoint selected; show info about all currently set breakpoints.
13835a988416SJim Ingham       result.AppendMessage("Current breakpoints:");
1384b9c1b51eSKate Stone       for (size_t i = 0; i < num_breakpoints; ++i) {
13855a988416SJim Ingham         Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get();
1386b842f2ecSJim Ingham         if (breakpoint->AllowList())
1387b842f2ecSJim Ingham           AddBreakpointDescription(&output_stream, breakpoint,
1388b842f2ecSJim Ingham                                    m_options.m_level);
13895a988416SJim Ingham       }
13905a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1391b9c1b51eSKate Stone     } else {
13925a988416SJim Ingham       // Particular breakpoints selected; show info about that breakpoint.
13935a988416SJim Ingham       BreakpointIDList valid_bp_ids;
1394b9c1b51eSKate Stone       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1395b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
1396b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::listPerm);
13975a988416SJim Ingham 
1398b9c1b51eSKate Stone       if (result.Succeeded()) {
1399b9c1b51eSKate Stone         for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) {
14005a988416SJim Ingham           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1401b9c1b51eSKate Stone           Breakpoint *breakpoint =
1402b9c1b51eSKate Stone               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1403b9c1b51eSKate Stone           AddBreakpointDescription(&output_stream, breakpoint,
1404b9c1b51eSKate Stone                                    m_options.m_level);
14055a988416SJim Ingham         }
14065a988416SJim Ingham         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1407b9c1b51eSKate Stone       } else {
14087428a18cSKate Stone         result.AppendError("Invalid breakpoint ID.");
14095a988416SJim Ingham         result.SetStatus(eReturnStatusFailed);
14105a988416SJim Ingham       }
14115a988416SJim Ingham     }
14125a988416SJim Ingham 
14135a988416SJim Ingham     return result.Succeeded();
14145a988416SJim Ingham   }
14155a988416SJim Ingham 
14165a988416SJim Ingham private:
14175a988416SJim Ingham   CommandOptions m_options;
14185a988416SJim Ingham };
14195a988416SJim Ingham 
14205a988416SJim Ingham //-------------------------------------------------------------------------
14215a988416SJim Ingham // CommandObjectBreakpointClear
14225a988416SJim Ingham //-------------------------------------------------------------------------
14231f0f5b5bSZachary Turner #pragma mark Clear::CommandOptions
14241f0f5b5bSZachary Turner 
14258fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_clear_options[] = {
14261f0f5b5bSZachary Turner     // clang-format off
14278fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specify the breakpoint by source location in this particular file." },
14288fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, true,  "line", 'l', OptionParser::eRequiredArgument, nullptr, {}, 0,                                         eArgTypeLineNum,  "Specify the breakpoint by source location at this particular line." }
14291f0f5b5bSZachary Turner     // clang-format on
14301f0f5b5bSZachary Turner };
14311f0f5b5bSZachary Turner 
14325a988416SJim Ingham #pragma mark Clear
14335a988416SJim Ingham 
1434b9c1b51eSKate Stone class CommandObjectBreakpointClear : public CommandObjectParsed {
14355a988416SJim Ingham public:
1436b9c1b51eSKate Stone   typedef enum BreakpointClearType {
14375a988416SJim Ingham     eClearTypeInvalid,
14385a988416SJim Ingham     eClearTypeFileAndLine
14395a988416SJim Ingham   } BreakpointClearType;
14405a988416SJim Ingham 
14417428a18cSKate Stone   CommandObjectBreakpointClear(CommandInterpreter &interpreter)
14427428a18cSKate Stone       : CommandObjectParsed(interpreter, "breakpoint clear",
1443b9c1b51eSKate Stone                             "Delete or disable breakpoints matching the "
1444b9c1b51eSKate Stone                             "specified source file and line.",
14455a988416SJim Ingham                             "breakpoint clear <cmd-options>"),
1446b9c1b51eSKate Stone         m_options() {}
14475a988416SJim Ingham 
14489e85e5a8SEugene Zelenko   ~CommandObjectBreakpointClear() override = default;
14495a988416SJim Ingham 
1450b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
14515a988416SJim Ingham 
1452b9c1b51eSKate Stone   class CommandOptions : public Options {
14535a988416SJim Ingham   public:
1454b9c1b51eSKate Stone     CommandOptions() : Options(), m_filename(), m_line_num(0) {}
14555a988416SJim Ingham 
14569e85e5a8SEugene Zelenko     ~CommandOptions() override = default;
14575a988416SJim Ingham 
145897206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1459b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
146097206d57SZachary Turner       Status error;
14613bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
14625a988416SJim Ingham 
1463b9c1b51eSKate Stone       switch (short_option) {
14645a988416SJim Ingham       case 'f':
14655a988416SJim Ingham         m_filename.assign(option_arg);
14665a988416SJim Ingham         break;
14675a988416SJim Ingham 
14685a988416SJim Ingham       case 'l':
1469fe11483bSZachary Turner         option_arg.getAsInteger(0, m_line_num);
14705a988416SJim Ingham         break;
14715a988416SJim Ingham 
14725a988416SJim Ingham       default:
1473b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
1474b9c1b51eSKate Stone                                        short_option);
14755a988416SJim Ingham         break;
14765a988416SJim Ingham       }
14775a988416SJim Ingham 
14785a988416SJim Ingham       return error;
14795a988416SJim Ingham     }
14805a988416SJim Ingham 
1481b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
14825a988416SJim Ingham       m_filename.clear();
14835a988416SJim Ingham       m_line_num = 0;
14845a988416SJim Ingham     }
14855a988416SJim Ingham 
14861f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
148770602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_clear_options);
14881f0f5b5bSZachary Turner     }
14895a988416SJim Ingham 
14905a988416SJim Ingham     // Instance variables to hold the values for command options.
14915a988416SJim Ingham 
14925a988416SJim Ingham     std::string m_filename;
14935a988416SJim Ingham     uint32_t m_line_num;
14945a988416SJim Ingham   };
14955a988416SJim Ingham 
14965a988416SJim Ingham protected:
1497b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1498893c932aSJim Ingham     Target *target = GetSelectedOrDummyTarget();
1499b9c1b51eSKate Stone     if (target == nullptr) {
15005a988416SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
15015a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
15025a988416SJim Ingham       return false;
15035a988416SJim Ingham     }
15045a988416SJim Ingham 
150505097246SAdrian Prantl     // The following are the various types of breakpoints that could be
150605097246SAdrian Prantl     // cleared:
15075a988416SJim Ingham     //   1). -f -l (clearing breakpoint by source location)
15085a988416SJim Ingham 
15095a988416SJim Ingham     BreakpointClearType break_type = eClearTypeInvalid;
15105a988416SJim Ingham 
15115a988416SJim Ingham     if (m_options.m_line_num != 0)
15125a988416SJim Ingham       break_type = eClearTypeFileAndLine;
15135a988416SJim Ingham 
1514bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1515bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
15165a988416SJim Ingham 
15175a988416SJim Ingham     BreakpointList &breakpoints = target->GetBreakpointList();
15185a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
15195a988416SJim Ingham 
15205a988416SJim Ingham     // Early return if there's no breakpoint at all.
1521b9c1b51eSKate Stone     if (num_breakpoints == 0) {
15225a988416SJim Ingham       result.AppendError("Breakpoint clear: No breakpoint cleared.");
15235a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
15245a988416SJim Ingham       return result.Succeeded();
15255a988416SJim Ingham     }
15265a988416SJim Ingham 
15275a988416SJim Ingham     // Find matching breakpoints and delete them.
15285a988416SJim Ingham 
15295a988416SJim Ingham     // First create a copy of all the IDs.
15305a988416SJim Ingham     std::vector<break_id_t> BreakIDs;
15315a988416SJim Ingham     for (size_t i = 0; i < num_breakpoints; ++i)
15329e85e5a8SEugene Zelenko       BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID());
15335a988416SJim Ingham 
15345a988416SJim Ingham     int num_cleared = 0;
15355a988416SJim Ingham     StreamString ss;
1536b9c1b51eSKate Stone     switch (break_type) {
15375a988416SJim Ingham     case eClearTypeFileAndLine: // Breakpoint by source position
15385a988416SJim Ingham     {
15395a988416SJim Ingham       const ConstString filename(m_options.m_filename.c_str());
15405a988416SJim Ingham       BreakpointLocationCollection loc_coll;
15415a988416SJim Ingham 
1542b9c1b51eSKate Stone       for (size_t i = 0; i < num_breakpoints; ++i) {
15435a988416SJim Ingham         Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
15445a988416SJim Ingham 
1545b9c1b51eSKate Stone         if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) {
1546b9c1b51eSKate Stone           // If the collection size is 0, it's a full match and we can just
1547b9c1b51eSKate Stone           // remove the breakpoint.
1548b9c1b51eSKate Stone           if (loc_coll.GetSize() == 0) {
15495a988416SJim Ingham             bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
15505a988416SJim Ingham             ss.EOL();
15515a988416SJim Ingham             target->RemoveBreakpointByID(bp->GetID());
15525a988416SJim Ingham             ++num_cleared;
15535a988416SJim Ingham           }
15545a988416SJim Ingham         }
15555a988416SJim Ingham       }
1556b9c1b51eSKate Stone     } break;
15575a988416SJim Ingham 
15585a988416SJim Ingham     default:
15595a988416SJim Ingham       break;
15605a988416SJim Ingham     }
15615a988416SJim Ingham 
1562b9c1b51eSKate Stone     if (num_cleared > 0) {
15635a988416SJim Ingham       Stream &output_stream = result.GetOutputStream();
15645a988416SJim Ingham       output_stream.Printf("%d breakpoints cleared:\n", num_cleared);
1565c156427dSZachary Turner       output_stream << ss.GetString();
15665a988416SJim Ingham       output_stream.EOL();
15675a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1568b9c1b51eSKate Stone     } else {
15695a988416SJim Ingham       result.AppendError("Breakpoint clear: No breakpoint cleared.");
15705a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
15715a988416SJim Ingham     }
15725a988416SJim Ingham 
15735a988416SJim Ingham     return result.Succeeded();
15745a988416SJim Ingham   }
15755a988416SJim Ingham 
15765a988416SJim Ingham private:
15775a988416SJim Ingham   CommandOptions m_options;
15785a988416SJim Ingham };
15795a988416SJim Ingham 
15805a988416SJim Ingham //-------------------------------------------------------------------------
15815a988416SJim Ingham // CommandObjectBreakpointDelete
15825a988416SJim Ingham //-------------------------------------------------------------------------
15838fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_delete_options[] = {
15841f0f5b5bSZachary Turner     // clang-format off
15858fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "force",             'f', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Delete all breakpoints without querying for confirmation." },
15868fe53c49STatyana Krasnukha   { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, {}, 0, eArgTypeNone, "Delete Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." },
15871f0f5b5bSZachary Turner     // clang-format on
15881f0f5b5bSZachary Turner };
15891f0f5b5bSZachary Turner 
15905a988416SJim Ingham #pragma mark Delete
15915a988416SJim Ingham 
1592b9c1b51eSKate Stone class CommandObjectBreakpointDelete : public CommandObjectParsed {
15935a988416SJim Ingham public:
1594b9c1b51eSKate Stone   CommandObjectBreakpointDelete(CommandInterpreter &interpreter)
1595b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "breakpoint delete",
1596b9c1b51eSKate Stone                             "Delete the specified breakpoint(s).  If no "
1597b9c1b51eSKate Stone                             "breakpoints are specified, delete them all.",
15989e85e5a8SEugene Zelenko                             nullptr),
1599b9c1b51eSKate Stone         m_options() {
16005a988416SJim Ingham     CommandArgumentEntry arg;
1601b9c1b51eSKate Stone     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1602b9c1b51eSKate Stone                                       eArgTypeBreakpointIDRange);
1603b9c1b51eSKate Stone     // Add the entry for the first argument for this command to the object's
1604b9c1b51eSKate Stone     // arguments vector.
16055a988416SJim Ingham     m_arguments.push_back(arg);
16065a988416SJim Ingham   }
16075a988416SJim Ingham 
16089e85e5a8SEugene Zelenko   ~CommandObjectBreakpointDelete() override = default;
16095a988416SJim Ingham 
1610b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
161133df7cd3SJim Ingham 
1612b9c1b51eSKate Stone   class CommandOptions : public Options {
161333df7cd3SJim Ingham   public:
1614b9c1b51eSKate Stone     CommandOptions() : Options(), m_use_dummy(false), m_force(false) {}
161533df7cd3SJim Ingham 
16169e85e5a8SEugene Zelenko     ~CommandOptions() override = default;
161733df7cd3SJim Ingham 
161897206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1619b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
162097206d57SZachary Turner       Status error;
162133df7cd3SJim Ingham       const int short_option = m_getopt_table[option_idx].val;
162233df7cd3SJim Ingham 
1623b9c1b51eSKate Stone       switch (short_option) {
162433df7cd3SJim Ingham       case 'f':
162533df7cd3SJim Ingham         m_force = true;
162633df7cd3SJim Ingham         break;
162733df7cd3SJim Ingham 
162833df7cd3SJim Ingham       case 'D':
162933df7cd3SJim Ingham         m_use_dummy = true;
163033df7cd3SJim Ingham         break;
163133df7cd3SJim Ingham 
163233df7cd3SJim Ingham       default:
1633b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
1634b9c1b51eSKate Stone                                        short_option);
163533df7cd3SJim Ingham         break;
163633df7cd3SJim Ingham       }
163733df7cd3SJim Ingham 
163833df7cd3SJim Ingham       return error;
163933df7cd3SJim Ingham     }
164033df7cd3SJim Ingham 
1641b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
164233df7cd3SJim Ingham       m_use_dummy = false;
164333df7cd3SJim Ingham       m_force = false;
164433df7cd3SJim Ingham     }
164533df7cd3SJim Ingham 
16461f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
164770602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_delete_options);
16481f0f5b5bSZachary Turner     }
164933df7cd3SJim Ingham 
165033df7cd3SJim Ingham     // Instance variables to hold the values for command options.
165133df7cd3SJim Ingham     bool m_use_dummy;
165233df7cd3SJim Ingham     bool m_force;
165333df7cd3SJim Ingham   };
165433df7cd3SJim Ingham 
16555a988416SJim Ingham protected:
1656b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
165733df7cd3SJim Ingham     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
165833df7cd3SJim Ingham 
1659b9c1b51eSKate Stone     if (target == nullptr) {
16605a988416SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
16615a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
16625a988416SJim Ingham       return false;
16635a988416SJim Ingham     }
16645a988416SJim Ingham 
1665bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1666bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
16675a988416SJim Ingham 
16685a988416SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
16695a988416SJim Ingham 
16705a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
16715a988416SJim Ingham 
1672b9c1b51eSKate Stone     if (num_breakpoints == 0) {
16735a988416SJim Ingham       result.AppendError("No breakpoints exist to be deleted.");
16745a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
16755a988416SJim Ingham       return false;
16765a988416SJim Ingham     }
16775a988416SJim Ingham 
167811eb9c64SZachary Turner     if (command.empty()) {
1679b9c1b51eSKate Stone       if (!m_options.m_force &&
1680b9c1b51eSKate Stone           !m_interpreter.Confirm(
1681b9c1b51eSKate Stone               "About to delete all breakpoints, do you want to do that?",
1682b9c1b51eSKate Stone               true)) {
16835a988416SJim Ingham         result.AppendMessage("Operation cancelled...");
1684b9c1b51eSKate Stone       } else {
1685b842f2ecSJim Ingham         target->RemoveAllowedBreakpoints();
1686b9c1b51eSKate Stone         result.AppendMessageWithFormat(
1687b9c1b51eSKate Stone             "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n",
1688b9c1b51eSKate Stone             (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");
16895a988416SJim Ingham       }
16905a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1691b9c1b51eSKate Stone     } else {
16925a988416SJim Ingham       // Particular breakpoint selected; disable that breakpoint.
16935a988416SJim Ingham       BreakpointIDList valid_bp_ids;
1694b9c1b51eSKate Stone       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1695b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
1696b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::deletePerm);
16975a988416SJim Ingham 
1698b9c1b51eSKate Stone       if (result.Succeeded()) {
16995a988416SJim Ingham         int delete_count = 0;
17005a988416SJim Ingham         int disable_count = 0;
17015a988416SJim Ingham         const size_t count = valid_bp_ids.GetSize();
1702b9c1b51eSKate Stone         for (size_t i = 0; i < count; ++i) {
17035a988416SJim Ingham           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
17045a988416SJim Ingham 
1705b9c1b51eSKate Stone           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1706b9c1b51eSKate Stone             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1707b9c1b51eSKate Stone               Breakpoint *breakpoint =
1708b9c1b51eSKate Stone                   target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1709b9c1b51eSKate Stone               BreakpointLocation *location =
1710b9c1b51eSKate Stone                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1711b9c1b51eSKate Stone               // It makes no sense to try to delete individual locations, so we
1712b9c1b51eSKate Stone               // disable them instead.
1713b9c1b51eSKate Stone               if (location) {
17145a988416SJim Ingham                 location->SetEnabled(false);
17155a988416SJim Ingham                 ++disable_count;
17165a988416SJim Ingham               }
1717b9c1b51eSKate Stone             } else {
17185a988416SJim Ingham               target->RemoveBreakpointByID(cur_bp_id.GetBreakpointID());
17195a988416SJim Ingham               ++delete_count;
17205a988416SJim Ingham             }
17215a988416SJim Ingham           }
17225a988416SJim Ingham         }
1723b9c1b51eSKate Stone         result.AppendMessageWithFormat(
1724b9c1b51eSKate Stone             "%d breakpoints deleted; %d breakpoint locations disabled.\n",
17255a988416SJim Ingham             delete_count, disable_count);
17265a988416SJim Ingham         result.SetStatus(eReturnStatusSuccessFinishNoResult);
17275a988416SJim Ingham       }
17285a988416SJim Ingham     }
17295a988416SJim Ingham     return result.Succeeded();
17305a988416SJim Ingham   }
17319e85e5a8SEugene Zelenko 
173233df7cd3SJim Ingham private:
173333df7cd3SJim Ingham   CommandOptions m_options;
173433df7cd3SJim Ingham };
173533df7cd3SJim Ingham 
173630fdc8d8SChris Lattner //-------------------------------------------------------------------------
17375e09c8c3SJim Ingham // CommandObjectBreakpointName
17385e09c8c3SJim Ingham //-------------------------------------------------------------------------
17395e09c8c3SJim Ingham 
17408fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_name_options[] = {
1741ac9c3a62SKate Stone     // clang-format off
17428fe53c49STatyana Krasnukha   {LLDB_OPT_SET_1, false, "name",              'N', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."},
17438fe53c49STatyana Krasnukha   {LLDB_OPT_SET_2, false, "breakpoint-id",     'B', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBreakpointID,   "Specify a breakpoint ID to use."},
17448fe53c49STatyana Krasnukha   {LLDB_OPT_SET_3, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument,       nullptr, {}, 0, eArgTypeNone,           "Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
17458fe53c49STatyana Krasnukha   {LLDB_OPT_SET_4, false, "help-string",       'H', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeNone,           "A help string describing the purpose of this name."},
1746ac9c3a62SKate Stone     // clang-format on
17475e09c8c3SJim Ingham };
1748b9c1b51eSKate Stone class BreakpointNameOptionGroup : public OptionGroup {
17495e09c8c3SJim Ingham public:
1750b9c1b51eSKate Stone   BreakpointNameOptionGroup()
1751b9c1b51eSKate Stone       : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) {
17525e09c8c3SJim Ingham   }
17535e09c8c3SJim Ingham 
17549e85e5a8SEugene Zelenko   ~BreakpointNameOptionGroup() override = default;
17555e09c8c3SJim Ingham 
17561f0f5b5bSZachary Turner   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
175770602439SZachary Turner     return llvm::makeArrayRef(g_breakpoint_name_options);
17585e09c8c3SJim Ingham   }
17595e09c8c3SJim Ingham 
176097206d57SZachary Turner   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1761b9c1b51eSKate Stone                         ExecutionContext *execution_context) override {
176297206d57SZachary Turner     Status error;
17635e09c8c3SJim Ingham     const int short_option = g_breakpoint_name_options[option_idx].short_option;
17645e09c8c3SJim Ingham 
1765b9c1b51eSKate Stone     switch (short_option) {
17665e09c8c3SJim Ingham     case 'N':
1767fe11483bSZachary Turner       if (BreakpointID::StringIsBreakpointName(option_arg, error) &&
1768b9c1b51eSKate Stone           error.Success())
1769fe11483bSZachary Turner         m_name.SetValueFromString(option_arg);
17705e09c8c3SJim Ingham       break;
17715e09c8c3SJim Ingham     case 'B':
1772fe11483bSZachary Turner       if (m_breakpoint.SetValueFromString(option_arg).Fail())
1773b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
17748cef4b0bSZachary Turner             "unrecognized value \"%s\" for breakpoint",
1775fe11483bSZachary Turner             option_arg.str().c_str());
17765e09c8c3SJim Ingham       break;
17775e09c8c3SJim Ingham     case 'D':
1778fe11483bSZachary Turner       if (m_use_dummy.SetValueFromString(option_arg).Fail())
1779b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
17808cef4b0bSZachary Turner             "unrecognized value \"%s\" for use-dummy",
1781fe11483bSZachary Turner             option_arg.str().c_str());
17825e09c8c3SJim Ingham       break;
1783e9632ebaSJim Ingham     case 'H':
1784e9632ebaSJim Ingham       m_help_string.SetValueFromString(option_arg);
1785e9632ebaSJim Ingham       break;
17865e09c8c3SJim Ingham 
17875e09c8c3SJim Ingham     default:
1788b9c1b51eSKate Stone       error.SetErrorStringWithFormat("unrecognized short option '%c'",
1789b9c1b51eSKate Stone                                      short_option);
17905e09c8c3SJim Ingham       break;
17915e09c8c3SJim Ingham     }
17925e09c8c3SJim Ingham     return error;
17935e09c8c3SJim Ingham   }
17945e09c8c3SJim Ingham 
1795b9c1b51eSKate Stone   void OptionParsingStarting(ExecutionContext *execution_context) override {
17965e09c8c3SJim Ingham     m_name.Clear();
17975e09c8c3SJim Ingham     m_breakpoint.Clear();
17985e09c8c3SJim Ingham     m_use_dummy.Clear();
17995e09c8c3SJim Ingham     m_use_dummy.SetDefaultValue(false);
1800e9632ebaSJim Ingham     m_help_string.Clear();
18015e09c8c3SJim Ingham   }
18025e09c8c3SJim Ingham 
18035e09c8c3SJim Ingham   OptionValueString m_name;
18045e09c8c3SJim Ingham   OptionValueUInt64 m_breakpoint;
18055e09c8c3SJim Ingham   OptionValueBoolean m_use_dummy;
1806e9632ebaSJim Ingham   OptionValueString m_help_string;
18075e09c8c3SJim Ingham };
18085e09c8c3SJim Ingham 
18098fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_access_options[] = {
1810b842f2ecSJim Ingham     // clang-format off
18118fe53c49STatyana Krasnukha   {LLDB_OPT_SET_1,   false, "allow-list",    'L', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Determines whether the breakpoint will show up in break list if not referred to explicitly."},
18128fe53c49STatyana Krasnukha   {LLDB_OPT_SET_2,   false, "allow-disable", 'A', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Determines whether the breakpoint can be disabled by name or when all breakpoints are disabled."},
18138fe53c49STatyana Krasnukha   {LLDB_OPT_SET_3,   false, "allow-delete",  'D', OptionParser::eRequiredArgument, nullptr, {}, 0, eArgTypeBoolean, "Determines whether the breakpoint can be deleted by name or when all breakpoints are deleted."},
1814b842f2ecSJim Ingham     // clang-format on
1815b842f2ecSJim Ingham };
1816b842f2ecSJim Ingham 
18178fe53c49STatyana Krasnukha class BreakpointAccessOptionGroup : public OptionGroup {
1818b842f2ecSJim Ingham public:
18198fe53c49STatyana Krasnukha   BreakpointAccessOptionGroup() : OptionGroup() {}
1820b842f2ecSJim Ingham 
1821b842f2ecSJim Ingham   ~BreakpointAccessOptionGroup() override = default;
1822b842f2ecSJim Ingham 
1823b842f2ecSJim Ingham   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1824b842f2ecSJim Ingham     return llvm::makeArrayRef(g_breakpoint_access_options);
1825b842f2ecSJim Ingham   }
1826b842f2ecSJim Ingham   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1827b842f2ecSJim Ingham                         ExecutionContext *execution_context) override {
1828b842f2ecSJim Ingham     Status error;
1829b842f2ecSJim Ingham     const int short_option
1830b842f2ecSJim Ingham         = g_breakpoint_access_options[option_idx].short_option;
1831b842f2ecSJim Ingham 
1832b842f2ecSJim Ingham     switch (short_option) {
1833b842f2ecSJim Ingham       case 'L': {
1834b842f2ecSJim Ingham         bool value, success;
183547cbf4a0SPavel Labath         value = OptionArgParser::ToBoolean(option_arg, false, &success);
1836b842f2ecSJim Ingham         if (success) {
1837b842f2ecSJim Ingham           m_permissions.SetAllowList(value);
1838b842f2ecSJim Ingham         } else
1839b842f2ecSJim Ingham           error.SetErrorStringWithFormat(
1840b842f2ecSJim Ingham               "invalid boolean value '%s' passed for -L option",
1841b842f2ecSJim Ingham               option_arg.str().c_str());
1842b842f2ecSJim Ingham       } break;
1843b842f2ecSJim Ingham       case 'A': {
1844b842f2ecSJim Ingham         bool value, success;
184547cbf4a0SPavel Labath         value = OptionArgParser::ToBoolean(option_arg, false, &success);
1846b842f2ecSJim Ingham         if (success) {
1847b842f2ecSJim Ingham           m_permissions.SetAllowDisable(value);
1848b842f2ecSJim Ingham         } else
1849b842f2ecSJim Ingham           error.SetErrorStringWithFormat(
1850b842f2ecSJim Ingham               "invalid boolean value '%s' passed for -L option",
1851b842f2ecSJim Ingham               option_arg.str().c_str());
1852b842f2ecSJim Ingham       } break;
1853b842f2ecSJim Ingham       case 'D': {
1854b842f2ecSJim Ingham         bool value, success;
185547cbf4a0SPavel Labath         value = OptionArgParser::ToBoolean(option_arg, false, &success);
1856b842f2ecSJim Ingham         if (success) {
1857b842f2ecSJim Ingham           m_permissions.SetAllowDelete(value);
1858b842f2ecSJim Ingham         } else
1859b842f2ecSJim Ingham           error.SetErrorStringWithFormat(
1860b842f2ecSJim Ingham               "invalid boolean value '%s' passed for -L option",
1861b842f2ecSJim Ingham               option_arg.str().c_str());
1862b842f2ecSJim Ingham       } break;
1863b842f2ecSJim Ingham 
1864b842f2ecSJim Ingham     }
1865b842f2ecSJim Ingham 
1866b842f2ecSJim Ingham     return error;
1867b842f2ecSJim Ingham   }
1868b842f2ecSJim Ingham 
1869b842f2ecSJim Ingham   void OptionParsingStarting(ExecutionContext *execution_context) override {
1870b842f2ecSJim Ingham   }
1871b842f2ecSJim Ingham 
1872b842f2ecSJim Ingham   const BreakpointName::Permissions &GetPermissions() const
1873b842f2ecSJim Ingham   {
1874b842f2ecSJim Ingham     return m_permissions;
1875b842f2ecSJim Ingham   }
1876b842f2ecSJim Ingham   BreakpointName::Permissions m_permissions;
1877b842f2ecSJim Ingham };
1878b842f2ecSJim Ingham 
1879b842f2ecSJim Ingham class CommandObjectBreakpointNameConfigure : public CommandObjectParsed {
1880b842f2ecSJim Ingham public:
1881b842f2ecSJim Ingham   CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter)
1882b842f2ecSJim Ingham       : CommandObjectParsed(
1883b842f2ecSJim Ingham             interpreter, "configure", "Configure the options for the breakpoint"
1884b842f2ecSJim Ingham             " name provided.  "
1885b842f2ecSJim Ingham             "If you provide a breakpoint id, the options will be copied from "
1886b842f2ecSJim Ingham             "the breakpoint, otherwise only the options specified will be set "
1887b842f2ecSJim Ingham             "on the name.",
1888b842f2ecSJim Ingham             "breakpoint name configure <command-options> "
1889b842f2ecSJim Ingham             "<breakpoint-name-list>"),
1890b842f2ecSJim Ingham         m_bp_opts(), m_option_group() {
1891b842f2ecSJim Ingham     // Create the first variant for the first (and only) argument for this
1892b842f2ecSJim Ingham     // command.
1893b842f2ecSJim Ingham     CommandArgumentEntry arg1;
1894b842f2ecSJim Ingham     CommandArgumentData id_arg;
1895b842f2ecSJim Ingham     id_arg.arg_type = eArgTypeBreakpointName;
1896b842f2ecSJim Ingham     id_arg.arg_repetition = eArgRepeatOptional;
1897b842f2ecSJim Ingham     arg1.push_back(id_arg);
1898b842f2ecSJim Ingham     m_arguments.push_back(arg1);
1899b842f2ecSJim Ingham 
1900b842f2ecSJim Ingham     m_option_group.Append(&m_bp_opts,
1901b842f2ecSJim Ingham                           LLDB_OPT_SET_ALL,
1902b842f2ecSJim Ingham                           LLDB_OPT_SET_1);
1903b842f2ecSJim Ingham     m_option_group.Append(&m_access_options,
1904b842f2ecSJim Ingham                           LLDB_OPT_SET_ALL,
1905b842f2ecSJim Ingham                           LLDB_OPT_SET_ALL);
1906e9632ebaSJim Ingham     m_option_group.Append(&m_bp_id,
1907e9632ebaSJim Ingham                           LLDB_OPT_SET_2|LLDB_OPT_SET_4,
1908e9632ebaSJim Ingham                           LLDB_OPT_SET_ALL);
1909b842f2ecSJim Ingham     m_option_group.Finalize();
1910b842f2ecSJim Ingham   }
1911b842f2ecSJim Ingham 
1912b842f2ecSJim Ingham   ~CommandObjectBreakpointNameConfigure() override = default;
1913b842f2ecSJim Ingham 
1914b842f2ecSJim Ingham   Options *GetOptions() override { return &m_option_group; }
1915b842f2ecSJim Ingham 
1916b842f2ecSJim Ingham protected:
1917b842f2ecSJim Ingham   bool DoExecute(Args &command, CommandReturnObject &result) override {
1918b842f2ecSJim Ingham 
1919b842f2ecSJim Ingham     const size_t argc = command.GetArgumentCount();
1920b842f2ecSJim Ingham     if (argc == 0) {
1921b842f2ecSJim Ingham       result.AppendError("No names provided.");
1922b842f2ecSJim Ingham       result.SetStatus(eReturnStatusFailed);
1923b842f2ecSJim Ingham       return false;
1924b842f2ecSJim Ingham     }
1925b842f2ecSJim Ingham 
1926b842f2ecSJim Ingham     Target *target =
1927b842f2ecSJim Ingham         GetSelectedOrDummyTarget(false);
1928b842f2ecSJim Ingham 
1929b842f2ecSJim Ingham     if (target == nullptr) {
1930b842f2ecSJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
1931b842f2ecSJim Ingham       result.SetStatus(eReturnStatusFailed);
1932b842f2ecSJim Ingham       return false;
1933b842f2ecSJim Ingham     }
1934b842f2ecSJim Ingham 
1935b842f2ecSJim Ingham     std::unique_lock<std::recursive_mutex> lock;
1936b842f2ecSJim Ingham     target->GetBreakpointList().GetListMutex(lock);
1937b842f2ecSJim Ingham 
1938b842f2ecSJim Ingham     // Make a pass through first to see that all the names are legal.
1939b842f2ecSJim Ingham     for (auto &entry : command.entries()) {
1940b842f2ecSJim Ingham       Status error;
1941b842f2ecSJim Ingham       if (!BreakpointID::StringIsBreakpointName(entry.ref, error))
1942b842f2ecSJim Ingham       {
1943b842f2ecSJim Ingham         result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s",
1944b842f2ecSJim Ingham                                      entry.c_str(), error.AsCString());
1945b842f2ecSJim Ingham         result.SetStatus(eReturnStatusFailed);
1946b842f2ecSJim Ingham         return false;
1947b842f2ecSJim Ingham       }
1948b842f2ecSJim Ingham     }
194905097246SAdrian Prantl     // Now configure them, we already pre-checked the names so we don't need to
195005097246SAdrian Prantl     // check the error:
1951b842f2ecSJim Ingham     BreakpointSP bp_sp;
1952b842f2ecSJim Ingham     if (m_bp_id.m_breakpoint.OptionWasSet())
1953b842f2ecSJim Ingham     {
1954b842f2ecSJim Ingham       lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value();
1955b842f2ecSJim Ingham       bp_sp = target->GetBreakpointByID(bp_id);
1956b842f2ecSJim Ingham       if (!bp_sp)
1957b842f2ecSJim Ingham       {
1958b842f2ecSJim Ingham         result.AppendErrorWithFormatv("Could not find specified breakpoint {0}",
1959b842f2ecSJim Ingham                            bp_id);
1960b842f2ecSJim Ingham         result.SetStatus(eReturnStatusFailed);
1961b842f2ecSJim Ingham         return false;
1962b842f2ecSJim Ingham       }
1963b842f2ecSJim Ingham     }
1964b842f2ecSJim Ingham 
1965b842f2ecSJim Ingham     Status error;
1966b842f2ecSJim Ingham     for (auto &entry : command.entries()) {
1967b842f2ecSJim Ingham       ConstString name(entry.c_str());
1968b842f2ecSJim Ingham       BreakpointName *bp_name = target->FindBreakpointName(name, true, error);
1969b842f2ecSJim Ingham       if (!bp_name)
1970b842f2ecSJim Ingham         continue;
1971e9632ebaSJim Ingham       if (m_bp_id.m_help_string.OptionWasSet())
1972e9632ebaSJim Ingham         bp_name->SetHelp(m_bp_id.m_help_string.GetStringValue().str().c_str());
1973e9632ebaSJim Ingham 
1974b842f2ecSJim Ingham       if (bp_sp)
1975b842f2ecSJim Ingham         target->ConfigureBreakpointName(*bp_name,
1976b842f2ecSJim Ingham                                        *bp_sp->GetOptions(),
1977b842f2ecSJim Ingham                                        m_access_options.GetPermissions());
1978b842f2ecSJim Ingham       else
1979b842f2ecSJim Ingham         target->ConfigureBreakpointName(*bp_name,
1980b842f2ecSJim Ingham                                        m_bp_opts.GetBreakpointOptions(),
1981b842f2ecSJim Ingham                                        m_access_options.GetPermissions());
1982b842f2ecSJim Ingham     }
1983b842f2ecSJim Ingham     return true;
1984b842f2ecSJim Ingham   }
1985b842f2ecSJim Ingham 
1986b842f2ecSJim Ingham private:
1987b842f2ecSJim Ingham   BreakpointNameOptionGroup m_bp_id; // Only using the id part of this.
1988b842f2ecSJim Ingham   BreakpointOptionGroup m_bp_opts;
1989b842f2ecSJim Ingham   BreakpointAccessOptionGroup m_access_options;
1990b842f2ecSJim Ingham   OptionGroupOptions m_option_group;
1991b842f2ecSJim Ingham };
1992b842f2ecSJim Ingham 
1993b9c1b51eSKate Stone class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
19945e09c8c3SJim Ingham public:
1995b9c1b51eSKate Stone   CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter)
1996b9c1b51eSKate Stone       : CommandObjectParsed(
1997b9c1b51eSKate Stone             interpreter, "add", "Add a name to the breakpoints provided.",
19985e09c8c3SJim Ingham             "breakpoint name add <command-options> <breakpoint-id-list>"),
1999b9c1b51eSKate Stone         m_name_options(), m_option_group() {
2000b9c1b51eSKate Stone     // Create the first variant for the first (and only) argument for this
2001b9c1b51eSKate Stone     // command.
20025e09c8c3SJim Ingham     CommandArgumentEntry arg1;
20035e09c8c3SJim Ingham     CommandArgumentData id_arg;
20045e09c8c3SJim Ingham     id_arg.arg_type = eArgTypeBreakpointID;
20055e09c8c3SJim Ingham     id_arg.arg_repetition = eArgRepeatOptional;
20065e09c8c3SJim Ingham     arg1.push_back(id_arg);
20075e09c8c3SJim Ingham     m_arguments.push_back(arg1);
20085e09c8c3SJim Ingham 
20095e09c8c3SJim Ingham     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
20105e09c8c3SJim Ingham     m_option_group.Finalize();
20115e09c8c3SJim Ingham   }
20125e09c8c3SJim Ingham 
20139e85e5a8SEugene Zelenko   ~CommandObjectBreakpointNameAdd() override = default;
20145e09c8c3SJim Ingham 
2015b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
20165e09c8c3SJim Ingham 
20175e09c8c3SJim Ingham protected:
2018b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
2019b9c1b51eSKate Stone     if (!m_name_options.m_name.OptionWasSet()) {
20205e09c8c3SJim Ingham       result.SetError("No name option provided.");
20215e09c8c3SJim Ingham       return false;
20225e09c8c3SJim Ingham     }
20235e09c8c3SJim Ingham 
2024b9c1b51eSKate Stone     Target *target =
2025b9c1b51eSKate Stone         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
20265e09c8c3SJim Ingham 
2027b9c1b51eSKate Stone     if (target == nullptr) {
20285e09c8c3SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
20295e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
20305e09c8c3SJim Ingham       return false;
20315e09c8c3SJim Ingham     }
20325e09c8c3SJim Ingham 
2033bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
2034bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
20355e09c8c3SJim Ingham 
20365e09c8c3SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
20375e09c8c3SJim Ingham 
20385e09c8c3SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
2039b9c1b51eSKate Stone     if (num_breakpoints == 0) {
20405e09c8c3SJim Ingham       result.SetError("No breakpoints, cannot add names.");
20415e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
20425e09c8c3SJim Ingham       return false;
20435e09c8c3SJim Ingham     }
20445e09c8c3SJim Ingham 
20455e09c8c3SJim Ingham     // Particular breakpoint selected; disable that breakpoint.
20465e09c8c3SJim Ingham     BreakpointIDList valid_bp_ids;
2047b9c1b51eSKate Stone     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2048b842f2ecSJim Ingham         command, target, result, &valid_bp_ids,
2049b842f2ecSJim Ingham         BreakpointName::Permissions::PermissionKinds::listPerm);
20505e09c8c3SJim Ingham 
2051b9c1b51eSKate Stone     if (result.Succeeded()) {
2052b9c1b51eSKate Stone       if (valid_bp_ids.GetSize() == 0) {
20535e09c8c3SJim Ingham         result.SetError("No breakpoints specified, cannot add names.");
20545e09c8c3SJim Ingham         result.SetStatus(eReturnStatusFailed);
20555e09c8c3SJim Ingham         return false;
20565e09c8c3SJim Ingham       }
20575e09c8c3SJim Ingham       size_t num_valid_ids = valid_bp_ids.GetSize();
2058b842f2ecSJim Ingham       const char *bp_name = m_name_options.m_name.GetCurrentValue();
2059b842f2ecSJim Ingham       Status error; // This error reports illegal names, but we've already
2060b842f2ecSJim Ingham                     // checked that, so we don't need to check it again here.
2061b9c1b51eSKate Stone       for (size_t index = 0; index < num_valid_ids; index++) {
2062b9c1b51eSKate Stone         lldb::break_id_t bp_id =
2063b9c1b51eSKate Stone             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
20645e09c8c3SJim Ingham         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
2065b842f2ecSJim Ingham         target->AddNameToBreakpoint(bp_sp, bp_name, error);
20665e09c8c3SJim Ingham       }
20675e09c8c3SJim Ingham     }
20685e09c8c3SJim Ingham 
20695e09c8c3SJim Ingham     return true;
20705e09c8c3SJim Ingham   }
20715e09c8c3SJim Ingham 
20725e09c8c3SJim Ingham private:
20735e09c8c3SJim Ingham   BreakpointNameOptionGroup m_name_options;
20745e09c8c3SJim Ingham   OptionGroupOptions m_option_group;
20755e09c8c3SJim Ingham };
20765e09c8c3SJim Ingham 
2077b9c1b51eSKate Stone class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
20785e09c8c3SJim Ingham public:
2079b9c1b51eSKate Stone   CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter)
2080b9c1b51eSKate Stone       : CommandObjectParsed(
2081b9c1b51eSKate Stone             interpreter, "delete",
20825e09c8c3SJim Ingham             "Delete a name from the breakpoints provided.",
20835e09c8c3SJim Ingham             "breakpoint name delete <command-options> <breakpoint-id-list>"),
2084b9c1b51eSKate Stone         m_name_options(), m_option_group() {
2085b9c1b51eSKate Stone     // Create the first variant for the first (and only) argument for this
2086b9c1b51eSKate Stone     // command.
20875e09c8c3SJim Ingham     CommandArgumentEntry arg1;
20885e09c8c3SJim Ingham     CommandArgumentData id_arg;
20895e09c8c3SJim Ingham     id_arg.arg_type = eArgTypeBreakpointID;
20905e09c8c3SJim Ingham     id_arg.arg_repetition = eArgRepeatOptional;
20915e09c8c3SJim Ingham     arg1.push_back(id_arg);
20925e09c8c3SJim Ingham     m_arguments.push_back(arg1);
20935e09c8c3SJim Ingham 
20945e09c8c3SJim Ingham     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
20955e09c8c3SJim Ingham     m_option_group.Finalize();
20965e09c8c3SJim Ingham   }
20975e09c8c3SJim Ingham 
20989e85e5a8SEugene Zelenko   ~CommandObjectBreakpointNameDelete() override = default;
20995e09c8c3SJim Ingham 
2100b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
21015e09c8c3SJim Ingham 
21025e09c8c3SJim Ingham protected:
2103b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
2104b9c1b51eSKate Stone     if (!m_name_options.m_name.OptionWasSet()) {
21055e09c8c3SJim Ingham       result.SetError("No name option provided.");
21065e09c8c3SJim Ingham       return false;
21075e09c8c3SJim Ingham     }
21085e09c8c3SJim Ingham 
2109b9c1b51eSKate Stone     Target *target =
2110b9c1b51eSKate Stone         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
21115e09c8c3SJim Ingham 
2112b9c1b51eSKate Stone     if (target == nullptr) {
21135e09c8c3SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
21145e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
21155e09c8c3SJim Ingham       return false;
21165e09c8c3SJim Ingham     }
21175e09c8c3SJim Ingham 
2118bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
2119bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
21205e09c8c3SJim Ingham 
21215e09c8c3SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
21225e09c8c3SJim Ingham 
21235e09c8c3SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
2124b9c1b51eSKate Stone     if (num_breakpoints == 0) {
21255e09c8c3SJim Ingham       result.SetError("No breakpoints, cannot delete names.");
21265e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
21275e09c8c3SJim Ingham       return false;
21285e09c8c3SJim Ingham     }
21295e09c8c3SJim Ingham 
21305e09c8c3SJim Ingham     // Particular breakpoint selected; disable that breakpoint.
21315e09c8c3SJim Ingham     BreakpointIDList valid_bp_ids;
2132b9c1b51eSKate Stone     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2133b842f2ecSJim Ingham         command, target, result, &valid_bp_ids,
2134b842f2ecSJim Ingham         BreakpointName::Permissions::PermissionKinds::deletePerm);
21355e09c8c3SJim Ingham 
2136b9c1b51eSKate Stone     if (result.Succeeded()) {
2137b9c1b51eSKate Stone       if (valid_bp_ids.GetSize() == 0) {
21385e09c8c3SJim Ingham         result.SetError("No breakpoints specified, cannot delete names.");
21395e09c8c3SJim Ingham         result.SetStatus(eReturnStatusFailed);
21405e09c8c3SJim Ingham         return false;
21415e09c8c3SJim Ingham       }
2142b842f2ecSJim Ingham       ConstString bp_name(m_name_options.m_name.GetCurrentValue());
21435e09c8c3SJim Ingham       size_t num_valid_ids = valid_bp_ids.GetSize();
2144b9c1b51eSKate Stone       for (size_t index = 0; index < num_valid_ids; index++) {
2145b9c1b51eSKate Stone         lldb::break_id_t bp_id =
2146b9c1b51eSKate Stone             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
21475e09c8c3SJim Ingham         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
2148b842f2ecSJim Ingham         target->RemoveNameFromBreakpoint(bp_sp, bp_name);
21495e09c8c3SJim Ingham       }
21505e09c8c3SJim Ingham     }
21515e09c8c3SJim Ingham 
21525e09c8c3SJim Ingham     return true;
21535e09c8c3SJim Ingham   }
21545e09c8c3SJim Ingham 
21555e09c8c3SJim Ingham private:
21565e09c8c3SJim Ingham   BreakpointNameOptionGroup m_name_options;
21575e09c8c3SJim Ingham   OptionGroupOptions m_option_group;
21585e09c8c3SJim Ingham };
21595e09c8c3SJim Ingham 
2160b9c1b51eSKate Stone class CommandObjectBreakpointNameList : public CommandObjectParsed {
21615e09c8c3SJim Ingham public:
2162b9c1b51eSKate Stone   CommandObjectBreakpointNameList(CommandInterpreter &interpreter)
2163b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "list",
2164b842f2ecSJim Ingham                             "List either the names for a breakpoint or info "
2165b842f2ecSJim Ingham                             "about a given name.  With no arguments, lists all "
2166b842f2ecSJim Ingham                             "names",
21675e09c8c3SJim Ingham                             "breakpoint name list <command-options>"),
2168b9c1b51eSKate Stone         m_name_options(), m_option_group() {
2169b842f2ecSJim Ingham     m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL);
21705e09c8c3SJim Ingham     m_option_group.Finalize();
21715e09c8c3SJim Ingham   }
21725e09c8c3SJim Ingham 
21739e85e5a8SEugene Zelenko   ~CommandObjectBreakpointNameList() override = default;
21745e09c8c3SJim Ingham 
2175b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
21765e09c8c3SJim Ingham 
21775e09c8c3SJim Ingham protected:
2178b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
2179b9c1b51eSKate Stone     Target *target =
2180b9c1b51eSKate Stone         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
21815e09c8c3SJim Ingham 
2182b9c1b51eSKate Stone     if (target == nullptr) {
21835e09c8c3SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
21845e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
21855e09c8c3SJim Ingham       return false;
21865e09c8c3SJim Ingham     }
21875e09c8c3SJim Ingham 
2188b842f2ecSJim Ingham 
2189b842f2ecSJim Ingham     std::vector<std::string> name_list;
2190b842f2ecSJim Ingham     if (command.empty()) {
2191b842f2ecSJim Ingham       target->GetBreakpointNames(name_list);
2192b842f2ecSJim Ingham     } else {
2193b842f2ecSJim Ingham       for (const Args::ArgEntry &arg : command)
2194b842f2ecSJim Ingham       {
2195b842f2ecSJim Ingham         name_list.push_back(arg.c_str());
2196b842f2ecSJim Ingham       }
2197b842f2ecSJim Ingham     }
2198b842f2ecSJim Ingham 
2199b842f2ecSJim Ingham     if (name_list.empty()) {
2200b842f2ecSJim Ingham       result.AppendMessage("No breakpoint names found.");
2201b842f2ecSJim Ingham     } else {
2202b842f2ecSJim Ingham       for (const std::string &name_str : name_list) {
2203b842f2ecSJim Ingham         const char *name = name_str.c_str();
2204b842f2ecSJim Ingham         // First print out the options for the name:
2205b842f2ecSJim Ingham         Status error;
2206b842f2ecSJim Ingham         BreakpointName *bp_name = target->FindBreakpointName(ConstString(name),
2207b842f2ecSJim Ingham                                                              false,
2208b842f2ecSJim Ingham                                                              error);
2209b842f2ecSJim Ingham         if (bp_name)
2210b842f2ecSJim Ingham         {
2211b842f2ecSJim Ingham           StreamString s;
2212b842f2ecSJim Ingham           result.AppendMessageWithFormat("Name: %s\n", name);
2213b842f2ecSJim Ingham           if (bp_name->GetDescription(&s, eDescriptionLevelFull))
2214b842f2ecSJim Ingham           {
2215b842f2ecSJim Ingham             result.AppendMessage(s.GetString());
2216b842f2ecSJim Ingham           }
2217b842f2ecSJim Ingham 
2218bb19a13cSSaleem Abdulrasool           std::unique_lock<std::recursive_mutex> lock;
2219bb19a13cSSaleem Abdulrasool           target->GetBreakpointList().GetListMutex(lock);
22205e09c8c3SJim Ingham 
22215e09c8c3SJim Ingham           BreakpointList &breakpoints = target->GetBreakpointList();
2222b842f2ecSJim Ingham           bool any_set = false;
2223b9c1b51eSKate Stone           for (BreakpointSP bp_sp : breakpoints.Breakpoints()) {
2224b9c1b51eSKate Stone             if (bp_sp->MatchesName(name)) {
22255e09c8c3SJim Ingham               StreamString s;
2226b842f2ecSJim Ingham               any_set = true;
22275e09c8c3SJim Ingham               bp_sp->GetDescription(&s, eDescriptionLevelBrief);
22285e09c8c3SJim Ingham               s.EOL();
2229c156427dSZachary Turner               result.AppendMessage(s.GetString());
22305e09c8c3SJim Ingham             }
22315e09c8c3SJim Ingham           }
2232b842f2ecSJim Ingham           if (!any_set)
2233b842f2ecSJim Ingham             result.AppendMessage("No breakpoints using this name.");
2234b9c1b51eSKate Stone         } else {
2235b842f2ecSJim Ingham           result.AppendMessageWithFormat("Name: %s not found.\n", name);
22365e09c8c3SJim Ingham         }
2237b842f2ecSJim Ingham       }
22385e09c8c3SJim Ingham     }
22395e09c8c3SJim Ingham     return true;
22405e09c8c3SJim Ingham   }
22415e09c8c3SJim Ingham 
22425e09c8c3SJim Ingham private:
22435e09c8c3SJim Ingham   BreakpointNameOptionGroup m_name_options;
22445e09c8c3SJim Ingham   OptionGroupOptions m_option_group;
22455e09c8c3SJim Ingham };
22465e09c8c3SJim Ingham 
22475e09c8c3SJim Ingham //-------------------------------------------------------------------------
2248e14dc268SJim Ingham // CommandObjectBreakpointName
22495e09c8c3SJim Ingham //-------------------------------------------------------------------------
2250b9c1b51eSKate Stone class CommandObjectBreakpointName : public CommandObjectMultiword {
22515e09c8c3SJim Ingham public:
22527428a18cSKate Stone   CommandObjectBreakpointName(CommandInterpreter &interpreter)
2253b9c1b51eSKate Stone       : CommandObjectMultiword(
2254b9c1b51eSKate Stone             interpreter, "name", "Commands to manage name tags for breakpoints",
2255b9c1b51eSKate Stone             "breakpoint name <subcommand> [<command-options>]") {
2256b9c1b51eSKate Stone     CommandObjectSP add_command_object(
2257b9c1b51eSKate Stone         new CommandObjectBreakpointNameAdd(interpreter));
2258b9c1b51eSKate Stone     CommandObjectSP delete_command_object(
2259b9c1b51eSKate Stone         new CommandObjectBreakpointNameDelete(interpreter));
2260b9c1b51eSKate Stone     CommandObjectSP list_command_object(
2261b9c1b51eSKate Stone         new CommandObjectBreakpointNameList(interpreter));
2262b842f2ecSJim Ingham     CommandObjectSP configure_command_object(
2263b842f2ecSJim Ingham         new CommandObjectBreakpointNameConfigure(interpreter));
22645e09c8c3SJim Ingham 
22655e09c8c3SJim Ingham     LoadSubCommand("add", add_command_object);
22665e09c8c3SJim Ingham     LoadSubCommand("delete", delete_command_object);
22675e09c8c3SJim Ingham     LoadSubCommand("list", list_command_object);
2268b842f2ecSJim Ingham     LoadSubCommand("configure", configure_command_object);
22695e09c8c3SJim Ingham   }
22705e09c8c3SJim Ingham 
22719e85e5a8SEugene Zelenko   ~CommandObjectBreakpointName() override = default;
22725e09c8c3SJim Ingham };
22735e09c8c3SJim Ingham 
22745e09c8c3SJim Ingham //-------------------------------------------------------------------------
2275e14dc268SJim Ingham // CommandObjectBreakpointRead
2276e14dc268SJim Ingham //-------------------------------------------------------------------------
22773acdf385SJim Ingham #pragma mark Read::CommandOptions
22788fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_read_options[] = {
22791f0f5b5bSZachary Turner     // clang-format off
22808fe53c49STatyana Krasnukha   {LLDB_OPT_SET_ALL, true,  "file",                   'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,       "The file from which to read the breakpoints." },
22818fe53c49STatyana Krasnukha   {LLDB_OPT_SET_ALL, false, "breakpoint-name",        'N', OptionParser::eRequiredArgument, nullptr, {}, 0,                                       eArgTypeBreakpointName, "Only read in breakpoints with this name."},
22821f0f5b5bSZachary Turner     // clang-format on
22831f0f5b5bSZachary Turner };
22841f0f5b5bSZachary Turner 
22851f0f5b5bSZachary Turner #pragma mark Read
2286e14dc268SJim Ingham 
2287e14dc268SJim Ingham class CommandObjectBreakpointRead : public CommandObjectParsed {
2288e14dc268SJim Ingham public:
2289e14dc268SJim Ingham   CommandObjectBreakpointRead(CommandInterpreter &interpreter)
2290e14dc268SJim Ingham       : CommandObjectParsed(interpreter, "breakpoint read",
2291e14dc268SJim Ingham                             "Read and set the breakpoints previously saved to "
2292e14dc268SJim Ingham                             "a file with \"breakpoint write\".  ",
2293e14dc268SJim Ingham                             nullptr),
2294e14dc268SJim Ingham         m_options() {
2295e14dc268SJim Ingham     CommandArgumentEntry arg;
2296e14dc268SJim Ingham     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2297e14dc268SJim Ingham                                       eArgTypeBreakpointIDRange);
2298e14dc268SJim Ingham     // Add the entry for the first argument for this command to the object's
2299e14dc268SJim Ingham     // arguments vector.
2300e14dc268SJim Ingham     m_arguments.push_back(arg);
2301e14dc268SJim Ingham   }
2302e14dc268SJim Ingham 
2303e14dc268SJim Ingham   ~CommandObjectBreakpointRead() override = default;
2304e14dc268SJim Ingham 
2305e14dc268SJim Ingham   Options *GetOptions() override { return &m_options; }
2306e14dc268SJim Ingham 
2307e14dc268SJim Ingham   class CommandOptions : public Options {
2308e14dc268SJim Ingham   public:
2309e14dc268SJim Ingham     CommandOptions() : Options() {}
2310e14dc268SJim Ingham 
2311e14dc268SJim Ingham     ~CommandOptions() override = default;
2312e14dc268SJim Ingham 
231397206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2314e14dc268SJim Ingham                           ExecutionContext *execution_context) override {
231597206d57SZachary Turner       Status error;
2316e14dc268SJim Ingham       const int short_option = m_getopt_table[option_idx].val;
2317e14dc268SJim Ingham 
2318e14dc268SJim Ingham       switch (short_option) {
2319e14dc268SJim Ingham       case 'f':
2320e14dc268SJim Ingham         m_filename.assign(option_arg);
2321e14dc268SJim Ingham         break;
23223acdf385SJim Ingham       case 'N': {
232397206d57SZachary Turner         Status name_error;
23243acdf385SJim Ingham         if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg),
23253acdf385SJim Ingham                                                   name_error)) {
23263acdf385SJim Ingham           error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
23273acdf385SJim Ingham                                          name_error.AsCString());
23283acdf385SJim Ingham         }
23293acdf385SJim Ingham         m_names.push_back(option_arg);
23303acdf385SJim Ingham         break;
23313acdf385SJim Ingham       }
2332e14dc268SJim Ingham       default:
2333e14dc268SJim Ingham         error.SetErrorStringWithFormat("unrecognized option '%c'",
2334e14dc268SJim Ingham                                        short_option);
2335e14dc268SJim Ingham         break;
2336e14dc268SJim Ingham       }
2337e14dc268SJim Ingham 
2338e14dc268SJim Ingham       return error;
2339e14dc268SJim Ingham     }
2340e14dc268SJim Ingham 
2341e14dc268SJim Ingham     void OptionParsingStarting(ExecutionContext *execution_context) override {
2342e14dc268SJim Ingham       m_filename.clear();
23433acdf385SJim Ingham       m_names.clear();
2344e14dc268SJim Ingham     }
2345e14dc268SJim Ingham 
23461f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
234770602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_read_options);
23481f0f5b5bSZachary Turner     }
2349e14dc268SJim Ingham 
2350e14dc268SJim Ingham     // Instance variables to hold the values for command options.
2351e14dc268SJim Ingham 
2352e14dc268SJim Ingham     std::string m_filename;
23533acdf385SJim Ingham     std::vector<std::string> m_names;
2354e14dc268SJim Ingham   };
2355e14dc268SJim Ingham 
2356e14dc268SJim Ingham protected:
2357e14dc268SJim Ingham   bool DoExecute(Args &command, CommandReturnObject &result) override {
2358e14dc268SJim Ingham     Target *target = GetSelectedOrDummyTarget();
2359e14dc268SJim Ingham     if (target == nullptr) {
2360e14dc268SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
2361e14dc268SJim Ingham       result.SetStatus(eReturnStatusFailed);
2362e14dc268SJim Ingham       return false;
2363e14dc268SJim Ingham     }
2364e14dc268SJim Ingham 
23653acdf385SJim Ingham     std::unique_lock<std::recursive_mutex> lock;
23663acdf385SJim Ingham     target->GetBreakpointList().GetListMutex(lock);
23673acdf385SJim Ingham 
23688f3be7a3SJonas Devlieghere     FileSpec input_spec(m_options.m_filename);
23698f3be7a3SJonas Devlieghere     FileSystem::Instance().Resolve(input_spec);
237001f16664SJim Ingham     BreakpointIDList new_bps;
237197206d57SZachary Turner     Status error = target->CreateBreakpointsFromFile(
237297206d57SZachary Turner         input_spec, m_options.m_names, new_bps);
2373e14dc268SJim Ingham 
2374e14dc268SJim Ingham     if (!error.Success()) {
237501f16664SJim Ingham       result.AppendError(error.AsCString());
2376e14dc268SJim Ingham       result.SetStatus(eReturnStatusFailed);
237701f16664SJim Ingham       return false;
2378e14dc268SJim Ingham     }
23793acdf385SJim Ingham 
23803acdf385SJim Ingham     Stream &output_stream = result.GetOutputStream();
23813acdf385SJim Ingham 
23823acdf385SJim Ingham     size_t num_breakpoints = new_bps.GetSize();
23833acdf385SJim Ingham     if (num_breakpoints == 0) {
23843acdf385SJim Ingham       result.AppendMessage("No breakpoints added.");
23853acdf385SJim Ingham     } else {
23863acdf385SJim Ingham       // No breakpoint selected; show info about all currently set breakpoints.
23873acdf385SJim Ingham       result.AppendMessage("New breakpoints:");
23883acdf385SJim Ingham       for (size_t i = 0; i < num_breakpoints; ++i) {
23893acdf385SJim Ingham         BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i);
23903acdf385SJim Ingham         Breakpoint *bp = target->GetBreakpointList()
23913acdf385SJim Ingham                              .FindBreakpointByID(bp_id.GetBreakpointID())
23923acdf385SJim Ingham                              .get();
23933acdf385SJim Ingham         if (bp)
23943acdf385SJim Ingham           bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
23953acdf385SJim Ingham                              false);
23963acdf385SJim Ingham       }
23973acdf385SJim Ingham     }
2398e14dc268SJim Ingham     return result.Succeeded();
2399e14dc268SJim Ingham   }
2400e14dc268SJim Ingham 
2401e14dc268SJim Ingham private:
2402e14dc268SJim Ingham   CommandOptions m_options;
2403e14dc268SJim Ingham };
2404e14dc268SJim Ingham 
2405e14dc268SJim Ingham //-------------------------------------------------------------------------
2406e14dc268SJim Ingham // CommandObjectBreakpointWrite
2407e14dc268SJim Ingham //-------------------------------------------------------------------------
24081f0f5b5bSZachary Turner #pragma mark Write::CommandOptions
24098fe53c49STatyana Krasnukha static constexpr OptionDefinition g_breakpoint_write_options[] = {
24101f0f5b5bSZachary Turner     // clang-format off
24118fe53c49STatyana Krasnukha   { LLDB_OPT_SET_ALL, true,  "file",  'f', OptionParser::eRequiredArgument, nullptr, {}, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,    "The file into which to write the breakpoints." },
24128fe53c49STatyana Krasnukha   { LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument,       nullptr, {}, 0,                                       eArgTypeNone,        "Append to saved breakpoints file if it exists."},
24131f0f5b5bSZachary Turner     // clang-format on
24141f0f5b5bSZachary Turner };
24151f0f5b5bSZachary Turner 
24161f0f5b5bSZachary Turner #pragma mark Write
2417e14dc268SJim Ingham class CommandObjectBreakpointWrite : public CommandObjectParsed {
2418e14dc268SJim Ingham public:
2419e14dc268SJim Ingham   CommandObjectBreakpointWrite(CommandInterpreter &interpreter)
2420e14dc268SJim Ingham       : CommandObjectParsed(interpreter, "breakpoint write",
2421e14dc268SJim Ingham                             "Write the breakpoints listed to a file that can "
2422e14dc268SJim Ingham                             "be read in with \"breakpoint read\".  "
2423e14dc268SJim Ingham                             "If given no arguments, writes all breakpoints.",
2424e14dc268SJim Ingham                             nullptr),
2425e14dc268SJim Ingham         m_options() {
2426e14dc268SJim Ingham     CommandArgumentEntry arg;
2427e14dc268SJim Ingham     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2428e14dc268SJim Ingham                                       eArgTypeBreakpointIDRange);
2429e14dc268SJim Ingham     // Add the entry for the first argument for this command to the object's
2430e14dc268SJim Ingham     // arguments vector.
2431e14dc268SJim Ingham     m_arguments.push_back(arg);
2432e14dc268SJim Ingham   }
2433e14dc268SJim Ingham 
2434e14dc268SJim Ingham   ~CommandObjectBreakpointWrite() override = default;
2435e14dc268SJim Ingham 
2436e14dc268SJim Ingham   Options *GetOptions() override { return &m_options; }
2437e14dc268SJim Ingham 
2438e14dc268SJim Ingham   class CommandOptions : public Options {
2439e14dc268SJim Ingham   public:
2440e14dc268SJim Ingham     CommandOptions() : Options() {}
2441e14dc268SJim Ingham 
2442e14dc268SJim Ingham     ~CommandOptions() override = default;
2443e14dc268SJim Ingham 
244497206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2445e14dc268SJim Ingham                           ExecutionContext *execution_context) override {
244697206d57SZachary Turner       Status error;
2447e14dc268SJim Ingham       const int short_option = m_getopt_table[option_idx].val;
2448e14dc268SJim Ingham 
2449e14dc268SJim Ingham       switch (short_option) {
2450e14dc268SJim Ingham       case 'f':
2451e14dc268SJim Ingham         m_filename.assign(option_arg);
2452e14dc268SJim Ingham         break;
24532d3628e1SJim Ingham       case 'a':
24542d3628e1SJim Ingham         m_append = true;
24552d3628e1SJim Ingham         break;
2456e14dc268SJim Ingham       default:
2457e14dc268SJim Ingham         error.SetErrorStringWithFormat("unrecognized option '%c'",
2458e14dc268SJim Ingham                                        short_option);
2459e14dc268SJim Ingham         break;
2460e14dc268SJim Ingham       }
2461e14dc268SJim Ingham 
2462e14dc268SJim Ingham       return error;
2463e14dc268SJim Ingham     }
2464e14dc268SJim Ingham 
2465e14dc268SJim Ingham     void OptionParsingStarting(ExecutionContext *execution_context) override {
2466e14dc268SJim Ingham       m_filename.clear();
24672d3628e1SJim Ingham       m_append = false;
2468e14dc268SJim Ingham     }
2469e14dc268SJim Ingham 
24701f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
247170602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_write_options);
24721f0f5b5bSZachary Turner     }
2473e14dc268SJim Ingham 
2474e14dc268SJim Ingham     // Instance variables to hold the values for command options.
2475e14dc268SJim Ingham 
2476e14dc268SJim Ingham     std::string m_filename;
24772d3628e1SJim Ingham     bool m_append = false;
2478e14dc268SJim Ingham   };
2479e14dc268SJim Ingham 
2480e14dc268SJim Ingham protected:
2481e14dc268SJim Ingham   bool DoExecute(Args &command, CommandReturnObject &result) override {
2482e14dc268SJim Ingham     Target *target = GetSelectedOrDummyTarget();
2483e14dc268SJim Ingham     if (target == nullptr) {
2484e14dc268SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
2485e14dc268SJim Ingham       result.SetStatus(eReturnStatusFailed);
2486e14dc268SJim Ingham       return false;
2487e14dc268SJim Ingham     }
2488e14dc268SJim Ingham 
2489e14dc268SJim Ingham     std::unique_lock<std::recursive_mutex> lock;
2490e14dc268SJim Ingham     target->GetBreakpointList().GetListMutex(lock);
2491e14dc268SJim Ingham 
2492e14dc268SJim Ingham     BreakpointIDList valid_bp_ids;
249311eb9c64SZachary Turner     if (!command.empty()) {
2494e14dc268SJim Ingham       CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2495b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
2496b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::listPerm);
2497e14dc268SJim Ingham 
249801f16664SJim Ingham       if (!result.Succeeded()) {
2499e14dc268SJim Ingham         result.SetStatus(eReturnStatusFailed);
2500e14dc268SJim Ingham         return false;
2501e14dc268SJim Ingham       }
2502e14dc268SJim Ingham     }
25038f3be7a3SJonas Devlieghere     FileSpec file_spec(m_options.m_filename);
25048f3be7a3SJonas Devlieghere     FileSystem::Instance().Resolve(file_spec);
25058f3be7a3SJonas Devlieghere     Status error = target->SerializeBreakpointsToFile(file_spec, valid_bp_ids,
25068f3be7a3SJonas Devlieghere                                                       m_options.m_append);
250701f16664SJim Ingham     if (!error.Success()) {
250801f16664SJim Ingham       result.AppendErrorWithFormat("error serializing breakpoints: %s.",
250901f16664SJim Ingham                                    error.AsCString());
251001f16664SJim Ingham       result.SetStatus(eReturnStatusFailed);
2511e14dc268SJim Ingham     }
2512e14dc268SJim Ingham     return result.Succeeded();
2513e14dc268SJim Ingham   }
2514e14dc268SJim Ingham 
2515e14dc268SJim Ingham private:
2516e14dc268SJim Ingham   CommandOptions m_options;
2517e14dc268SJim Ingham };
2518e14dc268SJim Ingham 
2519e14dc268SJim Ingham //-------------------------------------------------------------------------
252030fdc8d8SChris Lattner // CommandObjectMultiwordBreakpoint
252130fdc8d8SChris Lattner //-------------------------------------------------------------------------
2522ae1c4cf5SJim Ingham #pragma mark MultiwordBreakpoint
252330fdc8d8SChris Lattner 
2524b9c1b51eSKate Stone CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
2525b9c1b51eSKate Stone     CommandInterpreter &interpreter)
2526b9c1b51eSKate Stone     : CommandObjectMultiword(
2527b9c1b51eSKate Stone           interpreter, "breakpoint",
25287428a18cSKate Stone           "Commands for operating on breakpoints (see 'help b' for shorthand.)",
2529b9c1b51eSKate Stone           "breakpoint <subcommand> [<command-options>]") {
2530b9c1b51eSKate Stone   CommandObjectSP list_command_object(
2531b9c1b51eSKate Stone       new CommandObjectBreakpointList(interpreter));
2532b9c1b51eSKate Stone   CommandObjectSP enable_command_object(
2533b9c1b51eSKate Stone       new CommandObjectBreakpointEnable(interpreter));
2534b9c1b51eSKate Stone   CommandObjectSP disable_command_object(
2535b9c1b51eSKate Stone       new CommandObjectBreakpointDisable(interpreter));
2536b9c1b51eSKate Stone   CommandObjectSP clear_command_object(
2537b9c1b51eSKate Stone       new CommandObjectBreakpointClear(interpreter));
2538b9c1b51eSKate Stone   CommandObjectSP delete_command_object(
2539b9c1b51eSKate Stone       new CommandObjectBreakpointDelete(interpreter));
2540b9c1b51eSKate Stone   CommandObjectSP set_command_object(
2541b9c1b51eSKate Stone       new CommandObjectBreakpointSet(interpreter));
2542b9c1b51eSKate Stone   CommandObjectSP command_command_object(
2543b9c1b51eSKate Stone       new CommandObjectBreakpointCommand(interpreter));
2544b9c1b51eSKate Stone   CommandObjectSP modify_command_object(
2545b9c1b51eSKate Stone       new CommandObjectBreakpointModify(interpreter));
2546b9c1b51eSKate Stone   CommandObjectSP name_command_object(
2547b9c1b51eSKate Stone       new CommandObjectBreakpointName(interpreter));
2548e14dc268SJim Ingham   CommandObjectSP write_command_object(
2549e14dc268SJim Ingham       new CommandObjectBreakpointWrite(interpreter));
2550e14dc268SJim Ingham   CommandObjectSP read_command_object(
2551e14dc268SJim Ingham       new CommandObjectBreakpointRead(interpreter));
255230fdc8d8SChris Lattner 
2553b7234e40SJohnny Chen   list_command_object->SetCommandName("breakpoint list");
255430fdc8d8SChris Lattner   enable_command_object->SetCommandName("breakpoint enable");
255530fdc8d8SChris Lattner   disable_command_object->SetCommandName("breakpoint disable");
2556b7234e40SJohnny Chen   clear_command_object->SetCommandName("breakpoint clear");
2557b7234e40SJohnny Chen   delete_command_object->SetCommandName("breakpoint delete");
2558ae1c4cf5SJim Ingham   set_command_object->SetCommandName("breakpoint set");
2559b7234e40SJohnny Chen   command_command_object->SetCommandName("breakpoint command");
2560b7234e40SJohnny Chen   modify_command_object->SetCommandName("breakpoint modify");
25615e09c8c3SJim Ingham   name_command_object->SetCommandName("breakpoint name");
2562e14dc268SJim Ingham   write_command_object->SetCommandName("breakpoint write");
2563e14dc268SJim Ingham   read_command_object->SetCommandName("breakpoint read");
256430fdc8d8SChris Lattner 
256523f59509SGreg Clayton   LoadSubCommand("list", list_command_object);
256623f59509SGreg Clayton   LoadSubCommand("enable", enable_command_object);
256723f59509SGreg Clayton   LoadSubCommand("disable", disable_command_object);
256823f59509SGreg Clayton   LoadSubCommand("clear", clear_command_object);
256923f59509SGreg Clayton   LoadSubCommand("delete", delete_command_object);
257023f59509SGreg Clayton   LoadSubCommand("set", set_command_object);
257123f59509SGreg Clayton   LoadSubCommand("command", command_command_object);
257223f59509SGreg Clayton   LoadSubCommand("modify", modify_command_object);
25735e09c8c3SJim Ingham   LoadSubCommand("name", name_command_object);
2574e14dc268SJim Ingham   LoadSubCommand("write", write_command_object);
2575e14dc268SJim Ingham   LoadSubCommand("read", read_command_object);
257630fdc8d8SChris Lattner }
257730fdc8d8SChris Lattner 
25789e85e5a8SEugene Zelenko CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
257930fdc8d8SChris Lattner 
2580b9c1b51eSKate Stone void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target,
25815e09c8c3SJim Ingham                                                  bool allow_locations,
25825e09c8c3SJim Ingham                                                  CommandReturnObject &result,
2583b842f2ecSJim Ingham                                                  BreakpointIDList *valid_ids,
2584b842f2ecSJim Ingham                                                  BreakpointName::Permissions
2585b842f2ecSJim Ingham                                                      ::PermissionKinds
2586b842f2ecSJim Ingham                                                      purpose) {
258730fdc8d8SChris Lattner   // args can be strings representing 1). integers (for breakpoint ids)
2588b9c1b51eSKate Stone   //                                  2). the full breakpoint & location
2589b9c1b51eSKate Stone   //                                  canonical representation
2590b9c1b51eSKate Stone   //                                  3). the word "to" or a hyphen,
2591b9c1b51eSKate Stone   //                                  representing a range (in which case there
2592b9c1b51eSKate Stone   //                                      had *better* be an entry both before &
2593b9c1b51eSKate Stone   //                                      after of one of the first two types.
25945e09c8c3SJim Ingham   //                                  4). A breakpoint name
2595b9c1b51eSKate Stone   // If args is empty, we will use the last created breakpoint (if there is
2596b9c1b51eSKate Stone   // one.)
259730fdc8d8SChris Lattner 
259830fdc8d8SChris Lattner   Args temp_args;
259930fdc8d8SChris Lattner 
260011eb9c64SZachary Turner   if (args.empty()) {
2601b9c1b51eSKate Stone     if (target->GetLastCreatedBreakpoint()) {
2602b9c1b51eSKate Stone       valid_ids->AddBreakpointID(BreakpointID(
2603b9c1b51eSKate Stone           target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
260436f3b369SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2605b9c1b51eSKate Stone     } else {
2606b9c1b51eSKate Stone       result.AppendError(
2607b9c1b51eSKate Stone           "No breakpoint specified and no last created breakpoint.");
260836f3b369SJim Ingham       result.SetStatus(eReturnStatusFailed);
260936f3b369SJim Ingham     }
261036f3b369SJim Ingham     return;
261136f3b369SJim Ingham   }
261236f3b369SJim Ingham 
2613b9c1b51eSKate Stone   // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff
261405097246SAdrian Prantl   // directly from the old ARGS to the new TEMP_ARGS.  Do not copy breakpoint
261505097246SAdrian Prantl   // id range strings over; instead generate a list of strings for all the
261605097246SAdrian Prantl   // breakpoint ids in the range, and shove all of those breakpoint id strings
261705097246SAdrian Prantl   // into TEMP_ARGS.
261830fdc8d8SChris Lattner 
2619b9c1b51eSKate Stone   BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations,
2620b842f2ecSJim Ingham                                            purpose, result, temp_args);
262130fdc8d8SChris Lattner 
2622b9c1b51eSKate Stone   // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual
2623b9c1b51eSKate Stone   // BreakpointIDList:
262430fdc8d8SChris Lattner 
262516662f3cSPavel Labath   valid_ids->InsertStringArray(temp_args.GetArgumentArrayRef(), result);
262630fdc8d8SChris Lattner 
262705097246SAdrian Prantl   // At this point,  all of the breakpoint ids that the user passed in have
262805097246SAdrian Prantl   // been converted to breakpoint IDs and put into valid_ids.
262930fdc8d8SChris Lattner 
2630b9c1b51eSKate Stone   if (result.Succeeded()) {
2631b9c1b51eSKate Stone     // Now that we've converted everything from args into a list of breakpoint
263205097246SAdrian Prantl     // ids, go through our tentative list of breakpoint id's and verify that
263305097246SAdrian Prantl     // they correspond to valid/currently set breakpoints.
263430fdc8d8SChris Lattner 
2635c982c768SGreg Clayton     const size_t count = valid_ids->GetSize();
2636b9c1b51eSKate Stone     for (size_t i = 0; i < count; ++i) {
263730fdc8d8SChris Lattner       BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i);
2638b9c1b51eSKate Stone       Breakpoint *breakpoint =
2639b9c1b51eSKate Stone           target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
2640b9c1b51eSKate Stone       if (breakpoint != nullptr) {
2641c7bece56SGreg Clayton         const size_t num_locations = breakpoint->GetNumLocations();
2642b9c1b51eSKate Stone         if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {
264330fdc8d8SChris Lattner           StreamString id_str;
2644b9c1b51eSKate Stone           BreakpointID::GetCanonicalReference(
2645b9c1b51eSKate Stone               &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
2646c982c768SGreg Clayton           i = valid_ids->GetSize() + 1;
2647b9c1b51eSKate Stone           result.AppendErrorWithFormat(
2648b9c1b51eSKate Stone               "'%s' is not a currently valid breakpoint/location id.\n",
264930fdc8d8SChris Lattner               id_str.GetData());
265030fdc8d8SChris Lattner           result.SetStatus(eReturnStatusFailed);
265130fdc8d8SChris Lattner         }
2652b9c1b51eSKate Stone       } else {
2653c982c768SGreg Clayton         i = valid_ids->GetSize() + 1;
2654b9c1b51eSKate Stone         result.AppendErrorWithFormat(
2655b9c1b51eSKate Stone             "'%d' is not a currently valid breakpoint ID.\n",
26567428a18cSKate Stone             cur_bp_id.GetBreakpointID());
265730fdc8d8SChris Lattner         result.SetStatus(eReturnStatusFailed);
265830fdc8d8SChris Lattner       }
265930fdc8d8SChris Lattner     }
266030fdc8d8SChris Lattner   }
266130fdc8d8SChris Lattner }
2662