diff options
-rw-r--r-- | lldb/include/lldb/API/SBBreakpoint.h | 8 | ||||
-rw-r--r-- | lldb/include/lldb/API/SBBreakpointLocation.h | 6 | ||||
-rw-r--r-- | lldb/include/lldb/API/SBError.h | 2 | ||||
-rw-r--r-- | lldb/include/lldb/Interpreter/ScriptInterpreter.h | 32 | ||||
-rw-r--r-- | lldb/include/lldb/Interpreter/ScriptInterpreterPython.h | 16 | ||||
-rw-r--r-- | lldb/scripts/Python/interface/SBBreakpoint.i | 22 | ||||
-rw-r--r-- | lldb/scripts/Python/interface/SBBreakpointLocation.i | 23 | ||||
-rw-r--r-- | lldb/source/API/SBBreakpoint.cpp | 42 | ||||
-rw-r--r-- | lldb/source/API/SBBreakpointLocation.cpp | 46 | ||||
-rw-r--r-- | lldb/source/Commands/CommandObjectBreakpointCommand.cpp | 10 | ||||
-rw-r--r-- | lldb/source/Interpreter/ScriptInterpreterPython.cpp | 86 |
11 files changed, 236 insertions, 57 deletions
diff --git a/lldb/include/lldb/API/SBBreakpoint.h b/lldb/include/lldb/API/SBBreakpoint.h index be9c499798e..86d49c29a82 100644 --- a/lldb/include/lldb/API/SBBreakpoint.h +++ b/lldb/include/lldb/API/SBBreakpoint.h @@ -117,7 +117,13 @@ public: void SetCallback (BreakpointHitCallback callback, void *baton); - + + void + SetScriptCallbackFunction (const char *callback_function_name); + + SBError + SetScriptCallbackBody (const char *script_body_text); + size_t GetNumResolvedLocations() const; diff --git a/lldb/include/lldb/API/SBBreakpointLocation.h b/lldb/include/lldb/API/SBBreakpointLocation.h index 3b2ca2cf88e..fd9f246de4f 100644 --- a/lldb/include/lldb/API/SBBreakpointLocation.h +++ b/lldb/include/lldb/API/SBBreakpointLocation.h @@ -59,6 +59,12 @@ public: GetCondition (); void + SetScriptCallbackFunction (const char *callback_function_name); + + SBError + SetScriptCallbackBody (const char *script_body_text); + + void SetThreadID (lldb::tid_t sb_thread_id); lldb::tid_t diff --git a/lldb/include/lldb/API/SBError.h b/lldb/include/lldb/API/SBError.h index 25d7e81a3be..b9908658c5b 100644 --- a/lldb/include/lldb/API/SBError.h +++ b/lldb/include/lldb/API/SBError.h @@ -77,6 +77,8 @@ protected: friend class SBTarget; friend class SBValue; friend class SBWatchpoint; + friend class SBBreakpoint; + friend class SBBreakpointLocation; lldb_private::Error * get(); diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreter.h b/lldb/include/lldb/Interpreter/ScriptInterpreter.h index 1d62c9b0fb5..358e153b9b3 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreter.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreter.h @@ -254,16 +254,20 @@ public: return error; } - virtual bool + virtual Error ExportFunctionDefinitionToInterpreter (StringList &function_def) { - return false; + Error error; + error.SetErrorString("not implemented"); + return error; } - virtual bool + virtual Error GenerateBreakpointCommandCallbackData (StringList &input, std::string& output) { - return false; + Error error; + error.SetErrorString("not implemented"); + return error; } virtual bool @@ -359,10 +363,12 @@ public: return lldb::ScriptInterpreterObjectSP(); } - virtual bool + virtual Error GenerateFunction(const char *signature, const StringList &input) { - return false; + Error error; + error.SetErrorString("unimplemented"); + return error; } virtual void @@ -373,10 +379,20 @@ public: CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, CommandReturnObject &result); + /// Set the specified text as the callback for the breakpoint. + virtual Error + SetBreakpointCommandCallback (BreakpointOptions *bp_options, + const char *callback_text) + { + Error error; + error.SetErrorString("unimplemented"); + return error; + } + /// Set a one-liner as the callback for the breakpoint. virtual void - SetBreakpointCommandCallback (BreakpointOptions *bp_options, - const char *oneliner) + SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options, + const char *function_name) { return; } diff --git a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h index ba532808673..83cd0b5a58c 100644 --- a/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h +++ b/lldb/include/lldb/Interpreter/ScriptInterpreterPython.h @@ -56,7 +56,7 @@ public: ExecuteMultipleLines (const char *in_string, const ExecuteScriptOptions &options = ExecuteScriptOptions()); - bool + Error ExportFunctionDefinitionToInterpreter (StringList &function_def); bool @@ -130,10 +130,10 @@ public: lldb_private::CommandReturnObject& cmd_retobj, Error& error); - bool + Error GenerateFunction(const char *signature, const StringList &input); - bool + Error GenerateBreakpointCommandCallbackData (StringList &input, std::string& output); bool @@ -227,10 +227,14 @@ public: CollectDataForWatchpointCommandCallback (WatchpointOptions *wp_options, CommandReturnObject &result); - /// Set a Python one-liner as the callback for the breakpoint. - void + /// Set the callback body text into the callback for the breakpoint. + Error SetBreakpointCommandCallback (BreakpointOptions *bp_options, - const char *oneliner); + const char *callback_body); + + void + SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options, + const char *function_name); /// Set a one-liner as the callback for the watchpoint. void diff --git a/lldb/scripts/Python/interface/SBBreakpoint.i b/lldb/scripts/Python/interface/SBBreakpoint.i index 34274dda8b0..190c9b90dd6 100644 --- a/lldb/scripts/Python/interface/SBBreakpoint.i +++ b/lldb/scripts/Python/interface/SBBreakpoint.i @@ -177,9 +177,29 @@ public: const char * GetQueueName () const; + %feature("docstring", " + //------------------------------------------------------------------ + /// Set the name of the script function to be called when the breakpoint is hit. + //------------------------------------------------------------------ + ") SetScriptCallbackFunction; void - SetCallback (BreakpointHitCallback callback, void *baton); + SetScriptCallbackFunction (const char *callback_function_name); + %feature("docstring", " + //------------------------------------------------------------------ + /// Provide the body for the script function to be called when the breakpoint is hit. + /// The body will be wrapped in a function, which be passed two arguments: + /// 'frame' - which holds the bottom-most SBFrame of the thread that hit the breakpoint + /// 'bpno' - which is the SBBreakpointLocation to which the callback was attached. + /// + /// The error parameter is currently ignored, but will at some point hold the Python + /// compilation diagnostics. + /// Returns true if the body compiles successfully, false if not. + //------------------------------------------------------------------ + ") SetScriptCallbackBody; + SBError + SetScriptCallbackBody (const char *script_body_text); + size_t GetNumResolvedLocations() const; diff --git a/lldb/scripts/Python/interface/SBBreakpointLocation.i b/lldb/scripts/Python/interface/SBBreakpointLocation.i index 8c9b9c78246..a3073538e67 100644 --- a/lldb/scripts/Python/interface/SBBreakpointLocation.i +++ b/lldb/scripts/Python/interface/SBBreakpointLocation.i @@ -70,6 +70,29 @@ public: const char * GetCondition (); + %feature("docstring", " + //------------------------------------------------------------------ + /// Set the callback to the given Python function name. + //------------------------------------------------------------------ + ") SetScriptCallbackFunction; + void + SetScriptCallbackFunction (const char *callback_function_name); + + %feature("docstring", " + //------------------------------------------------------------------ + /// Provide the body for the script function to be called when the breakpoint location is hit. + /// The body will be wrapped in a function, which be passed two arguments: + /// 'frame' - which holds the bottom-most SBFrame of the thread that hit the breakpoint + /// 'bpno' - which is the SBBreakpointLocation to which the callback was attached. + /// + /// The error parameter is currently ignored, but will at some point hold the Python + /// compilation diagnostics. + /// Returns true if the body compiles successfully, false if not. + //------------------------------------------------------------------ + ") SetScriptCallbackBody; + SBError + SetScriptCallbackBody (const char *script_body_text); + void SetThreadID (lldb::tid_t sb_thread_id); diff --git a/lldb/source/API/SBBreakpoint.cpp b/lldb/source/API/SBBreakpoint.cpp index fbdc0e32f49..2c9cd12f18e 100644 --- a/lldb/source/API/SBBreakpoint.cpp +++ b/lldb/source/API/SBBreakpoint.cpp @@ -19,9 +19,12 @@ #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Address.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreter.h" #include "lldb/Target/Process.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" @@ -579,6 +582,45 @@ SBBreakpoint::SetCallback (BreakpointHitCallback callback, void *baton) } } +void +SBBreakpoint::SetScriptCallbackFunction (const char *callback_function_name) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpoint(%p)::SetScriptCallbackFunction (callback=%s)", m_opaque_sp.get(), callback_function_name); + + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); + BreakpointOptions *bp_options = m_opaque_sp->GetOptions(); + m_opaque_sp->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter()->SetBreakpointCommandCallbackFunction (bp_options, + callback_function_name); + } +} + +SBError +SBBreakpoint::SetScriptCallbackBody (const char *callback_body_text) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpoint(%p)::SetScriptCallbackBody: callback body:\n%s)", m_opaque_sp.get(), callback_body_text); + + SBError sb_error; + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetTarget().GetAPIMutex()); + BreakpointOptions *bp_options = m_opaque_sp->GetOptions(); + Error error = m_opaque_sp->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, + callback_body_text); + sb_error.SetError(error); + } + else + sb_error.SetErrorString("invalid breakpoint"); + + return sb_error; +} lldb_private::Breakpoint * SBBreakpoint::operator->() const diff --git a/lldb/source/API/SBBreakpointLocation.cpp b/lldb/source/API/SBBreakpointLocation.cpp index 6fdf59f38b4..b2b94484f9c 100644 --- a/lldb/source/API/SBBreakpointLocation.cpp +++ b/lldb/source/API/SBBreakpointLocation.cpp @@ -17,10 +17,13 @@ #include "lldb/lldb-defines.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" -#include "lldb/Target/ThreadSpec.h" +#include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" #include "lldb/Core/StreamFile.h" +#include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Target/ThreadSpec.h" #include "lldb/Target/Target.h" #include "lldb/Target/ThreadSpec.h" @@ -160,6 +163,47 @@ SBBreakpointLocation::GetCondition () } void +SBBreakpointLocation::SetScriptCallbackFunction (const char *callback_function_name) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpointLocation(%p)::SetScriptCallbackFunction (callback=%s)", m_opaque_sp.get(), callback_function_name); + + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex()); + BreakpointOptions *bp_options = m_opaque_sp->GetLocationOptions(); + m_opaque_sp->GetBreakpoint().GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter()->SetBreakpointCommandCallbackFunction (bp_options, + callback_function_name); + + } +} + +SBError +SBBreakpointLocation::SetScriptCallbackBody (const char *callback_body_text) +{ + Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); + + if (log) + log->Printf ("SBBreakpoint(%p)::SetScriptCallbackBody: callback body:\n%s)", m_opaque_sp.get(), callback_body_text); + + SBError sb_error; + if (m_opaque_sp) + { + Mutex::Locker api_locker (m_opaque_sp->GetBreakpoint().GetTarget().GetAPIMutex()); + BreakpointOptions *bp_options = m_opaque_sp->GetLocationOptions(); + Error error = m_opaque_sp->GetBreakpoint().GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, + callback_body_text); + sb_error.SetError(error); + } + else + sb_error.SetErrorString("invalid breakpoint"); + + return sb_error; +} + +void SBBreakpointLocation::SetThreadID (tid_t thread_id) { if (m_opaque_sp) diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp index 532d6cedc83..0b28cc3e2cc 100644 --- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp +++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp @@ -504,16 +504,10 @@ protected: m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, m_options.m_one_liner.c_str()); } - // Special handling for using a Python function by name - // instead of extending the breakpoint callback data structures, we just automatize - // what the user would do manually: make their breakpoint command be a function call else if (m_options.m_function_name.size()) { - std::string oneliner("return "); - oneliner += m_options.m_function_name; - oneliner += "(frame, bp_loc, internal_dict)"; - m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, - oneliner.c_str()); + m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallbackFunction (bp_options, + m_options.m_function_name.c_str()); } else { diff --git a/lldb/source/Interpreter/ScriptInterpreterPython.cpp b/lldb/source/Interpreter/ScriptInterpreterPython.cpp index b9723275bed..4bb247307c9 100644 --- a/lldb/source/Interpreter/ScriptInterpreterPython.cpp +++ b/lldb/source/Interpreter/ScriptInterpreterPython.cpp @@ -254,7 +254,7 @@ ScriptInterpreterPython::IOHandlerInputComplete (IOHandler &io_handler, std::str { data_ap->user_source.SplitIntoLines(data); - if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source)) + if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source).Success()) { BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); @@ -1083,27 +1083,39 @@ ScriptInterpreterPython::CollectDataForWatchpointCommandCallback (WatchpointOpti m_interpreter.GetPythonCommandsFromIOHandler (" ", *this, true, wp_options); } -// Set a Python one-liner as the callback for the breakpoint. void +ScriptInterpreterPython::SetBreakpointCommandCallbackFunction (BreakpointOptions *bp_options, + const char *function_name) +{ + // For now just cons up a oneliner that calls the provided function. + std::string oneliner("return "); + oneliner += function_name; + oneliner += "(frame, bp_loc, internal_dict)"; + m_interpreter.GetScriptInterpreter()->SetBreakpointCommandCallback (bp_options, + oneliner.c_str()); +} + +// Set a Python one-liner as the callback for the breakpoint. +Error ScriptInterpreterPython::SetBreakpointCommandCallback (BreakpointOptions *bp_options, - const char *oneliner) + const char *command_body_text) { std::unique_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData()); - // It's necessary to set both user_source and script_source to the oneliner. - // The former is used to generate callback description (as in breakpoint command list) - // while the latter is used for Python to interpret during the actual callback. - - data_ap->user_source.AppendString (oneliner); - data_ap->script_source.assign (oneliner); - - if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source)) + // Split the command_body_text into lines, and pass that to GenerateBreakpointCommandCallbackData. That will + // wrap the body in an auto-generated function, and return the function name in script_source. That is what + // the callback will actually invoke. + + data_ap->user_source.SplitIntoLines(command_body_text); + Error error = GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source); + if (error.Success()) { BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release())); bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp); + return error; } - - return; + else + return error; } // Set a Python one-liner as the callback for the watchpoint. @@ -1129,24 +1141,32 @@ ScriptInterpreterPython::SetWatchpointCommandCallback (WatchpointOptions *wp_opt return; } -bool +Error ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def) { // Convert StringList to one long, newline delimited, const char *. std::string function_def_string(function_def.CopyList()); - return ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)).Success(); + Error error = ExecuteMultipleLines (function_def_string.c_str(), ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)); + return error; } -bool +Error ScriptInterpreterPython::GenerateFunction(const char *signature, const StringList &input) { + Error error; int num_lines = input.GetSize (); if (num_lines == 0) - return false; + { + error.SetErrorString ("No input data."); + return error; + } if (!signature || *signature == 0) - return false; + { + error.SetErrorString("No output function name."); + return error; + } StreamString sstr; StringList auto_generated_function; @@ -1173,11 +1193,9 @@ ScriptInterpreterPython::GenerateFunction(const char *signature, const StringLis // Verify that the results are valid Python. - if (!ExportFunctionDefinitionToInterpreter (auto_generated_function)) - return false; + error = ExportFunctionDefinitionToInterpreter (auto_generated_function); - return true; - + return error; } bool @@ -1197,7 +1215,7 @@ ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, std std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_type_print_func", num_created_functions, name_token)); sstr.Printf ("def %s (valobj, internal_dict):", auto_generated_function_name.c_str()); - if (!GenerateFunction(sstr.GetData(), user_input)) + if (!GenerateFunction(sstr.GetData(), user_input).Success()) return false; // Store the name of the auto-generated function to be called. @@ -1220,7 +1238,7 @@ ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, st sstr.Printf ("def %s (debugger, args, result, internal_dict):", auto_generated_function_name.c_str()); - if (!GenerateFunction(sstr.GetData(),user_input)) + if (!GenerateFunction(sstr.GetData(),user_input).Success()) return false; // Store the name of the auto-generated function to be called. @@ -1266,7 +1284,7 @@ ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::st // Verify that the results are valid Python. // (even though the method is ExportFunctionDefinitionToInterpreter, a class will actually be exported) // (TODO: rename that method to ExportDefinitionToInterpreter) - if (!ExportFunctionDefinitionToInterpreter (auto_generated_class)) + if (!ExportFunctionDefinitionToInterpreter (auto_generated_class).Success()) return false; // Store the name of the auto-generated class @@ -1668,25 +1686,29 @@ ScriptInterpreterPython::GenerateTypeSynthClass (const char* oneliner, std::stri } -bool +Error ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, std::string& output) { static uint32_t num_created_functions = 0; user_input.RemoveBlankLines (); StreamString sstr; - + Error error; if (user_input.GetSize() == 0) - return false; + { + error.SetErrorString("No input data."); + return error; + } std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_bp_callback_func_",num_created_functions)); sstr.Printf ("def %s (frame, bp_loc, internal_dict):", auto_generated_function_name.c_str()); - if (!GenerateFunction(sstr.GetData(), user_input)) - return false; + error = GenerateFunction(sstr.GetData(), user_input); + if (!error.Success()) + return error; // Store the name of the auto-generated function to be called. output.assign(auto_generated_function_name); - return true; + return error; } bool @@ -1702,7 +1724,7 @@ ScriptInterpreterPython::GenerateWatchpointCommandCallbackData (StringList &user std::string auto_generated_function_name(GenerateUniqueName("lldb_autogen_python_wp_callback_func_",num_created_functions)); sstr.Printf ("def %s (frame, wp, internal_dict):", auto_generated_function_name.c_str()); - if (!GenerateFunction(sstr.GetData(), user_input)) + if (!GenerateFunction(sstr.GetData(), user_input).Success()) return false; // Store the name of the auto-generated function to be called. |