130fdc8d8SChris Lattner //===-- CommandObjectBreakpoint.cpp -----------------------------*- C++ -*-===//
230fdc8d8SChris Lattner //
330fdc8d8SChris Lattner //                     The LLVM Compiler Infrastructure
430fdc8d8SChris Lattner //
530fdc8d8SChris Lattner // This file is distributed under the University of Illinois Open Source
630fdc8d8SChris Lattner // License. See LICENSE.TXT for details.
730fdc8d8SChris Lattner //
830fdc8d8SChris Lattner //===----------------------------------------------------------------------===//
930fdc8d8SChris Lattner 
1030fdc8d8SChris Lattner // C Includes
1130fdc8d8SChris Lattner // C++ Includes
129e85e5a8SEugene Zelenko #include <vector>
139e85e5a8SEugene Zelenko 
1430fdc8d8SChris Lattner // Other libraries and framework includes
1530fdc8d8SChris Lattner // Project includes
169e85e5a8SEugene Zelenko #include "CommandObjectBreakpoint.h"
179e85e5a8SEugene Zelenko #include "CommandObjectBreakpointCommand.h"
1830fdc8d8SChris Lattner #include "lldb/Breakpoint/Breakpoint.h"
1930fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointIDList.h"
2030fdc8d8SChris Lattner #include "lldb/Breakpoint/BreakpointLocation.h"
213eb2b44dSZachary Turner #include "lldb/Host/OptionParser.h"
22b9c1b51eSKate Stone #include "lldb/Interpreter/CommandCompletions.h"
23b9c1b51eSKate Stone #include "lldb/Interpreter/CommandInterpreter.h"
24b9c1b51eSKate Stone #include "lldb/Interpreter/CommandReturnObject.h"
2532abc6edSZachary Turner #include "lldb/Interpreter/OptionValueBoolean.h"
265e09c8c3SJim Ingham #include "lldb/Interpreter/OptionValueString.h"
275e09c8c3SJim Ingham #include "lldb/Interpreter/OptionValueUInt64.h"
28b9c1b51eSKate Stone #include "lldb/Interpreter/Options.h"
290e0984eeSJim Ingham #include "lldb/Target/Language.h"
30b57e4a1bSJason Molenda #include "lldb/Target/StackFrame.h"
31b9c1b51eSKate Stone #include "lldb/Target/Target.h"
321b54c88cSJim Ingham #include "lldb/Target/Thread.h"
331b54c88cSJim Ingham #include "lldb/Target/ThreadSpec.h"
34bf9a7730SZachary Turner #include "lldb/Utility/RegularExpression.h"
35bf9a7730SZachary Turner #include "lldb/Utility/StreamString.h"
3630fdc8d8SChris Lattner 
3730fdc8d8SChris Lattner using namespace lldb;
3830fdc8d8SChris Lattner using namespace lldb_private;
3930fdc8d8SChris Lattner 
40b9c1b51eSKate Stone static void AddBreakpointDescription(Stream *s, Breakpoint *bp,
41b9c1b51eSKate Stone                                      lldb::DescriptionLevel level) {
4230fdc8d8SChris Lattner   s->IndentMore();
4330fdc8d8SChris Lattner   bp->GetDescription(s, level, true);
4430fdc8d8SChris Lattner   s->IndentLess();
4530fdc8d8SChris Lattner   s->EOL();
4630fdc8d8SChris Lattner }
4730fdc8d8SChris Lattner 
48*b842f2ecSJim Ingham //-------------------------------------------------------------------------
49*b842f2ecSJim Ingham // Modifiable Breakpoint Options
50*b842f2ecSJim Ingham //-------------------------------------------------------------------------
51*b842f2ecSJim Ingham #pragma mark Modify::CommandOptions
52*b842f2ecSJim Ingham static OptionDefinition g_breakpoint_modify_options[] = {
53*b842f2ecSJim Ingham     // clang-format off
54*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "ignore-count", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCount,       "Set the number of times this breakpoint is skipped before stopping." },
55*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "one-shot",     'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean,     "The breakpoint is deleted the first time it stop causes a stop." },
56*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "thread-index", 'x', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadIndex, "The breakpoint stops only for the thread whose index matches this argument." },
57*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "thread-id",    't', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadID,    "The breakpoint stops only for the thread whose TID matches this argument." },
58*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "thread-name",  'T', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeThreadName,  "The breakpoint stops only for the thread whose thread name matches this argument." },
59*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "queue-name",   'q', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeQueueName,   "The breakpoint stops only for threads in the queue whose name is given by this argument." },
60*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "condition",    'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeExpression,  "The breakpoint stops only if this condition expression evaluates to true." },
61*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "auto-continue",'G', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean,     "The breakpoint will auto-continue after running its commands." },
62*b842f2ecSJim Ingham   { LLDB_OPT_SET_2, false, "enable",       'e', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,        "Enable the breakpoint." },
63*b842f2ecSJim Ingham   { LLDB_OPT_SET_3, false, "disable",      'd', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,        "Disable the breakpoint." },
64*b842f2ecSJim Ingham   { LLDB_OPT_SET_4, false, "command",      'C', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommand,     "A command to run when the breakpoint is hit, can be provided more than once, the commands will get run in order left to right." },
65*b842f2ecSJim Ingham     // clang-format on
66*b842f2ecSJim Ingham };
67*b842f2ecSJim Ingham class lldb_private::BreakpointOptionGroup : public OptionGroup
68*b842f2ecSJim Ingham {
69*b842f2ecSJim Ingham public:
70*b842f2ecSJim Ingham   BreakpointOptionGroup() :
71*b842f2ecSJim Ingham           OptionGroup(),
72*b842f2ecSJim Ingham           m_bp_opts(false) {}
73*b842f2ecSJim Ingham 
74*b842f2ecSJim Ingham   ~BreakpointOptionGroup() override = default;
75*b842f2ecSJim Ingham 
76*b842f2ecSJim Ingham   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
77*b842f2ecSJim Ingham     return llvm::makeArrayRef(g_breakpoint_modify_options);
78*b842f2ecSJim Ingham   }
79*b842f2ecSJim Ingham 
80*b842f2ecSJim Ingham   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
81*b842f2ecSJim Ingham                           ExecutionContext *execution_context) override {
82*b842f2ecSJim Ingham     Status error;
83*b842f2ecSJim Ingham     const int short_option = g_breakpoint_modify_options[option_idx].short_option;
84*b842f2ecSJim Ingham 
85*b842f2ecSJim Ingham     switch (short_option) {
86*b842f2ecSJim Ingham     case 'c':
87*b842f2ecSJim Ingham       // Normally an empty breakpoint condition marks is as unset.
88*b842f2ecSJim Ingham       // But we need to say it was passed in.
89*b842f2ecSJim Ingham       m_bp_opts.SetCondition(option_arg.str().c_str());
90*b842f2ecSJim Ingham       m_bp_opts.m_set_flags.Set(BreakpointOptions::eCondition);
91*b842f2ecSJim Ingham       break;
92*b842f2ecSJim Ingham     case 'C':
93*b842f2ecSJim Ingham       m_commands.push_back(option_arg);
94*b842f2ecSJim Ingham       break;
95*b842f2ecSJim Ingham     case 'd':
96*b842f2ecSJim Ingham       m_bp_opts.SetEnabled(false);
97*b842f2ecSJim Ingham       break;
98*b842f2ecSJim Ingham     case 'e':
99*b842f2ecSJim Ingham       m_bp_opts.SetEnabled(true);
100*b842f2ecSJim Ingham       break;
101*b842f2ecSJim Ingham     case 'G': {
102*b842f2ecSJim Ingham       bool value, success;
103*b842f2ecSJim Ingham       value = Args::StringToBoolean(option_arg, false, &success);
104*b842f2ecSJim Ingham       if (success) {
105*b842f2ecSJim Ingham         m_bp_opts.SetAutoContinue(value);
106*b842f2ecSJim Ingham       } else
107*b842f2ecSJim Ingham         error.SetErrorStringWithFormat(
108*b842f2ecSJim Ingham             "invalid boolean value '%s' passed for -G option",
109*b842f2ecSJim Ingham             option_arg.str().c_str());
110*b842f2ecSJim Ingham     }
111*b842f2ecSJim Ingham     break;
112*b842f2ecSJim Ingham     case 'i':
113*b842f2ecSJim Ingham     {
114*b842f2ecSJim Ingham       uint32_t ignore_count;
115*b842f2ecSJim Ingham       if (option_arg.getAsInteger(0, ignore_count))
116*b842f2ecSJim Ingham         error.SetErrorStringWithFormat("invalid ignore count '%s'",
117*b842f2ecSJim Ingham                                        option_arg.str().c_str());
118*b842f2ecSJim Ingham       else
119*b842f2ecSJim Ingham         m_bp_opts.SetIgnoreCount(ignore_count);
120*b842f2ecSJim Ingham     }
121*b842f2ecSJim Ingham     break;
122*b842f2ecSJim Ingham     case 'o': {
123*b842f2ecSJim Ingham       bool value, success;
124*b842f2ecSJim Ingham       value = Args::StringToBoolean(option_arg, false, &success);
125*b842f2ecSJim Ingham       if (success) {
126*b842f2ecSJim Ingham         m_bp_opts.SetOneShot(value);
127*b842f2ecSJim Ingham       } else
128*b842f2ecSJim Ingham         error.SetErrorStringWithFormat(
129*b842f2ecSJim Ingham             "invalid boolean value '%s' passed for -o option",
130*b842f2ecSJim Ingham             option_arg.str().c_str());
131*b842f2ecSJim Ingham     } break;
132*b842f2ecSJim Ingham     case 't':
133*b842f2ecSJim Ingham     {
134*b842f2ecSJim Ingham       lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID;
135*b842f2ecSJim Ingham       if (option_arg[0] != '\0') {
136*b842f2ecSJim Ingham         if (option_arg.getAsInteger(0, thread_id))
137*b842f2ecSJim Ingham           error.SetErrorStringWithFormat("invalid thread id string '%s'",
138*b842f2ecSJim Ingham                                          option_arg.str().c_str());
139*b842f2ecSJim Ingham       }
140*b842f2ecSJim Ingham       m_bp_opts.SetThreadID(thread_id);
141*b842f2ecSJim Ingham     }
142*b842f2ecSJim Ingham     break;
143*b842f2ecSJim Ingham     case 'T':
144*b842f2ecSJim Ingham       m_bp_opts.GetThreadSpec()->SetName(option_arg.str().c_str());
145*b842f2ecSJim Ingham       break;
146*b842f2ecSJim Ingham     case 'q':
147*b842f2ecSJim Ingham       m_bp_opts.GetThreadSpec()->SetQueueName(option_arg.str().c_str());
148*b842f2ecSJim Ingham       break;
149*b842f2ecSJim Ingham     case 'x':
150*b842f2ecSJim Ingham     {
151*b842f2ecSJim Ingham       uint32_t thread_index = UINT32_MAX;
152*b842f2ecSJim Ingham       if (option_arg[0] != '\n') {
153*b842f2ecSJim Ingham         if (option_arg.getAsInteger(0, thread_index))
154*b842f2ecSJim Ingham           error.SetErrorStringWithFormat("invalid thread index string '%s'",
155*b842f2ecSJim Ingham                                          option_arg.str().c_str());
156*b842f2ecSJim Ingham       }
157*b842f2ecSJim Ingham       m_bp_opts.GetThreadSpec()->SetIndex(thread_index);
158*b842f2ecSJim Ingham     }
159*b842f2ecSJim Ingham     break;
160*b842f2ecSJim Ingham     default:
161*b842f2ecSJim Ingham       error.SetErrorStringWithFormat("unrecognized option '%c'",
162*b842f2ecSJim Ingham                                      short_option);
163*b842f2ecSJim Ingham       break;
164*b842f2ecSJim Ingham     }
165*b842f2ecSJim Ingham 
166*b842f2ecSJim Ingham     return error;
167*b842f2ecSJim Ingham   }
168*b842f2ecSJim Ingham 
169*b842f2ecSJim Ingham   void OptionParsingStarting(ExecutionContext *execution_context) override {
170*b842f2ecSJim Ingham     m_bp_opts.Clear();
171*b842f2ecSJim Ingham     m_commands.clear();
172*b842f2ecSJim Ingham   }
173*b842f2ecSJim Ingham 
174*b842f2ecSJim Ingham   Status OptionParsingFinished(ExecutionContext *execution_context) override {
175*b842f2ecSJim Ingham     if (!m_commands.empty())
176*b842f2ecSJim Ingham     {
177*b842f2ecSJim Ingham       if (!m_commands.empty())
178*b842f2ecSJim Ingham       {
179*b842f2ecSJim Ingham           auto cmd_data = llvm::make_unique<BreakpointOptions::CommandData>();
180*b842f2ecSJim Ingham 
181*b842f2ecSJim Ingham           for (std::string &str : m_commands)
182*b842f2ecSJim Ingham             cmd_data->user_source.AppendString(str);
183*b842f2ecSJim Ingham 
184*b842f2ecSJim Ingham           cmd_data->stop_on_error = true;
185*b842f2ecSJim Ingham           m_bp_opts.SetCommandDataCallback(cmd_data);
186*b842f2ecSJim Ingham       }
187*b842f2ecSJim Ingham     }
188*b842f2ecSJim Ingham     return Status();
189*b842f2ecSJim Ingham   }
190*b842f2ecSJim Ingham 
191*b842f2ecSJim Ingham   const BreakpointOptions &GetBreakpointOptions()
192*b842f2ecSJim Ingham   {
193*b842f2ecSJim Ingham     return m_bp_opts;
194*b842f2ecSJim Ingham   }
195*b842f2ecSJim Ingham 
196*b842f2ecSJim Ingham   std::vector<std::string> m_commands;
197*b842f2ecSJim Ingham   BreakpointOptions m_bp_opts;
198*b842f2ecSJim Ingham 
199*b842f2ecSJim Ingham };
200*b842f2ecSJim Ingham static OptionDefinition g_breakpoint_dummy_options[] = {
201*b842f2ecSJim Ingham     // clang-format off
202*b842f2ecSJim Ingham   { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Act on Dummy breakpoints - i.e. breakpoints set before a file is provided, "
203*b842f2ecSJim Ingham   "which prime new targets." },
204*b842f2ecSJim Ingham     // clang-format on
205*b842f2ecSJim Ingham };
206*b842f2ecSJim Ingham 
207*b842f2ecSJim Ingham class BreakpointDummyOptionGroup : public OptionGroup
208*b842f2ecSJim Ingham {
209*b842f2ecSJim Ingham public:
210*b842f2ecSJim Ingham   BreakpointDummyOptionGroup() :
211*b842f2ecSJim Ingham           OptionGroup() {}
212*b842f2ecSJim Ingham 
213*b842f2ecSJim Ingham   ~BreakpointDummyOptionGroup() override = default;
214*b842f2ecSJim Ingham 
215*b842f2ecSJim Ingham   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
216*b842f2ecSJim Ingham     return llvm::makeArrayRef(g_breakpoint_dummy_options);
217*b842f2ecSJim Ingham   }
218*b842f2ecSJim Ingham 
219*b842f2ecSJim Ingham   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
220*b842f2ecSJim Ingham                           ExecutionContext *execution_context) override {
221*b842f2ecSJim Ingham     Status error;
222*b842f2ecSJim Ingham     const int short_option = g_breakpoint_modify_options[option_idx].short_option;
223*b842f2ecSJim Ingham 
224*b842f2ecSJim Ingham     switch (short_option) {
225*b842f2ecSJim Ingham       case 'D':
226*b842f2ecSJim Ingham         m_use_dummy = true;
227*b842f2ecSJim Ingham         break;
228*b842f2ecSJim Ingham     default:
229*b842f2ecSJim Ingham       error.SetErrorStringWithFormat("unrecognized option '%c'",
230*b842f2ecSJim Ingham                                      short_option);
231*b842f2ecSJim Ingham       break;
232*b842f2ecSJim Ingham     }
233*b842f2ecSJim Ingham 
234*b842f2ecSJim Ingham     return error;
235*b842f2ecSJim Ingham   }
236*b842f2ecSJim Ingham 
237*b842f2ecSJim Ingham   void OptionParsingStarting(ExecutionContext *execution_context) override {
238*b842f2ecSJim Ingham     m_use_dummy = false;
239*b842f2ecSJim Ingham   }
240*b842f2ecSJim Ingham 
241*b842f2ecSJim Ingham   bool m_use_dummy;
242*b842f2ecSJim Ingham 
243*b842f2ecSJim Ingham };
244*b842f2ecSJim Ingham 
2451f0f5b5bSZachary Turner // If an additional option set beyond LLDB_OPTION_SET_10 is added, make sure to
2461f0f5b5bSZachary Turner // update the numbers passed to LLDB_OPT_SET_FROM_TO(...) appropriately.
2471f0f5b5bSZachary Turner #define LLDB_OPT_FILE (LLDB_OPT_SET_FROM_TO(1, 9) & ~LLDB_OPT_SET_2)
2481f0f5b5bSZachary Turner #define LLDB_OPT_NOT_10 (LLDB_OPT_SET_FROM_TO(1, 10) & ~LLDB_OPT_SET_10)
2491f0f5b5bSZachary Turner #define LLDB_OPT_SKIP_PROLOGUE (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
2501f0f5b5bSZachary Turner #define LLDB_OPT_OFFSET_APPLIES (LLDB_OPT_SET_1 | LLDB_OPT_SET_FROM_TO(3, 8))
2511f0f5b5bSZachary Turner #define LLDB_OPT_MOVE_TO_NEAREST_CODE (LLDB_OPT_SET_1 | LLDB_OPT_SET_9)
2521f0f5b5bSZachary Turner #define LLDB_OPT_EXPR_LANGUAGE (LLDB_OPT_SET_FROM_TO(3, 8))
2531f0f5b5bSZachary Turner 
2541f0f5b5bSZachary Turner static OptionDefinition g_breakpoint_set_options[] = {
2551f0f5b5bSZachary Turner     // clang-format off
2561f0f5b5bSZachary Turner   { LLDB_OPT_NOT_10,               false, "shlib",                  's', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eModuleCompletion,     eArgTypeShlibName,           "Set the breakpoint only in this shared library.  Can repeat this option "
2571f0f5b5bSZachary Turner   "multiple times to specify multiple shared libraries." },
2581f0f5b5bSZachary Turner   { LLDB_OPT_SET_ALL,              false, "hardware",               'H', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                         eArgTypeNone,                "Require the breakpoint to use hardware breakpoints." },
2591f0f5b5bSZachary Turner   { LLDB_OPT_FILE,                 false, "file",                   'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename,            "Specifies the source file in which to set this breakpoint.  Note, by default "
2601f0f5b5bSZachary Turner   "lldb only looks for files that are #included if they use the standard include "
2611f0f5b5bSZachary Turner   "file extensions.  To set breakpoints on .c/.cpp/.m/.mm files that are "
2621f0f5b5bSZachary Turner   "#included, set target.inline-breakpoint-strategy to \"always\"." },
2631f0f5b5bSZachary Turner   { LLDB_OPT_SET_1,                true,  "line",                   'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLineNum,             "Specifies the line number on which to set this breakpoint." },
2641f0f5b5bSZachary Turner 
2651f0f5b5bSZachary Turner   // Comment out this option for the moment, as we don't actually use it, but will in the future.
2661f0f5b5bSZachary Turner   // This way users won't see it, but the infrastructure is left in place.
2671f0f5b5bSZachary Turner   //    { 0, false, "column",     'C', OptionParser::eRequiredArgument, nullptr, "<column>",
2681f0f5b5bSZachary Turner   //    "Set the breakpoint by source location at this particular column."},
2691f0f5b5bSZachary Turner 
2701f0f5b5bSZachary Turner   { LLDB_OPT_SET_2,                true,  "address",                'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeAddressOrExpression, "Set the breakpoint at the specified address.  If the address maps uniquely to "
2711f0f5b5bSZachary Turner   "a particular binary, then the address will be converted to a \"file\" "
2721f0f5b5bSZachary Turner   "address, so that the breakpoint will track that binary+offset no matter where "
2731f0f5b5bSZachary Turner   "the binary eventually loads.  Alternately, if you also specify the module - "
2741f0f5b5bSZachary Turner   "with the -s option - then the address will be treated as a file address in "
2751f0f5b5bSZachary Turner   "that module, and resolved accordingly.  Again, this will allow lldb to track "
2761f0f5b5bSZachary Turner   "that offset on subsequent reloads.  The module need not have been loaded at "
2771f0f5b5bSZachary Turner   "the time you specify this breakpoint, and will get resolved when the module "
2781f0f5b5bSZachary Turner   "is loaded." },
2791f0f5b5bSZachary Turner   { LLDB_OPT_SET_3,                true,  "name",                   'n', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "Set the breakpoint by function name.  Can be repeated multiple times to make "
2801f0f5b5bSZachary Turner   "one breakpoint for multiple names" },
2811f0f5b5bSZachary Turner   { LLDB_OPT_SET_9,                false, "source-regexp-function", 'X', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "When used with '-p' limits the source regex to source contained in the named "
2821f0f5b5bSZachary Turner   "functions.  Can be repeated multiple times." },
2831f0f5b5bSZachary Turner   { LLDB_OPT_SET_4,                true,  "fullname",               'F', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion,     eArgTypeFullName,            "Set the breakpoint by fully qualified function names. For C++ this means "
2841f0f5b5bSZachary Turner   "namespaces and all arguments, and for Objective C this means a full function "
2851f0f5b5bSZachary Turner   "prototype with class and selector.  Can be repeated multiple times to make "
2861f0f5b5bSZachary Turner   "one breakpoint for multiple names." },
2871f0f5b5bSZachary Turner   { LLDB_OPT_SET_5,                true,  "selector",               'S', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeSelector,            "Set the breakpoint by ObjC selector name. Can be repeated multiple times to "
2881f0f5b5bSZachary Turner   "make one breakpoint for multiple Selectors." },
2891f0f5b5bSZachary Turner   { LLDB_OPT_SET_6,                true,  "method",                 'M', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeMethod,              "Set the breakpoint by C++ method names.  Can be repeated multiple times to "
2901f0f5b5bSZachary Turner   "make one breakpoint for multiple methods." },
2911f0f5b5bSZachary Turner   { LLDB_OPT_SET_7,                true,  "func-regex",             'r', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeRegularExpression,   "Set the breakpoint by function name, evaluating a regular-expression to find "
2921f0f5b5bSZachary Turner   "the function name(s)." },
2931f0f5b5bSZachary Turner   { LLDB_OPT_SET_8,                true,  "basename",               'b', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSymbolCompletion,     eArgTypeFunctionName,        "Set the breakpoint by function basename (C++ namespaces and arguments will be "
2941f0f5b5bSZachary Turner   "ignored).  Can be repeated multiple times to make one breakpoint for multiple "
2951f0f5b5bSZachary Turner   "symbols." },
2961f0f5b5bSZachary Turner   { LLDB_OPT_SET_9,                true,  "source-pattern-regexp",  'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeRegularExpression,   "Set the breakpoint by specifying a regular expression which is matched "
2971f0f5b5bSZachary Turner   "against the source text in a source file or files specified with the -f "
2981f0f5b5bSZachary Turner   "option.  The -f option can be specified more than once.  If no source files "
2991f0f5b5bSZachary Turner   "are specified, uses the current \"default source file\".  If you want to "
3001f0f5b5bSZachary Turner   "match against all source files, pass the \"--all-files\" option." },
3011f0f5b5bSZachary Turner   { LLDB_OPT_SET_9,                false, "all-files",              'A', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                         eArgTypeNone,                "All files are searched for source pattern matches." },
3021f0f5b5bSZachary Turner   { LLDB_OPT_SET_10,               true,  "language-exception",     'E', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLanguage,            "Set the breakpoint on exceptions thrown by the specified language (without "
3031f0f5b5bSZachary Turner   "options, on throw but not catch.)" },
3041f0f5b5bSZachary Turner   { LLDB_OPT_SET_10,               false, "on-throw",               'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBoolean,             "Set the breakpoint on exception throW." },
3051f0f5b5bSZachary Turner   { LLDB_OPT_SET_10,               false, "on-catch",               'h', OptionParser::eRequiredArgument, nullptr, 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 
3111f0f5b5bSZachary Turner   { LLDB_OPT_EXPR_LANGUAGE,        false, "language",               'L', OptionParser::eRequiredArgument, nullptr, 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." },
3141f0f5b5bSZachary Turner   { LLDB_OPT_SKIP_PROLOGUE,        false, "skip-prologue",          'K', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBoolean,             "sKip the prologue if the breakpoint is at the beginning of a function.  "
3151f0f5b5bSZachary Turner   "If not set the target.skip-prologue setting is used." },
3161f0f5b5bSZachary Turner   { LLDB_OPT_SET_ALL,              false, "breakpoint-name",        'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeBreakpointName,      "Adds this to the list of names for this breakpoint." },
3171f0f5b5bSZachary Turner   { LLDB_OPT_OFFSET_APPLIES,       false, "address-slide",          'R', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeAddress,             "Add the specified offset to whatever address(es) the breakpoint resolves to.  "
3181f0f5b5bSZachary Turner   "At present this applies the offset directly as given, and doesn't try to align it to instruction boundaries." },
3191f0f5b5bSZachary Turner   { LLDB_OPT_MOVE_TO_NEAREST_CODE, false, "move-to-nearest-code", 'm', OptionParser::eRequiredArgument,   nullptr, nullptr, 0,                                         eArgTypeBoolean,             "Move breakpoints to nearest code. If not set the target.move-to-nearest-code "
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,
3375a988416SJim Ingham     eSetTypeException
3385a988416SJim Ingham   } BreakpointSetType;
3395a988416SJim Ingham 
340b9c1b51eSKate Stone   CommandObjectBreakpointSet(CommandInterpreter &interpreter)
341b9c1b51eSKate Stone       : CommandObjectParsed(
342b9c1b51eSKate Stone             interpreter, "breakpoint set",
3435a988416SJim Ingham             "Sets a breakpoint or set of breakpoints in the executable.",
3445a988416SJim Ingham             "breakpoint set <cmd-options>"),
345*b842f2ecSJim Ingham         m_bp_opts(), m_options() {
346*b842f2ecSJim Ingham           // We're picking up all the normal options, commands and disable.
347*b842f2ecSJim Ingham           m_all_options.Append(&m_bp_opts,
348*b842f2ecSJim Ingham                                LLDB_OPT_SET_1 | LLDB_OPT_SET_3 | LLDB_OPT_SET_4,
349*b842f2ecSJim Ingham                                LLDB_OPT_SET_ALL);
350*b842f2ecSJim Ingham           m_all_options.Append(&m_dummy_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
351*b842f2ecSJim Ingham           m_all_options.Append(&m_options);
352*b842f2ecSJim Ingham           m_all_options.Finalize();
353*b842f2ecSJim Ingham         }
3545a988416SJim Ingham 
3559e85e5a8SEugene Zelenko   ~CommandObjectBreakpointSet() override = default;
3565a988416SJim Ingham 
357*b842f2ecSJim Ingham   Options *GetOptions() override { return &m_all_options; }
3585a988416SJim Ingham 
359*b842f2ecSJim Ingham   class CommandOptions : public OptionGroup {
3605a988416SJim Ingham   public:
361b9c1b51eSKate Stone     CommandOptions()
362*b842f2ecSJim Ingham         : OptionGroup(), m_condition(), m_filenames(), m_line_num(0), m_column(0),
363b9c1b51eSKate Stone           m_func_names(), m_func_name_type_mask(eFunctionNameTypeNone),
364b9c1b51eSKate Stone           m_func_regexp(), m_source_text_regexp(), m_modules(), m_load_addr(),
365b9c1b51eSKate Stone           m_catch_bp(false), m_throw_bp(true), m_hardware(false),
366a72b31c7SJim Ingham           m_exception_language(eLanguageTypeUnknown),
36723b1decbSDawn Perchik           m_language(lldb::eLanguageTypeUnknown),
368*b842f2ecSJim Ingham           m_skip_prologue(eLazyBoolCalculate),
369b9c1b51eSKate Stone           m_all_files(false), m_move_to_nearest_code(eLazyBoolCalculate) {}
37030fdc8d8SChris Lattner 
3719e85e5a8SEugene Zelenko     ~CommandOptions() override = default;
37287df91b8SJim Ingham 
37397206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
374b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
37597206d57SZachary Turner       Status error;
376*b842f2ecSJim Ingham       const int short_option = g_breakpoint_set_options[option_idx].short_option;
37730fdc8d8SChris Lattner 
378b9c1b51eSKate Stone       switch (short_option) {
379b9c1b51eSKate Stone       case 'a': {
380b9c1b51eSKate Stone         m_load_addr = Args::StringToAddress(execution_context, option_arg,
381e1cfbc79STodd Fiala                                             LLDB_INVALID_ADDRESS, &error);
382b9c1b51eSKate Stone       } break;
38330fdc8d8SChris Lattner 
384e732052fSJim Ingham       case 'A':
385e732052fSJim Ingham         m_all_files = true;
386e732052fSJim Ingham         break;
387e732052fSJim Ingham 
388ca36cd16SJim Ingham       case 'b':
389ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
390ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeBase;
391ca36cd16SJim Ingham         break;
392ca36cd16SJim Ingham 
393fe11483bSZachary Turner       case 'C':
394fe11483bSZachary Turner         if (option_arg.getAsInteger(0, m_column))
395b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid column number: %s",
396fe11483bSZachary Turner                                          option_arg.str().c_str());
39730fdc8d8SChris Lattner         break;
3989e85e5a8SEugene Zelenko 
399b9c1b51eSKate Stone       case 'E': {
400fe11483bSZachary Turner         LanguageType language = Language::GetLanguageTypeFromString(option_arg);
401fab10e89SJim Ingham 
402b9c1b51eSKate Stone         switch (language) {
403fab10e89SJim Ingham         case eLanguageTypeC89:
404fab10e89SJim Ingham         case eLanguageTypeC:
405fab10e89SJim Ingham         case eLanguageTypeC99:
4061d0089faSBruce Mitchener         case eLanguageTypeC11:
407a72b31c7SJim Ingham           m_exception_language = eLanguageTypeC;
408fab10e89SJim Ingham           break;
409fab10e89SJim Ingham         case eLanguageTypeC_plus_plus:
4101d0089faSBruce Mitchener         case eLanguageTypeC_plus_plus_03:
4111d0089faSBruce Mitchener         case eLanguageTypeC_plus_plus_11:
4122ba84a6aSBruce Mitchener         case eLanguageTypeC_plus_plus_14:
413a72b31c7SJim Ingham           m_exception_language = eLanguageTypeC_plus_plus;
414fab10e89SJim Ingham           break;
415fab10e89SJim Ingham         case eLanguageTypeObjC:
416a72b31c7SJim Ingham           m_exception_language = eLanguageTypeObjC;
417fab10e89SJim Ingham           break;
418fab10e89SJim Ingham         case eLanguageTypeObjC_plus_plus:
419b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
420b9c1b51eSKate Stone               "Set exception breakpoints separately for c++ and objective-c");
421fab10e89SJim Ingham           break;
422fab10e89SJim Ingham         case eLanguageTypeUnknown:
423b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
424b9c1b51eSKate Stone               "Unknown language type: '%s' for exception breakpoint",
425fe11483bSZachary Turner               option_arg.str().c_str());
426fab10e89SJim Ingham           break;
427fab10e89SJim Ingham         default:
428b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
429b9c1b51eSKate Stone               "Unsupported language type: '%s' for exception breakpoint",
430fe11483bSZachary Turner               option_arg.str().c_str());
431fab10e89SJim Ingham         }
432b9c1b51eSKate Stone       } break;
433ca36cd16SJim Ingham 
434ca36cd16SJim Ingham       case 'f':
435ca36cd16SJim Ingham         m_filenames.AppendIfUnique(FileSpec(option_arg, false));
436fab10e89SJim Ingham         break;
437ca36cd16SJim Ingham 
438ca36cd16SJim Ingham       case 'F':
439ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
440ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeFull;
441ca36cd16SJim Ingham         break;
442ca36cd16SJim Ingham 
443b9c1b51eSKate Stone       case 'h': {
444fab10e89SJim Ingham         bool success;
445fe11483bSZachary Turner         m_catch_bp = Args::StringToBoolean(option_arg, true, &success);
446fab10e89SJim Ingham         if (!success)
447b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
448fe11483bSZachary Turner               "Invalid boolean value for on-catch option: '%s'",
449fe11483bSZachary Turner               option_arg.str().c_str());
450b9c1b51eSKate Stone       } break;
451eb023e75SGreg Clayton 
452eb023e75SGreg Clayton       case 'H':
453eb023e75SGreg Clayton         m_hardware = true;
454eb023e75SGreg Clayton         break;
455eb023e75SGreg Clayton 
456b9c1b51eSKate Stone       case 'K': {
457a8558b62SJim Ingham         bool success;
458a8558b62SJim Ingham         bool value;
459fe11483bSZachary Turner         value = Args::StringToBoolean(option_arg, true, &success);
460a8558b62SJim Ingham         if (value)
461a8558b62SJim Ingham           m_skip_prologue = eLazyBoolYes;
462a8558b62SJim Ingham         else
463a8558b62SJim Ingham           m_skip_prologue = eLazyBoolNo;
464a8558b62SJim Ingham 
465a8558b62SJim Ingham         if (!success)
466b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
467b9c1b51eSKate Stone               "Invalid boolean value for skip prologue option: '%s'",
468fe11483bSZachary Turner               option_arg.str().c_str());
469b9c1b51eSKate Stone       } break;
470ca36cd16SJim Ingham 
471fe11483bSZachary Turner       case 'l':
472fe11483bSZachary Turner         if (option_arg.getAsInteger(0, m_line_num))
473b9c1b51eSKate Stone           error.SetErrorStringWithFormat("invalid line number: %s.",
474fe11483bSZachary Turner                                          option_arg.str().c_str());
475ca36cd16SJim Ingham         break;
476055ad9beSIlia K 
47723b1decbSDawn Perchik       case 'L':
478fe11483bSZachary Turner         m_language = Language::GetLanguageTypeFromString(option_arg);
47923b1decbSDawn Perchik         if (m_language == eLanguageTypeUnknown)
480b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
481fe11483bSZachary Turner               "Unknown language type: '%s' for breakpoint",
482fe11483bSZachary Turner               option_arg.str().c_str());
48323b1decbSDawn Perchik         break;
48423b1decbSDawn Perchik 
485b9c1b51eSKate Stone       case 'm': {
486055ad9beSIlia K         bool success;
487055ad9beSIlia K         bool value;
488fe11483bSZachary Turner         value = Args::StringToBoolean(option_arg, true, &success);
489055ad9beSIlia K         if (value)
490055ad9beSIlia K           m_move_to_nearest_code = eLazyBoolYes;
491055ad9beSIlia K         else
492055ad9beSIlia K           m_move_to_nearest_code = eLazyBoolNo;
493055ad9beSIlia K 
494055ad9beSIlia K         if (!success)
495b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
496b9c1b51eSKate Stone               "Invalid boolean value for move-to-nearest-code option: '%s'",
497fe11483bSZachary Turner               option_arg.str().c_str());
498055ad9beSIlia K         break;
499055ad9beSIlia K       }
500055ad9beSIlia K 
501ca36cd16SJim Ingham       case 'M':
502ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
503ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeMethod;
504ca36cd16SJim Ingham         break;
505ca36cd16SJim Ingham 
506ca36cd16SJim Ingham       case 'n':
507ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
508ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeAuto;
509ca36cd16SJim Ingham         break;
510ca36cd16SJim Ingham 
5116fa7681bSZachary Turner       case 'N': {
512fe11483bSZachary Turner         if (BreakpointID::StringIsBreakpointName(option_arg, error))
5135e09c8c3SJim Ingham           m_breakpoint_names.push_back(option_arg);
514ff9a91eaSJim Ingham         else
515ff9a91eaSJim Ingham           error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
516fe11483bSZachary Turner                                          option_arg.str().c_str());
5175e09c8c3SJim Ingham         break;
5186fa7681bSZachary Turner       }
5195e09c8c3SJim Ingham 
520b9c1b51eSKate Stone       case 'R': {
5212411167fSJim Ingham         lldb::addr_t tmp_offset_addr;
522e1cfbc79STodd Fiala         tmp_offset_addr =
523b9c1b51eSKate Stone             Args::StringToAddress(execution_context, option_arg, 0, &error);
5242411167fSJim Ingham         if (error.Success())
5252411167fSJim Ingham           m_offset_addr = tmp_offset_addr;
526b9c1b51eSKate Stone       } break;
5272411167fSJim Ingham 
528a72b31c7SJim Ingham       case 'O':
529fe11483bSZachary Turner         m_exception_extra_args.AppendArgument("-O");
530fe11483bSZachary Turner         m_exception_extra_args.AppendArgument(option_arg);
531a72b31c7SJim Ingham         break;
532a72b31c7SJim Ingham 
533ca36cd16SJim Ingham       case 'p':
534ca36cd16SJim Ingham         m_source_text_regexp.assign(option_arg);
535ca36cd16SJim Ingham         break;
536ca36cd16SJim Ingham 
537ca36cd16SJim Ingham       case 'r':
538ca36cd16SJim Ingham         m_func_regexp.assign(option_arg);
539ca36cd16SJim Ingham         break;
540ca36cd16SJim Ingham 
541ca36cd16SJim Ingham       case 's':
542ca36cd16SJim Ingham         m_modules.AppendIfUnique(FileSpec(option_arg, false));
543ca36cd16SJim Ingham         break;
544ca36cd16SJim Ingham 
545ca36cd16SJim Ingham       case 'S':
546ca36cd16SJim Ingham         m_func_names.push_back(option_arg);
547ca36cd16SJim Ingham         m_func_name_type_mask |= eFunctionNameTypeSelector;
548ca36cd16SJim Ingham         break;
549ca36cd16SJim Ingham 
550b9c1b51eSKate Stone       case 'w': {
551ca36cd16SJim Ingham         bool success;
552fe11483bSZachary Turner         m_throw_bp = Args::StringToBoolean(option_arg, true, &success);
553ca36cd16SJim Ingham         if (!success)
554b9c1b51eSKate Stone           error.SetErrorStringWithFormat(
555fe11483bSZachary Turner               "Invalid boolean value for on-throw option: '%s'",
556fe11483bSZachary Turner               option_arg.str().c_str());
557b9c1b51eSKate Stone       } break;
558ca36cd16SJim Ingham 
55976bb8d67SJim Ingham       case 'X':
56076bb8d67SJim Ingham         m_source_regex_func_names.insert(option_arg);
56176bb8d67SJim Ingham         break;
56276bb8d67SJim Ingham 
56330fdc8d8SChris Lattner       default:
564b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
565b9c1b51eSKate Stone                                        short_option);
56630fdc8d8SChris Lattner         break;
56730fdc8d8SChris Lattner       }
56830fdc8d8SChris Lattner 
56930fdc8d8SChris Lattner       return error;
57030fdc8d8SChris Lattner     }
5719e85e5a8SEugene Zelenko 
572b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
57387df91b8SJim Ingham       m_filenames.Clear();
57430fdc8d8SChris Lattner       m_line_num = 0;
57530fdc8d8SChris Lattner       m_column = 0;
576fab10e89SJim Ingham       m_func_names.clear();
5771f746071SGreg Clayton       m_func_name_type_mask = eFunctionNameTypeNone;
57830fdc8d8SChris Lattner       m_func_regexp.clear();
5791f746071SGreg Clayton       m_source_text_regexp.clear();
58087df91b8SJim Ingham       m_modules.Clear();
5811f746071SGreg Clayton       m_load_addr = LLDB_INVALID_ADDRESS;
5822411167fSJim Ingham       m_offset_addr = 0;
583fab10e89SJim Ingham       m_catch_bp = false;
584fab10e89SJim Ingham       m_throw_bp = true;
585eb023e75SGreg Clayton       m_hardware = false;
586a72b31c7SJim Ingham       m_exception_language = eLanguageTypeUnknown;
58723b1decbSDawn Perchik       m_language = lldb::eLanguageTypeUnknown;
588a8558b62SJim Ingham       m_skip_prologue = eLazyBoolCalculate;
5895e09c8c3SJim Ingham       m_breakpoint_names.clear();
590e732052fSJim Ingham       m_all_files = false;
591a72b31c7SJim Ingham       m_exception_extra_args.Clear();
592055ad9beSIlia K       m_move_to_nearest_code = eLazyBoolCalculate;
59376bb8d67SJim Ingham       m_source_regex_func_names.clear();
59430fdc8d8SChris Lattner     }
59530fdc8d8SChris Lattner 
5961f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
59770602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_set_options);
5981f0f5b5bSZachary Turner     }
59930fdc8d8SChris Lattner 
6005a988416SJim Ingham     // Instance variables to hold the values for command options.
601969795f1SJim Ingham 
6025a988416SJim Ingham     std::string m_condition;
6035a988416SJim Ingham     FileSpecList m_filenames;
6045a988416SJim Ingham     uint32_t m_line_num;
6055a988416SJim Ingham     uint32_t m_column;
6065a988416SJim Ingham     std::vector<std::string> m_func_names;
6075e09c8c3SJim Ingham     std::vector<std::string> m_breakpoint_names;
6085a988416SJim Ingham     uint32_t m_func_name_type_mask;
6095a988416SJim Ingham     std::string m_func_regexp;
6105a988416SJim Ingham     std::string m_source_text_regexp;
6115a988416SJim Ingham     FileSpecList m_modules;
6125a988416SJim Ingham     lldb::addr_t m_load_addr;
6132411167fSJim Ingham     lldb::addr_t m_offset_addr;
6145a988416SJim Ingham     bool m_catch_bp;
6155a988416SJim Ingham     bool m_throw_bp;
616eb023e75SGreg Clayton     bool m_hardware; // Request to use hardware breakpoints
617a72b31c7SJim Ingham     lldb::LanguageType m_exception_language;
61823b1decbSDawn Perchik     lldb::LanguageType m_language;
6195a988416SJim Ingham     LazyBool m_skip_prologue;
620e732052fSJim Ingham     bool m_all_files;
621a72b31c7SJim Ingham     Args m_exception_extra_args;
622055ad9beSIlia K     LazyBool m_move_to_nearest_code;
62376bb8d67SJim Ingham     std::unordered_set<std::string> m_source_regex_func_names;
6245a988416SJim Ingham   };
6255a988416SJim Ingham 
6265a988416SJim Ingham protected:
627b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
628*b842f2ecSJim Ingham     Target *target = GetSelectedOrDummyTarget(m_dummy_options.m_use_dummy);
62933df7cd3SJim Ingham 
630b9c1b51eSKate Stone     if (target == nullptr) {
631b9c1b51eSKate Stone       result.AppendError("Invalid target.  Must set target before setting "
632b9c1b51eSKate Stone                          "breakpoints (see 'target create' command).");
63330fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
63430fdc8d8SChris Lattner       return false;
63530fdc8d8SChris Lattner     }
63630fdc8d8SChris Lattner 
63730fdc8d8SChris Lattner     // The following are the various types of breakpoints that could be set:
63830fdc8d8SChris Lattner     //   1).  -f -l -p  [-s -g]   (setting breakpoint by source location)
63930fdc8d8SChris Lattner     //   2).  -a  [-s -g]         (setting breakpoint by address)
64030fdc8d8SChris Lattner     //   3).  -n  [-s -g]         (setting breakpoint by function name)
641b9c1b51eSKate Stone     //   4).  -r  [-s -g]         (setting breakpoint by function name regular
642b9c1b51eSKate Stone     //   expression)
643b9c1b51eSKate Stone     //   5).  -p -f               (setting a breakpoint by comparing a reg-exp
644b9c1b51eSKate Stone     //   to source text)
645b9c1b51eSKate Stone     //   6).  -E [-w -h]          (setting a breakpoint for exceptions for a
646b9c1b51eSKate Stone     //   given language.)
64730fdc8d8SChris Lattner 
64830fdc8d8SChris Lattner     BreakpointSetType break_type = eSetTypeInvalid;
64930fdc8d8SChris Lattner 
65030fdc8d8SChris Lattner     if (m_options.m_line_num != 0)
65130fdc8d8SChris Lattner       break_type = eSetTypeFileAndLine;
65230fdc8d8SChris Lattner     else if (m_options.m_load_addr != LLDB_INVALID_ADDRESS)
65330fdc8d8SChris Lattner       break_type = eSetTypeAddress;
654fab10e89SJim Ingham     else if (!m_options.m_func_names.empty())
65530fdc8d8SChris Lattner       break_type = eSetTypeFunctionName;
65630fdc8d8SChris Lattner     else if (!m_options.m_func_regexp.empty())
65730fdc8d8SChris Lattner       break_type = eSetTypeFunctionRegexp;
658969795f1SJim Ingham     else if (!m_options.m_source_text_regexp.empty())
659969795f1SJim Ingham       break_type = eSetTypeSourceRegexp;
660a72b31c7SJim Ingham     else if (m_options.m_exception_language != eLanguageTypeUnknown)
661fab10e89SJim Ingham       break_type = eSetTypeException;
66230fdc8d8SChris Lattner 
663*b842f2ecSJim Ingham     BreakpointSP bp_sp = nullptr;
664274060b6SGreg Clayton     FileSpec module_spec;
665a8558b62SJim Ingham     const bool internal = false;
666a8558b62SJim Ingham 
667b9c1b51eSKate Stone     // If the user didn't specify skip-prologue, having an offset should turn
668b9c1b51eSKate Stone     // that off.
669b9c1b51eSKate Stone     if (m_options.m_offset_addr != 0 &&
670b9c1b51eSKate Stone         m_options.m_skip_prologue == eLazyBoolCalculate)
6712411167fSJim Ingham       m_options.m_skip_prologue = eLazyBoolNo;
6722411167fSJim Ingham 
673b9c1b51eSKate Stone     switch (break_type) {
67430fdc8d8SChris Lattner     case eSetTypeFileAndLine: // Breakpoint by source position
67530fdc8d8SChris Lattner     {
67630fdc8d8SChris Lattner       FileSpec file;
677c7bece56SGreg Clayton       const size_t num_files = m_options.m_filenames.GetSize();
678b9c1b51eSKate Stone       if (num_files == 0) {
679b9c1b51eSKate Stone         if (!GetDefaultFile(target, file, result)) {
68087df91b8SJim Ingham           result.AppendError("No file supplied and no default file available.");
68187df91b8SJim Ingham           result.SetStatus(eReturnStatusFailed);
68287df91b8SJim Ingham           return false;
68387df91b8SJim Ingham         }
684b9c1b51eSKate Stone       } else if (num_files > 1) {
685b9c1b51eSKate Stone         result.AppendError("Only one file at a time is allowed for file and "
686b9c1b51eSKate Stone                            "line breakpoints.");
68787df91b8SJim Ingham         result.SetStatus(eReturnStatusFailed);
68887df91b8SJim Ingham         return false;
689b9c1b51eSKate Stone       } else
69087df91b8SJim Ingham         file = m_options.m_filenames.GetFileSpecAtIndex(0);
69130fdc8d8SChris Lattner 
6921f746071SGreg Clayton       // Only check for inline functions if
6931f746071SGreg Clayton       LazyBool check_inlines = eLazyBoolCalculate;
6941f746071SGreg Clayton 
695*b842f2ecSJim Ingham       bp_sp = target->CreateBreakpoint(&(m_options.m_modules),
696*b842f2ecSJim Ingham                                        file,
697*b842f2ecSJim Ingham                                        m_options.m_line_num,
698*b842f2ecSJim Ingham                                        m_options.m_offset_addr,
699*b842f2ecSJim Ingham                                        check_inlines,
700*b842f2ecSJim Ingham                                        m_options.m_skip_prologue,
701*b842f2ecSJim Ingham                                        internal,
702*b842f2ecSJim Ingham                                        m_options.m_hardware,
703*b842f2ecSJim Ingham                                        m_options.m_move_to_nearest_code);
704b9c1b51eSKate Stone     } break;
7056eee5aa0SGreg Clayton 
70630fdc8d8SChris Lattner     case eSetTypeAddress: // Breakpoint by address
707055a08a4SJim Ingham     {
708b9c1b51eSKate Stone       // If a shared library has been specified, make an lldb_private::Address
709*b842f2ecSJim Ingham       // with the library, and use that.  That way the address breakpoint
710*b842f2ecSJim Ingham       //  will track the load location of the library.
711055a08a4SJim Ingham       size_t num_modules_specified = m_options.m_modules.GetSize();
712b9c1b51eSKate Stone       if (num_modules_specified == 1) {
713b9c1b51eSKate Stone         const FileSpec *file_spec =
714b9c1b51eSKate Stone             m_options.m_modules.GetFileSpecPointerAtIndex(0);
715*b842f2ecSJim Ingham         bp_sp = target->CreateAddressInModuleBreakpoint(m_options.m_load_addr,
716b9c1b51eSKate Stone                                                         internal, file_spec,
717*b842f2ecSJim Ingham                                                         m_options.m_hardware);
718b9c1b51eSKate Stone       } else if (num_modules_specified == 0) {
719*b842f2ecSJim Ingham         bp_sp = target->CreateBreakpoint(m_options.m_load_addr, internal,
720*b842f2ecSJim Ingham                                          m_options.m_hardware);
721b9c1b51eSKate Stone       } else {
722b9c1b51eSKate Stone         result.AppendError("Only one shared library can be specified for "
723b9c1b51eSKate Stone                            "address breakpoints.");
724055a08a4SJim Ingham         result.SetStatus(eReturnStatusFailed);
725055a08a4SJim Ingham         return false;
726055a08a4SJim Ingham       }
72730fdc8d8SChris Lattner       break;
728055a08a4SJim Ingham     }
72930fdc8d8SChris Lattner     case eSetTypeFunctionName: // Breakpoint by function name
7300c5cd90dSGreg Clayton     {
7310c5cd90dSGreg Clayton       uint32_t name_type_mask = m_options.m_func_name_type_mask;
7320c5cd90dSGreg Clayton 
7330c5cd90dSGreg Clayton       if (name_type_mask == 0)
734e02b8504SGreg Clayton         name_type_mask = eFunctionNameTypeAuto;
7350c5cd90dSGreg Clayton 
736*b842f2ecSJim Ingham       bp_sp = target->CreateBreakpoint(&(m_options.m_modules),
737*b842f2ecSJim Ingham                                        &(m_options.m_filenames),
738*b842f2ecSJim Ingham                                        m_options.m_func_names,
739*b842f2ecSJim Ingham                                        name_type_mask,
740*b842f2ecSJim Ingham                                        m_options.m_language,
741*b842f2ecSJim Ingham                                        m_options.m_offset_addr,
742*b842f2ecSJim Ingham                                        m_options.m_skip_prologue,
743*b842f2ecSJim Ingham                                        internal,
744*b842f2ecSJim Ingham                                        m_options.m_hardware);
745b9c1b51eSKate Stone     } break;
7460c5cd90dSGreg Clayton 
747b9c1b51eSKate Stone     case eSetTypeFunctionRegexp: // Breakpoint by regular expression function
748b9c1b51eSKate Stone                                  // name
74930fdc8d8SChris Lattner       {
75095eae423SZachary Turner         RegularExpression regexp(m_options.m_func_regexp);
751b9c1b51eSKate Stone         if (!regexp.IsValid()) {
752969795f1SJim Ingham           char err_str[1024];
753969795f1SJim Ingham           regexp.GetErrorAsCString(err_str, sizeof(err_str));
754b9c1b51eSKate Stone           result.AppendErrorWithFormat(
755b9c1b51eSKate Stone               "Function name regular expression could not be compiled: \"%s\"",
756969795f1SJim Ingham               err_str);
75730fdc8d8SChris Lattner           result.SetStatus(eReturnStatusFailed);
758969795f1SJim Ingham           return false;
75930fdc8d8SChris Lattner         }
76087df91b8SJim Ingham 
761*b842f2ecSJim Ingham         bp_sp = target->CreateFuncRegexBreakpoint(&(m_options.m_modules),
762*b842f2ecSJim Ingham                                                   &(m_options.m_filenames),
763*b842f2ecSJim Ingham                                                   regexp,
764*b842f2ecSJim Ingham                                                   m_options.m_language,
765*b842f2ecSJim Ingham                                                   m_options.m_skip_prologue,
766*b842f2ecSJim Ingham                                                   internal,
767*b842f2ecSJim Ingham                                                   m_options.m_hardware);
768e14dc268SJim Ingham       }
769e14dc268SJim Ingham       break;
770969795f1SJim Ingham     case eSetTypeSourceRegexp: // Breakpoint by regexp on source text.
771969795f1SJim Ingham     {
772c7bece56SGreg Clayton       const size_t num_files = m_options.m_filenames.GetSize();
77387df91b8SJim Ingham 
774b9c1b51eSKate Stone       if (num_files == 0 && !m_options.m_all_files) {
775969795f1SJim Ingham         FileSpec file;
776b9c1b51eSKate Stone         if (!GetDefaultFile(target, file, result)) {
777b9c1b51eSKate Stone           result.AppendError(
778b9c1b51eSKate Stone               "No files provided and could not find default file.");
77987df91b8SJim Ingham           result.SetStatus(eReturnStatusFailed);
78087df91b8SJim Ingham           return false;
781b9c1b51eSKate Stone         } else {
78287df91b8SJim Ingham           m_options.m_filenames.Append(file);
78387df91b8SJim Ingham         }
78487df91b8SJim Ingham       }
7850c5cd90dSGreg Clayton 
78695eae423SZachary Turner       RegularExpression regexp(m_options.m_source_text_regexp);
787b9c1b51eSKate Stone       if (!regexp.IsValid()) {
788969795f1SJim Ingham         char err_str[1024];
789969795f1SJim Ingham         regexp.GetErrorAsCString(err_str, sizeof(err_str));
790b9c1b51eSKate Stone         result.AppendErrorWithFormat(
791b9c1b51eSKate Stone             "Source text regular expression could not be compiled: \"%s\"",
792969795f1SJim Ingham             err_str);
793969795f1SJim Ingham         result.SetStatus(eReturnStatusFailed);
794969795f1SJim Ingham         return false;
795969795f1SJim Ingham       }
796*b842f2ecSJim Ingham       bp_sp =
797*b842f2ecSJim Ingham           target->CreateSourceRegexBreakpoint(&(m_options.m_modules),
798*b842f2ecSJim Ingham                                               &(m_options.m_filenames),
799*b842f2ecSJim Ingham                                               m_options
800*b842f2ecSJim Ingham                                                   .m_source_regex_func_names,
801*b842f2ecSJim Ingham                                               regexp,
802*b842f2ecSJim Ingham                                               internal,
803*b842f2ecSJim Ingham                                               m_options.m_hardware,
804*b842f2ecSJim Ingham                                               m_options.m_move_to_nearest_code);
805b9c1b51eSKate Stone     } break;
806b9c1b51eSKate Stone     case eSetTypeException: {
80797206d57SZachary Turner       Status precond_error;
808*b842f2ecSJim Ingham       bp_sp = target->CreateExceptionBreakpoint(m_options.m_exception_language,
809*b842f2ecSJim Ingham                                                 m_options.m_catch_bp,
810*b842f2ecSJim Ingham                                                 m_options.m_throw_bp,
811*b842f2ecSJim Ingham                                                 internal,
812*b842f2ecSJim Ingham                                                 &m_options
813*b842f2ecSJim Ingham                                                     .m_exception_extra_args,
814*b842f2ecSJim Ingham                                                 &precond_error);
815b9c1b51eSKate Stone       if (precond_error.Fail()) {
816b9c1b51eSKate Stone         result.AppendErrorWithFormat(
817b9c1b51eSKate Stone             "Error setting extra exception arguments: %s",
818a72b31c7SJim Ingham             precond_error.AsCString());
819*b842f2ecSJim Ingham         target->RemoveBreakpointByID(bp_sp->GetID());
820a72b31c7SJim Ingham         result.SetStatus(eReturnStatusFailed);
821a72b31c7SJim Ingham         return false;
822a72b31c7SJim Ingham       }
823b9c1b51eSKate Stone     } break;
82430fdc8d8SChris Lattner     default:
82530fdc8d8SChris Lattner       break;
82630fdc8d8SChris Lattner     }
82730fdc8d8SChris Lattner 
8281b54c88cSJim Ingham     // Now set the various options that were passed in:
829*b842f2ecSJim Ingham     if (bp_sp) {
830*b842f2ecSJim Ingham       bp_sp->GetOptions()->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
831ca36cd16SJim Ingham 
832b9c1b51eSKate Stone       if (!m_options.m_breakpoint_names.empty()) {
83397206d57SZachary Turner         Status name_error;
834ff9a91eaSJim Ingham         for (auto name : m_options.m_breakpoint_names) {
835*b842f2ecSJim Ingham           target->AddNameToBreakpoint(bp_sp, name.c_str(), name_error);
836ff9a91eaSJim Ingham           if (name_error.Fail()) {
837ff9a91eaSJim Ingham             result.AppendErrorWithFormat("Invalid breakpoint name: %s",
838ff9a91eaSJim Ingham                                          name.c_str());
839*b842f2ecSJim Ingham             target->RemoveBreakpointByID(bp_sp->GetID());
840ff9a91eaSJim Ingham             result.SetStatus(eReturnStatusFailed);
841ff9a91eaSJim Ingham             return false;
842ff9a91eaSJim Ingham           }
843ff9a91eaSJim Ingham         }
8445e09c8c3SJim Ingham       }
8451b54c88cSJim Ingham     }
8461b54c88cSJim Ingham 
847*b842f2ecSJim Ingham     if (bp_sp) {
84885e8b814SJim Ingham       Stream &output_stream = result.GetOutputStream();
8491391cc7dSJim Ingham       const bool show_locations = false;
850*b842f2ecSJim Ingham       bp_sp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
851b9c1b51eSKate Stone                          show_locations);
8524aeb1989SJim Ingham       if (target == m_interpreter.GetDebugger().GetDummyTarget())
853b9c1b51eSKate Stone         output_stream.Printf("Breakpoint set in dummy target, will get copied "
854b9c1b51eSKate Stone                              "into future targets.\n");
855b9c1b51eSKate Stone       else {
856b9c1b51eSKate Stone         // Don't print out this warning for exception breakpoints.  They can get
857*b842f2ecSJim Ingham         // set before the target is set, but we won't know how to actually set
858*b842f2ecSJim Ingham         // the breakpoint till we run.
859*b842f2ecSJim Ingham         if (bp_sp->GetNumLocations() == 0 && break_type != eSetTypeException) {
860b9c1b51eSKate Stone           output_stream.Printf("WARNING:  Unable to resolve breakpoint to any "
861b9c1b51eSKate Stone                                "actual locations.\n");
8624aeb1989SJim Ingham         }
8634aeb1989SJim Ingham       }
86430fdc8d8SChris Lattner       result.SetStatus(eReturnStatusSuccessFinishResult);
865*b842f2ecSJim Ingham     } else if (!bp_sp) {
86630fdc8d8SChris Lattner       result.AppendError("Breakpoint creation failed: No breakpoint created.");
86730fdc8d8SChris Lattner       result.SetStatus(eReturnStatusFailed);
86830fdc8d8SChris Lattner     }
86930fdc8d8SChris Lattner 
87030fdc8d8SChris Lattner     return result.Succeeded();
87130fdc8d8SChris Lattner   }
87230fdc8d8SChris Lattner 
8735a988416SJim Ingham private:
874b9c1b51eSKate Stone   bool GetDefaultFile(Target *target, FileSpec &file,
875b9c1b51eSKate Stone                       CommandReturnObject &result) {
8765a988416SJim Ingham     uint32_t default_line;
8775a988416SJim Ingham     // First use the Source Manager's default file.
8785a988416SJim Ingham     // Then use the current stack frame's file.
879b9c1b51eSKate Stone     if (!target->GetSourceManager().GetDefaultFileAndLine(file, default_line)) {
880b57e4a1bSJason Molenda       StackFrame *cur_frame = m_exe_ctx.GetFramePtr();
881b9c1b51eSKate Stone       if (cur_frame == nullptr) {
882b9c1b51eSKate Stone         result.AppendError(
883b9c1b51eSKate Stone             "No selected frame to use to find the default file.");
8845a988416SJim Ingham         result.SetStatus(eReturnStatusFailed);
8855a988416SJim Ingham         return false;
886b9c1b51eSKate Stone       } else if (!cur_frame->HasDebugInformation()) {
887b9c1b51eSKate Stone         result.AppendError("Cannot use the selected frame to find the default "
888b9c1b51eSKate Stone                            "file, it has no debug info.");
8895a988416SJim Ingham         result.SetStatus(eReturnStatusFailed);
8905a988416SJim Ingham         return false;
891b9c1b51eSKate Stone       } else {
892b9c1b51eSKate Stone         const SymbolContext &sc =
893b9c1b51eSKate Stone             cur_frame->GetSymbolContext(eSymbolContextLineEntry);
894b9c1b51eSKate Stone         if (sc.line_entry.file) {
8955a988416SJim Ingham           file = sc.line_entry.file;
896b9c1b51eSKate Stone         } else {
897b9c1b51eSKate Stone           result.AppendError("Can't find the file for the selected frame to "
898b9c1b51eSKate Stone                              "use as the default file.");
8995a988416SJim Ingham           result.SetStatus(eReturnStatusFailed);
9005a988416SJim Ingham           return false;
9015a988416SJim Ingham         }
9025a988416SJim Ingham       }
9035a988416SJim Ingham     }
9045a988416SJim Ingham     return true;
9055a988416SJim Ingham   }
9065a988416SJim Ingham 
907*b842f2ecSJim Ingham   BreakpointOptionGroup m_bp_opts;
908*b842f2ecSJim Ingham   BreakpointDummyOptionGroup m_dummy_options;
9095a988416SJim Ingham   CommandOptions m_options;
910*b842f2ecSJim Ingham   OptionGroupOptions m_all_options;
9115a988416SJim Ingham };
9129e85e5a8SEugene Zelenko 
9135a988416SJim Ingham //-------------------------------------------------------------------------
9145a988416SJim Ingham // CommandObjectBreakpointModify
9155a988416SJim Ingham //-------------------------------------------------------------------------
9165a988416SJim Ingham #pragma mark Modify
9175a988416SJim Ingham 
918b9c1b51eSKate Stone class CommandObjectBreakpointModify : public CommandObjectParsed {
9195a988416SJim Ingham public:
920b9c1b51eSKate Stone   CommandObjectBreakpointModify(CommandInterpreter &interpreter)
921b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "breakpoint modify",
922b9c1b51eSKate Stone                             "Modify the options on a breakpoint or set of "
923b9c1b51eSKate Stone                             "breakpoints in the executable.  "
924b9c1b51eSKate Stone                             "If no breakpoint is specified, acts on the last "
925b9c1b51eSKate Stone                             "created breakpoint.  "
926b9c1b51eSKate Stone                             "With the exception of -e, -d and -i, passing an "
927b9c1b51eSKate Stone                             "empty argument clears the modification.",
9289e85e5a8SEugene Zelenko                             nullptr),
929b9c1b51eSKate Stone         m_options() {
9305a988416SJim Ingham     CommandArgumentEntry arg;
931b9c1b51eSKate Stone     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
932b9c1b51eSKate Stone                                       eArgTypeBreakpointIDRange);
933b9c1b51eSKate Stone     // Add the entry for the first argument for this command to the object's
934b9c1b51eSKate Stone     // arguments vector.
9355a988416SJim Ingham     m_arguments.push_back(arg);
936*b842f2ecSJim Ingham 
937*b842f2ecSJim Ingham     m_options.Append(&m_bp_opts,
938*b842f2ecSJim Ingham                      LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3,
939*b842f2ecSJim Ingham                      LLDB_OPT_SET_ALL);
940*b842f2ecSJim Ingham     m_options.Append(&m_dummy_opts, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
941*b842f2ecSJim Ingham     m_options.Finalize();
9425a988416SJim Ingham   }
9435a988416SJim Ingham 
9449e85e5a8SEugene Zelenko   ~CommandObjectBreakpointModify() override = default;
9455a988416SJim Ingham 
946b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
9475a988416SJim Ingham 
9485a988416SJim Ingham protected:
949b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
950*b842f2ecSJim Ingham     Target *target = GetSelectedOrDummyTarget(m_dummy_opts.m_use_dummy);
951b9c1b51eSKate Stone     if (target == nullptr) {
9525a988416SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
9535a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
9545a988416SJim Ingham       return false;
9555a988416SJim Ingham     }
9565a988416SJim Ingham 
957bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
958bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
9595a988416SJim Ingham 
9605a988416SJim Ingham     BreakpointIDList valid_bp_ids;
9615a988416SJim Ingham 
962b9c1b51eSKate Stone     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
963*b842f2ecSJim Ingham         command, target, result, &valid_bp_ids,
964*b842f2ecSJim Ingham         BreakpointName::Permissions::PermissionKinds::disablePerm);
9655a988416SJim Ingham 
966b9c1b51eSKate Stone     if (result.Succeeded()) {
9675a988416SJim Ingham       const size_t count = valid_bp_ids.GetSize();
968b9c1b51eSKate Stone       for (size_t i = 0; i < count; ++i) {
9695a988416SJim Ingham         BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
9705a988416SJim Ingham 
971b9c1b51eSKate Stone         if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
972b9c1b51eSKate Stone           Breakpoint *bp =
973b9c1b51eSKate Stone               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
974b9c1b51eSKate Stone           if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
975b9c1b51eSKate Stone             BreakpointLocation *location =
976b9c1b51eSKate Stone                 bp->FindLocationByID(cur_bp_id.GetLocationID()).get();
977*b842f2ecSJim Ingham             if (location)
978*b842f2ecSJim Ingham               location->GetLocationOptions()
979*b842f2ecSJim Ingham                   ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
980b9c1b51eSKate Stone           } else {
981*b842f2ecSJim Ingham             bp->GetOptions()
982*b842f2ecSJim Ingham                 ->CopyOverSetOptions(m_bp_opts.GetBreakpointOptions());
9835a988416SJim Ingham           }
9845a988416SJim Ingham         }
9855a988416SJim Ingham       }
9865a988416SJim Ingham     }
9875a988416SJim Ingham 
9885a988416SJim Ingham     return result.Succeeded();
9895a988416SJim Ingham   }
9905a988416SJim Ingham 
9915a988416SJim Ingham private:
992*b842f2ecSJim Ingham   BreakpointOptionGroup m_bp_opts;
993*b842f2ecSJim Ingham   BreakpointDummyOptionGroup m_dummy_opts;
994*b842f2ecSJim Ingham   OptionGroupOptions m_options;
9955a988416SJim Ingham };
9965a988416SJim Ingham 
9975a988416SJim Ingham //-------------------------------------------------------------------------
9985a988416SJim Ingham // CommandObjectBreakpointEnable
9995a988416SJim Ingham //-------------------------------------------------------------------------
10005a988416SJim Ingham #pragma mark Enable
10015a988416SJim Ingham 
1002b9c1b51eSKate Stone class CommandObjectBreakpointEnable : public CommandObjectParsed {
10035a988416SJim Ingham public:
1004b9c1b51eSKate Stone   CommandObjectBreakpointEnable(CommandInterpreter &interpreter)
1005b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "enable",
1006b9c1b51eSKate Stone                             "Enable the specified disabled breakpoint(s). If "
1007b9c1b51eSKate Stone                             "no breakpoints are specified, enable all of them.",
1008b9c1b51eSKate Stone                             nullptr) {
10095a988416SJim Ingham     CommandArgumentEntry arg;
1010b9c1b51eSKate Stone     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1011b9c1b51eSKate Stone                                       eArgTypeBreakpointIDRange);
1012b9c1b51eSKate Stone     // Add the entry for the first argument for this command to the object's
1013b9c1b51eSKate Stone     // arguments vector.
10145a988416SJim Ingham     m_arguments.push_back(arg);
10155a988416SJim Ingham   }
10165a988416SJim Ingham 
10179e85e5a8SEugene Zelenko   ~CommandObjectBreakpointEnable() override = default;
10185a988416SJim Ingham 
10195a988416SJim Ingham protected:
1020b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1021893c932aSJim Ingham     Target *target = GetSelectedOrDummyTarget();
1022b9c1b51eSKate Stone     if (target == nullptr) {
10235a988416SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
10245a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
10255a988416SJim Ingham       return false;
10265a988416SJim Ingham     }
10275a988416SJim Ingham 
1028bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1029bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
10305a988416SJim Ingham 
10315a988416SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
10325a988416SJim Ingham 
10335a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
10345a988416SJim Ingham 
1035b9c1b51eSKate Stone     if (num_breakpoints == 0) {
10365a988416SJim Ingham       result.AppendError("No breakpoints exist to be enabled.");
10375a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
10385a988416SJim Ingham       return false;
10395a988416SJim Ingham     }
10405a988416SJim Ingham 
104111eb9c64SZachary Turner     if (command.empty()) {
10425a988416SJim Ingham       // No breakpoint selected; enable all currently set breakpoints.
1043*b842f2ecSJim Ingham       target->EnableAllowedBreakpoints();
1044b9c1b51eSKate Stone       result.AppendMessageWithFormat("All breakpoints enabled. (%" PRIu64
1045b9c1b51eSKate Stone                                      " breakpoints)\n",
1046b9c1b51eSKate Stone                                      (uint64_t)num_breakpoints);
10475a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1048b9c1b51eSKate Stone     } else {
10495a988416SJim Ingham       // Particular breakpoint selected; enable that breakpoint.
10505a988416SJim Ingham       BreakpointIDList valid_bp_ids;
1051b9c1b51eSKate Stone       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1052*b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
1053*b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::disablePerm);
10545a988416SJim Ingham 
1055b9c1b51eSKate Stone       if (result.Succeeded()) {
10565a988416SJim Ingham         int enable_count = 0;
10575a988416SJim Ingham         int loc_count = 0;
10585a988416SJim Ingham         const size_t count = valid_bp_ids.GetSize();
1059b9c1b51eSKate Stone         for (size_t i = 0; i < count; ++i) {
10605a988416SJim Ingham           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
10615a988416SJim Ingham 
1062b9c1b51eSKate Stone           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1063b9c1b51eSKate Stone             Breakpoint *breakpoint =
1064b9c1b51eSKate Stone                 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1065b9c1b51eSKate Stone             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1066b9c1b51eSKate Stone               BreakpointLocation *location =
1067b9c1b51eSKate Stone                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1068b9c1b51eSKate Stone               if (location) {
10695a988416SJim Ingham                 location->SetEnabled(true);
10705a988416SJim Ingham                 ++loc_count;
10715a988416SJim Ingham               }
1072b9c1b51eSKate Stone             } else {
10735a988416SJim Ingham               breakpoint->SetEnabled(true);
10745a988416SJim Ingham               ++enable_count;
10755a988416SJim Ingham             }
10765a988416SJim Ingham           }
10775a988416SJim Ingham         }
1078b9c1b51eSKate Stone         result.AppendMessageWithFormat("%d breakpoints enabled.\n",
1079b9c1b51eSKate Stone                                        enable_count + loc_count);
10805a988416SJim Ingham         result.SetStatus(eReturnStatusSuccessFinishNoResult);
10815a988416SJim Ingham       }
10825a988416SJim Ingham     }
10835a988416SJim Ingham 
10845a988416SJim Ingham     return result.Succeeded();
10855a988416SJim Ingham   }
10865a988416SJim Ingham };
10875a988416SJim Ingham 
10885a988416SJim Ingham //-------------------------------------------------------------------------
10895a988416SJim Ingham // CommandObjectBreakpointDisable
10905a988416SJim Ingham //-------------------------------------------------------------------------
10915a988416SJim Ingham #pragma mark Disable
10925a988416SJim Ingham 
1093b9c1b51eSKate Stone class CommandObjectBreakpointDisable : public CommandObjectParsed {
10945a988416SJim Ingham public:
10957428a18cSKate Stone   CommandObjectBreakpointDisable(CommandInterpreter &interpreter)
1096b9c1b51eSKate Stone       : CommandObjectParsed(
1097b9c1b51eSKate Stone             interpreter, "breakpoint disable",
1098b9c1b51eSKate Stone             "Disable the specified breakpoint(s) without deleting "
10997428a18cSKate Stone             "them.  If none are specified, disable all "
11007428a18cSKate Stone             "breakpoints.",
1101b9c1b51eSKate Stone             nullptr) {
1102b9c1b51eSKate Stone     SetHelpLong(
1103b9c1b51eSKate Stone         "Disable the specified breakpoint(s) without deleting them.  \
11047428a18cSKate Stone If none are specified, disable all breakpoints."
11057428a18cSKate Stone         R"(
1106ea671fbdSKate Stone 
11077428a18cSKate Stone )"
11087428a18cSKate Stone         "Note: disabling a breakpoint will cause none of its locations to be hit \
11097428a18cSKate Stone regardless of whether individual locations are enabled or disabled.  After the sequence:"
11107428a18cSKate Stone         R"(
1111ea671fbdSKate Stone 
1112ea671fbdSKate Stone     (lldb) break disable 1
1113ea671fbdSKate Stone     (lldb) break enable 1.1
1114ea671fbdSKate Stone 
1115ea671fbdSKate Stone execution will NOT stop at location 1.1.  To achieve that, type:
1116ea671fbdSKate Stone 
1117ea671fbdSKate Stone     (lldb) break disable 1.*
1118ea671fbdSKate Stone     (lldb) break enable 1.1
1119ea671fbdSKate Stone 
11207428a18cSKate Stone )"
11217428a18cSKate Stone         "The first command disables all locations for breakpoint 1, \
11227428a18cSKate Stone the second re-enables the first location.");
1123b0fac509SJim Ingham 
11245a988416SJim Ingham     CommandArgumentEntry arg;
1125b9c1b51eSKate Stone     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1126b9c1b51eSKate Stone                                       eArgTypeBreakpointIDRange);
1127b9c1b51eSKate Stone     // Add the entry for the first argument for this command to the object's
1128b9c1b51eSKate Stone     // arguments vector.
11295a988416SJim Ingham     m_arguments.push_back(arg);
11305a988416SJim Ingham   }
11315a988416SJim Ingham 
11329e85e5a8SEugene Zelenko   ~CommandObjectBreakpointDisable() override = default;
11335a988416SJim Ingham 
11345a988416SJim Ingham protected:
1135b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1136893c932aSJim Ingham     Target *target = GetSelectedOrDummyTarget();
1137b9c1b51eSKate Stone     if (target == nullptr) {
11385a988416SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
11395a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
11405a988416SJim Ingham       return false;
11415a988416SJim Ingham     }
11425a988416SJim Ingham 
1143bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1144bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
11455a988416SJim Ingham 
11465a988416SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
11475a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
11485a988416SJim Ingham 
1149b9c1b51eSKate Stone     if (num_breakpoints == 0) {
11505a988416SJim Ingham       result.AppendError("No breakpoints exist to be disabled.");
11515a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
11525a988416SJim Ingham       return false;
11535a988416SJim Ingham     }
11545a988416SJim Ingham 
115511eb9c64SZachary Turner     if (command.empty()) {
11565a988416SJim Ingham       // No breakpoint selected; disable all currently set breakpoints.
1157*b842f2ecSJim Ingham       target->DisableAllowedBreakpoints();
1158b9c1b51eSKate Stone       result.AppendMessageWithFormat("All breakpoints disabled. (%" PRIu64
1159b9c1b51eSKate Stone                                      " breakpoints)\n",
1160b9c1b51eSKate Stone                                      (uint64_t)num_breakpoints);
11615a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1162b9c1b51eSKate Stone     } else {
11635a988416SJim Ingham       // Particular breakpoint selected; disable that breakpoint.
11645a988416SJim Ingham       BreakpointIDList valid_bp_ids;
11655a988416SJim Ingham 
1166b9c1b51eSKate Stone       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1167*b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
1168*b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::disablePerm);
11695a988416SJim Ingham 
1170b9c1b51eSKate Stone       if (result.Succeeded()) {
11715a988416SJim Ingham         int disable_count = 0;
11725a988416SJim Ingham         int loc_count = 0;
11735a988416SJim Ingham         const size_t count = valid_bp_ids.GetSize();
1174b9c1b51eSKate Stone         for (size_t i = 0; i < count; ++i) {
11755a988416SJim Ingham           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
11765a988416SJim Ingham 
1177b9c1b51eSKate Stone           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1178b9c1b51eSKate Stone             Breakpoint *breakpoint =
1179b9c1b51eSKate Stone                 target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1180b9c1b51eSKate Stone             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1181b9c1b51eSKate Stone               BreakpointLocation *location =
1182b9c1b51eSKate Stone                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1183b9c1b51eSKate Stone               if (location) {
11845a988416SJim Ingham                 location->SetEnabled(false);
11855a988416SJim Ingham                 ++loc_count;
11865a988416SJim Ingham               }
1187b9c1b51eSKate Stone             } else {
11885a988416SJim Ingham               breakpoint->SetEnabled(false);
11895a988416SJim Ingham               ++disable_count;
11905a988416SJim Ingham             }
11915a988416SJim Ingham           }
11925a988416SJim Ingham         }
1193b9c1b51eSKate Stone         result.AppendMessageWithFormat("%d breakpoints disabled.\n",
1194b9c1b51eSKate Stone                                        disable_count + loc_count);
11955a988416SJim Ingham         result.SetStatus(eReturnStatusSuccessFinishNoResult);
11965a988416SJim Ingham       }
11975a988416SJim Ingham     }
11985a988416SJim Ingham 
11995a988416SJim Ingham     return result.Succeeded();
12005a988416SJim Ingham   }
12015a988416SJim Ingham };
12025a988416SJim Ingham 
12035a988416SJim Ingham //-------------------------------------------------------------------------
12045a988416SJim Ingham // CommandObjectBreakpointList
12055a988416SJim Ingham //-------------------------------------------------------------------------
12061f0f5b5bSZachary Turner 
12071f0f5b5bSZachary Turner #pragma mark List::CommandOptions
12081f0f5b5bSZachary Turner static OptionDefinition g_breakpoint_list_options[] = {
12091f0f5b5bSZachary Turner     // clang-format off
12101f0f5b5bSZachary Turner   { LLDB_OPT_SET_ALL, false, "internal",          'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Show debugger internal breakpoints" },
12111f0f5b5bSZachary Turner   { LLDB_OPT_SET_1,   false, "brief",             'b', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a brief description of the breakpoint (no location info)." },
12121f0f5b5bSZachary Turner   // FIXME: We need to add an "internal" command, and then add this sort of thing to it.
12131f0f5b5bSZachary Turner   // But I need to see it for now, and don't want to wait.
12141f0f5b5bSZachary Turner   { LLDB_OPT_SET_2,   false, "full",              'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Give a full description of the breakpoint and its locations." },
12151f0f5b5bSZachary Turner   { LLDB_OPT_SET_3,   false, "verbose",           'v', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Explain everything we know about the breakpoint (for debugging debugger bugs)." },
12161f0f5b5bSZachary Turner   { LLDB_OPT_SET_ALL, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "List Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." },
12171f0f5b5bSZachary Turner     // clang-format on
12181f0f5b5bSZachary Turner };
12191f0f5b5bSZachary Turner 
12205a988416SJim Ingham #pragma mark List
12215a988416SJim Ingham 
1222b9c1b51eSKate Stone class CommandObjectBreakpointList : public CommandObjectParsed {
12235a988416SJim Ingham public:
1224b9c1b51eSKate Stone   CommandObjectBreakpointList(CommandInterpreter &interpreter)
1225b9c1b51eSKate Stone       : CommandObjectParsed(
1226b9c1b51eSKate Stone             interpreter, "breakpoint list",
12275a988416SJim Ingham             "List some or all breakpoints at configurable levels of detail.",
12289e85e5a8SEugene Zelenko             nullptr),
1229b9c1b51eSKate Stone         m_options() {
12305a988416SJim Ingham     CommandArgumentEntry arg;
12315a988416SJim Ingham     CommandArgumentData bp_id_arg;
12325a988416SJim Ingham 
12335a988416SJim Ingham     // Define the first (and only) variant of this arg.
12345a988416SJim Ingham     bp_id_arg.arg_type = eArgTypeBreakpointID;
12355a988416SJim Ingham     bp_id_arg.arg_repetition = eArgRepeatOptional;
12365a988416SJim Ingham 
1237b9c1b51eSKate Stone     // There is only one variant this argument could be; put it into the
1238b9c1b51eSKate Stone     // argument entry.
12395a988416SJim Ingham     arg.push_back(bp_id_arg);
12405a988416SJim Ingham 
12415a988416SJim Ingham     // Push the data for the first argument into the m_arguments vector.
12425a988416SJim Ingham     m_arguments.push_back(arg);
12435a988416SJim Ingham   }
12445a988416SJim Ingham 
12459e85e5a8SEugene Zelenko   ~CommandObjectBreakpointList() override = default;
12465a988416SJim Ingham 
1247b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
12485a988416SJim Ingham 
1249b9c1b51eSKate Stone   class CommandOptions : public Options {
12505a988416SJim Ingham   public:
1251b9c1b51eSKate Stone     CommandOptions()
1252b9c1b51eSKate Stone         : Options(), m_level(lldb::eDescriptionLevelBrief), m_use_dummy(false) {
12535a988416SJim Ingham     }
12545a988416SJim Ingham 
12559e85e5a8SEugene Zelenko     ~CommandOptions() override = default;
12565a988416SJim Ingham 
125797206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1258b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
125997206d57SZachary Turner       Status error;
12603bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
12615a988416SJim Ingham 
1262b9c1b51eSKate Stone       switch (short_option) {
12635a988416SJim Ingham       case 'b':
12645a988416SJim Ingham         m_level = lldb::eDescriptionLevelBrief;
12655a988416SJim Ingham         break;
126633df7cd3SJim Ingham       case 'D':
126733df7cd3SJim Ingham         m_use_dummy = true;
126833df7cd3SJim Ingham         break;
12695a988416SJim Ingham       case 'f':
12705a988416SJim Ingham         m_level = lldb::eDescriptionLevelFull;
12715a988416SJim Ingham         break;
12725a988416SJim Ingham       case 'v':
12735a988416SJim Ingham         m_level = lldb::eDescriptionLevelVerbose;
12745a988416SJim Ingham         break;
12755a988416SJim Ingham       case 'i':
12765a988416SJim Ingham         m_internal = true;
12775a988416SJim Ingham         break;
12785a988416SJim Ingham       default:
1279b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
1280b9c1b51eSKate Stone                                        short_option);
12815a988416SJim Ingham         break;
12825a988416SJim Ingham       }
12835a988416SJim Ingham 
12845a988416SJim Ingham       return error;
12855a988416SJim Ingham     }
12865a988416SJim Ingham 
1287b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
12885a988416SJim Ingham       m_level = lldb::eDescriptionLevelFull;
12895a988416SJim Ingham       m_internal = false;
129033df7cd3SJim Ingham       m_use_dummy = false;
12915a988416SJim Ingham     }
12925a988416SJim Ingham 
12931f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
129470602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_list_options);
12951f0f5b5bSZachary Turner     }
12965a988416SJim Ingham 
12975a988416SJim Ingham     // Instance variables to hold the values for command options.
12985a988416SJim Ingham 
12995a988416SJim Ingham     lldb::DescriptionLevel m_level;
13005a988416SJim Ingham 
13015a988416SJim Ingham     bool m_internal;
130233df7cd3SJim Ingham     bool m_use_dummy;
13035a988416SJim Ingham   };
13045a988416SJim Ingham 
13055a988416SJim Ingham protected:
1306b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
130733df7cd3SJim Ingham     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
130833df7cd3SJim Ingham 
1309b9c1b51eSKate Stone     if (target == nullptr) {
13105a988416SJim Ingham       result.AppendError("Invalid target. No current target or breakpoints.");
13115a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
13125a988416SJim Ingham       return true;
13135a988416SJim Ingham     }
13145a988416SJim Ingham 
1315b9c1b51eSKate Stone     const BreakpointList &breakpoints =
1316b9c1b51eSKate Stone         target->GetBreakpointList(m_options.m_internal);
1317bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1318bb19a13cSSaleem Abdulrasool     target->GetBreakpointList(m_options.m_internal).GetListMutex(lock);
13195a988416SJim Ingham 
13205a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
13215a988416SJim Ingham 
1322b9c1b51eSKate Stone     if (num_breakpoints == 0) {
13235a988416SJim Ingham       result.AppendMessage("No breakpoints currently set.");
13245a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
13255a988416SJim Ingham       return true;
13265a988416SJim Ingham     }
13275a988416SJim Ingham 
13285a988416SJim Ingham     Stream &output_stream = result.GetOutputStream();
13295a988416SJim Ingham 
133011eb9c64SZachary Turner     if (command.empty()) {
13315a988416SJim Ingham       // No breakpoint selected; show info about all currently set breakpoints.
13325a988416SJim Ingham       result.AppendMessage("Current breakpoints:");
1333b9c1b51eSKate Stone       for (size_t i = 0; i < num_breakpoints; ++i) {
13345a988416SJim Ingham         Breakpoint *breakpoint = breakpoints.GetBreakpointAtIndex(i).get();
1335*b842f2ecSJim Ingham         if (breakpoint->AllowList())
1336*b842f2ecSJim Ingham           AddBreakpointDescription(&output_stream, breakpoint,
1337*b842f2ecSJim Ingham                                    m_options.m_level);
13385a988416SJim Ingham       }
13395a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1340b9c1b51eSKate Stone     } else {
13415a988416SJim Ingham       // Particular breakpoints selected; show info about that breakpoint.
13425a988416SJim Ingham       BreakpointIDList valid_bp_ids;
1343b9c1b51eSKate Stone       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1344*b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
1345*b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::listPerm);
13465a988416SJim Ingham 
1347b9c1b51eSKate Stone       if (result.Succeeded()) {
1348b9c1b51eSKate Stone         for (size_t i = 0; i < valid_bp_ids.GetSize(); ++i) {
13495a988416SJim Ingham           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
1350b9c1b51eSKate Stone           Breakpoint *breakpoint =
1351b9c1b51eSKate Stone               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1352b9c1b51eSKate Stone           AddBreakpointDescription(&output_stream, breakpoint,
1353b9c1b51eSKate Stone                                    m_options.m_level);
13545a988416SJim Ingham         }
13555a988416SJim Ingham         result.SetStatus(eReturnStatusSuccessFinishNoResult);
1356b9c1b51eSKate Stone       } else {
13577428a18cSKate Stone         result.AppendError("Invalid breakpoint ID.");
13585a988416SJim Ingham         result.SetStatus(eReturnStatusFailed);
13595a988416SJim Ingham       }
13605a988416SJim Ingham     }
13615a988416SJim Ingham 
13625a988416SJim Ingham     return result.Succeeded();
13635a988416SJim Ingham   }
13645a988416SJim Ingham 
13655a988416SJim Ingham private:
13665a988416SJim Ingham   CommandOptions m_options;
13675a988416SJim Ingham };
13685a988416SJim Ingham 
13695a988416SJim Ingham //-------------------------------------------------------------------------
13705a988416SJim Ingham // CommandObjectBreakpointClear
13715a988416SJim Ingham //-------------------------------------------------------------------------
13721f0f5b5bSZachary Turner #pragma mark Clear::CommandOptions
13731f0f5b5bSZachary Turner 
13741f0f5b5bSZachary Turner static OptionDefinition g_breakpoint_clear_options[] = {
13751f0f5b5bSZachary Turner     // clang-format off
13761f0f5b5bSZachary Turner   { LLDB_OPT_SET_1, false, "file", 'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eSourceFileCompletion, eArgTypeFilename, "Specify the breakpoint by source location in this particular file." },
13771f0f5b5bSZachary Turner   { LLDB_OPT_SET_1, true,  "line", 'l', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                         eArgTypeLineNum,  "Specify the breakpoint by source location at this particular line." }
13781f0f5b5bSZachary Turner     // clang-format on
13791f0f5b5bSZachary Turner };
13801f0f5b5bSZachary Turner 
13815a988416SJim Ingham #pragma mark Clear
13825a988416SJim Ingham 
1383b9c1b51eSKate Stone class CommandObjectBreakpointClear : public CommandObjectParsed {
13845a988416SJim Ingham public:
1385b9c1b51eSKate Stone   typedef enum BreakpointClearType {
13865a988416SJim Ingham     eClearTypeInvalid,
13875a988416SJim Ingham     eClearTypeFileAndLine
13885a988416SJim Ingham   } BreakpointClearType;
13895a988416SJim Ingham 
13907428a18cSKate Stone   CommandObjectBreakpointClear(CommandInterpreter &interpreter)
13917428a18cSKate Stone       : CommandObjectParsed(interpreter, "breakpoint clear",
1392b9c1b51eSKate Stone                             "Delete or disable breakpoints matching the "
1393b9c1b51eSKate Stone                             "specified source file and line.",
13945a988416SJim Ingham                             "breakpoint clear <cmd-options>"),
1395b9c1b51eSKate Stone         m_options() {}
13965a988416SJim Ingham 
13979e85e5a8SEugene Zelenko   ~CommandObjectBreakpointClear() override = default;
13985a988416SJim Ingham 
1399b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
14005a988416SJim Ingham 
1401b9c1b51eSKate Stone   class CommandOptions : public Options {
14025a988416SJim Ingham   public:
1403b9c1b51eSKate Stone     CommandOptions() : Options(), m_filename(), m_line_num(0) {}
14045a988416SJim Ingham 
14059e85e5a8SEugene Zelenko     ~CommandOptions() override = default;
14065a988416SJim Ingham 
140797206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1408b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
140997206d57SZachary Turner       Status error;
14103bcdfc0eSGreg Clayton       const int short_option = m_getopt_table[option_idx].val;
14115a988416SJim Ingham 
1412b9c1b51eSKate Stone       switch (short_option) {
14135a988416SJim Ingham       case 'f':
14145a988416SJim Ingham         m_filename.assign(option_arg);
14155a988416SJim Ingham         break;
14165a988416SJim Ingham 
14175a988416SJim Ingham       case 'l':
1418fe11483bSZachary Turner         option_arg.getAsInteger(0, m_line_num);
14195a988416SJim Ingham         break;
14205a988416SJim Ingham 
14215a988416SJim Ingham       default:
1422b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
1423b9c1b51eSKate Stone                                        short_option);
14245a988416SJim Ingham         break;
14255a988416SJim Ingham       }
14265a988416SJim Ingham 
14275a988416SJim Ingham       return error;
14285a988416SJim Ingham     }
14295a988416SJim Ingham 
1430b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
14315a988416SJim Ingham       m_filename.clear();
14325a988416SJim Ingham       m_line_num = 0;
14335a988416SJim Ingham     }
14345a988416SJim Ingham 
14351f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
143670602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_clear_options);
14371f0f5b5bSZachary Turner     }
14385a988416SJim Ingham 
14395a988416SJim Ingham     // Instance variables to hold the values for command options.
14405a988416SJim Ingham 
14415a988416SJim Ingham     std::string m_filename;
14425a988416SJim Ingham     uint32_t m_line_num;
14435a988416SJim Ingham   };
14445a988416SJim Ingham 
14455a988416SJim Ingham protected:
1446b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1447893c932aSJim Ingham     Target *target = GetSelectedOrDummyTarget();
1448b9c1b51eSKate Stone     if (target == nullptr) {
14495a988416SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
14505a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
14515a988416SJim Ingham       return false;
14525a988416SJim Ingham     }
14535a988416SJim Ingham 
14545a988416SJim Ingham     // The following are the various types of breakpoints that could be cleared:
14555a988416SJim Ingham     //   1). -f -l (clearing breakpoint by source location)
14565a988416SJim Ingham 
14575a988416SJim Ingham     BreakpointClearType break_type = eClearTypeInvalid;
14585a988416SJim Ingham 
14595a988416SJim Ingham     if (m_options.m_line_num != 0)
14605a988416SJim Ingham       break_type = eClearTypeFileAndLine;
14615a988416SJim Ingham 
1462bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1463bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
14645a988416SJim Ingham 
14655a988416SJim Ingham     BreakpointList &breakpoints = target->GetBreakpointList();
14665a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
14675a988416SJim Ingham 
14685a988416SJim Ingham     // Early return if there's no breakpoint at all.
1469b9c1b51eSKate Stone     if (num_breakpoints == 0) {
14705a988416SJim Ingham       result.AppendError("Breakpoint clear: No breakpoint cleared.");
14715a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
14725a988416SJim Ingham       return result.Succeeded();
14735a988416SJim Ingham     }
14745a988416SJim Ingham 
14755a988416SJim Ingham     // Find matching breakpoints and delete them.
14765a988416SJim Ingham 
14775a988416SJim Ingham     // First create a copy of all the IDs.
14785a988416SJim Ingham     std::vector<break_id_t> BreakIDs;
14795a988416SJim Ingham     for (size_t i = 0; i < num_breakpoints; ++i)
14809e85e5a8SEugene Zelenko       BreakIDs.push_back(breakpoints.GetBreakpointAtIndex(i)->GetID());
14815a988416SJim Ingham 
14825a988416SJim Ingham     int num_cleared = 0;
14835a988416SJim Ingham     StreamString ss;
1484b9c1b51eSKate Stone     switch (break_type) {
14855a988416SJim Ingham     case eClearTypeFileAndLine: // Breakpoint by source position
14865a988416SJim Ingham     {
14875a988416SJim Ingham       const ConstString filename(m_options.m_filename.c_str());
14885a988416SJim Ingham       BreakpointLocationCollection loc_coll;
14895a988416SJim Ingham 
1490b9c1b51eSKate Stone       for (size_t i = 0; i < num_breakpoints; ++i) {
14915a988416SJim Ingham         Breakpoint *bp = breakpoints.FindBreakpointByID(BreakIDs[i]).get();
14925a988416SJim Ingham 
1493b9c1b51eSKate Stone         if (bp->GetMatchingFileLine(filename, m_options.m_line_num, loc_coll)) {
1494b9c1b51eSKate Stone           // If the collection size is 0, it's a full match and we can just
1495b9c1b51eSKate Stone           // remove the breakpoint.
1496b9c1b51eSKate Stone           if (loc_coll.GetSize() == 0) {
14975a988416SJim Ingham             bp->GetDescription(&ss, lldb::eDescriptionLevelBrief);
14985a988416SJim Ingham             ss.EOL();
14995a988416SJim Ingham             target->RemoveBreakpointByID(bp->GetID());
15005a988416SJim Ingham             ++num_cleared;
15015a988416SJim Ingham           }
15025a988416SJim Ingham         }
15035a988416SJim Ingham       }
1504b9c1b51eSKate Stone     } break;
15055a988416SJim Ingham 
15065a988416SJim Ingham     default:
15075a988416SJim Ingham       break;
15085a988416SJim Ingham     }
15095a988416SJim Ingham 
1510b9c1b51eSKate Stone     if (num_cleared > 0) {
15115a988416SJim Ingham       Stream &output_stream = result.GetOutputStream();
15125a988416SJim Ingham       output_stream.Printf("%d breakpoints cleared:\n", num_cleared);
1513c156427dSZachary Turner       output_stream << ss.GetString();
15145a988416SJim Ingham       output_stream.EOL();
15155a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1516b9c1b51eSKate Stone     } else {
15175a988416SJim Ingham       result.AppendError("Breakpoint clear: No breakpoint cleared.");
15185a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
15195a988416SJim Ingham     }
15205a988416SJim Ingham 
15215a988416SJim Ingham     return result.Succeeded();
15225a988416SJim Ingham   }
15235a988416SJim Ingham 
15245a988416SJim Ingham private:
15255a988416SJim Ingham   CommandOptions m_options;
15265a988416SJim Ingham };
15275a988416SJim Ingham 
15285a988416SJim Ingham //-------------------------------------------------------------------------
15295a988416SJim Ingham // CommandObjectBreakpointDelete
15305a988416SJim Ingham //-------------------------------------------------------------------------
15311f0f5b5bSZachary Turner static OptionDefinition g_breakpoint_delete_options[] = {
15321f0f5b5bSZachary Turner     // clang-format off
15331f0f5b5bSZachary Turner   { LLDB_OPT_SET_1, false, "force",             'f', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete all breakpoints without querying for confirmation." },
15341f0f5b5bSZachary Turner   { LLDB_OPT_SET_1, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Delete Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets." },
15351f0f5b5bSZachary Turner     // clang-format on
15361f0f5b5bSZachary Turner };
15371f0f5b5bSZachary Turner 
15385a988416SJim Ingham #pragma mark Delete
15395a988416SJim Ingham 
1540b9c1b51eSKate Stone class CommandObjectBreakpointDelete : public CommandObjectParsed {
15415a988416SJim Ingham public:
1542b9c1b51eSKate Stone   CommandObjectBreakpointDelete(CommandInterpreter &interpreter)
1543b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "breakpoint delete",
1544b9c1b51eSKate Stone                             "Delete the specified breakpoint(s).  If no "
1545b9c1b51eSKate Stone                             "breakpoints are specified, delete them all.",
15469e85e5a8SEugene Zelenko                             nullptr),
1547b9c1b51eSKate Stone         m_options() {
15485a988416SJim Ingham     CommandArgumentEntry arg;
1549b9c1b51eSKate Stone     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
1550b9c1b51eSKate Stone                                       eArgTypeBreakpointIDRange);
1551b9c1b51eSKate Stone     // Add the entry for the first argument for this command to the object's
1552b9c1b51eSKate Stone     // arguments vector.
15535a988416SJim Ingham     m_arguments.push_back(arg);
15545a988416SJim Ingham   }
15555a988416SJim Ingham 
15569e85e5a8SEugene Zelenko   ~CommandObjectBreakpointDelete() override = default;
15575a988416SJim Ingham 
1558b9c1b51eSKate Stone   Options *GetOptions() override { return &m_options; }
155933df7cd3SJim Ingham 
1560b9c1b51eSKate Stone   class CommandOptions : public Options {
156133df7cd3SJim Ingham   public:
1562b9c1b51eSKate Stone     CommandOptions() : Options(), m_use_dummy(false), m_force(false) {}
156333df7cd3SJim Ingham 
15649e85e5a8SEugene Zelenko     ~CommandOptions() override = default;
156533df7cd3SJim Ingham 
156697206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1567b9c1b51eSKate Stone                           ExecutionContext *execution_context) override {
156897206d57SZachary Turner       Status error;
156933df7cd3SJim Ingham       const int short_option = m_getopt_table[option_idx].val;
157033df7cd3SJim Ingham 
1571b9c1b51eSKate Stone       switch (short_option) {
157233df7cd3SJim Ingham       case 'f':
157333df7cd3SJim Ingham         m_force = true;
157433df7cd3SJim Ingham         break;
157533df7cd3SJim Ingham 
157633df7cd3SJim Ingham       case 'D':
157733df7cd3SJim Ingham         m_use_dummy = true;
157833df7cd3SJim Ingham         break;
157933df7cd3SJim Ingham 
158033df7cd3SJim Ingham       default:
1581b9c1b51eSKate Stone         error.SetErrorStringWithFormat("unrecognized option '%c'",
1582b9c1b51eSKate Stone                                        short_option);
158333df7cd3SJim Ingham         break;
158433df7cd3SJim Ingham       }
158533df7cd3SJim Ingham 
158633df7cd3SJim Ingham       return error;
158733df7cd3SJim Ingham     }
158833df7cd3SJim Ingham 
1589b9c1b51eSKate Stone     void OptionParsingStarting(ExecutionContext *execution_context) override {
159033df7cd3SJim Ingham       m_use_dummy = false;
159133df7cd3SJim Ingham       m_force = false;
159233df7cd3SJim Ingham     }
159333df7cd3SJim Ingham 
15941f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
159570602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_delete_options);
15961f0f5b5bSZachary Turner     }
159733df7cd3SJim Ingham 
159833df7cd3SJim Ingham     // Instance variables to hold the values for command options.
159933df7cd3SJim Ingham     bool m_use_dummy;
160033df7cd3SJim Ingham     bool m_force;
160133df7cd3SJim Ingham   };
160233df7cd3SJim Ingham 
16035a988416SJim Ingham protected:
1604b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
160533df7cd3SJim Ingham     Target *target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
160633df7cd3SJim Ingham 
1607b9c1b51eSKate Stone     if (target == nullptr) {
16085a988416SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
16095a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
16105a988416SJim Ingham       return false;
16115a988416SJim Ingham     }
16125a988416SJim Ingham 
1613bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1614bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
16155a988416SJim Ingham 
16165a988416SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
16175a988416SJim Ingham 
16185a988416SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
16195a988416SJim Ingham 
1620b9c1b51eSKate Stone     if (num_breakpoints == 0) {
16215a988416SJim Ingham       result.AppendError("No breakpoints exist to be deleted.");
16225a988416SJim Ingham       result.SetStatus(eReturnStatusFailed);
16235a988416SJim Ingham       return false;
16245a988416SJim Ingham     }
16255a988416SJim Ingham 
162611eb9c64SZachary Turner     if (command.empty()) {
1627b9c1b51eSKate Stone       if (!m_options.m_force &&
1628b9c1b51eSKate Stone           !m_interpreter.Confirm(
1629b9c1b51eSKate Stone               "About to delete all breakpoints, do you want to do that?",
1630b9c1b51eSKate Stone               true)) {
16315a988416SJim Ingham         result.AppendMessage("Operation cancelled...");
1632b9c1b51eSKate Stone       } else {
1633*b842f2ecSJim Ingham         target->RemoveAllowedBreakpoints();
1634b9c1b51eSKate Stone         result.AppendMessageWithFormat(
1635b9c1b51eSKate Stone             "All breakpoints removed. (%" PRIu64 " breakpoint%s)\n",
1636b9c1b51eSKate Stone             (uint64_t)num_breakpoints, num_breakpoints > 1 ? "s" : "");
16375a988416SJim Ingham       }
16385a988416SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
1639b9c1b51eSKate Stone     } else {
16405a988416SJim Ingham       // Particular breakpoint selected; disable that breakpoint.
16415a988416SJim Ingham       BreakpointIDList valid_bp_ids;
1642b9c1b51eSKate Stone       CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
1643*b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
1644*b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::deletePerm);
16455a988416SJim Ingham 
1646b9c1b51eSKate Stone       if (result.Succeeded()) {
16475a988416SJim Ingham         int delete_count = 0;
16485a988416SJim Ingham         int disable_count = 0;
16495a988416SJim Ingham         const size_t count = valid_bp_ids.GetSize();
1650b9c1b51eSKate Stone         for (size_t i = 0; i < count; ++i) {
16515a988416SJim Ingham           BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
16525a988416SJim Ingham 
1653b9c1b51eSKate Stone           if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
1654b9c1b51eSKate Stone             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
1655b9c1b51eSKate Stone               Breakpoint *breakpoint =
1656b9c1b51eSKate Stone                   target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
1657b9c1b51eSKate Stone               BreakpointLocation *location =
1658b9c1b51eSKate Stone                   breakpoint->FindLocationByID(cur_bp_id.GetLocationID()).get();
1659b9c1b51eSKate Stone               // It makes no sense to try to delete individual locations, so we
1660b9c1b51eSKate Stone               // disable them instead.
1661b9c1b51eSKate Stone               if (location) {
16625a988416SJim Ingham                 location->SetEnabled(false);
16635a988416SJim Ingham                 ++disable_count;
16645a988416SJim Ingham               }
1665b9c1b51eSKate Stone             } else {
16665a988416SJim Ingham               target->RemoveBreakpointByID(cur_bp_id.GetBreakpointID());
16675a988416SJim Ingham               ++delete_count;
16685a988416SJim Ingham             }
16695a988416SJim Ingham           }
16705a988416SJim Ingham         }
1671b9c1b51eSKate Stone         result.AppendMessageWithFormat(
1672b9c1b51eSKate Stone             "%d breakpoints deleted; %d breakpoint locations disabled.\n",
16735a988416SJim Ingham             delete_count, disable_count);
16745a988416SJim Ingham         result.SetStatus(eReturnStatusSuccessFinishNoResult);
16755a988416SJim Ingham       }
16765a988416SJim Ingham     }
16775a988416SJim Ingham     return result.Succeeded();
16785a988416SJim Ingham   }
16799e85e5a8SEugene Zelenko 
168033df7cd3SJim Ingham private:
168133df7cd3SJim Ingham   CommandOptions m_options;
168233df7cd3SJim Ingham };
168333df7cd3SJim Ingham 
168430fdc8d8SChris Lattner //-------------------------------------------------------------------------
16855e09c8c3SJim Ingham // CommandObjectBreakpointName
16865e09c8c3SJim Ingham //-------------------------------------------------------------------------
16875e09c8c3SJim Ingham 
16887428a18cSKate Stone static OptionDefinition g_breakpoint_name_options[] = {
1689ac9c3a62SKate Stone     // clang-format off
1690ac9c3a62SKate Stone   {LLDB_OPT_SET_1,   false, "name",              'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointName, "Specifies a breakpoint name to use."},
1691ac9c3a62SKate Stone   {LLDB_OPT_SET_2,   false, "breakpoint-id",     'B', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBreakpointID,   "Specify a breakpoint ID to use."},
1692*b842f2ecSJim Ingham   {LLDB_OPT_SET_3, false, "dummy-breakpoints", 'D', OptionParser::eNoArgument,       nullptr, nullptr, 0, eArgTypeNone,           "Operate on Dummy breakpoints - i.e. breakpoints set before a file is provided, which prime new targets."},
1693ac9c3a62SKate Stone     // clang-format on
16945e09c8c3SJim Ingham };
1695b9c1b51eSKate Stone class BreakpointNameOptionGroup : public OptionGroup {
16965e09c8c3SJim Ingham public:
1697b9c1b51eSKate Stone   BreakpointNameOptionGroup()
1698b9c1b51eSKate Stone       : OptionGroup(), m_breakpoint(LLDB_INVALID_BREAK_ID), m_use_dummy(false) {
16995e09c8c3SJim Ingham   }
17005e09c8c3SJim Ingham 
17019e85e5a8SEugene Zelenko   ~BreakpointNameOptionGroup() override = default;
17025e09c8c3SJim Ingham 
17031f0f5b5bSZachary Turner   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
170470602439SZachary Turner     return llvm::makeArrayRef(g_breakpoint_name_options);
17055e09c8c3SJim Ingham   }
17065e09c8c3SJim Ingham 
170797206d57SZachary Turner   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1708b9c1b51eSKate Stone                         ExecutionContext *execution_context) override {
170997206d57SZachary Turner     Status error;
17105e09c8c3SJim Ingham     const int short_option = g_breakpoint_name_options[option_idx].short_option;
17115e09c8c3SJim Ingham 
1712b9c1b51eSKate Stone     switch (short_option) {
17135e09c8c3SJim Ingham     case 'N':
1714fe11483bSZachary Turner       if (BreakpointID::StringIsBreakpointName(option_arg, error) &&
1715b9c1b51eSKate Stone           error.Success())
1716fe11483bSZachary Turner         m_name.SetValueFromString(option_arg);
17175e09c8c3SJim Ingham       break;
17185e09c8c3SJim Ingham 
17195e09c8c3SJim Ingham     case 'B':
1720fe11483bSZachary Turner       if (m_breakpoint.SetValueFromString(option_arg).Fail())
1721b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
17228cef4b0bSZachary Turner             "unrecognized value \"%s\" for breakpoint",
1723fe11483bSZachary Turner             option_arg.str().c_str());
17245e09c8c3SJim Ingham       break;
17255e09c8c3SJim Ingham     case 'D':
1726fe11483bSZachary Turner       if (m_use_dummy.SetValueFromString(option_arg).Fail())
1727b9c1b51eSKate Stone         error.SetErrorStringWithFormat(
17288cef4b0bSZachary Turner             "unrecognized value \"%s\" for use-dummy",
1729fe11483bSZachary Turner             option_arg.str().c_str());
17305e09c8c3SJim Ingham       break;
17315e09c8c3SJim Ingham 
17325e09c8c3SJim Ingham     default:
1733b9c1b51eSKate Stone       error.SetErrorStringWithFormat("unrecognized short option '%c'",
1734b9c1b51eSKate Stone                                      short_option);
17355e09c8c3SJim Ingham       break;
17365e09c8c3SJim Ingham     }
17375e09c8c3SJim Ingham     return error;
17385e09c8c3SJim Ingham   }
17395e09c8c3SJim Ingham 
1740b9c1b51eSKate Stone   void OptionParsingStarting(ExecutionContext *execution_context) override {
17415e09c8c3SJim Ingham     m_name.Clear();
17425e09c8c3SJim Ingham     m_breakpoint.Clear();
17435e09c8c3SJim Ingham     m_use_dummy.Clear();
17445e09c8c3SJim Ingham     m_use_dummy.SetDefaultValue(false);
17455e09c8c3SJim Ingham   }
17465e09c8c3SJim Ingham 
17475e09c8c3SJim Ingham   OptionValueString m_name;
17485e09c8c3SJim Ingham   OptionValueUInt64 m_breakpoint;
17495e09c8c3SJim Ingham   OptionValueBoolean m_use_dummy;
17505e09c8c3SJim Ingham };
17515e09c8c3SJim Ingham 
1752*b842f2ecSJim Ingham static OptionDefinition g_breakpoint_access_options[] = {
1753*b842f2ecSJim Ingham     // clang-format off
1754*b842f2ecSJim Ingham   {LLDB_OPT_SET_1,   false, "allow-list",    'L', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint will show up in break list if not referred to explicitly."},
1755*b842f2ecSJim Ingham   {LLDB_OPT_SET_2,   false, "allow-disable", 'A', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint can be disabled by name or when all breakpoints are disabled."},
1756*b842f2ecSJim Ingham   {LLDB_OPT_SET_3,   false, "allow-delete",  'D', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Determines whether the breakpoint can be deleted by name or when all breakpoints are deleted."},
1757*b842f2ecSJim Ingham     // clang-format on
1758*b842f2ecSJim Ingham };
1759*b842f2ecSJim Ingham 
1760*b842f2ecSJim Ingham class BreakpointAccessOptionGroup : public OptionGroup
1761*b842f2ecSJim Ingham {
1762*b842f2ecSJim Ingham public:
1763*b842f2ecSJim Ingham   BreakpointAccessOptionGroup() :
1764*b842f2ecSJim Ingham           OptionGroup()
1765*b842f2ecSJim Ingham    {}
1766*b842f2ecSJim Ingham 
1767*b842f2ecSJim Ingham   ~BreakpointAccessOptionGroup() override = default;
1768*b842f2ecSJim Ingham 
1769*b842f2ecSJim Ingham   llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
1770*b842f2ecSJim Ingham     return llvm::makeArrayRef(g_breakpoint_access_options);
1771*b842f2ecSJim Ingham   }
1772*b842f2ecSJim Ingham   Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
1773*b842f2ecSJim Ingham                         ExecutionContext *execution_context) override {
1774*b842f2ecSJim Ingham     Status error;
1775*b842f2ecSJim Ingham     const int short_option
1776*b842f2ecSJim Ingham         = g_breakpoint_access_options[option_idx].short_option;
1777*b842f2ecSJim Ingham 
1778*b842f2ecSJim Ingham     switch (short_option) {
1779*b842f2ecSJim Ingham       case 'L': {
1780*b842f2ecSJim Ingham         bool value, success;
1781*b842f2ecSJim Ingham         value = Args::StringToBoolean(option_arg, false, &success);
1782*b842f2ecSJim Ingham         if (success) {
1783*b842f2ecSJim Ingham           m_permissions.SetAllowList(value);
1784*b842f2ecSJim Ingham         } else
1785*b842f2ecSJim Ingham           error.SetErrorStringWithFormat(
1786*b842f2ecSJim Ingham               "invalid boolean value '%s' passed for -L option",
1787*b842f2ecSJim Ingham               option_arg.str().c_str());
1788*b842f2ecSJim Ingham       } break;
1789*b842f2ecSJim Ingham       case 'A': {
1790*b842f2ecSJim Ingham         bool value, success;
1791*b842f2ecSJim Ingham         value = Args::StringToBoolean(option_arg, false, &success);
1792*b842f2ecSJim Ingham         if (success) {
1793*b842f2ecSJim Ingham           m_permissions.SetAllowDisable(value);
1794*b842f2ecSJim Ingham         } else
1795*b842f2ecSJim Ingham           error.SetErrorStringWithFormat(
1796*b842f2ecSJim Ingham               "invalid boolean value '%s' passed for -L option",
1797*b842f2ecSJim Ingham               option_arg.str().c_str());
1798*b842f2ecSJim Ingham       } break;
1799*b842f2ecSJim Ingham       case 'D': {
1800*b842f2ecSJim Ingham         bool value, success;
1801*b842f2ecSJim Ingham         value = Args::StringToBoolean(option_arg, false, &success);
1802*b842f2ecSJim Ingham         if (success) {
1803*b842f2ecSJim Ingham           m_permissions.SetAllowDelete(value);
1804*b842f2ecSJim Ingham         } else
1805*b842f2ecSJim Ingham           error.SetErrorStringWithFormat(
1806*b842f2ecSJim Ingham               "invalid boolean value '%s' passed for -L option",
1807*b842f2ecSJim Ingham               option_arg.str().c_str());
1808*b842f2ecSJim Ingham       } break;
1809*b842f2ecSJim Ingham 
1810*b842f2ecSJim Ingham     }
1811*b842f2ecSJim Ingham 
1812*b842f2ecSJim Ingham     return error;
1813*b842f2ecSJim Ingham   }
1814*b842f2ecSJim Ingham 
1815*b842f2ecSJim Ingham   void OptionParsingStarting(ExecutionContext *execution_context) override {
1816*b842f2ecSJim Ingham   }
1817*b842f2ecSJim Ingham 
1818*b842f2ecSJim Ingham   const BreakpointName::Permissions &GetPermissions() const
1819*b842f2ecSJim Ingham   {
1820*b842f2ecSJim Ingham     return m_permissions;
1821*b842f2ecSJim Ingham   }
1822*b842f2ecSJim Ingham   BreakpointName::Permissions m_permissions;
1823*b842f2ecSJim Ingham };
1824*b842f2ecSJim Ingham 
1825*b842f2ecSJim Ingham class CommandObjectBreakpointNameConfigure : public CommandObjectParsed {
1826*b842f2ecSJim Ingham public:
1827*b842f2ecSJim Ingham   CommandObjectBreakpointNameConfigure(CommandInterpreter &interpreter)
1828*b842f2ecSJim Ingham       : CommandObjectParsed(
1829*b842f2ecSJim Ingham             interpreter, "configure", "Configure the options for the breakpoint"
1830*b842f2ecSJim Ingham             " name provided.  "
1831*b842f2ecSJim Ingham             "If you provide a breakpoint id, the options will be copied from "
1832*b842f2ecSJim Ingham             "the breakpoint, otherwise only the options specified will be set "
1833*b842f2ecSJim Ingham             "on the name.",
1834*b842f2ecSJim Ingham             "breakpoint name configure <command-options> "
1835*b842f2ecSJim Ingham             "<breakpoint-name-list>"),
1836*b842f2ecSJim Ingham         m_bp_opts(), m_option_group() {
1837*b842f2ecSJim Ingham     // Create the first variant for the first (and only) argument for this
1838*b842f2ecSJim Ingham     // command.
1839*b842f2ecSJim Ingham     CommandArgumentEntry arg1;
1840*b842f2ecSJim Ingham     CommandArgumentData id_arg;
1841*b842f2ecSJim Ingham     id_arg.arg_type = eArgTypeBreakpointName;
1842*b842f2ecSJim Ingham     id_arg.arg_repetition = eArgRepeatOptional;
1843*b842f2ecSJim Ingham     arg1.push_back(id_arg);
1844*b842f2ecSJim Ingham     m_arguments.push_back(arg1);
1845*b842f2ecSJim Ingham 
1846*b842f2ecSJim Ingham     m_option_group.Append(&m_bp_opts,
1847*b842f2ecSJim Ingham                           LLDB_OPT_SET_ALL,
1848*b842f2ecSJim Ingham                           LLDB_OPT_SET_1);
1849*b842f2ecSJim Ingham     m_option_group.Append(&m_access_options,
1850*b842f2ecSJim Ingham                           LLDB_OPT_SET_ALL,
1851*b842f2ecSJim Ingham                           LLDB_OPT_SET_ALL);
1852*b842f2ecSJim Ingham     m_option_group.Append(&m_bp_id, LLDB_OPT_SET_2, LLDB_OPT_SET_2);
1853*b842f2ecSJim Ingham     m_option_group.Finalize();
1854*b842f2ecSJim Ingham   }
1855*b842f2ecSJim Ingham 
1856*b842f2ecSJim Ingham   ~CommandObjectBreakpointNameConfigure() override = default;
1857*b842f2ecSJim Ingham 
1858*b842f2ecSJim Ingham   Options *GetOptions() override { return &m_option_group; }
1859*b842f2ecSJim Ingham 
1860*b842f2ecSJim Ingham protected:
1861*b842f2ecSJim Ingham   bool DoExecute(Args &command, CommandReturnObject &result) override {
1862*b842f2ecSJim Ingham 
1863*b842f2ecSJim Ingham     const size_t argc = command.GetArgumentCount();
1864*b842f2ecSJim Ingham     if (argc == 0) {
1865*b842f2ecSJim Ingham       result.AppendError("No names provided.");
1866*b842f2ecSJim Ingham       result.SetStatus(eReturnStatusFailed);
1867*b842f2ecSJim Ingham       return false;
1868*b842f2ecSJim Ingham     }
1869*b842f2ecSJim Ingham 
1870*b842f2ecSJim Ingham     Target *target =
1871*b842f2ecSJim Ingham         GetSelectedOrDummyTarget(false);
1872*b842f2ecSJim Ingham 
1873*b842f2ecSJim Ingham     if (target == nullptr) {
1874*b842f2ecSJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
1875*b842f2ecSJim Ingham       result.SetStatus(eReturnStatusFailed);
1876*b842f2ecSJim Ingham       return false;
1877*b842f2ecSJim Ingham     }
1878*b842f2ecSJim Ingham 
1879*b842f2ecSJim Ingham     std::unique_lock<std::recursive_mutex> lock;
1880*b842f2ecSJim Ingham     target->GetBreakpointList().GetListMutex(lock);
1881*b842f2ecSJim Ingham 
1882*b842f2ecSJim Ingham     // Make a pass through first to see that all the names are legal.
1883*b842f2ecSJim Ingham     for (auto &entry : command.entries()) {
1884*b842f2ecSJim Ingham       Status error;
1885*b842f2ecSJim Ingham       if (!BreakpointID::StringIsBreakpointName(entry.ref, error))
1886*b842f2ecSJim Ingham       {
1887*b842f2ecSJim Ingham         result.AppendErrorWithFormat("Invalid breakpoint name: %s - %s",
1888*b842f2ecSJim Ingham                                      entry.c_str(), error.AsCString());
1889*b842f2ecSJim Ingham         result.SetStatus(eReturnStatusFailed);
1890*b842f2ecSJim Ingham         return false;
1891*b842f2ecSJim Ingham       }
1892*b842f2ecSJim Ingham     }
1893*b842f2ecSJim Ingham     // Now configure them, we already pre-checked the names so we don't need
1894*b842f2ecSJim Ingham     // to check the error:
1895*b842f2ecSJim Ingham     BreakpointSP bp_sp;
1896*b842f2ecSJim Ingham     if (m_bp_id.m_breakpoint.OptionWasSet())
1897*b842f2ecSJim Ingham     {
1898*b842f2ecSJim Ingham       lldb::break_id_t bp_id = m_bp_id.m_breakpoint.GetUInt64Value();
1899*b842f2ecSJim Ingham       bp_sp = target->GetBreakpointByID(bp_id);
1900*b842f2ecSJim Ingham       if (!bp_sp)
1901*b842f2ecSJim Ingham       {
1902*b842f2ecSJim Ingham         result.AppendErrorWithFormatv("Could not find specified breakpoint {0}",
1903*b842f2ecSJim Ingham                            bp_id);
1904*b842f2ecSJim Ingham         result.SetStatus(eReturnStatusFailed);
1905*b842f2ecSJim Ingham         return false;
1906*b842f2ecSJim Ingham       }
1907*b842f2ecSJim Ingham     }
1908*b842f2ecSJim Ingham 
1909*b842f2ecSJim Ingham     Status error;
1910*b842f2ecSJim Ingham     for (auto &entry : command.entries()) {
1911*b842f2ecSJim Ingham       ConstString name(entry.c_str());
1912*b842f2ecSJim Ingham       BreakpointName *bp_name = target->FindBreakpointName(name, true, error);
1913*b842f2ecSJim Ingham       if (!bp_name)
1914*b842f2ecSJim Ingham         continue;
1915*b842f2ecSJim Ingham       if (bp_sp)
1916*b842f2ecSJim Ingham         target->ConfigureBreakpointName(*bp_name,
1917*b842f2ecSJim Ingham                                        *bp_sp->GetOptions(),
1918*b842f2ecSJim Ingham                                        m_access_options.GetPermissions());
1919*b842f2ecSJim Ingham       else
1920*b842f2ecSJim Ingham         target->ConfigureBreakpointName(*bp_name,
1921*b842f2ecSJim Ingham                                        m_bp_opts.GetBreakpointOptions(),
1922*b842f2ecSJim Ingham                                        m_access_options.GetPermissions());
1923*b842f2ecSJim Ingham     }
1924*b842f2ecSJim Ingham     return true;
1925*b842f2ecSJim Ingham   }
1926*b842f2ecSJim Ingham 
1927*b842f2ecSJim Ingham private:
1928*b842f2ecSJim Ingham   BreakpointNameOptionGroup m_bp_id; // Only using the id part of this.
1929*b842f2ecSJim Ingham   BreakpointOptionGroup m_bp_opts;
1930*b842f2ecSJim Ingham   BreakpointAccessOptionGroup m_access_options;
1931*b842f2ecSJim Ingham   OptionGroupOptions m_option_group;
1932*b842f2ecSJim Ingham };
1933*b842f2ecSJim Ingham 
1934b9c1b51eSKate Stone class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
19355e09c8c3SJim Ingham public:
1936b9c1b51eSKate Stone   CommandObjectBreakpointNameAdd(CommandInterpreter &interpreter)
1937b9c1b51eSKate Stone       : CommandObjectParsed(
1938b9c1b51eSKate Stone             interpreter, "add", "Add a name to the breakpoints provided.",
19395e09c8c3SJim Ingham             "breakpoint name add <command-options> <breakpoint-id-list>"),
1940b9c1b51eSKate Stone         m_name_options(), m_option_group() {
1941b9c1b51eSKate Stone     // Create the first variant for the first (and only) argument for this
1942b9c1b51eSKate Stone     // command.
19435e09c8c3SJim Ingham     CommandArgumentEntry arg1;
19445e09c8c3SJim Ingham     CommandArgumentData id_arg;
19455e09c8c3SJim Ingham     id_arg.arg_type = eArgTypeBreakpointID;
19465e09c8c3SJim Ingham     id_arg.arg_repetition = eArgRepeatOptional;
19475e09c8c3SJim Ingham     arg1.push_back(id_arg);
19485e09c8c3SJim Ingham     m_arguments.push_back(arg1);
19495e09c8c3SJim Ingham 
19505e09c8c3SJim Ingham     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
19515e09c8c3SJim Ingham     m_option_group.Finalize();
19525e09c8c3SJim Ingham   }
19535e09c8c3SJim Ingham 
19549e85e5a8SEugene Zelenko   ~CommandObjectBreakpointNameAdd() override = default;
19555e09c8c3SJim Ingham 
1956b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
19575e09c8c3SJim Ingham 
19585e09c8c3SJim Ingham protected:
1959b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
1960b9c1b51eSKate Stone     if (!m_name_options.m_name.OptionWasSet()) {
19615e09c8c3SJim Ingham       result.SetError("No name option provided.");
19625e09c8c3SJim Ingham       return false;
19635e09c8c3SJim Ingham     }
19645e09c8c3SJim Ingham 
1965b9c1b51eSKate Stone     Target *target =
1966b9c1b51eSKate Stone         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
19675e09c8c3SJim Ingham 
1968b9c1b51eSKate Stone     if (target == nullptr) {
19695e09c8c3SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
19705e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
19715e09c8c3SJim Ingham       return false;
19725e09c8c3SJim Ingham     }
19735e09c8c3SJim Ingham 
1974bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
1975bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
19765e09c8c3SJim Ingham 
19775e09c8c3SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
19785e09c8c3SJim Ingham 
19795e09c8c3SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
1980b9c1b51eSKate Stone     if (num_breakpoints == 0) {
19815e09c8c3SJim Ingham       result.SetError("No breakpoints, cannot add names.");
19825e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
19835e09c8c3SJim Ingham       return false;
19845e09c8c3SJim Ingham     }
19855e09c8c3SJim Ingham 
19865e09c8c3SJim Ingham     // Particular breakpoint selected; disable that breakpoint.
19875e09c8c3SJim Ingham     BreakpointIDList valid_bp_ids;
1988b9c1b51eSKate Stone     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
1989*b842f2ecSJim Ingham         command, target, result, &valid_bp_ids,
1990*b842f2ecSJim Ingham         BreakpointName::Permissions::PermissionKinds::listPerm);
19915e09c8c3SJim Ingham 
1992b9c1b51eSKate Stone     if (result.Succeeded()) {
1993b9c1b51eSKate Stone       if (valid_bp_ids.GetSize() == 0) {
19945e09c8c3SJim Ingham         result.SetError("No breakpoints specified, cannot add names.");
19955e09c8c3SJim Ingham         result.SetStatus(eReturnStatusFailed);
19965e09c8c3SJim Ingham         return false;
19975e09c8c3SJim Ingham       }
19985e09c8c3SJim Ingham       size_t num_valid_ids = valid_bp_ids.GetSize();
1999*b842f2ecSJim Ingham       const char *bp_name = m_name_options.m_name.GetCurrentValue();
2000*b842f2ecSJim Ingham       Status error; // This error reports illegal names, but we've already
2001*b842f2ecSJim Ingham                     // checked that, so we don't need to check it again here.
2002b9c1b51eSKate Stone       for (size_t index = 0; index < num_valid_ids; index++) {
2003b9c1b51eSKate Stone         lldb::break_id_t bp_id =
2004b9c1b51eSKate Stone             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
20055e09c8c3SJim Ingham         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
2006*b842f2ecSJim Ingham         target->AddNameToBreakpoint(bp_sp, bp_name, error);
20075e09c8c3SJim Ingham       }
20085e09c8c3SJim Ingham     }
20095e09c8c3SJim Ingham 
20105e09c8c3SJim Ingham     return true;
20115e09c8c3SJim Ingham   }
20125e09c8c3SJim Ingham 
20135e09c8c3SJim Ingham private:
20145e09c8c3SJim Ingham   BreakpointNameOptionGroup m_name_options;
20155e09c8c3SJim Ingham   OptionGroupOptions m_option_group;
20165e09c8c3SJim Ingham };
20175e09c8c3SJim Ingham 
2018b9c1b51eSKate Stone class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
20195e09c8c3SJim Ingham public:
2020b9c1b51eSKate Stone   CommandObjectBreakpointNameDelete(CommandInterpreter &interpreter)
2021b9c1b51eSKate Stone       : CommandObjectParsed(
2022b9c1b51eSKate Stone             interpreter, "delete",
20235e09c8c3SJim Ingham             "Delete a name from the breakpoints provided.",
20245e09c8c3SJim Ingham             "breakpoint name delete <command-options> <breakpoint-id-list>"),
2025b9c1b51eSKate Stone         m_name_options(), m_option_group() {
2026b9c1b51eSKate Stone     // Create the first variant for the first (and only) argument for this
2027b9c1b51eSKate Stone     // command.
20285e09c8c3SJim Ingham     CommandArgumentEntry arg1;
20295e09c8c3SJim Ingham     CommandArgumentData id_arg;
20305e09c8c3SJim Ingham     id_arg.arg_type = eArgTypeBreakpointID;
20315e09c8c3SJim Ingham     id_arg.arg_repetition = eArgRepeatOptional;
20325e09c8c3SJim Ingham     arg1.push_back(id_arg);
20335e09c8c3SJim Ingham     m_arguments.push_back(arg1);
20345e09c8c3SJim Ingham 
20355e09c8c3SJim Ingham     m_option_group.Append(&m_name_options, LLDB_OPT_SET_1, LLDB_OPT_SET_ALL);
20365e09c8c3SJim Ingham     m_option_group.Finalize();
20375e09c8c3SJim Ingham   }
20385e09c8c3SJim Ingham 
20399e85e5a8SEugene Zelenko   ~CommandObjectBreakpointNameDelete() override = default;
20405e09c8c3SJim Ingham 
2041b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
20425e09c8c3SJim Ingham 
20435e09c8c3SJim Ingham protected:
2044b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
2045b9c1b51eSKate Stone     if (!m_name_options.m_name.OptionWasSet()) {
20465e09c8c3SJim Ingham       result.SetError("No name option provided.");
20475e09c8c3SJim Ingham       return false;
20485e09c8c3SJim Ingham     }
20495e09c8c3SJim Ingham 
2050b9c1b51eSKate Stone     Target *target =
2051b9c1b51eSKate Stone         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
20525e09c8c3SJim Ingham 
2053b9c1b51eSKate Stone     if (target == nullptr) {
20545e09c8c3SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
20555e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
20565e09c8c3SJim Ingham       return false;
20575e09c8c3SJim Ingham     }
20585e09c8c3SJim Ingham 
2059bb19a13cSSaleem Abdulrasool     std::unique_lock<std::recursive_mutex> lock;
2060bb19a13cSSaleem Abdulrasool     target->GetBreakpointList().GetListMutex(lock);
20615e09c8c3SJim Ingham 
20625e09c8c3SJim Ingham     const BreakpointList &breakpoints = target->GetBreakpointList();
20635e09c8c3SJim Ingham 
20645e09c8c3SJim Ingham     size_t num_breakpoints = breakpoints.GetSize();
2065b9c1b51eSKate Stone     if (num_breakpoints == 0) {
20665e09c8c3SJim Ingham       result.SetError("No breakpoints, cannot delete names.");
20675e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
20685e09c8c3SJim Ingham       return false;
20695e09c8c3SJim Ingham     }
20705e09c8c3SJim Ingham 
20715e09c8c3SJim Ingham     // Particular breakpoint selected; disable that breakpoint.
20725e09c8c3SJim Ingham     BreakpointIDList valid_bp_ids;
2073b9c1b51eSKate Stone     CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2074*b842f2ecSJim Ingham         command, target, result, &valid_bp_ids,
2075*b842f2ecSJim Ingham         BreakpointName::Permissions::PermissionKinds::deletePerm);
20765e09c8c3SJim Ingham 
2077b9c1b51eSKate Stone     if (result.Succeeded()) {
2078b9c1b51eSKate Stone       if (valid_bp_ids.GetSize() == 0) {
20795e09c8c3SJim Ingham         result.SetError("No breakpoints specified, cannot delete names.");
20805e09c8c3SJim Ingham         result.SetStatus(eReturnStatusFailed);
20815e09c8c3SJim Ingham         return false;
20825e09c8c3SJim Ingham       }
2083*b842f2ecSJim Ingham       ConstString bp_name(m_name_options.m_name.GetCurrentValue());
20845e09c8c3SJim Ingham       size_t num_valid_ids = valid_bp_ids.GetSize();
2085b9c1b51eSKate Stone       for (size_t index = 0; index < num_valid_ids; index++) {
2086b9c1b51eSKate Stone         lldb::break_id_t bp_id =
2087b9c1b51eSKate Stone             valid_bp_ids.GetBreakpointIDAtIndex(index).GetBreakpointID();
20885e09c8c3SJim Ingham         BreakpointSP bp_sp = breakpoints.FindBreakpointByID(bp_id);
2089*b842f2ecSJim Ingham         target->RemoveNameFromBreakpoint(bp_sp, bp_name);
20905e09c8c3SJim Ingham       }
20915e09c8c3SJim Ingham     }
20925e09c8c3SJim Ingham 
20935e09c8c3SJim Ingham     return true;
20945e09c8c3SJim Ingham   }
20955e09c8c3SJim Ingham 
20965e09c8c3SJim Ingham private:
20975e09c8c3SJim Ingham   BreakpointNameOptionGroup m_name_options;
20985e09c8c3SJim Ingham   OptionGroupOptions m_option_group;
20995e09c8c3SJim Ingham };
21005e09c8c3SJim Ingham 
2101b9c1b51eSKate Stone class CommandObjectBreakpointNameList : public CommandObjectParsed {
21025e09c8c3SJim Ingham public:
2103b9c1b51eSKate Stone   CommandObjectBreakpointNameList(CommandInterpreter &interpreter)
2104b9c1b51eSKate Stone       : CommandObjectParsed(interpreter, "list",
2105*b842f2ecSJim Ingham                             "List either the names for a breakpoint or info "
2106*b842f2ecSJim Ingham                             "about a given name.  With no arguments, lists all "
2107*b842f2ecSJim Ingham                             "names",
21085e09c8c3SJim Ingham                             "breakpoint name list <command-options>"),
2109b9c1b51eSKate Stone         m_name_options(), m_option_group() {
2110*b842f2ecSJim Ingham     m_option_group.Append(&m_name_options, LLDB_OPT_SET_3, LLDB_OPT_SET_ALL);
21115e09c8c3SJim Ingham     m_option_group.Finalize();
21125e09c8c3SJim Ingham   }
21135e09c8c3SJim Ingham 
21149e85e5a8SEugene Zelenko   ~CommandObjectBreakpointNameList() override = default;
21155e09c8c3SJim Ingham 
2116b9c1b51eSKate Stone   Options *GetOptions() override { return &m_option_group; }
21175e09c8c3SJim Ingham 
21185e09c8c3SJim Ingham protected:
2119b9c1b51eSKate Stone   bool DoExecute(Args &command, CommandReturnObject &result) override {
2120b9c1b51eSKate Stone     Target *target =
2121b9c1b51eSKate Stone         GetSelectedOrDummyTarget(m_name_options.m_use_dummy.GetCurrentValue());
21225e09c8c3SJim Ingham 
2123b9c1b51eSKate Stone     if (target == nullptr) {
21245e09c8c3SJim Ingham       result.AppendError("Invalid target. No existing target or breakpoints.");
21255e09c8c3SJim Ingham       result.SetStatus(eReturnStatusFailed);
21265e09c8c3SJim Ingham       return false;
21275e09c8c3SJim Ingham     }
21285e09c8c3SJim Ingham 
2129*b842f2ecSJim Ingham 
2130*b842f2ecSJim Ingham     std::vector<std::string> name_list;
2131*b842f2ecSJim Ingham     if (command.empty()) {
2132*b842f2ecSJim Ingham       target->GetBreakpointNames(name_list);
2133*b842f2ecSJim Ingham     } else {
2134*b842f2ecSJim Ingham       for (const Args::ArgEntry &arg : command)
2135*b842f2ecSJim Ingham       {
2136*b842f2ecSJim Ingham         name_list.push_back(arg.c_str());
2137*b842f2ecSJim Ingham       }
2138*b842f2ecSJim Ingham     }
2139*b842f2ecSJim Ingham 
2140*b842f2ecSJim Ingham     if (name_list.empty()) {
2141*b842f2ecSJim Ingham       result.AppendMessage("No breakpoint names found.");
2142*b842f2ecSJim Ingham     } else {
2143*b842f2ecSJim Ingham       for (const std::string &name_str : name_list) {
2144*b842f2ecSJim Ingham         const char *name = name_str.c_str();
2145*b842f2ecSJim Ingham         // First print out the options for the name:
2146*b842f2ecSJim Ingham         Status error;
2147*b842f2ecSJim Ingham         BreakpointName *bp_name = target->FindBreakpointName(ConstString(name),
2148*b842f2ecSJim Ingham                                                              false,
2149*b842f2ecSJim Ingham                                                              error);
2150*b842f2ecSJim Ingham         if (bp_name)
2151*b842f2ecSJim Ingham         {
2152*b842f2ecSJim Ingham           StreamString s;
2153*b842f2ecSJim Ingham           result.AppendMessageWithFormat("Name: %s\n", name);
2154*b842f2ecSJim Ingham           if (bp_name->GetDescription(&s, eDescriptionLevelFull))
2155*b842f2ecSJim Ingham           {
2156*b842f2ecSJim Ingham             result.AppendMessage(s.GetString());
2157*b842f2ecSJim Ingham           }
2158*b842f2ecSJim Ingham 
2159bb19a13cSSaleem Abdulrasool           std::unique_lock<std::recursive_mutex> lock;
2160bb19a13cSSaleem Abdulrasool           target->GetBreakpointList().GetListMutex(lock);
21615e09c8c3SJim Ingham 
21625e09c8c3SJim Ingham           BreakpointList &breakpoints = target->GetBreakpointList();
2163*b842f2ecSJim Ingham           bool any_set = false;
2164b9c1b51eSKate Stone           for (BreakpointSP bp_sp : breakpoints.Breakpoints()) {
2165b9c1b51eSKate Stone             if (bp_sp->MatchesName(name)) {
21665e09c8c3SJim Ingham               StreamString s;
2167*b842f2ecSJim Ingham               any_set = true;
21685e09c8c3SJim Ingham               bp_sp->GetDescription(&s, eDescriptionLevelBrief);
21695e09c8c3SJim Ingham               s.EOL();
2170c156427dSZachary Turner               result.AppendMessage(s.GetString());
21715e09c8c3SJim Ingham             }
21725e09c8c3SJim Ingham           }
2173*b842f2ecSJim Ingham           if (!any_set)
2174*b842f2ecSJim Ingham             result.AppendMessage("No breakpoints using this name.");
2175b9c1b51eSKate Stone         } else {
2176*b842f2ecSJim Ingham           result.AppendMessageWithFormat("Name: %s not found.\n", name);
21775e09c8c3SJim Ingham         }
2178*b842f2ecSJim Ingham       }
21795e09c8c3SJim Ingham     }
21805e09c8c3SJim Ingham     return true;
21815e09c8c3SJim Ingham   }
21825e09c8c3SJim Ingham 
21835e09c8c3SJim Ingham private:
21845e09c8c3SJim Ingham   BreakpointNameOptionGroup m_name_options;
21855e09c8c3SJim Ingham   OptionGroupOptions m_option_group;
21865e09c8c3SJim Ingham };
21875e09c8c3SJim Ingham 
21885e09c8c3SJim Ingham //-------------------------------------------------------------------------
2189e14dc268SJim Ingham // CommandObjectBreakpointName
21905e09c8c3SJim Ingham //-------------------------------------------------------------------------
2191b9c1b51eSKate Stone class CommandObjectBreakpointName : public CommandObjectMultiword {
21925e09c8c3SJim Ingham public:
21937428a18cSKate Stone   CommandObjectBreakpointName(CommandInterpreter &interpreter)
2194b9c1b51eSKate Stone       : CommandObjectMultiword(
2195b9c1b51eSKate Stone             interpreter, "name", "Commands to manage name tags for breakpoints",
2196b9c1b51eSKate Stone             "breakpoint name <subcommand> [<command-options>]") {
2197b9c1b51eSKate Stone     CommandObjectSP add_command_object(
2198b9c1b51eSKate Stone         new CommandObjectBreakpointNameAdd(interpreter));
2199b9c1b51eSKate Stone     CommandObjectSP delete_command_object(
2200b9c1b51eSKate Stone         new CommandObjectBreakpointNameDelete(interpreter));
2201b9c1b51eSKate Stone     CommandObjectSP list_command_object(
2202b9c1b51eSKate Stone         new CommandObjectBreakpointNameList(interpreter));
2203*b842f2ecSJim Ingham     CommandObjectSP configure_command_object(
2204*b842f2ecSJim Ingham         new CommandObjectBreakpointNameConfigure(interpreter));
22055e09c8c3SJim Ingham 
22065e09c8c3SJim Ingham     LoadSubCommand("add", add_command_object);
22075e09c8c3SJim Ingham     LoadSubCommand("delete", delete_command_object);
22085e09c8c3SJim Ingham     LoadSubCommand("list", list_command_object);
2209*b842f2ecSJim Ingham     LoadSubCommand("configure", configure_command_object);
22105e09c8c3SJim Ingham   }
22115e09c8c3SJim Ingham 
22129e85e5a8SEugene Zelenko   ~CommandObjectBreakpointName() override = default;
22135e09c8c3SJim Ingham };
22145e09c8c3SJim Ingham 
22155e09c8c3SJim Ingham //-------------------------------------------------------------------------
2216e14dc268SJim Ingham // CommandObjectBreakpointRead
2217e14dc268SJim Ingham //-------------------------------------------------------------------------
22183acdf385SJim Ingham #pragma mark Read::CommandOptions
22191f0f5b5bSZachary Turner static OptionDefinition g_breakpoint_read_options[] = {
22201f0f5b5bSZachary Turner     // clang-format off
22211f0f5b5bSZachary Turner   { LLDB_OPT_SET_ALL, true, "file",                   'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,       "The file from which to read the breakpoints." },
22223acdf385SJim Ingham   {LLDB_OPT_SET_ALL, false, "breakpoint-name",        'N', OptionParser::eRequiredArgument, nullptr, nullptr, 0,                                       eArgTypeBreakpointName, "Only read in breakpoints with this name."},
22231f0f5b5bSZachary Turner     // clang-format on
22241f0f5b5bSZachary Turner };
22251f0f5b5bSZachary Turner 
22261f0f5b5bSZachary Turner #pragma mark Read
2227e14dc268SJim Ingham 
2228e14dc268SJim Ingham class CommandObjectBreakpointRead : public CommandObjectParsed {
2229e14dc268SJim Ingham public:
2230e14dc268SJim Ingham   CommandObjectBreakpointRead(CommandInterpreter &interpreter)
2231e14dc268SJim Ingham       : CommandObjectParsed(interpreter, "breakpoint read",
2232e14dc268SJim Ingham                             "Read and set the breakpoints previously saved to "
2233e14dc268SJim Ingham                             "a file with \"breakpoint write\".  ",
2234e14dc268SJim Ingham                             nullptr),
2235e14dc268SJim Ingham         m_options() {
2236e14dc268SJim Ingham     CommandArgumentEntry arg;
2237e14dc268SJim Ingham     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2238e14dc268SJim Ingham                                       eArgTypeBreakpointIDRange);
2239e14dc268SJim Ingham     // Add the entry for the first argument for this command to the object's
2240e14dc268SJim Ingham     // arguments vector.
2241e14dc268SJim Ingham     m_arguments.push_back(arg);
2242e14dc268SJim Ingham   }
2243e14dc268SJim Ingham 
2244e14dc268SJim Ingham   ~CommandObjectBreakpointRead() override = default;
2245e14dc268SJim Ingham 
2246e14dc268SJim Ingham   Options *GetOptions() override { return &m_options; }
2247e14dc268SJim Ingham 
2248e14dc268SJim Ingham   class CommandOptions : public Options {
2249e14dc268SJim Ingham   public:
2250e14dc268SJim Ingham     CommandOptions() : Options() {}
2251e14dc268SJim Ingham 
2252e14dc268SJim Ingham     ~CommandOptions() override = default;
2253e14dc268SJim Ingham 
225497206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2255e14dc268SJim Ingham                           ExecutionContext *execution_context) override {
225697206d57SZachary Turner       Status error;
2257e14dc268SJim Ingham       const int short_option = m_getopt_table[option_idx].val;
2258e14dc268SJim Ingham 
2259e14dc268SJim Ingham       switch (short_option) {
2260e14dc268SJim Ingham       case 'f':
2261e14dc268SJim Ingham         m_filename.assign(option_arg);
2262e14dc268SJim Ingham         break;
22633acdf385SJim Ingham       case 'N': {
226497206d57SZachary Turner         Status name_error;
22653acdf385SJim Ingham         if (!BreakpointID::StringIsBreakpointName(llvm::StringRef(option_arg),
22663acdf385SJim Ingham                                                   name_error)) {
22673acdf385SJim Ingham           error.SetErrorStringWithFormat("Invalid breakpoint name: %s",
22683acdf385SJim Ingham                                          name_error.AsCString());
22693acdf385SJim Ingham         }
22703acdf385SJim Ingham         m_names.push_back(option_arg);
22713acdf385SJim Ingham         break;
22723acdf385SJim Ingham       }
2273e14dc268SJim Ingham       default:
2274e14dc268SJim Ingham         error.SetErrorStringWithFormat("unrecognized option '%c'",
2275e14dc268SJim Ingham                                        short_option);
2276e14dc268SJim Ingham         break;
2277e14dc268SJim Ingham       }
2278e14dc268SJim Ingham 
2279e14dc268SJim Ingham       return error;
2280e14dc268SJim Ingham     }
2281e14dc268SJim Ingham 
2282e14dc268SJim Ingham     void OptionParsingStarting(ExecutionContext *execution_context) override {
2283e14dc268SJim Ingham       m_filename.clear();
22843acdf385SJim Ingham       m_names.clear();
2285e14dc268SJim Ingham     }
2286e14dc268SJim Ingham 
22871f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
228870602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_read_options);
22891f0f5b5bSZachary Turner     }
2290e14dc268SJim Ingham 
2291e14dc268SJim Ingham     // Instance variables to hold the values for command options.
2292e14dc268SJim Ingham 
2293e14dc268SJim Ingham     std::string m_filename;
22943acdf385SJim Ingham     std::vector<std::string> m_names;
2295e14dc268SJim Ingham   };
2296e14dc268SJim Ingham 
2297e14dc268SJim Ingham protected:
2298e14dc268SJim Ingham   bool DoExecute(Args &command, CommandReturnObject &result) override {
2299e14dc268SJim Ingham     Target *target = GetSelectedOrDummyTarget();
2300e14dc268SJim Ingham     if (target == nullptr) {
2301e14dc268SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
2302e14dc268SJim Ingham       result.SetStatus(eReturnStatusFailed);
2303e14dc268SJim Ingham       return false;
2304e14dc268SJim Ingham     }
2305e14dc268SJim Ingham 
23063acdf385SJim Ingham     std::unique_lock<std::recursive_mutex> lock;
23073acdf385SJim Ingham     target->GetBreakpointList().GetListMutex(lock);
23083acdf385SJim Ingham 
2309e14dc268SJim Ingham     FileSpec input_spec(m_options.m_filename, true);
231001f16664SJim Ingham     BreakpointIDList new_bps;
231197206d57SZachary Turner     Status error = target->CreateBreakpointsFromFile(
231297206d57SZachary Turner         input_spec, m_options.m_names, new_bps);
2313e14dc268SJim Ingham 
2314e14dc268SJim Ingham     if (!error.Success()) {
231501f16664SJim Ingham       result.AppendError(error.AsCString());
2316e14dc268SJim Ingham       result.SetStatus(eReturnStatusFailed);
231701f16664SJim Ingham       return false;
2318e14dc268SJim Ingham     }
23193acdf385SJim Ingham 
23203acdf385SJim Ingham     Stream &output_stream = result.GetOutputStream();
23213acdf385SJim Ingham 
23223acdf385SJim Ingham     size_t num_breakpoints = new_bps.GetSize();
23233acdf385SJim Ingham     if (num_breakpoints == 0) {
23243acdf385SJim Ingham       result.AppendMessage("No breakpoints added.");
23253acdf385SJim Ingham     } else {
23263acdf385SJim Ingham       // No breakpoint selected; show info about all currently set breakpoints.
23273acdf385SJim Ingham       result.AppendMessage("New breakpoints:");
23283acdf385SJim Ingham       for (size_t i = 0; i < num_breakpoints; ++i) {
23293acdf385SJim Ingham         BreakpointID bp_id = new_bps.GetBreakpointIDAtIndex(i);
23303acdf385SJim Ingham         Breakpoint *bp = target->GetBreakpointList()
23313acdf385SJim Ingham                              .FindBreakpointByID(bp_id.GetBreakpointID())
23323acdf385SJim Ingham                              .get();
23333acdf385SJim Ingham         if (bp)
23343acdf385SJim Ingham           bp->GetDescription(&output_stream, lldb::eDescriptionLevelInitial,
23353acdf385SJim Ingham                              false);
23363acdf385SJim Ingham       }
23373acdf385SJim Ingham     }
2338e14dc268SJim Ingham     return result.Succeeded();
2339e14dc268SJim Ingham   }
2340e14dc268SJim Ingham 
2341e14dc268SJim Ingham private:
2342e14dc268SJim Ingham   CommandOptions m_options;
2343e14dc268SJim Ingham };
2344e14dc268SJim Ingham 
2345e14dc268SJim Ingham //-------------------------------------------------------------------------
2346e14dc268SJim Ingham // CommandObjectBreakpointWrite
2347e14dc268SJim Ingham //-------------------------------------------------------------------------
23481f0f5b5bSZachary Turner #pragma mark Write::CommandOptions
23491f0f5b5bSZachary Turner static OptionDefinition g_breakpoint_write_options[] = {
23501f0f5b5bSZachary Turner     // clang-format off
23511f0f5b5bSZachary Turner   { LLDB_OPT_SET_ALL, true,  "file",  'f', OptionParser::eRequiredArgument, nullptr, nullptr, CommandCompletions::eDiskFileCompletion, eArgTypeFilename,    "The file into which to write the breakpoints." },
23522d3628e1SJim Ingham   { LLDB_OPT_SET_ALL, false, "append",'a', OptionParser::eNoArgument,       nullptr, nullptr, 0,                                       eArgTypeNone,        "Append to saved breakpoints file if it exists."},
23531f0f5b5bSZachary Turner     // clang-format on
23541f0f5b5bSZachary Turner };
23551f0f5b5bSZachary Turner 
23561f0f5b5bSZachary Turner #pragma mark Write
2357e14dc268SJim Ingham class CommandObjectBreakpointWrite : public CommandObjectParsed {
2358e14dc268SJim Ingham public:
2359e14dc268SJim Ingham   CommandObjectBreakpointWrite(CommandInterpreter &interpreter)
2360e14dc268SJim Ingham       : CommandObjectParsed(interpreter, "breakpoint write",
2361e14dc268SJim Ingham                             "Write the breakpoints listed to a file that can "
2362e14dc268SJim Ingham                             "be read in with \"breakpoint read\".  "
2363e14dc268SJim Ingham                             "If given no arguments, writes all breakpoints.",
2364e14dc268SJim Ingham                             nullptr),
2365e14dc268SJim Ingham         m_options() {
2366e14dc268SJim Ingham     CommandArgumentEntry arg;
2367e14dc268SJim Ingham     CommandObject::AddIDsArgumentData(arg, eArgTypeBreakpointID,
2368e14dc268SJim Ingham                                       eArgTypeBreakpointIDRange);
2369e14dc268SJim Ingham     // Add the entry for the first argument for this command to the object's
2370e14dc268SJim Ingham     // arguments vector.
2371e14dc268SJim Ingham     m_arguments.push_back(arg);
2372e14dc268SJim Ingham   }
2373e14dc268SJim Ingham 
2374e14dc268SJim Ingham   ~CommandObjectBreakpointWrite() override = default;
2375e14dc268SJim Ingham 
2376e14dc268SJim Ingham   Options *GetOptions() override { return &m_options; }
2377e14dc268SJim Ingham 
2378e14dc268SJim Ingham   class CommandOptions : public Options {
2379e14dc268SJim Ingham   public:
2380e14dc268SJim Ingham     CommandOptions() : Options() {}
2381e14dc268SJim Ingham 
2382e14dc268SJim Ingham     ~CommandOptions() override = default;
2383e14dc268SJim Ingham 
238497206d57SZachary Turner     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
2385e14dc268SJim Ingham                           ExecutionContext *execution_context) override {
238697206d57SZachary Turner       Status error;
2387e14dc268SJim Ingham       const int short_option = m_getopt_table[option_idx].val;
2388e14dc268SJim Ingham 
2389e14dc268SJim Ingham       switch (short_option) {
2390e14dc268SJim Ingham       case 'f':
2391e14dc268SJim Ingham         m_filename.assign(option_arg);
2392e14dc268SJim Ingham         break;
23932d3628e1SJim Ingham       case 'a':
23942d3628e1SJim Ingham         m_append = true;
23952d3628e1SJim Ingham         break;
2396e14dc268SJim Ingham       default:
2397e14dc268SJim Ingham         error.SetErrorStringWithFormat("unrecognized option '%c'",
2398e14dc268SJim Ingham                                        short_option);
2399e14dc268SJim Ingham         break;
2400e14dc268SJim Ingham       }
2401e14dc268SJim Ingham 
2402e14dc268SJim Ingham       return error;
2403e14dc268SJim Ingham     }
2404e14dc268SJim Ingham 
2405e14dc268SJim Ingham     void OptionParsingStarting(ExecutionContext *execution_context) override {
2406e14dc268SJim Ingham       m_filename.clear();
24072d3628e1SJim Ingham       m_append = false;
2408e14dc268SJim Ingham     }
2409e14dc268SJim Ingham 
24101f0f5b5bSZachary Turner     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
241170602439SZachary Turner       return llvm::makeArrayRef(g_breakpoint_write_options);
24121f0f5b5bSZachary Turner     }
2413e14dc268SJim Ingham 
2414e14dc268SJim Ingham     // Instance variables to hold the values for command options.
2415e14dc268SJim Ingham 
2416e14dc268SJim Ingham     std::string m_filename;
24172d3628e1SJim Ingham     bool m_append = false;
2418e14dc268SJim Ingham   };
2419e14dc268SJim Ingham 
2420e14dc268SJim Ingham protected:
2421e14dc268SJim Ingham   bool DoExecute(Args &command, CommandReturnObject &result) override {
2422e14dc268SJim Ingham     Target *target = GetSelectedOrDummyTarget();
2423e14dc268SJim Ingham     if (target == nullptr) {
2424e14dc268SJim Ingham       result.AppendError("Invalid target.  No existing target or breakpoints.");
2425e14dc268SJim Ingham       result.SetStatus(eReturnStatusFailed);
2426e14dc268SJim Ingham       return false;
2427e14dc268SJim Ingham     }
2428e14dc268SJim Ingham 
2429e14dc268SJim Ingham     std::unique_lock<std::recursive_mutex> lock;
2430e14dc268SJim Ingham     target->GetBreakpointList().GetListMutex(lock);
2431e14dc268SJim Ingham 
2432e14dc268SJim Ingham     BreakpointIDList valid_bp_ids;
243311eb9c64SZachary Turner     if (!command.empty()) {
2434e14dc268SJim Ingham       CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs(
2435*b842f2ecSJim Ingham           command, target, result, &valid_bp_ids,
2436*b842f2ecSJim Ingham           BreakpointName::Permissions::PermissionKinds::listPerm);
2437e14dc268SJim Ingham 
243801f16664SJim Ingham       if (!result.Succeeded()) {
2439e14dc268SJim Ingham         result.SetStatus(eReturnStatusFailed);
2440e14dc268SJim Ingham         return false;
2441e14dc268SJim Ingham       }
2442e14dc268SJim Ingham     }
244397206d57SZachary Turner     Status error = target->SerializeBreakpointsToFile(
2444771ef6d4SMalcolm Parsons         FileSpec(m_options.m_filename, true), valid_bp_ids, m_options.m_append);
244501f16664SJim Ingham     if (!error.Success()) {
244601f16664SJim Ingham       result.AppendErrorWithFormat("error serializing breakpoints: %s.",
244701f16664SJim Ingham                                    error.AsCString());
244801f16664SJim Ingham       result.SetStatus(eReturnStatusFailed);
2449e14dc268SJim Ingham     }
2450e14dc268SJim Ingham     return result.Succeeded();
2451e14dc268SJim Ingham   }
2452e14dc268SJim Ingham 
2453e14dc268SJim Ingham private:
2454e14dc268SJim Ingham   CommandOptions m_options;
2455e14dc268SJim Ingham };
2456e14dc268SJim Ingham 
2457e14dc268SJim Ingham //-------------------------------------------------------------------------
245830fdc8d8SChris Lattner // CommandObjectMultiwordBreakpoint
245930fdc8d8SChris Lattner //-------------------------------------------------------------------------
2460ae1c4cf5SJim Ingham #pragma mark MultiwordBreakpoint
246130fdc8d8SChris Lattner 
2462b9c1b51eSKate Stone CommandObjectMultiwordBreakpoint::CommandObjectMultiwordBreakpoint(
2463b9c1b51eSKate Stone     CommandInterpreter &interpreter)
2464b9c1b51eSKate Stone     : CommandObjectMultiword(
2465b9c1b51eSKate Stone           interpreter, "breakpoint",
24667428a18cSKate Stone           "Commands for operating on breakpoints (see 'help b' for shorthand.)",
2467b9c1b51eSKate Stone           "breakpoint <subcommand> [<command-options>]") {
2468b9c1b51eSKate Stone   CommandObjectSP list_command_object(
2469b9c1b51eSKate Stone       new CommandObjectBreakpointList(interpreter));
2470b9c1b51eSKate Stone   CommandObjectSP enable_command_object(
2471b9c1b51eSKate Stone       new CommandObjectBreakpointEnable(interpreter));
2472b9c1b51eSKate Stone   CommandObjectSP disable_command_object(
2473b9c1b51eSKate Stone       new CommandObjectBreakpointDisable(interpreter));
2474b9c1b51eSKate Stone   CommandObjectSP clear_command_object(
2475b9c1b51eSKate Stone       new CommandObjectBreakpointClear(interpreter));
2476b9c1b51eSKate Stone   CommandObjectSP delete_command_object(
2477b9c1b51eSKate Stone       new CommandObjectBreakpointDelete(interpreter));
2478b9c1b51eSKate Stone   CommandObjectSP set_command_object(
2479b9c1b51eSKate Stone       new CommandObjectBreakpointSet(interpreter));
2480b9c1b51eSKate Stone   CommandObjectSP command_command_object(
2481b9c1b51eSKate Stone       new CommandObjectBreakpointCommand(interpreter));
2482b9c1b51eSKate Stone   CommandObjectSP modify_command_object(
2483b9c1b51eSKate Stone       new CommandObjectBreakpointModify(interpreter));
2484b9c1b51eSKate Stone   CommandObjectSP name_command_object(
2485b9c1b51eSKate Stone       new CommandObjectBreakpointName(interpreter));
2486e14dc268SJim Ingham   CommandObjectSP write_command_object(
2487e14dc268SJim Ingham       new CommandObjectBreakpointWrite(interpreter));
2488e14dc268SJim Ingham   CommandObjectSP read_command_object(
2489e14dc268SJim Ingham       new CommandObjectBreakpointRead(interpreter));
249030fdc8d8SChris Lattner 
2491b7234e40SJohnny Chen   list_command_object->SetCommandName("breakpoint list");
249230fdc8d8SChris Lattner   enable_command_object->SetCommandName("breakpoint enable");
249330fdc8d8SChris Lattner   disable_command_object->SetCommandName("breakpoint disable");
2494b7234e40SJohnny Chen   clear_command_object->SetCommandName("breakpoint clear");
2495b7234e40SJohnny Chen   delete_command_object->SetCommandName("breakpoint delete");
2496ae1c4cf5SJim Ingham   set_command_object->SetCommandName("breakpoint set");
2497b7234e40SJohnny Chen   command_command_object->SetCommandName("breakpoint command");
2498b7234e40SJohnny Chen   modify_command_object->SetCommandName("breakpoint modify");
24995e09c8c3SJim Ingham   name_command_object->SetCommandName("breakpoint name");
2500e14dc268SJim Ingham   write_command_object->SetCommandName("breakpoint write");
2501e14dc268SJim Ingham   read_command_object->SetCommandName("breakpoint read");
250230fdc8d8SChris Lattner 
250323f59509SGreg Clayton   LoadSubCommand("list", list_command_object);
250423f59509SGreg Clayton   LoadSubCommand("enable", enable_command_object);
250523f59509SGreg Clayton   LoadSubCommand("disable", disable_command_object);
250623f59509SGreg Clayton   LoadSubCommand("clear", clear_command_object);
250723f59509SGreg Clayton   LoadSubCommand("delete", delete_command_object);
250823f59509SGreg Clayton   LoadSubCommand("set", set_command_object);
250923f59509SGreg Clayton   LoadSubCommand("command", command_command_object);
251023f59509SGreg Clayton   LoadSubCommand("modify", modify_command_object);
25115e09c8c3SJim Ingham   LoadSubCommand("name", name_command_object);
2512e14dc268SJim Ingham   LoadSubCommand("write", write_command_object);
2513e14dc268SJim Ingham   LoadSubCommand("read", read_command_object);
251430fdc8d8SChris Lattner }
251530fdc8d8SChris Lattner 
25169e85e5a8SEugene Zelenko CommandObjectMultiwordBreakpoint::~CommandObjectMultiwordBreakpoint() = default;
251730fdc8d8SChris Lattner 
2518b9c1b51eSKate Stone void CommandObjectMultiwordBreakpoint::VerifyIDs(Args &args, Target *target,
25195e09c8c3SJim Ingham                                                  bool allow_locations,
25205e09c8c3SJim Ingham                                                  CommandReturnObject &result,
2521*b842f2ecSJim Ingham                                                  BreakpointIDList *valid_ids,
2522*b842f2ecSJim Ingham                                                  BreakpointName::Permissions
2523*b842f2ecSJim Ingham                                                      ::PermissionKinds
2524*b842f2ecSJim Ingham                                                      purpose) {
252530fdc8d8SChris Lattner   // args can be strings representing 1). integers (for breakpoint ids)
2526b9c1b51eSKate Stone   //                                  2). the full breakpoint & location
2527b9c1b51eSKate Stone   //                                  canonical representation
2528b9c1b51eSKate Stone   //                                  3). the word "to" or a hyphen,
2529b9c1b51eSKate Stone   //                                  representing a range (in which case there
2530b9c1b51eSKate Stone   //                                      had *better* be an entry both before &
2531b9c1b51eSKate Stone   //                                      after of one of the first two types.
25325e09c8c3SJim Ingham   //                                  4). A breakpoint name
2533b9c1b51eSKate Stone   // If args is empty, we will use the last created breakpoint (if there is
2534b9c1b51eSKate Stone   // one.)
253530fdc8d8SChris Lattner 
253630fdc8d8SChris Lattner   Args temp_args;
253730fdc8d8SChris Lattner 
253811eb9c64SZachary Turner   if (args.empty()) {
2539b9c1b51eSKate Stone     if (target->GetLastCreatedBreakpoint()) {
2540b9c1b51eSKate Stone       valid_ids->AddBreakpointID(BreakpointID(
2541b9c1b51eSKate Stone           target->GetLastCreatedBreakpoint()->GetID(), LLDB_INVALID_BREAK_ID));
254236f3b369SJim Ingham       result.SetStatus(eReturnStatusSuccessFinishNoResult);
2543b9c1b51eSKate Stone     } else {
2544b9c1b51eSKate Stone       result.AppendError(
2545b9c1b51eSKate Stone           "No breakpoint specified and no last created breakpoint.");
254636f3b369SJim Ingham       result.SetStatus(eReturnStatusFailed);
254736f3b369SJim Ingham     }
254836f3b369SJim Ingham     return;
254936f3b369SJim Ingham   }
255036f3b369SJim Ingham 
2551b9c1b51eSKate Stone   // Create a new Args variable to use; copy any non-breakpoint-id-ranges stuff
2552b9c1b51eSKate Stone   // directly from the old ARGS to
2553b9c1b51eSKate Stone   // the new TEMP_ARGS.  Do not copy breakpoint id range strings over; instead
2554b9c1b51eSKate Stone   // generate a list of strings for
2555b9c1b51eSKate Stone   // all the breakpoint ids in the range, and shove all of those breakpoint id
2556b9c1b51eSKate Stone   // strings into TEMP_ARGS.
255730fdc8d8SChris Lattner 
2558b9c1b51eSKate Stone   BreakpointIDList::FindAndReplaceIDRanges(args, target, allow_locations,
2559*b842f2ecSJim Ingham                                            purpose, result, temp_args);
256030fdc8d8SChris Lattner 
2561b9c1b51eSKate Stone   // NOW, convert the list of breakpoint id strings in TEMP_ARGS into an actual
2562b9c1b51eSKate Stone   // BreakpointIDList:
256330fdc8d8SChris Lattner 
2564b9c1b51eSKate Stone   valid_ids->InsertStringArray(temp_args.GetConstArgumentVector(),
2565b9c1b51eSKate Stone                                temp_args.GetArgumentCount(), result);
256630fdc8d8SChris Lattner 
2567b9c1b51eSKate Stone   // At this point,  all of the breakpoint ids that the user passed in have been
2568b9c1b51eSKate Stone   // converted to breakpoint IDs
256930fdc8d8SChris Lattner   // and put into valid_ids.
257030fdc8d8SChris Lattner 
2571b9c1b51eSKate Stone   if (result.Succeeded()) {
2572b9c1b51eSKate Stone     // Now that we've converted everything from args into a list of breakpoint
2573b9c1b51eSKate Stone     // ids, go through our tentative list
2574b9c1b51eSKate Stone     // of breakpoint id's and verify that they correspond to valid/currently set
2575b9c1b51eSKate Stone     // breakpoints.
257630fdc8d8SChris Lattner 
2577c982c768SGreg Clayton     const size_t count = valid_ids->GetSize();
2578b9c1b51eSKate Stone     for (size_t i = 0; i < count; ++i) {
257930fdc8d8SChris Lattner       BreakpointID cur_bp_id = valid_ids->GetBreakpointIDAtIndex(i);
2580b9c1b51eSKate Stone       Breakpoint *breakpoint =
2581b9c1b51eSKate Stone           target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
2582b9c1b51eSKate Stone       if (breakpoint != nullptr) {
2583c7bece56SGreg Clayton         const size_t num_locations = breakpoint->GetNumLocations();
2584b9c1b51eSKate Stone         if (static_cast<size_t>(cur_bp_id.GetLocationID()) > num_locations) {
258530fdc8d8SChris Lattner           StreamString id_str;
2586b9c1b51eSKate Stone           BreakpointID::GetCanonicalReference(
2587b9c1b51eSKate Stone               &id_str, cur_bp_id.GetBreakpointID(), cur_bp_id.GetLocationID());
2588c982c768SGreg Clayton           i = valid_ids->GetSize() + 1;
2589b9c1b51eSKate Stone           result.AppendErrorWithFormat(
2590b9c1b51eSKate Stone               "'%s' is not a currently valid breakpoint/location id.\n",
259130fdc8d8SChris Lattner               id_str.GetData());
259230fdc8d8SChris Lattner           result.SetStatus(eReturnStatusFailed);
259330fdc8d8SChris Lattner         }
2594b9c1b51eSKate Stone       } else {
2595c982c768SGreg Clayton         i = valid_ids->GetSize() + 1;
2596b9c1b51eSKate Stone         result.AppendErrorWithFormat(
2597b9c1b51eSKate Stone             "'%d' is not a currently valid breakpoint ID.\n",
25987428a18cSKate Stone             cur_bp_id.GetBreakpointID());
259930fdc8d8SChris Lattner         result.SetStatus(eReturnStatusFailed);
260030fdc8d8SChris Lattner       }
260130fdc8d8SChris Lattner     }
260230fdc8d8SChris Lattner   }
260330fdc8d8SChris Lattner }
2604