1254721Semaste//===-- CommandObjectBreakpointCommand.cpp ----------------------*- C++ -*-===//
2254721Semaste//
3254721Semaste//                     The LLVM Compiler Infrastructure
4254721Semaste//
5254721Semaste// This file is distributed under the University of Illinois Open Source
6254721Semaste// License. See LICENSE.TXT for details.
7254721Semaste//
8254721Semaste//===----------------------------------------------------------------------===//
9254721Semaste
10254721Semaste#include "lldb/lldb-python.h"
11254721Semaste
12254721Semaste// C Includes
13254721Semaste// C++ Includes
14254721Semaste
15254721Semaste
16254721Semaste#include "CommandObjectBreakpointCommand.h"
17254721Semaste#include "CommandObjectBreakpoint.h"
18254721Semaste
19254721Semaste#include "lldb/Interpreter/CommandInterpreter.h"
20254721Semaste#include "lldb/Interpreter/CommandReturnObject.h"
21254721Semaste#include "lldb/Target/Target.h"
22254721Semaste#include "lldb/Target/Thread.h"
23254721Semaste#include "lldb/Breakpoint/BreakpointIDList.h"
24254721Semaste#include "lldb/Breakpoint/Breakpoint.h"
25254721Semaste#include "lldb/Breakpoint/BreakpointLocation.h"
26254721Semaste#include "lldb/Breakpoint/StoppointCallbackContext.h"
27254721Semaste#include "lldb/Core/State.h"
28254721Semaste
29254721Semasteusing namespace lldb;
30254721Semasteusing namespace lldb_private;
31254721Semaste
32254721Semaste//-------------------------------------------------------------------------
33254721Semaste// CommandObjectBreakpointCommandAdd
34254721Semaste//-------------------------------------------------------------------------
35254721Semaste
36254721Semaste
37254721Semasteclass CommandObjectBreakpointCommandAdd : public CommandObjectParsed
38254721Semaste{
39254721Semastepublic:
40254721Semaste
41254721Semaste    CommandObjectBreakpointCommandAdd (CommandInterpreter &interpreter) :
42254721Semaste        CommandObjectParsed (interpreter,
43254721Semaste                             "add",
44254721Semaste                             "Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.",
45254721Semaste                             NULL),
46254721Semaste        m_options (interpreter)
47254721Semaste    {
48254721Semaste        SetHelpLong (
49254721Semaste"\nGeneral information about entering breakpoint commands\n\
50254721Semaste------------------------------------------------------\n\
51254721Semaste\n\
52254721SemasteThis command will cause you to be prompted to enter the command or set of\n\
53254721Semastecommands you wish to be executed when the specified breakpoint is hit. You\n\
54254721Semastewill be told to enter your command(s), and will see a '> 'prompt. Because\n\
55254721Semasteyou can enter one or many commands to be executed when a breakpoint is hit,\n\
56254721Semasteyou will continue to be prompted after each new-line that you enter, until you\n\
57254721Semasteenter the word 'DONE', which will cause the commands you have entered to be\n\
58254721Semastestored with the breakpoint and executed when the breakpoint is hit.\n\
59254721Semaste\n\
60254721SemasteSyntax checking is not necessarily done when breakpoint commands are entered.\n\
61254721SemasteAn improperly written breakpoint command will attempt to get executed when the\n\
62254721Semastebreakpoint gets hit, and usually silently fail.  If your breakpoint command does\n\
63254721Semastenot appear to be getting executed, go back and check your syntax.\n\
64254721Semaste\n\
65254721SemasteSpecial information about PYTHON breakpoint commands\n\
66254721Semaste----------------------------------------------------\n\
67254721Semaste\n\
68254721SemasteYou may enter either one line of Python, multiple lines of Python (including\n\
69254721Semastefunction definitions), or specify a Python function in a module that has already,\n\
70254721Semasteor will be imported.  If you enter a single line of Python, that will be passed\n\
71254721Semasteto the Python interpreter 'as is' when the breakpoint gets hit.  If you enter\n\
72254721Semastefunction definitions, they will be passed to the Python interpreter as soon as\n\
73254721Semasteyou finish entering the breakpoint command, and they can be called later (don't\n\
74254721Semasteforget to add calls to them, if you want them called when the breakpoint is\n\
75254721Semastehit).  If you enter multiple lines of Python that are not function definitions,\n\
76254721Semastethey will be collected into a new, automatically generated Python function, and\n\
77254721Semastea call to the newly generated function will be attached to the breakpoint.\n\
78254721Semaste\n\
79254721Semaste\n\
80254721SemasteThis auto-generated function is passed in three arguments:\n\
81254721Semaste\n\
82254721Semaste    frame:  a lldb.SBFrame object for the frame which hit breakpoint.\n\
83254721Semaste    bp_loc: a lldb.SBBreakpointLocation object that represents the breakpoint\n\
84254721Semaste            location that was hit.\n\
85254721Semaste    dict:   the python session dictionary hit.\n\
86254721Semaste\n\
87254721SemasteWhen specifying a python function with the --python-function option, you need\n\
88254721Semasteto supply the function name prepended by the module name. So if you import a\n\
89254721Semastemodule named 'myutils' that contains a 'breakpoint_callback' function, you would\n\
90254721Semastespecify the option as:\n\
91254721Semaste\n\
92254721Semaste    --python-function myutils.breakpoint_callback\n\
93254721Semaste\n\
94254721SemasteThe function itself must have the following prototype:\n\
95254721Semaste\n\
96254721Semastedef breakpoint_callback(frame, bp_loc, dict):\n\
97254721Semaste  # Your code goes here\n\
98254721Semaste\n\
99254721SemasteThe arguments are the same as the 3 auto generation function arguments listed\n\
100254721Semasteabove. Note that the global variable 'lldb.frame' will NOT be setup when this\n\
101254721Semastefunction is called, so be sure to use the 'frame' argument. The 'frame' argument\n\
102254721Semastecan get you to the thread (frame.GetThread()), the thread can get you to the\n\
103254721Semasteprocess (thread.GetProcess()), and the process can get you back to the target\n\
104254721Semaste(process.GetTarget()).\n\
105254721Semaste\n\
106254721SemasteImportant Note: Because loose Python code gets collected into functions, if you\n\
107254721Semastewant to access global variables in the 'loose' code, you need to specify that\n\
108254721Semastethey are global, using the 'global' keyword.  Be sure to use correct Python\n\
109254721Semastesyntax, including indentation, when entering Python breakpoint commands.\n\
110254721Semaste\n\
111254721SemasteAs a third option, you can pass the name of an already existing Python function\n\
112254721Semasteand that function will be attached to the breakpoint. It will get passed the\n\
113254721Semasteframe and bp_loc arguments mentioned above.\n\
114254721Semaste\n\
115254721SemasteExample Python one-line breakpoint command:\n\
116254721Semaste\n\
117254721Semaste(lldb) breakpoint command add -s python 1\n\
118254721SemasteEnter your Python command(s). Type 'DONE' to end.\n\
119254721Semaste> print \"Hit this breakpoint!\"\n\
120254721Semaste> DONE\n\
121254721Semaste\n\
122254721SemasteAs a convenience, this also works for a short Python one-liner:\n\
123254721Semaste(lldb) breakpoint command add -s python 1 -o \"import time; print time.asctime()\"\n\
124254721Semaste(lldb) run\n\
125254721SemasteLaunching '.../a.out'  (x86_64)\n\
126254721Semaste(lldb) Fri Sep 10 12:17:45 2010\n\
127254721SemasteProcess 21778 Stopped\n\
128254721Semaste* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread\n\
129254721Semaste  36   	\n\
130254721Semaste  37   	int c(int val)\n\
131254721Semaste  38   	{\n\
132254721Semaste  39 ->	    return val + 3;\n\
133254721Semaste  40   	}\n\
134254721Semaste  41   	\n\
135254721Semaste  42   	int main (int argc, char const *argv[])\n\
136254721Semaste(lldb)\n\
137254721Semaste\n\
138254721SemasteExample multiple line Python breakpoint command, using function definition:\n\
139254721Semaste\n\
140254721Semaste(lldb) breakpoint command add -s python 1\n\
141254721SemasteEnter your Python command(s). Type 'DONE' to end.\n\
142254721Semaste> def breakpoint_output (bp_no):\n\
143254721Semaste>     out_string = \"Hit breakpoint number \" + repr (bp_no)\n\
144254721Semaste>     print out_string\n\
145254721Semaste>     return True\n\
146254721Semaste> breakpoint_output (1)\n\
147254721Semaste> DONE\n\
148254721Semaste\n\
149254721Semaste\n\
150254721SemasteExample multiple line Python breakpoint command, using 'loose' Python:\n\
151254721Semaste\n\
152254721Semaste(lldb) breakpoint command add -s p 1\n\
153254721SemasteEnter your Python command(s). Type 'DONE' to end.\n\
154254721Semaste> global bp_count\n\
155254721Semaste> bp_count = bp_count + 1\n\
156254721Semaste> print \"Hit this breakpoint \" + repr(bp_count) + \" times!\"\n\
157254721Semaste> DONE\n\
158254721Semaste\n\
159254721SemasteIn this case, since there is a reference to a global variable,\n\
160254721Semaste'bp_count', you will also need to make sure 'bp_count' exists and is\n\
161254721Semasteinitialized:\n\
162254721Semaste\n\
163254721Semaste(lldb) script\n\
164254721Semaste>>> bp_count = 0\n\
165254721Semaste>>> quit()\n\
166254721Semaste\n\
167254721Semaste(lldb)\n\
168254721Semaste\n\
169254721Semaste\n\
170254721SemasteYour Python code, however organized, can optionally return a value.\n\
171254721SemasteIf the returned value is False, that tells LLDB not to stop at the breakpoint\n\
172254721Semasteto which the code is associated. Returning anything other than False, or even\n\
173254721Semastereturning None, or even omitting a return statement entirely, will cause\n\
174254721SemasteLLDB to stop.\n\
175254721Semaste\n\
176254721SemasteFinal Note:  If you get a warning that no breakpoint command was generated, but\n\
177254721Semasteyou did not get any syntax errors, you probably forgot to add a call to your\n\
178254721Semastefunctions.\n\
179254721Semaste\n\
180254721SemasteSpecial information about debugger command breakpoint commands\n\
181254721Semaste--------------------------------------------------------------\n\
182254721Semaste\n\
183254721SemasteYou may enter any debugger command, exactly as you would at the debugger prompt.\n\
184254721SemasteYou may enter as many debugger commands as you like, but do NOT enter more than\n\
185254721Semasteone command per line.\n" );
186254721Semaste
187254721Semaste        CommandArgumentEntry arg;
188254721Semaste        CommandArgumentData bp_id_arg;
189254721Semaste
190254721Semaste        // Define the first (and only) variant of this arg.
191254721Semaste        bp_id_arg.arg_type = eArgTypeBreakpointID;
192254721Semaste        bp_id_arg.arg_repetition = eArgRepeatPlain;
193254721Semaste
194254721Semaste        // There is only one variant this argument could be; put it into the argument entry.
195254721Semaste        arg.push_back (bp_id_arg);
196254721Semaste
197254721Semaste        // Push the data for the first argument into the m_arguments vector.
198254721Semaste        m_arguments.push_back (arg);
199254721Semaste    }
200254721Semaste
201254721Semaste    virtual
202254721Semaste    ~CommandObjectBreakpointCommandAdd () {}
203254721Semaste
204254721Semaste    virtual Options *
205254721Semaste    GetOptions ()
206254721Semaste    {
207254721Semaste        return &m_options;
208254721Semaste    }
209254721Semaste
210254721Semaste    void
211254721Semaste    CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
212254721Semaste                                             CommandReturnObject &result)
213254721Semaste    {
214254721Semaste        InputReaderSP reader_sp (new InputReader(m_interpreter.GetDebugger()));
215254721Semaste        std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
216254721Semaste        if (reader_sp && data_ap.get())
217254721Semaste        {
218254721Semaste            BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
219254721Semaste            bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
220254721Semaste
221254721Semaste            Error err (reader_sp->Initialize (CommandObjectBreakpointCommandAdd::GenerateBreakpointCommandCallback,
222254721Semaste                                              bp_options,                   // baton
223254721Semaste                                              eInputReaderGranularityLine,  // token size, to pass to callback function
224254721Semaste                                              "DONE",                       // end token
225254721Semaste                                              "> ",                         // prompt
226254721Semaste                                              true));                       // echo input
227254721Semaste            if (err.Success())
228254721Semaste            {
229254721Semaste                m_interpreter.GetDebugger().PushInputReader (reader_sp);
230254721Semaste                result.SetStatus (eReturnStatusSuccessFinishNoResult);
231254721Semaste            }
232254721Semaste            else
233254721Semaste            {
234254721Semaste                result.AppendError (err.AsCString());
235254721Semaste                result.SetStatus (eReturnStatusFailed);
236254721Semaste            }
237254721Semaste        }
238254721Semaste        else
239254721Semaste        {
240254721Semaste            result.AppendError("out of memory");
241254721Semaste            result.SetStatus (eReturnStatusFailed);
242254721Semaste        }
243254721Semaste
244254721Semaste    }
245254721Semaste
246254721Semaste    /// Set a one-liner as the callback for the breakpoint.
247254721Semaste    void
248254721Semaste    SetBreakpointCommandCallback (BreakpointOptions *bp_options,
249254721Semaste                                  const char *oneliner)
250254721Semaste    {
251254721Semaste        std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
252254721Semaste
253254721Semaste        // It's necessary to set both user_source and script_source to the oneliner.
254254721Semaste        // The former is used to generate callback description (as in breakpoint command list)
255254721Semaste        // while the latter is used for Python to interpret during the actual callback.
256254721Semaste        data_ap->user_source.AppendString (oneliner);
257254721Semaste        data_ap->script_source.assign (oneliner);
258254721Semaste        data_ap->stop_on_error = m_options.m_stop_on_error;
259254721Semaste
260254721Semaste        BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
261254721Semaste        bp_options->SetCallback (BreakpointOptionsCallbackFunction, baton_sp);
262254721Semaste
263254721Semaste        return;
264254721Semaste    }
265254721Semaste
266254721Semaste    static size_t
267254721Semaste    GenerateBreakpointCommandCallback (void *baton,
268254721Semaste                                       InputReader &reader,
269254721Semaste                                       lldb::InputReaderAction notification,
270254721Semaste                                       const char *bytes,
271254721Semaste                                       size_t bytes_len)
272254721Semaste    {
273254721Semaste        StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
274254721Semaste        bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
275254721Semaste
276254721Semaste        switch (notification)
277254721Semaste        {
278254721Semaste        case eInputReaderActivate:
279254721Semaste            if (!batch_mode)
280254721Semaste            {
281254721Semaste                out_stream->Printf ("%s\n", g_reader_instructions);
282254721Semaste                if (reader.GetPrompt())
283254721Semaste                    out_stream->Printf ("%s", reader.GetPrompt());
284254721Semaste                out_stream->Flush();
285254721Semaste            }
286254721Semaste            break;
287254721Semaste
288254721Semaste        case eInputReaderDeactivate:
289254721Semaste            break;
290254721Semaste
291254721Semaste        case eInputReaderReactivate:
292254721Semaste            if (reader.GetPrompt() && !batch_mode)
293254721Semaste            {
294254721Semaste                out_stream->Printf ("%s", reader.GetPrompt());
295254721Semaste                out_stream->Flush();
296254721Semaste            }
297254721Semaste            break;
298254721Semaste
299254721Semaste        case eInputReaderAsynchronousOutputWritten:
300254721Semaste            break;
301254721Semaste
302254721Semaste        case eInputReaderGotToken:
303254721Semaste            if (bytes && bytes_len && baton)
304254721Semaste            {
305254721Semaste                BreakpointOptions *bp_options = (BreakpointOptions *) baton;
306254721Semaste                if (bp_options)
307254721Semaste                {
308254721Semaste                    Baton *bp_options_baton = bp_options->GetBaton();
309254721Semaste                    if (bp_options_baton)
310254721Semaste                        ((BreakpointOptions::CommandData *)bp_options_baton->m_data)->user_source.AppendString (bytes, bytes_len);
311254721Semaste                }
312254721Semaste            }
313254721Semaste            if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
314254721Semaste            {
315254721Semaste                out_stream->Printf ("%s", reader.GetPrompt());
316254721Semaste                out_stream->Flush();
317254721Semaste            }
318254721Semaste            break;
319254721Semaste
320254721Semaste        case eInputReaderInterrupt:
321254721Semaste            {
322254721Semaste                // Finish, and cancel the breakpoint command.
323254721Semaste                reader.SetIsDone (true);
324254721Semaste                BreakpointOptions *bp_options = (BreakpointOptions *) baton;
325254721Semaste                if (bp_options)
326254721Semaste                {
327254721Semaste                    Baton *bp_options_baton = bp_options->GetBaton ();
328254721Semaste                    if (bp_options_baton)
329254721Semaste                    {
330254721Semaste                        ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->user_source.Clear();
331254721Semaste                        ((BreakpointOptions::CommandData *) bp_options_baton->m_data)->script_source.clear();
332254721Semaste                    }
333254721Semaste                }
334254721Semaste                if (!batch_mode)
335254721Semaste                {
336254721Semaste                    out_stream->Printf ("Warning: No command attached to breakpoint.\n");
337254721Semaste                    out_stream->Flush();
338254721Semaste                }
339254721Semaste            }
340254721Semaste            break;
341254721Semaste
342254721Semaste        case eInputReaderEndOfFile:
343254721Semaste            reader.SetIsDone (true);
344254721Semaste            break;
345254721Semaste
346254721Semaste        case eInputReaderDone:
347254721Semaste            break;
348254721Semaste        }
349254721Semaste
350254721Semaste        return bytes_len;
351254721Semaste    }
352254721Semaste
353254721Semaste    static bool
354254721Semaste    BreakpointOptionsCallbackFunction (void *baton,
355254721Semaste                                       StoppointCallbackContext *context,
356254721Semaste                                       lldb::user_id_t break_id,
357254721Semaste                                       lldb::user_id_t break_loc_id)
358254721Semaste    {
359254721Semaste        bool ret_value = true;
360254721Semaste        if (baton == NULL)
361254721Semaste            return true;
362254721Semaste
363254721Semaste
364254721Semaste        BreakpointOptions::CommandData *data = (BreakpointOptions::CommandData *) baton;
365254721Semaste        StringList &commands = data->user_source;
366254721Semaste
367254721Semaste        if (commands.GetSize() > 0)
368254721Semaste        {
369254721Semaste            ExecutionContext exe_ctx (context->exe_ctx_ref);
370254721Semaste            Target *target = exe_ctx.GetTargetPtr();
371254721Semaste            if (target)
372254721Semaste            {
373254721Semaste                CommandReturnObject result;
374254721Semaste                Debugger &debugger = target->GetDebugger();
375254721Semaste                // Rig up the results secondary output stream to the debugger's, so the output will come out synchronously
376254721Semaste                // if the debugger is set up that way.
377254721Semaste
378254721Semaste                StreamSP output_stream (debugger.GetAsyncOutputStream());
379254721Semaste                StreamSP error_stream (debugger.GetAsyncErrorStream());
380254721Semaste                result.SetImmediateOutputStream (output_stream);
381254721Semaste                result.SetImmediateErrorStream (error_stream);
382254721Semaste
383254721Semaste                bool stop_on_continue = true;
384254721Semaste                bool echo_commands    = false;
385254721Semaste                bool print_results    = true;
386254721Semaste
387254721Semaste                debugger.GetCommandInterpreter().HandleCommands (commands,
388254721Semaste                                                                 &exe_ctx,
389254721Semaste                                                                 stop_on_continue,
390254721Semaste                                                                 data->stop_on_error,
391254721Semaste                                                                 echo_commands,
392254721Semaste                                                                 print_results,
393254721Semaste                                                                 eLazyBoolNo,
394254721Semaste                                                                 result);
395254721Semaste                result.GetImmediateOutputStream()->Flush();
396254721Semaste                result.GetImmediateErrorStream()->Flush();
397254721Semaste           }
398254721Semaste        }
399254721Semaste        return ret_value;
400254721Semaste    }
401254721Semaste
402254721Semaste    class CommandOptions : public Options
403254721Semaste    {
404254721Semaste    public:
405254721Semaste
406254721Semaste        CommandOptions (CommandInterpreter &interpreter) :
407254721Semaste            Options (interpreter),
408254721Semaste            m_use_commands (false),
409254721Semaste            m_use_script_language (false),
410254721Semaste            m_script_language (eScriptLanguageNone),
411254721Semaste            m_use_one_liner (false),
412254721Semaste            m_one_liner(),
413254721Semaste            m_function_name()
414254721Semaste        {
415254721Semaste        }
416254721Semaste
417254721Semaste        virtual
418254721Semaste        ~CommandOptions () {}
419254721Semaste
420254721Semaste        virtual Error
421254721Semaste        SetOptionValue (uint32_t option_idx, const char *option_arg)
422254721Semaste        {
423254721Semaste            Error error;
424254721Semaste            const int short_option = m_getopt_table[option_idx].val;
425254721Semaste
426254721Semaste            switch (short_option)
427254721Semaste            {
428254721Semaste            case 'o':
429254721Semaste                m_use_one_liner = true;
430254721Semaste                m_one_liner = option_arg;
431254721Semaste                break;
432254721Semaste
433254721Semaste            case 's':
434254721Semaste                m_script_language = (lldb::ScriptLanguage) Args::StringToOptionEnum (option_arg,
435254721Semaste                                                                                     g_option_table[option_idx].enum_values,
436254721Semaste                                                                                     eScriptLanguageNone,
437254721Semaste                                                                                     error);
438254721Semaste
439254721Semaste                if (m_script_language == eScriptLanguagePython || m_script_language == eScriptLanguageDefault)
440254721Semaste                {
441254721Semaste                    m_use_script_language = true;
442254721Semaste                }
443254721Semaste                else
444254721Semaste                {
445254721Semaste                    m_use_script_language = false;
446254721Semaste                }
447254721Semaste                break;
448254721Semaste
449254721Semaste            case 'e':
450254721Semaste                {
451254721Semaste                    bool success = false;
452254721Semaste                    m_stop_on_error = Args::StringToBoolean(option_arg, false, &success);
453254721Semaste                    if (!success)
454254721Semaste                        error.SetErrorStringWithFormat("invalid value for stop-on-error: \"%s\"", option_arg);
455254721Semaste                }
456254721Semaste                break;
457254721Semaste
458254721Semaste            case 'F':
459254721Semaste                {
460254721Semaste                    m_use_one_liner = false;
461254721Semaste                    m_use_script_language = true;
462254721Semaste                    m_function_name.assign(option_arg);
463254721Semaste                }
464254721Semaste                break;
465254721Semaste
466254721Semaste            default:
467254721Semaste                break;
468254721Semaste            }
469254721Semaste            return error;
470254721Semaste        }
471254721Semaste        void
472254721Semaste        OptionParsingStarting ()
473254721Semaste        {
474254721Semaste            m_use_commands = true;
475254721Semaste            m_use_script_language = false;
476254721Semaste            m_script_language = eScriptLanguageNone;
477254721Semaste
478254721Semaste            m_use_one_liner = false;
479254721Semaste            m_stop_on_error = true;
480254721Semaste            m_one_liner.clear();
481254721Semaste            m_function_name.clear();
482254721Semaste        }
483254721Semaste
484254721Semaste        const OptionDefinition*
485254721Semaste        GetDefinitions ()
486254721Semaste        {
487254721Semaste            return g_option_table;
488254721Semaste        }
489254721Semaste
490254721Semaste        // Options table: Required for subclasses of Options.
491254721Semaste
492254721Semaste        static OptionDefinition g_option_table[];
493254721Semaste
494254721Semaste        // Instance variables to hold the values for command options.
495254721Semaste
496254721Semaste        bool m_use_commands;
497254721Semaste        bool m_use_script_language;
498254721Semaste        lldb::ScriptLanguage m_script_language;
499254721Semaste
500254721Semaste        // Instance variables to hold the values for one_liner options.
501254721Semaste        bool m_use_one_liner;
502254721Semaste        std::string m_one_liner;
503254721Semaste        bool m_stop_on_error;
504254721Semaste        std::string m_function_name;
505254721Semaste    };
506254721Semaste
507254721Semasteprotected:
508254721Semaste    virtual bool
509254721Semaste    DoExecute (Args& command, CommandReturnObject &result)
510254721Semaste    {
511254721Semaste        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
512254721Semaste
513254721Semaste        if (target == NULL)
514254721Semaste        {
515254721Semaste            result.AppendError ("There is not a current executable; there are no breakpoints to which to add commands");
516254721Semaste            result.SetStatus (eReturnStatusFailed);
517254721Semaste            return false;
518254721Semaste        }
519254721Semaste
520254721Semaste        const BreakpointList &breakpoints = target->GetBreakpointList();
521254721Semaste        size_t num_breakpoints = breakpoints.GetSize();
522254721Semaste
523254721Semaste        if (num_breakpoints == 0)
524254721Semaste        {
525254721Semaste            result.AppendError ("No breakpoints exist to have commands added");
526254721Semaste            result.SetStatus (eReturnStatusFailed);
527254721Semaste            return false;
528254721Semaste        }
529254721Semaste
530254721Semaste        if (m_options.m_use_script_language == false && m_options.m_function_name.size())
531254721Semaste        {
532254721Semaste            result.AppendError ("need to enable scripting to have a function run as a breakpoint command");
533254721Semaste            result.SetStatus (eReturnStatusFailed);
534254721Semaste            return false;
535254721Semaste        }
536254721Semaste
537254721Semaste        BreakpointIDList valid_bp_ids;
538254721Semaste        CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
539254721Semaste
540254721Semaste        if (result.Succeeded())
541254721Semaste        {
542254721Semaste            const size_t count = valid_bp_ids.GetSize();
543254721Semaste            if (count > 1)
544254721Semaste            {
545254721Semaste                result.AppendError ("can only add commands to one breakpoint at a time.");
546254721Semaste                result.SetStatus (eReturnStatusFailed);
547254721Semaste                return false;
548254721Semaste            }
549254721Semaste
550254721Semaste            for (size_t i = 0; i < count; ++i)
551254721Semaste            {
552254721Semaste                BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
553254721Semaste                if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
554254721Semaste                {
555254721Semaste                    Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
556254721Semaste                    BreakpointOptions *bp_options = NULL;
557254721Semaste                    if (cur_bp_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
558254721Semaste                    {
559254721Semaste                        // This breakpoint does not have an associated location.
560254721Semaste                        bp_options = bp->GetOptions();
561254721Semaste                    }
562254721Semaste                    else
563254721Semaste                    {
564254721Semaste                        BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
565254721Semaste                        // This breakpoint does have an associated location.
566254721Semaste                        // Get its breakpoint options.
567254721Semaste                        if (bp_loc_sp)
568254721Semaste                            bp_options = bp_loc_sp->GetLocationOptions();
569254721Semaste                    }
570254721Semaste
571254721Semaste                    // Skip this breakpoint if bp_options is not good.
572254721Semaste                    if (bp_options == NULL) continue;
573254721Semaste
574254721Semaste                    // If we are using script language, get the script interpreter
575254721Semaste                    // in order to set or collect command callback.  Otherwise, call
576254721Semaste                    // the methods associated with this object.
577254721Semaste                    if (m_options.m_use_script_language)
578254721Semaste                    {
579254721Semaste                        // Special handling for one-liner specified inline.
580254721Semaste                        if (m_options.m_use_one_liner)
581254721Semaste                        {
582254721Semaste                            m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
583254721Semaste                                                                                                m_options.m_one_liner.c_str());
584254721Semaste                        }
585254721Semaste                        // Special handling for using a Python function by name
586254721Semaste                        // instead of extending the breakpoint callback data structures, we just automatize
587254721Semaste                        // what the user would do manually: make their breakpoint command be a function call
588254721Semaste                        else if (m_options.m_function_name.size())
589254721Semaste                        {
590254721Semaste                            std::string oneliner("return ");
591254721Semaste                            oneliner += m_options.m_function_name;
592254721Semaste                            oneliner += "(frame, bp_loc, internal_dict)";
593254721Semaste                            m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options,
594254721Semaste                                                                                                oneliner.c_str());
595254721Semaste                        }
596254721Semaste                        else
597254721Semaste                        {
598254721Semaste                            m_interpreter.GetScriptInterpreter()->CollectDataForBreakpointCommandCallback (bp_options,
599254721Semaste                                                                                                           result);
600254721Semaste                        }
601254721Semaste                    }
602254721Semaste                    else
603254721Semaste                    {
604254721Semaste                        // Special handling for one-liner specified inline.
605254721Semaste                        if (m_options.m_use_one_liner)
606254721Semaste                            SetBreakpointCommandCallback (bp_options,
607254721Semaste                                                          m_options.m_one_liner.c_str());
608254721Semaste                        else
609254721Semaste                            CollectDataForBreakpointCommandCallback (bp_options,
610254721Semaste                                                                     result);
611254721Semaste                    }
612254721Semaste                }
613254721Semaste            }
614254721Semaste        }
615254721Semaste
616254721Semaste        return result.Succeeded();
617254721Semaste    }
618254721Semaste
619254721Semasteprivate:
620254721Semaste    CommandOptions m_options;
621254721Semaste    static const char *g_reader_instructions;
622254721Semaste
623254721Semaste};
624254721Semaste
625254721Semasteconst char *
626254721SemasteCommandObjectBreakpointCommandAdd::g_reader_instructions = "Enter your debugger command(s).  Type 'DONE' to end.";
627254721Semaste
628254721Semaste// FIXME: "script-type" needs to have its contents determined dynamically, so somebody can add a new scripting
629254721Semaste// language to lldb and have it pickable here without having to change this enumeration by hand and rebuild lldb proper.
630254721Semaste
631254721Semastestatic OptionEnumValueElement
632254721Semasteg_script_option_enumeration[4] =
633254721Semaste{
634254721Semaste    { eScriptLanguageNone,    "command",         "Commands are in the lldb command interpreter language"},
635254721Semaste    { eScriptLanguagePython,  "python",          "Commands are in the Python language."},
636254721Semaste    { eSortOrderByName,       "default-script",  "Commands are in the default scripting language."},
637254721Semaste    { 0,                      NULL,              NULL }
638254721Semaste};
639254721Semaste
640254721SemasteOptionDefinition
641254721SemasteCommandObjectBreakpointCommandAdd::CommandOptions::g_option_table[] =
642254721Semaste{
643254721Semaste    { LLDB_OPT_SET_1, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeOneLiner,
644254721Semaste        "Specify a one-line breakpoint command inline. Be sure to surround it with quotes." },
645254721Semaste
646254721Semaste    { LLDB_OPT_SET_ALL, false, "stop-on-error", 'e', required_argument, NULL, 0, eArgTypeBoolean,
647254721Semaste        "Specify whether breakpoint command execution should terminate on error." },
648254721Semaste
649254721Semaste    { LLDB_OPT_SET_ALL,   false, "script-type",     's', required_argument, g_script_option_enumeration, 0, eArgTypeNone,
650254721Semaste        "Specify the language for the commands - if none is specified, the lldb command interpreter will be used."},
651254721Semaste
652254721Semaste    { LLDB_OPT_SET_2,   false, "python-function",     'F', required_argument, NULL, 0, eArgTypePythonFunction,
653254721Semaste        "Give the name of a Python function to run as command for this breakpoint. Be sure to give a module name if appropriate."},
654254721Semaste
655254721Semaste    { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
656254721Semaste};
657254721Semaste
658254721Semaste//-------------------------------------------------------------------------
659254721Semaste// CommandObjectBreakpointCommandDelete
660254721Semaste//-------------------------------------------------------------------------
661254721Semaste
662254721Semasteclass CommandObjectBreakpointCommandDelete : public CommandObjectParsed
663254721Semaste{
664254721Semastepublic:
665254721Semaste    CommandObjectBreakpointCommandDelete (CommandInterpreter &interpreter) :
666254721Semaste        CommandObjectParsed (interpreter,
667254721Semaste                             "delete",
668254721Semaste                             "Delete the set of commands from a breakpoint.",
669254721Semaste                             NULL)
670254721Semaste    {
671254721Semaste        CommandArgumentEntry arg;
672254721Semaste        CommandArgumentData bp_id_arg;
673254721Semaste
674254721Semaste        // Define the first (and only) variant of this arg.
675254721Semaste        bp_id_arg.arg_type = eArgTypeBreakpointID;
676254721Semaste        bp_id_arg.arg_repetition = eArgRepeatPlain;
677254721Semaste
678254721Semaste        // There is only one variant this argument could be; put it into the argument entry.
679254721Semaste        arg.push_back (bp_id_arg);
680254721Semaste
681254721Semaste        // Push the data for the first argument into the m_arguments vector.
682254721Semaste        m_arguments.push_back (arg);
683254721Semaste    }
684254721Semaste
685254721Semaste
686254721Semaste    virtual
687254721Semaste    ~CommandObjectBreakpointCommandDelete () {}
688254721Semaste
689254721Semasteprotected:
690254721Semaste    virtual bool
691254721Semaste    DoExecute (Args& command, CommandReturnObject &result)
692254721Semaste    {
693254721Semaste        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
694254721Semaste
695254721Semaste        if (target == NULL)
696254721Semaste        {
697254721Semaste            result.AppendError ("There is not a current executable; there are no breakpoints from which to delete commands");
698254721Semaste            result.SetStatus (eReturnStatusFailed);
699254721Semaste            return false;
700254721Semaste        }
701254721Semaste
702254721Semaste        const BreakpointList &breakpoints = target->GetBreakpointList();
703254721Semaste        size_t num_breakpoints = breakpoints.GetSize();
704254721Semaste
705254721Semaste        if (num_breakpoints == 0)
706254721Semaste        {
707254721Semaste            result.AppendError ("No breakpoints exist to have commands deleted");
708254721Semaste            result.SetStatus (eReturnStatusFailed);
709254721Semaste            return false;
710254721Semaste        }
711254721Semaste
712254721Semaste        if (command.GetArgumentCount() == 0)
713254721Semaste        {
714254721Semaste            result.AppendError ("No breakpoint specified from which to delete the commands");
715254721Semaste            result.SetStatus (eReturnStatusFailed);
716254721Semaste            return false;
717254721Semaste        }
718254721Semaste
719254721Semaste        BreakpointIDList valid_bp_ids;
720254721Semaste        CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
721254721Semaste
722254721Semaste        if (result.Succeeded())
723254721Semaste        {
724254721Semaste            const size_t count = valid_bp_ids.GetSize();
725254721Semaste            for (size_t i = 0; i < count; ++i)
726254721Semaste            {
727254721Semaste                BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
728254721Semaste                if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
729254721Semaste                {
730254721Semaste                    Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
731254721Semaste                    if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
732254721Semaste                    {
733254721Semaste                        BreakpointLocationSP bp_loc_sp (bp->FindLocationByID (cur_bp_id.GetLocationID()));
734254721Semaste                        if (bp_loc_sp)
735254721Semaste                            bp_loc_sp->ClearCallback();
736254721Semaste                        else
737254721Semaste                        {
738254721Semaste                            result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
739254721Semaste                                                         cur_bp_id.GetBreakpointID(),
740254721Semaste                                                         cur_bp_id.GetLocationID());
741254721Semaste                            result.SetStatus (eReturnStatusFailed);
742254721Semaste                            return false;
743254721Semaste                        }
744254721Semaste                    }
745254721Semaste                    else
746254721Semaste                    {
747254721Semaste                        bp->ClearCallback();
748254721Semaste                    }
749254721Semaste                }
750254721Semaste            }
751254721Semaste        }
752254721Semaste        return result.Succeeded();
753254721Semaste    }
754254721Semaste};
755254721Semaste
756254721Semaste//-------------------------------------------------------------------------
757254721Semaste// CommandObjectBreakpointCommandList
758254721Semaste//-------------------------------------------------------------------------
759254721Semaste
760254721Semasteclass CommandObjectBreakpointCommandList : public CommandObjectParsed
761254721Semaste{
762254721Semastepublic:
763254721Semaste    CommandObjectBreakpointCommandList (CommandInterpreter &interpreter) :
764254721Semaste        CommandObjectParsed (interpreter,
765254721Semaste                             "list",
766254721Semaste                             "List the script or set of commands to be executed when the breakpoint is hit.",
767254721Semaste                              NULL)
768254721Semaste    {
769254721Semaste        CommandArgumentEntry arg;
770254721Semaste        CommandArgumentData bp_id_arg;
771254721Semaste
772254721Semaste        // Define the first (and only) variant of this arg.
773254721Semaste        bp_id_arg.arg_type = eArgTypeBreakpointID;
774254721Semaste        bp_id_arg.arg_repetition = eArgRepeatPlain;
775254721Semaste
776254721Semaste        // There is only one variant this argument could be; put it into the argument entry.
777254721Semaste        arg.push_back (bp_id_arg);
778254721Semaste
779254721Semaste        // Push the data for the first argument into the m_arguments vector.
780254721Semaste        m_arguments.push_back (arg);
781254721Semaste    }
782254721Semaste
783254721Semaste    virtual
784254721Semaste    ~CommandObjectBreakpointCommandList () {}
785254721Semaste
786254721Semasteprotected:
787254721Semaste    virtual bool
788254721Semaste    DoExecute (Args& command,
789254721Semaste             CommandReturnObject &result)
790254721Semaste    {
791254721Semaste        Target *target = m_interpreter.GetDebugger().GetSelectedTarget().get();
792254721Semaste
793254721Semaste        if (target == NULL)
794254721Semaste        {
795254721Semaste            result.AppendError ("There is not a current executable; there are no breakpoints for which to list commands");
796254721Semaste            result.SetStatus (eReturnStatusFailed);
797254721Semaste            return false;
798254721Semaste        }
799254721Semaste
800254721Semaste        const BreakpointList &breakpoints = target->GetBreakpointList();
801254721Semaste        size_t num_breakpoints = breakpoints.GetSize();
802254721Semaste
803254721Semaste        if (num_breakpoints == 0)
804254721Semaste        {
805254721Semaste            result.AppendError ("No breakpoints exist for which to list commands");
806254721Semaste            result.SetStatus (eReturnStatusFailed);
807254721Semaste            return false;
808254721Semaste        }
809254721Semaste
810254721Semaste        if (command.GetArgumentCount() == 0)
811254721Semaste        {
812254721Semaste            result.AppendError ("No breakpoint specified for which to list the commands");
813254721Semaste            result.SetStatus (eReturnStatusFailed);
814254721Semaste            return false;
815254721Semaste        }
816254721Semaste
817254721Semaste        BreakpointIDList valid_bp_ids;
818254721Semaste        CommandObjectMultiwordBreakpoint::VerifyBreakpointIDs (command, target, result, &valid_bp_ids);
819254721Semaste
820254721Semaste        if (result.Succeeded())
821254721Semaste        {
822254721Semaste            const size_t count = valid_bp_ids.GetSize();
823254721Semaste            for (size_t i = 0; i < count; ++i)
824254721Semaste            {
825254721Semaste                BreakpointID cur_bp_id = valid_bp_ids.GetBreakpointIDAtIndex (i);
826254721Semaste                if (cur_bp_id.GetBreakpointID() != LLDB_INVALID_BREAK_ID)
827254721Semaste                {
828254721Semaste                    Breakpoint *bp = target->GetBreakpointByID (cur_bp_id.GetBreakpointID()).get();
829254721Semaste
830254721Semaste                    if (bp)
831254721Semaste                    {
832254721Semaste                        const BreakpointOptions *bp_options = NULL;
833254721Semaste                        if (cur_bp_id.GetLocationID() != LLDB_INVALID_BREAK_ID)
834254721Semaste                        {
835254721Semaste                            BreakpointLocationSP bp_loc_sp(bp->FindLocationByID (cur_bp_id.GetLocationID()));
836254721Semaste                            if (bp_loc_sp)
837254721Semaste                                bp_options = bp_loc_sp->GetOptionsNoCreate();
838254721Semaste                            else
839254721Semaste                            {
840254721Semaste                                result.AppendErrorWithFormat("Invalid breakpoint ID: %u.%u.\n",
841254721Semaste                                                             cur_bp_id.GetBreakpointID(),
842254721Semaste                                                             cur_bp_id.GetLocationID());
843254721Semaste                                result.SetStatus (eReturnStatusFailed);
844254721Semaste                                return false;
845254721Semaste                            }
846254721Semaste                        }
847254721Semaste                        else
848254721Semaste                        {
849254721Semaste                            bp_options = bp->GetOptions();
850254721Semaste                        }
851254721Semaste
852254721Semaste                        if (bp_options)
853254721Semaste                        {
854254721Semaste                            StreamString id_str;
855254721Semaste                            BreakpointID::GetCanonicalReference (&id_str,
856254721Semaste                                                                 cur_bp_id.GetBreakpointID(),
857254721Semaste                                                                 cur_bp_id.GetLocationID());
858254721Semaste                            const Baton *baton = bp_options->GetBaton();
859254721Semaste                            if (baton)
860254721Semaste                            {
861254721Semaste                                result.GetOutputStream().Printf ("Breakpoint %s:\n", id_str.GetData());
862254721Semaste                                result.GetOutputStream().IndentMore ();
863254721Semaste                                baton->GetDescription(&result.GetOutputStream(), eDescriptionLevelFull);
864254721Semaste                                result.GetOutputStream().IndentLess ();
865254721Semaste                            }
866254721Semaste                            else
867254721Semaste                            {
868254721Semaste                                result.AppendMessageWithFormat ("Breakpoint %s does not have an associated command.\n",
869254721Semaste                                                                id_str.GetData());
870254721Semaste                            }
871254721Semaste                        }
872254721Semaste                        result.SetStatus (eReturnStatusSuccessFinishResult);
873254721Semaste                    }
874254721Semaste                    else
875254721Semaste                    {
876254721Semaste                        result.AppendErrorWithFormat("Invalid breakpoint ID: %u.\n", cur_bp_id.GetBreakpointID());
877254721Semaste                        result.SetStatus (eReturnStatusFailed);
878254721Semaste                    }
879254721Semaste
880254721Semaste                }
881254721Semaste            }
882254721Semaste        }
883254721Semaste
884254721Semaste        return result.Succeeded();
885254721Semaste    }
886254721Semaste};
887254721Semaste
888254721Semaste//-------------------------------------------------------------------------
889254721Semaste// CommandObjectBreakpointCommand
890254721Semaste//-------------------------------------------------------------------------
891254721Semaste
892254721SemasteCommandObjectBreakpointCommand::CommandObjectBreakpointCommand (CommandInterpreter &interpreter) :
893254721Semaste    CommandObjectMultiword (interpreter,
894254721Semaste                            "command",
895254721Semaste                            "A set of commands for adding, removing and examining bits of code to be executed when the breakpoint is hit (breakpoint 'commmands').",
896254721Semaste                            "command <sub-command> [<sub-command-options>] <breakpoint-id>")
897254721Semaste{
898254721Semaste    CommandObjectSP add_command_object (new CommandObjectBreakpointCommandAdd (interpreter));
899254721Semaste    CommandObjectSP delete_command_object (new CommandObjectBreakpointCommandDelete (interpreter));
900254721Semaste    CommandObjectSP list_command_object (new CommandObjectBreakpointCommandList (interpreter));
901254721Semaste
902254721Semaste    add_command_object->SetCommandName ("breakpoint command add");
903254721Semaste    delete_command_object->SetCommandName ("breakpoint command delete");
904254721Semaste    list_command_object->SetCommandName ("breakpoint command list");
905254721Semaste
906254721Semaste    LoadSubCommand ("add",    add_command_object);
907254721Semaste    LoadSubCommand ("delete", delete_command_object);
908254721Semaste    LoadSubCommand ("list",   list_command_object);
909254721Semaste}
910254721Semaste
911254721SemasteCommandObjectBreakpointCommand::~CommandObjectBreakpointCommand ()
912254721Semaste{
913254721Semaste}
914254721Semaste
915254721Semaste
916