Adds support for running a Lua function when a breakpoint is hit.
Example:
breakpoint command add -s lua -F abc
The above runs the Lua function 'abc' passing 2 arguments. 'frame', 'bp_loc' and 'extra_args'.
A third parameter 'extra_args' is only present when there is structured data
declared in the command line.
Example:
breakpoint command add -s lua -F abc -k foo -v bar
Differential Revision: https://reviews.llvm.org/D93649
{
SWIG_NewPointerObj(L, breakpoint_location_sb, SWIGTYPE_p_lldb__SBBreakpointLocation, 0);
}
+
+void
+PushSBClass (lua_State* L, lldb::SBStructuredData* structured_data_sb)
+{
+ SWIG_NewPointerObj(L, structured_data_sb, SWIGTYPE_p_lldb__SBStructuredData, 0);
+}
//===----------------------------------------------------------------------===//
+// FIXME:
+// Ideally all the typemaps should be revisited in a future SB API revision.
+// Typemaps, usually, modifies the function signatures and might spawn
+// different LLDB APIs across languages (C++, Python, Lua...).
+// Historically, typemaps have been used to replace SWIG's deficiencies,
+// but SWIG itself evolved and some API design choices are now redundant.
+
+//===----------------------------------------------------------------------===//
+
// Typemap definitions to allow SWIG to properly handle char buffer.
// typemap for a char buffer
(
lua_State *L,
lldb::StackFrameSP stop_frame_sp,
- lldb::BreakpointLocationSP bp_loc_sp
+ lldb::BreakpointLocationSP bp_loc_sp,
+ StructuredDataImpl *extra_args_impl
)
{
lldb::SBFrame sb_frame(stop_frame_sp);
lldb::SBBreakpointLocation sb_bp_loc(bp_loc_sp);
+ int nargs = 2;
+
+ llvm::Optional<lldb::SBStructuredData> extra_args;
+ if (extra_args_impl)
+ extra_args = lldb::SBStructuredData(extra_args_impl);
// Push the Lua wrappers
PushSBClass(L, &sb_frame);
PushSBClass(L, &sb_bp_loc);
+ if (extra_args.hasValue()) {
+ PushSBClass(L, extra_args.getPointer());
+ nargs++;
+ }
+
// Call into the Lua callback passing 'sb_frame' and 'sb_bp_loc'.
// Expects a boolean return.
- if (lua_pcall(L, 2, 1, 0) != LUA_OK) {
+ if (lua_pcall(L, nargs, 1, 0) != LUA_OK) {
llvm::Error E = llvm::make_error<llvm::StringError>(
llvm::formatv("{0}\n", lua_tostring(L, -1)),
llvm::inconvertibleErrorCode());
#pragma warning (disable : 4190)
#endif
-extern "C" llvm::Expected<bool>
-LLDBSwigLuaBreakpointCallbackFunction(lua_State *L,
- lldb::StackFrameSP stop_frame_sp,
- lldb::BreakpointLocationSP bp_loc_sp);
+extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction(
+ lua_State *L, lldb::StackFrameSP stop_frame_sp,
+ lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl);
#if _MSC_VER
#pragma warning (pop)
llvm::Expected<bool>
Lua::CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
- lldb::BreakpointLocationSP bp_loc_sp) {
+ lldb::BreakpointLocationSP bp_loc_sp,
+ StructuredData::ObjectSP extra_args_sp) {
+
lua_pushlightuserdata(m_lua_state, baton);
lua_gettable(m_lua_state, LUA_REGISTRYINDEX);
+ auto *extra_args_impl = [&]() -> StructuredDataImpl * {
+ if (extra_args_sp == nullptr)
+ return nullptr;
+ auto *extra_args_impl = new StructuredDataImpl();
+ extra_args_impl->SetObjectSP(extra_args_sp);
+ return extra_args_impl;
+ }();
return LLDBSwigLuaBreakpointCallbackFunction(m_lua_state, stop_frame_sp,
- bp_loc_sp);
+ bp_loc_sp, extra_args_impl);
}
llvm::Error Lua::CheckSyntax(llvm::StringRef buffer) {
#include "lldb/API/SBBreakpointLocation.h"
#include "lldb/API/SBFrame.h"
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
llvm::Error RegisterBreakpointCallback(void *baton, const char *body);
llvm::Expected<bool>
CallBreakpointCallback(void *baton, lldb::StackFrameSP stop_frame_sp,
- lldb::BreakpointLocationSP bp_loc_sp);
+ lldb::BreakpointLocationSP bp_loc_sp,
+ StructuredData::ObjectSP extra_args_sp);
llvm::Error LoadModule(llvm::StringRef filename);
llvm::Error CheckSyntax(llvm::StringRef buffer);
llvm::Error ChangeIO(FILE *out, FILE *err);
debugger.GetScriptInterpreter(true, eScriptLanguageLua));
Lua &lua = lua_interpreter->GetLua();
- llvm::Expected<bool> BoolOrErr =
- lua.CallBreakpointCallback(baton, stop_frame_sp, bp_loc_sp);
+ CommandDataLua *bp_option_data = static_cast<CommandDataLua *>(baton);
+ llvm::Expected<bool> BoolOrErr = lua.CallBreakpointCallback(
+ baton, stop_frame_sp, bp_loc_sp, bp_option_data->m_extra_args_sp);
if (llvm::Error E = BoolOrErr.takeError()) {
debugger.GetErrorStream() << toString(std::move(E));
return true;
m_debugger.RunIOHandlerAsync(io_handler_sp);
}
+Status ScriptInterpreterLua::SetBreakpointCommandCallbackFunction(
+ BreakpointOptions *bp_options, const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) {
+ const char *fmt_str = "return {0}(frame, bp_loc, ...)";
+ std::string oneliner = llvm::formatv(fmt_str, function_name).str();
+ return RegisterBreakpointCallback(bp_options, oneliner.c_str(),
+ extra_args_sp);
+}
+
Status ScriptInterpreterLua::SetBreakpointCommandCallback(
BreakpointOptions *bp_options, const char *command_body_text) {
+ return RegisterBreakpointCallback(bp_options, command_body_text, {});
+}
+
+Status ScriptInterpreterLua::RegisterBreakpointCallback(
+ BreakpointOptions *bp_options, const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp) {
Status error;
- auto data_up = std::make_unique<CommandDataLua>();
+ auto data_up = std::make_unique<CommandDataLua>(extra_args_sp);
error = m_lua->RegisterBreakpointCallback(data_up.get(), command_body_text);
if (error.Fail())
return error;
#ifndef liblldb_ScriptInterpreterLua_h_
#define liblldb_ScriptInterpreterLua_h_
+#include "lldb/Core/StructuredDataImpl.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Utility/Status.h"
#include "lldb/lldb-enumerations.h"
CommandDataLua() : BreakpointOptions::CommandData() {
interpreter = lldb::eScriptLanguageLua;
}
+ CommandDataLua(StructuredData::ObjectSP extra_args_sp)
+ : BreakpointOptions::CommandData(), m_extra_args_sp(extra_args_sp) {
+ interpreter = lldb::eScriptLanguageLua;
+ }
+ StructuredData::ObjectSP m_extra_args_sp;
};
ScriptInterpreterLua(Debugger &debugger);
Status SetBreakpointCommandCallback(BreakpointOptions *bp_options,
const char *command_body_text) override;
+ Status SetBreakpointCommandCallbackFunction(
+ BreakpointOptions *bp_options, const char *function_name,
+ StructuredData::ObjectSP extra_args_sp) override;
+
private:
std::unique_ptr<Lua> m_lua;
bool m_session_is_active = false;
+
+ Status RegisterBreakpointCallback(BreakpointOptions *bp_options,
+ const char *command_body_text,
+ StructuredData::ObjectSP extra_args_sp);
};
} // namespace lldb_private
--- /dev/null
+# REQUIRES: lua
+# RUN: echo "int main() { return 0; }" | %clang_host -x c - -o %t
+# RUN: %lldb -s %s --script-language lua %t 2>&1 | FileCheck %s
+b main
+script
+function abc(a, b, c, ...)
+print(c)
+if c then print(c:GetValueForKey("foo"):GetStringValue(32)) end
+end
+quit
+breakpoint command add -s lua -F abc
+r
+# CHECK: nil
+breakpoint command add -s lua -F abc -k foo -v 123pizza!
+r
+# CHECK: <userdata of type 'lldb::SBStructuredData *' at {{0x[[:xdigit:]]+}}>
+# CHECK: 123pizza!
+breakpoint command add -s lua -o "abc(frame, bp_loc, ...)"
+r
+# CHECK: nil
+breakpoint command add -s lua -F typo
+r
+# CHECK: attempt to call a nil value
#pragma warning (disable : 4190)
#endif
-extern "C" llvm::Expected<bool>
-LLDBSwigLuaBreakpointCallbackFunction(lua_State *L,
- lldb::StackFrameSP stop_frame_sp,
- lldb::BreakpointLocationSP bp_loc_sp) {
+extern "C" llvm::Expected<bool> LLDBSwigLuaBreakpointCallbackFunction(
+ lua_State *L, lldb::StackFrameSP stop_frame_sp,
+ lldb::BreakpointLocationSP bp_loc_sp, StructuredDataImpl *extra_args_impl) {
return false;
}