xref: /src/contrib/llvm-project/lldb/source/Commands/CommandObjectBreakpointCommand.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1cfca06d7SDimitry Andric //===-- CommandObjectBreakpointCommand.cpp --------------------------------===//
2f034231aSEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f034231aSEd Maste //
7f034231aSEd Maste //===----------------------------------------------------------------------===//
8f034231aSEd Maste 
9f034231aSEd Maste #include "CommandObjectBreakpointCommand.h"
10f034231aSEd Maste #include "CommandObjectBreakpoint.h"
1114f1b3e8SDimitry Andric #include "lldb/Breakpoint/Breakpoint.h"
1214f1b3e8SDimitry Andric #include "lldb/Breakpoint/BreakpointIDList.h"
1314f1b3e8SDimitry Andric #include "lldb/Breakpoint/BreakpointLocation.h"
14866dcdacSEd Maste #include "lldb/Core/IOHandler.h"
1574a628f7SDimitry Andric #include "lldb/Host/OptionParser.h"
16f034231aSEd Maste #include "lldb/Interpreter/CommandInterpreter.h"
174b4fe385SDimitry Andric #include "lldb/Interpreter/CommandOptionArgumentTable.h"
18f034231aSEd Maste #include "lldb/Interpreter/CommandReturnObject.h"
19f73363f1SDimitry Andric #include "lldb/Interpreter/OptionArgParser.h"
20706b4fc4SDimitry Andric #include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
21f034231aSEd Maste #include "lldb/Target/Target.h"
22f034231aSEd Maste 
23f034231aSEd Maste using namespace lldb;
24f034231aSEd Maste using namespace lldb_private;
25f034231aSEd Maste 
26ead24645SDimitry Andric #define LLDB_OPTIONS_breakpoint_command_add
27ead24645SDimitry Andric #include "CommandOptions.inc"
2814f1b3e8SDimitry Andric 
2914f1b3e8SDimitry Andric class CommandObjectBreakpointCommandAdd : public CommandObjectParsed,
3014f1b3e8SDimitry Andric                                           public IOHandlerDelegateMultiline {
31f034231aSEd Maste public:
CommandObjectBreakpointCommandAdd(CommandInterpreter & interpreter)32f3fbd1c0SDimitry Andric   CommandObjectBreakpointCommandAdd(CommandInterpreter &interpreter)
33f3fbd1c0SDimitry Andric       : CommandObjectParsed(interpreter, "add",
3414f1b3e8SDimitry Andric                             "Add LLDB commands to a breakpoint, to be executed "
3514f1b3e8SDimitry Andric                             "whenever the breakpoint is hit.  "
36344a3780SDimitry Andric                             "The commands added to the breakpoint replace any "
37344a3780SDimitry Andric                             "commands previously added to it."
3814f1b3e8SDimitry Andric                             "  If no breakpoint is specified, adds the "
3914f1b3e8SDimitry Andric                             "commands to the last created breakpoint.",
40f3fbd1c0SDimitry Andric                             nullptr),
4114f1b3e8SDimitry Andric         IOHandlerDelegateMultiline("DONE",
4214f1b3e8SDimitry Andric                                    IOHandlerDelegate::Completion::LLDBCommand),
436f8fc217SDimitry Andric         m_func_options("breakpoint command", false, 'F') {
44f034231aSEd Maste     SetHelpLong(
45027f1c96SDimitry Andric         R"(
46027f1c96SDimitry Andric General information about entering breakpoint commands
47027f1c96SDimitry Andric ------------------------------------------------------
48027f1c96SDimitry Andric 
4914f1b3e8SDimitry Andric )"
5014f1b3e8SDimitry Andric         "This command will prompt for commands to be executed when the specified \
51027f1c96SDimitry Andric breakpoint is hit.  Each command is typed on its own line following the '> ' \
5214f1b3e8SDimitry Andric prompt until 'DONE' is entered."
5314f1b3e8SDimitry Andric         R"(
54027f1c96SDimitry Andric 
5514f1b3e8SDimitry Andric )"
5614f1b3e8SDimitry Andric         "Syntactic errors may not be detected when initially entered, and many \
57027f1c96SDimitry Andric malformed commands can silently fail when executed.  If your breakpoint commands \
5814f1b3e8SDimitry Andric do not appear to be executing, double-check the command syntax."
5914f1b3e8SDimitry Andric         R"(
60027f1c96SDimitry Andric 
6114f1b3e8SDimitry Andric )"
6214f1b3e8SDimitry Andric         "Note: You may enter any debugger command exactly as you would at the debugger \
63027f1c96SDimitry Andric prompt.  There is no limit to the number of commands supplied, but do NOT enter \
6414f1b3e8SDimitry Andric more than one command per line."
6514f1b3e8SDimitry Andric         R"(
66027f1c96SDimitry Andric 
67027f1c96SDimitry Andric Special information about PYTHON breakpoint commands
68027f1c96SDimitry Andric ----------------------------------------------------
69027f1c96SDimitry Andric 
7014f1b3e8SDimitry Andric )"
7114f1b3e8SDimitry Andric         "You may enter either one or more lines of Python, including function \
72027f1c96SDimitry Andric definitions or calls to functions that will have been imported by the time \
73027f1c96SDimitry Andric the code executes.  Single line breakpoint commands will be interpreted 'as is' \
74027f1c96SDimitry Andric when the breakpoint is hit.  Multiple lines of Python will be wrapped in a \
7514f1b3e8SDimitry Andric generated function, and a call to the function will be attached to the breakpoint."
7614f1b3e8SDimitry Andric         R"(
77027f1c96SDimitry Andric 
78027f1c96SDimitry Andric This auto-generated function is passed in three arguments:
79027f1c96SDimitry Andric 
80027f1c96SDimitry Andric     frame:  an lldb.SBFrame object for the frame which hit breakpoint.
81027f1c96SDimitry Andric 
82027f1c96SDimitry Andric     bp_loc: an lldb.SBBreakpointLocation object that represents the breakpoint location that was hit.
83027f1c96SDimitry Andric 
84027f1c96SDimitry Andric     dict:   the python session dictionary hit.
85027f1c96SDimitry Andric 
8614f1b3e8SDimitry Andric )"
8714f1b3e8SDimitry Andric         "When specifying a python function with the --python-function option, you need \
8814f1b3e8SDimitry Andric to supply the function name prepended by the module name:"
8914f1b3e8SDimitry Andric         R"(
90027f1c96SDimitry Andric 
91027f1c96SDimitry Andric     --python-function myutils.breakpoint_callback
92027f1c96SDimitry Andric 
93344a3780SDimitry Andric The function itself must have either of the following prototypes:
94027f1c96SDimitry Andric 
95344a3780SDimitry Andric def breakpoint_callback(frame, bp_loc, internal_dict):
96344a3780SDimitry Andric   # Your code goes here
97344a3780SDimitry Andric 
98344a3780SDimitry Andric or:
99344a3780SDimitry Andric 
100344a3780SDimitry Andric def breakpoint_callback(frame, bp_loc, extra_args, internal_dict):
101027f1c96SDimitry Andric   # Your code goes here
102027f1c96SDimitry Andric 
10314f1b3e8SDimitry Andric )"
10414f1b3e8SDimitry Andric         "The arguments are the same as the arguments passed to generated functions as \
105344a3780SDimitry Andric described above.  In the second form, any -k and -v pairs provided to the command will \
106344a3780SDimitry Andric be packaged into a SBDictionary in an SBStructuredData and passed as the extra_args parameter. \
107344a3780SDimitry Andric \n\n\
108344a3780SDimitry Andric Note that the global variable 'lldb.frame' will NOT be updated when \
109027f1c96SDimitry Andric this function is called, so be sure to use the 'frame' argument. The 'frame' argument \
110027f1c96SDimitry Andric can get you to the thread via frame.GetThread(), the thread can get you to the \
111027f1c96SDimitry Andric process via thread.GetProcess(), and the process can get you back to the target \
11214f1b3e8SDimitry Andric via process.GetTarget()."
11314f1b3e8SDimitry Andric         R"(
114027f1c96SDimitry Andric 
11514f1b3e8SDimitry Andric )"
11614f1b3e8SDimitry Andric         "Important Note: As Python code gets collected into functions, access to global \
117027f1c96SDimitry Andric variables requires explicit scoping using the 'global' keyword.  Be sure to use correct \
11814f1b3e8SDimitry Andric Python syntax, including indentation, when entering Python breakpoint commands."
11914f1b3e8SDimitry Andric         R"(
120027f1c96SDimitry Andric 
121027f1c96SDimitry Andric Example Python one-line breakpoint command:
122027f1c96SDimitry Andric 
123027f1c96SDimitry Andric (lldb) breakpoint command add -s python 1
124027f1c96SDimitry Andric Enter your Python command(s). Type 'DONE' to end.
125b60736ecSDimitry Andric def function (frame, bp_loc, internal_dict):
126b60736ecSDimitry Andric     """frame: the lldb.SBFrame for the location at which you stopped
127b60736ecSDimitry Andric        bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information
128b60736ecSDimitry Andric        internal_dict: an LLDB support object not to be used"""
129b60736ecSDimitry Andric     print("Hit this breakpoint!")
130b60736ecSDimitry Andric     DONE
131027f1c96SDimitry Andric 
132027f1c96SDimitry Andric As a convenience, this also works for a short Python one-liner:
133027f1c96SDimitry Andric 
134b60736ecSDimitry Andric (lldb) breakpoint command add -s python 1 -o 'import time; print(time.asctime())'
135027f1c96SDimitry Andric (lldb) run
136027f1c96SDimitry Andric Launching '.../a.out'  (x86_64)
137027f1c96SDimitry Andric (lldb) Fri Sep 10 12:17:45 2010
138027f1c96SDimitry Andric Process 21778 Stopped
139027f1c96SDimitry Andric * thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread
140027f1c96SDimitry Andric   36
141027f1c96SDimitry Andric   37   	int c(int val)
142027f1c96SDimitry Andric   38   	{
143027f1c96SDimitry Andric   39 ->	    return val + 3;
144027f1c96SDimitry Andric   40   	}
145027f1c96SDimitry Andric   41
146027f1c96SDimitry Andric   42   	int main (int argc, char const *argv[])
147027f1c96SDimitry Andric 
148027f1c96SDimitry Andric Example multiple line Python breakpoint command:
149027f1c96SDimitry Andric 
150027f1c96SDimitry Andric (lldb) breakpoint command add -s p 1
151027f1c96SDimitry Andric Enter your Python command(s). Type 'DONE' to end.
152b60736ecSDimitry Andric def function (frame, bp_loc, internal_dict):
153b60736ecSDimitry Andric     """frame: the lldb.SBFrame for the location at which you stopped
154b60736ecSDimitry Andric        bp_loc: an lldb.SBBreakpointLocation for the breakpoint location information
155b60736ecSDimitry Andric        internal_dict: an LLDB support object not to be used"""
156b60736ecSDimitry Andric     global bp_count
157b60736ecSDimitry Andric     bp_count = bp_count + 1
158b60736ecSDimitry Andric     print("Hit this breakpoint " + repr(bp_count) + " times!")
159b60736ecSDimitry Andric     DONE
160027f1c96SDimitry Andric 
16114f1b3e8SDimitry Andric )"
16214f1b3e8SDimitry Andric         "In this case, since there is a reference to a global variable, \
163027f1c96SDimitry Andric 'bp_count', you will also need to make sure 'bp_count' exists and is \
16414f1b3e8SDimitry Andric initialized:"
16514f1b3e8SDimitry Andric         R"(
166027f1c96SDimitry Andric 
167027f1c96SDimitry Andric (lldb) script
168027f1c96SDimitry Andric >>> bp_count = 0
169027f1c96SDimitry Andric >>> quit()
170027f1c96SDimitry Andric 
17114f1b3e8SDimitry Andric )"
17214f1b3e8SDimitry Andric         "Your Python code, however organized, can optionally return a value.  \
173027f1c96SDimitry Andric If the returned value is False, that tells LLDB not to stop at the breakpoint \
174027f1c96SDimitry Andric to which the code is associated. Returning anything other than False, or even \
175027f1c96SDimitry Andric returning None, or even omitting a return statement entirely, will cause \
17614f1b3e8SDimitry Andric LLDB to stop."
17714f1b3e8SDimitry Andric         R"(
178027f1c96SDimitry Andric 
17914f1b3e8SDimitry Andric )"
18014f1b3e8SDimitry Andric         "Final Note: A warning that no breakpoint command was generated when there \
18114f1b3e8SDimitry Andric are no syntax errors may indicate that a function was declared but never called.");
182f034231aSEd Maste 
183706b4fc4SDimitry Andric     m_all_options.Append(&m_options);
184706b4fc4SDimitry Andric     m_all_options.Append(&m_func_options, LLDB_OPT_SET_2 | LLDB_OPT_SET_3,
185706b4fc4SDimitry Andric                          LLDB_OPT_SET_2);
186706b4fc4SDimitry Andric     m_all_options.Finalize();
187706b4fc4SDimitry Andric 
188ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeBreakpointID, eArgRepeatOptional);
189f034231aSEd Maste   }
190f034231aSEd Maste 
191f3fbd1c0SDimitry Andric   ~CommandObjectBreakpointCommandAdd() override = default;
192f034231aSEd Maste 
GetOptions()193706b4fc4SDimitry Andric   Options *GetOptions() override { return &m_all_options; }
194f034231aSEd Maste 
IOHandlerActivated(IOHandler & io_handler,bool interactive)1955f29bb8aSDimitry Andric   void IOHandlerActivated(IOHandler &io_handler, bool interactive) override {
196ead24645SDimitry Andric     StreamFileSP output_sp(io_handler.GetOutputStreamFileSP());
1975f29bb8aSDimitry Andric     if (output_sp && interactive) {
198866dcdacSEd Maste       output_sp->PutCString(g_reader_instructions);
199866dcdacSEd Maste       output_sp->Flush();
200866dcdacSEd Maste     }
201866dcdacSEd Maste   }
202866dcdacSEd Maste 
IOHandlerInputComplete(IOHandler & io_handler,std::string & line)20314f1b3e8SDimitry Andric   void IOHandlerInputComplete(IOHandler &io_handler,
20414f1b3e8SDimitry Andric                               std::string &line) override {
205866dcdacSEd Maste     io_handler.SetIsDone(true);
206866dcdacSEd Maste 
207344a3780SDimitry Andric     std::vector<std::reference_wrapper<BreakpointOptions>> *bp_options_vec =
208344a3780SDimitry Andric         (std::vector<std::reference_wrapper<BreakpointOptions>> *)
209344a3780SDimitry Andric             io_handler.GetUserData();
210344a3780SDimitry Andric     for (BreakpointOptions &bp_options : *bp_options_vec) {
211ead24645SDimitry Andric       auto cmd_data = std::make_unique<BreakpointOptions::CommandData>();
21214f1b3e8SDimitry Andric       cmd_data->user_source.SplitIntoLines(line.c_str(), line.size());
213344a3780SDimitry Andric       bp_options.SetCommandDataCallback(cmd_data);
214866dcdacSEd Maste     }
215866dcdacSEd Maste   }
216866dcdacSEd Maste 
CollectDataForBreakpointCommandCallback(std::vector<std::reference_wrapper<BreakpointOptions>> & bp_options_vec,CommandReturnObject & result)21714f1b3e8SDimitry Andric   void CollectDataForBreakpointCommandCallback(
218344a3780SDimitry Andric       std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
21914f1b3e8SDimitry Andric       CommandReturnObject &result) {
22014f1b3e8SDimitry Andric     m_interpreter.GetLLDBCommandsFromIOHandler(
22114f1b3e8SDimitry Andric         "> ",             // Prompt
222866dcdacSEd Maste         *this,            // IOHandlerDelegate
22314f1b3e8SDimitry Andric         &bp_options_vec); // Baton for the "io_handler" that will be passed back
22414f1b3e8SDimitry Andric                           // into our IOHandlerDelegate functions
225f034231aSEd Maste   }
226f034231aSEd Maste 
227f034231aSEd Maste   /// Set a one-liner as the callback for the breakpoint.
SetBreakpointCommandCallback(std::vector<std::reference_wrapper<BreakpointOptions>> & bp_options_vec,const char * oneliner)228344a3780SDimitry Andric   void SetBreakpointCommandCallback(
229344a3780SDimitry Andric       std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
23014f1b3e8SDimitry Andric       const char *oneliner) {
231344a3780SDimitry Andric     for (BreakpointOptions &bp_options : bp_options_vec) {
232ead24645SDimitry Andric       auto cmd_data = std::make_unique<BreakpointOptions::CommandData>();
233f034231aSEd Maste 
23414f1b3e8SDimitry Andric       cmd_data->user_source.AppendString(oneliner);
23514f1b3e8SDimitry Andric       cmd_data->stop_on_error = m_options.m_stop_on_error;
236f034231aSEd Maste 
237344a3780SDimitry Andric       bp_options.SetCommandDataCallback(cmd_data);
2380cac4ca3SEd Maste     }
239f034231aSEd Maste   }
240f034231aSEd Maste 
241706b4fc4SDimitry Andric   class CommandOptions : public OptionGroup {
242f034231aSEd Maste   public:
243145449b1SDimitry Andric     CommandOptions() = default;
244f034231aSEd Maste 
245f3fbd1c0SDimitry Andric     ~CommandOptions() override = default;
246f034231aSEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)247b76161e4SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
24814f1b3e8SDimitry Andric                           ExecutionContext *execution_context) override {
249b76161e4SDimitry Andric       Status error;
250706b4fc4SDimitry Andric       const int short_option =
251706b4fc4SDimitry Andric           g_breakpoint_command_add_options[option_idx].short_option;
252f034231aSEd Maste 
25314f1b3e8SDimitry Andric       switch (short_option) {
254f034231aSEd Maste       case 'o':
255f034231aSEd Maste         m_use_one_liner = true;
256cfca06d7SDimitry Andric         m_one_liner = std::string(option_arg);
257f034231aSEd Maste         break;
258f034231aSEd Maste 
259f034231aSEd Maste       case 's':
260f73363f1SDimitry Andric         m_script_language = (lldb::ScriptLanguage)OptionArgParser::ToOptionEnum(
261ead24645SDimitry Andric             option_arg,
262ead24645SDimitry Andric             g_breakpoint_command_add_options[option_idx].enum_values,
26314f1b3e8SDimitry Andric             eScriptLanguageNone, error);
264706b4fc4SDimitry Andric         switch (m_script_language) {
265706b4fc4SDimitry Andric         case eScriptLanguagePython:
266706b4fc4SDimitry Andric         case eScriptLanguageLua:
267f034231aSEd Maste           m_use_script_language = true;
268706b4fc4SDimitry Andric           break;
269706b4fc4SDimitry Andric         case eScriptLanguageNone:
270706b4fc4SDimitry Andric         case eScriptLanguageUnknown:
271f034231aSEd Maste           m_use_script_language = false;
272706b4fc4SDimitry Andric           break;
273f034231aSEd Maste         }
274f034231aSEd Maste         break;
275f034231aSEd Maste 
27614f1b3e8SDimitry Andric       case 'e': {
277f034231aSEd Maste         bool success = false;
278f73363f1SDimitry Andric         m_stop_on_error =
279f73363f1SDimitry Andric             OptionArgParser::ToBoolean(option_arg, false, &success);
280f034231aSEd Maste         if (!success)
28114f1b3e8SDimitry Andric           error.SetErrorStringWithFormat(
28214f1b3e8SDimitry Andric               "invalid value for stop-on-error: \"%s\"",
28314f1b3e8SDimitry Andric               option_arg.str().c_str());
28414f1b3e8SDimitry Andric       } break;
285f034231aSEd Maste 
286205afe67SEd Maste       case 'D':
287205afe67SEd Maste         m_use_dummy = true;
288205afe67SEd Maste         break;
289205afe67SEd Maste 
290f034231aSEd Maste       default:
291ead24645SDimitry Andric         llvm_unreachable("Unimplemented option");
292f034231aSEd Maste       }
293f034231aSEd Maste       return error;
294f034231aSEd Maste     }
295f3fbd1c0SDimitry Andric 
OptionParsingStarting(ExecutionContext * execution_context)29614f1b3e8SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
297f034231aSEd Maste       m_use_commands = true;
298f034231aSEd Maste       m_use_script_language = false;
299f034231aSEd Maste       m_script_language = eScriptLanguageNone;
300f034231aSEd Maste 
301f034231aSEd Maste       m_use_one_liner = false;
302f034231aSEd Maste       m_stop_on_error = true;
303f034231aSEd Maste       m_one_liner.clear();
304205afe67SEd Maste       m_use_dummy = false;
305f034231aSEd Maste     }
306f034231aSEd Maste 
GetDefinitions()30714f1b3e8SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
308e3b55780SDimitry Andric       return llvm::ArrayRef(g_breakpoint_command_add_options);
309f034231aSEd Maste     }
310f034231aSEd Maste 
311f034231aSEd Maste     // Instance variables to hold the values for command options.
312f034231aSEd Maste 
313344a3780SDimitry Andric     bool m_use_commands = false;
314344a3780SDimitry Andric     bool m_use_script_language = false;
315344a3780SDimitry Andric     lldb::ScriptLanguage m_script_language = eScriptLanguageNone;
316f034231aSEd Maste 
317f034231aSEd Maste     // Instance variables to hold the values for one_liner options.
318344a3780SDimitry Andric     bool m_use_one_liner = false;
319f034231aSEd Maste     std::string m_one_liner;
320f034231aSEd Maste     bool m_stop_on_error;
321205afe67SEd Maste     bool m_use_dummy;
322f034231aSEd Maste   };
323f034231aSEd Maste 
324f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)325b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
326ead24645SDimitry Andric     Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
327f034231aSEd Maste 
328ead24645SDimitry Andric     const BreakpointList &breakpoints = target.GetBreakpointList();
329f034231aSEd Maste     size_t num_breakpoints = breakpoints.GetSize();
330f034231aSEd Maste 
33114f1b3e8SDimitry Andric     if (num_breakpoints == 0) {
332f034231aSEd Maste       result.AppendError("No breakpoints exist to have commands added");
333b1c73532SDimitry Andric       return;
334f034231aSEd Maste     }
335f034231aSEd Maste 
336706b4fc4SDimitry Andric     if (!m_func_options.GetName().empty()) {
337706b4fc4SDimitry Andric       m_options.m_use_one_liner = false;
338706b4fc4SDimitry Andric       if (!m_options.m_use_script_language) {
339706b4fc4SDimitry Andric         m_options.m_script_language = GetDebugger().GetScriptLanguage();
340706b4fc4SDimitry Andric         m_options.m_use_script_language = true;
341706b4fc4SDimitry Andric       }
342f034231aSEd Maste     }
343f034231aSEd Maste 
344f034231aSEd Maste     BreakpointIDList valid_bp_ids;
34514f1b3e8SDimitry Andric     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
346ead24645SDimitry Andric         command, &target, result, &valid_bp_ids,
347ef5d0b5eSDimitry Andric         BreakpointName::Permissions::PermissionKinds::listPerm);
348f034231aSEd Maste 
3490cac4ca3SEd Maste     m_bp_options_vec.clear();
3500cac4ca3SEd Maste 
35114f1b3e8SDimitry Andric     if (result.Succeeded()) {
352f034231aSEd Maste       const size_t count = valid_bp_ids.GetSize();
353f034231aSEd Maste 
35414f1b3e8SDimitry Andric       for (size_t i = 0; i < count; ++i) {
355f034231aSEd Maste         BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
35614f1b3e8SDimitry Andric         if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
35714f1b3e8SDimitry Andric           Breakpoint *bp =
358ead24645SDimitry Andric               target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
35914f1b3e8SDimitry Andric           if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID) {
360f034231aSEd Maste             // This breakpoint does not have an associated location.
361344a3780SDimitry Andric             m_bp_options_vec.push_back(bp->GetOptions());
36214f1b3e8SDimitry Andric           } else {
36314f1b3e8SDimitry Andric             BreakpointLocationSP bp_loc_sp(
36414f1b3e8SDimitry Andric                 bp->FindLocationByID(cur_bp_id.GetLocationID()));
365f73363f1SDimitry Andric             // This breakpoint does have an associated location. Get its
366f73363f1SDimitry Andric             // breakpoint options.
367f034231aSEd Maste             if (bp_loc_sp)
368344a3780SDimitry Andric               m_bp_options_vec.push_back(bp_loc_sp->GetLocationOptions());
369f034231aSEd Maste           }
3700cac4ca3SEd Maste         }
3710cac4ca3SEd Maste       }
372f034231aSEd Maste 
373f73363f1SDimitry Andric       // If we are using script language, get the script interpreter in order
374f73363f1SDimitry Andric       // to set or collect command callback.  Otherwise, call the methods
375f73363f1SDimitry Andric       // associated with this object.
37614f1b3e8SDimitry Andric       if (m_options.m_use_script_language) {
377b60736ecSDimitry Andric         Status error;
378706b4fc4SDimitry Andric         ScriptInterpreter *script_interp = GetDebugger().GetScriptInterpreter(
379706b4fc4SDimitry Andric             /*can_create=*/true, m_options.m_script_language);
380f034231aSEd Maste         // Special handling for one-liner specified inline.
38114f1b3e8SDimitry Andric         if (m_options.m_use_one_liner) {
382b60736ecSDimitry Andric           error = script_interp->SetBreakpointCommandCallback(
38314f1b3e8SDimitry Andric               m_bp_options_vec, m_options.m_one_liner.c_str());
384706b4fc4SDimitry Andric         } else if (!m_func_options.GetName().empty()) {
385b60736ecSDimitry Andric           error = script_interp->SetBreakpointCommandCallbackFunction(
386706b4fc4SDimitry Andric               m_bp_options_vec, m_func_options.GetName().c_str(),
387706b4fc4SDimitry Andric               m_func_options.GetStructuredData());
38814f1b3e8SDimitry Andric         } else {
38914f1b3e8SDimitry Andric           script_interp->CollectDataForBreakpointCommandCallback(
39014f1b3e8SDimitry Andric               m_bp_options_vec, result);
391f034231aSEd Maste         }
392b60736ecSDimitry Andric         if (!error.Success())
393b60736ecSDimitry Andric           result.SetError(error);
39414f1b3e8SDimitry Andric       } else {
395f034231aSEd Maste         // Special handling for one-liner specified inline.
396f034231aSEd Maste         if (m_options.m_use_one_liner)
3970cac4ca3SEd Maste           SetBreakpointCommandCallback(m_bp_options_vec,
398f034231aSEd Maste                                        m_options.m_one_liner.c_str());
399f034231aSEd Maste         else
40014f1b3e8SDimitry Andric           CollectDataForBreakpointCommandCallback(m_bp_options_vec, result);
401f034231aSEd Maste       }
402f034231aSEd Maste     }
403f034231aSEd Maste   }
404f034231aSEd Maste 
405f034231aSEd Maste private:
406f034231aSEd Maste   CommandOptions m_options;
407706b4fc4SDimitry Andric   OptionGroupPythonClassWithDict m_func_options;
408706b4fc4SDimitry Andric   OptionGroupOptions m_all_options;
409706b4fc4SDimitry Andric 
410344a3780SDimitry Andric   std::vector<std::reference_wrapper<BreakpointOptions>>
411344a3780SDimitry Andric       m_bp_options_vec; // This stores the
41214f1b3e8SDimitry Andric                         // breakpoint options that
41314f1b3e8SDimitry Andric                         // we are currently
414f73363f1SDimitry Andric   // collecting commands for.  In the CollectData... calls we need to hand this
415f73363f1SDimitry Andric   // off to the IOHandler, which may run asynchronously. So we have to have
416f73363f1SDimitry Andric   // some way to keep it alive, and not leak it. Making it an ivar of the
417f73363f1SDimitry Andric   // command object, which never goes away achieves this.  Note that if we were
418f73363f1SDimitry Andric   // able to run the same command concurrently in one interpreter we'd have to
419f73363f1SDimitry Andric   // make this "per invocation".  But there are many more reasons why it is not
420f73363f1SDimitry Andric   // in general safe to do that in lldb at present, so it isn't worthwhile to
421f73363f1SDimitry Andric   // come up with a more complex mechanism to address this particular weakness
422f73363f1SDimitry Andric   // right now.
423f034231aSEd Maste   static const char *g_reader_instructions;
424f034231aSEd Maste };
425f034231aSEd Maste 
42614f1b3e8SDimitry Andric const char *CommandObjectBreakpointCommandAdd::g_reader_instructions =
42714f1b3e8SDimitry Andric     "Enter your debugger command(s).  Type 'DONE' to end.\n";
428f034231aSEd Maste 
429f034231aSEd Maste // CommandObjectBreakpointCommandDelete
430f034231aSEd Maste 
431ead24645SDimitry Andric #define LLDB_OPTIONS_breakpoint_command_delete
432ead24645SDimitry Andric #include "CommandOptions.inc"
43314f1b3e8SDimitry Andric 
43414f1b3e8SDimitry Andric class CommandObjectBreakpointCommandDelete : public CommandObjectParsed {
435f034231aSEd Maste public:
CommandObjectBreakpointCommandDelete(CommandInterpreter & interpreter)43614f1b3e8SDimitry Andric   CommandObjectBreakpointCommandDelete(CommandInterpreter &interpreter)
43714f1b3e8SDimitry Andric       : CommandObjectParsed(interpreter, "delete",
438f034231aSEd Maste                             "Delete the set of commands from a breakpoint.",
4396f8fc217SDimitry Andric                             nullptr) {
440ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeBreakpointID);
441f034231aSEd Maste   }
442f034231aSEd Maste 
443f3fbd1c0SDimitry Andric   ~CommandObjectBreakpointCommandDelete() override = default;
444f034231aSEd Maste 
GetOptions()44514f1b3e8SDimitry Andric   Options *GetOptions() override { return &m_options; }
446205afe67SEd Maste 
44714f1b3e8SDimitry Andric   class CommandOptions : public Options {
448205afe67SEd Maste   public:
449145449b1SDimitry Andric     CommandOptions() = default;
450205afe67SEd Maste 
451f3fbd1c0SDimitry Andric     ~CommandOptions() override = default;
452205afe67SEd Maste 
SetOptionValue(uint32_t option_idx,llvm::StringRef option_arg,ExecutionContext * execution_context)453b76161e4SDimitry Andric     Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
45414f1b3e8SDimitry Andric                           ExecutionContext *execution_context) override {
455b76161e4SDimitry Andric       Status error;
456205afe67SEd Maste       const int short_option = m_getopt_table[option_idx].val;
457205afe67SEd Maste 
45814f1b3e8SDimitry Andric       switch (short_option) {
459205afe67SEd Maste       case 'D':
460205afe67SEd Maste         m_use_dummy = true;
461205afe67SEd Maste         break;
462205afe67SEd Maste 
463205afe67SEd Maste       default:
464ead24645SDimitry Andric         llvm_unreachable("Unimplemented option");
465205afe67SEd Maste       }
466205afe67SEd Maste 
467205afe67SEd Maste       return error;
468205afe67SEd Maste     }
469205afe67SEd Maste 
OptionParsingStarting(ExecutionContext * execution_context)47014f1b3e8SDimitry Andric     void OptionParsingStarting(ExecutionContext *execution_context) override {
471205afe67SEd Maste       m_use_dummy = false;
472205afe67SEd Maste     }
473205afe67SEd Maste 
GetDefinitions()47414f1b3e8SDimitry Andric     llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
475e3b55780SDimitry Andric       return llvm::ArrayRef(g_breakpoint_command_delete_options);
476205afe67SEd Maste     }
477205afe67SEd Maste 
478205afe67SEd Maste     // Instance variables to hold the values for command options.
479344a3780SDimitry Andric     bool m_use_dummy = false;
480205afe67SEd Maste   };
481205afe67SEd Maste 
482f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)483b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
484ead24645SDimitry Andric     Target &target = GetSelectedOrDummyTarget(m_options.m_use_dummy);
485f034231aSEd Maste 
486ead24645SDimitry Andric     const BreakpointList &breakpoints = target.GetBreakpointList();
487f034231aSEd Maste     size_t num_breakpoints = breakpoints.GetSize();
488f034231aSEd Maste 
48914f1b3e8SDimitry Andric     if (num_breakpoints == 0) {
490f034231aSEd Maste       result.AppendError("No breakpoints exist to have commands deleted");
491b1c73532SDimitry Andric       return;
492f034231aSEd Maste     }
493f034231aSEd Maste 
49414f1b3e8SDimitry Andric     if (command.empty()) {
49514f1b3e8SDimitry Andric       result.AppendError(
49614f1b3e8SDimitry Andric           "No breakpoint specified from which to delete the commands");
497b1c73532SDimitry Andric       return;
498f034231aSEd Maste     }
499f034231aSEd Maste 
500f034231aSEd Maste     BreakpointIDList valid_bp_ids;
50114f1b3e8SDimitry Andric     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
502ead24645SDimitry Andric         command, &target, result, &valid_bp_ids,
503ef5d0b5eSDimitry Andric         BreakpointName::Permissions::PermissionKinds::listPerm);
504f034231aSEd Maste 
50514f1b3e8SDimitry Andric     if (result.Succeeded()) {
506f034231aSEd Maste       const size_t count = valid_bp_ids.GetSize();
50714f1b3e8SDimitry Andric       for (size_t i = 0; i < count; ++i) {
508f034231aSEd Maste         BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
50914f1b3e8SDimitry Andric         if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
51014f1b3e8SDimitry Andric           Breakpoint *bp =
511ead24645SDimitry Andric               target.GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
51214f1b3e8SDimitry Andric           if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
51314f1b3e8SDimitry Andric             BreakpointLocationSP bp_loc_sp(
51414f1b3e8SDimitry Andric                 bp->FindLocationByID(cur_bp_id.GetLocationID()));
515f034231aSEd Maste             if (bp_loc_sp)
516f034231aSEd Maste               bp_loc_sp->ClearCallback();
51714f1b3e8SDimitry Andric             else {
518f034231aSEd Maste               result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
519f034231aSEd Maste                                            cur_bp_id.GetBreakpointID(),
520f034231aSEd Maste                                            cur_bp_id.GetLocationID());
521b1c73532SDimitry Andric               return;
522f034231aSEd Maste             }
52314f1b3e8SDimitry Andric           } else {
524f034231aSEd Maste             bp->ClearCallback();
525f034231aSEd Maste           }
526f034231aSEd Maste         }
527f034231aSEd Maste       }
528f034231aSEd Maste     }
529f034231aSEd Maste   }
530f3fbd1c0SDimitry Andric 
531205afe67SEd Maste private:
532205afe67SEd Maste   CommandOptions m_options;
533f034231aSEd Maste };
534f034231aSEd Maste 
535f034231aSEd Maste // CommandObjectBreakpointCommandList
536f034231aSEd Maste 
53714f1b3e8SDimitry Andric class CommandObjectBreakpointCommandList : public CommandObjectParsed {
538f034231aSEd Maste public:
CommandObjectBreakpointCommandList(CommandInterpreter & interpreter)53914f1b3e8SDimitry Andric   CommandObjectBreakpointCommandList(CommandInterpreter &interpreter)
540ead24645SDimitry Andric       : CommandObjectParsed(interpreter, "list",
541ead24645SDimitry Andric                             "List the script or set of commands to be "
542ead24645SDimitry Andric                             "executed when the breakpoint is hit.",
543ead24645SDimitry Andric                             nullptr, eCommandRequiresTarget) {
544ac9a064cSDimitry Andric     AddSimpleArgumentList(eArgTypeBreakpointID);
545f034231aSEd Maste   }
546f034231aSEd Maste 
547f3fbd1c0SDimitry Andric   ~CommandObjectBreakpointCommandList() override = default;
548f034231aSEd Maste 
549f034231aSEd Maste protected:
DoExecute(Args & command,CommandReturnObject & result)550b1c73532SDimitry Andric   void DoExecute(Args &command, CommandReturnObject &result) override {
551ead24645SDimitry Andric     Target *target = &GetSelectedTarget();
552f034231aSEd Maste 
553f034231aSEd Maste     const BreakpointList &breakpoints = target->GetBreakpointList();
554f034231aSEd Maste     size_t num_breakpoints = breakpoints.GetSize();
555f034231aSEd Maste 
55614f1b3e8SDimitry Andric     if (num_breakpoints == 0) {
557f034231aSEd Maste       result.AppendError("No breakpoints exist for which to list commands");
558b1c73532SDimitry Andric       return;
559f034231aSEd Maste     }
560f034231aSEd Maste 
56114f1b3e8SDimitry Andric     if (command.empty()) {
56214f1b3e8SDimitry Andric       result.AppendError(
56314f1b3e8SDimitry Andric           "No breakpoint specified for which to list the commands");
564b1c73532SDimitry Andric       return;
565f034231aSEd Maste     }
566f034231aSEd Maste 
567f034231aSEd Maste     BreakpointIDList valid_bp_ids;
56814f1b3e8SDimitry Andric     CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
569ef5d0b5eSDimitry Andric         command, target, result, &valid_bp_ids,
570ef5d0b5eSDimitry Andric         BreakpointName::Permissions::PermissionKinds::listPerm);
571f034231aSEd Maste 
57214f1b3e8SDimitry Andric     if (result.Succeeded()) {
573f034231aSEd Maste       const size_t count = valid_bp_ids.GetSize();
57414f1b3e8SDimitry Andric       for (size_t i = 0; i < count; ++i) {
575f034231aSEd Maste         BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex(i);
57614f1b3e8SDimitry Andric         if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID) {
57714f1b3e8SDimitry Andric           Breakpoint *bp =
57814f1b3e8SDimitry Andric               target->GetBreakpointByID(cur_bp_id.GetBreakpointID()).get();
579f034231aSEd Maste 
58014f1b3e8SDimitry Andric           if (bp) {
581ef5d0b5eSDimitry Andric             BreakpointLocationSP bp_loc_sp;
58214f1b3e8SDimitry Andric             if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID) {
583ef5d0b5eSDimitry Andric               bp_loc_sp = bp->FindLocationByID(cur_bp_id.GetLocationID());
584706b4fc4SDimitry Andric               if (!bp_loc_sp) {
585f034231aSEd Maste                 result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
586f034231aSEd Maste                                              cur_bp_id.GetBreakpointID(),
587f034231aSEd Maste                                              cur_bp_id.GetLocationID());
588b1c73532SDimitry Andric                 return;
589f034231aSEd Maste               }
590f034231aSEd Maste             }
591f034231aSEd Maste 
592f034231aSEd Maste             StreamString id_str;
593f034231aSEd Maste             BreakpointID::GetCanonicalReference(&id_str,
594f034231aSEd Maste                                                 cur_bp_id.GetBreakpointID(),
595f034231aSEd Maste                                                 cur_bp_id.GetLocationID());
596ef5d0b5eSDimitry Andric             const Baton *baton = nullptr;
597ef5d0b5eSDimitry Andric             if (bp_loc_sp)
598706b4fc4SDimitry Andric               baton =
599706b4fc4SDimitry Andric                   bp_loc_sp
600ef5d0b5eSDimitry Andric                       ->GetOptionsSpecifyingKind(BreakpointOptions::eCallback)
601344a3780SDimitry Andric                       .GetBaton();
602ef5d0b5eSDimitry Andric             else
603344a3780SDimitry Andric               baton = bp->GetOptions().GetBaton();
604ef5d0b5eSDimitry Andric 
60514f1b3e8SDimitry Andric             if (baton) {
60614f1b3e8SDimitry Andric               result.GetOutputStream().Printf("Breakpoint %s:\n",
60714f1b3e8SDimitry Andric                                               id_str.GetData());
608706b4fc4SDimitry Andric               baton->GetDescription(result.GetOutputStream().AsRawOstream(),
609706b4fc4SDimitry Andric                                     eDescriptionLevelFull,
610706b4fc4SDimitry Andric                                     result.GetOutputStream().GetIndentLevel() +
611706b4fc4SDimitry Andric                                         2);
61214f1b3e8SDimitry Andric             } else {
61314f1b3e8SDimitry Andric               result.AppendMessageWithFormat(
61414f1b3e8SDimitry Andric                   "Breakpoint %s does not have an associated command.\n",
615f034231aSEd Maste                   id_str.GetData());
616f034231aSEd Maste             }
617f034231aSEd Maste           }
618f034231aSEd Maste           result.SetStatus(eReturnStatusSuccessFinishResult);
61914f1b3e8SDimitry Andric         } else {
62014f1b3e8SDimitry Andric           result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n",
62114f1b3e8SDimitry Andric                                        cur_bp_id.GetBreakpointID());
622f034231aSEd Maste         }
623f034231aSEd Maste       }
624f034231aSEd Maste     }
625f034231aSEd Maste   }
626f034231aSEd Maste };
627f034231aSEd Maste 
628f034231aSEd Maste // CommandObjectBreakpointCommand
629f034231aSEd Maste 
CommandObjectBreakpointCommand(CommandInterpreter & interpreter)63014f1b3e8SDimitry Andric CommandObjectBreakpointCommand::CommandObjectBreakpointCommand(
63114f1b3e8SDimitry Andric     CommandInterpreter &interpreter)
632f3fbd1c0SDimitry Andric     : CommandObjectMultiword(
633706b4fc4SDimitry Andric           interpreter, "command",
634706b4fc4SDimitry Andric           "Commands for adding, removing and listing "
63514f1b3e8SDimitry Andric           "LLDB commands executed when a breakpoint is "
63614f1b3e8SDimitry Andric           "hit.",
63714f1b3e8SDimitry Andric           "command <sub-command> [<sub-command-options>] <breakpoint-id>") {
63814f1b3e8SDimitry Andric   CommandObjectSP add_command_object(
63914f1b3e8SDimitry Andric       new CommandObjectBreakpointCommandAdd(interpreter));
64014f1b3e8SDimitry Andric   CommandObjectSP delete_command_object(
64114f1b3e8SDimitry Andric       new CommandObjectBreakpointCommandDelete(interpreter));
64214f1b3e8SDimitry Andric   CommandObjectSP list_command_object(
64314f1b3e8SDimitry Andric       new CommandObjectBreakpointCommandList(interpreter));
644f034231aSEd Maste 
645f034231aSEd Maste   add_command_object->SetCommandName("breakpoint command add");
646f034231aSEd Maste   delete_command_object->SetCommandName("breakpoint command delete");
647f034231aSEd Maste   list_command_object->SetCommandName("breakpoint command list");
648f034231aSEd Maste 
649f034231aSEd Maste   LoadSubCommand("add", add_command_object);
650f034231aSEd Maste   LoadSubCommand("delete", delete_command_object);
651f034231aSEd Maste   LoadSubCommand("list", list_command_object);
652f034231aSEd Maste }
653f034231aSEd Maste 
654f3fbd1c0SDimitry Andric CommandObjectBreakpointCommand::~CommandObjectBreakpointCommand() = default;
655