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