siger-young updated this revision to Diff 367971.
siger-young added a comment.
This update adds some tests for Lua LLDB module.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D108090/new/
https://reviews.llvm.org/D108090
Files:
lldb/CMakeLists.txt
lldb/bindings/lua/CMakeLists.txt
lldb/bindings/lua/lua-typemaps.swig
lldb/bindings/lua/lua-wrapper.swig
lldb/bindings/lua/lua.swig
lldb/source/API/liblldb-private.exports
lldb/source/API/liblldb.exports
lldb/test/API/lit.site.cfg.py.in
lldb/test/API/lldbtest.py
lldb/test/API/lua_api/Makefile
lldb/test/API/lua_api/TestBreakpointAPI.lua
lldb/test/API/lua_api/TestComprehensive.lua
lldb/test/API/lua_api/TestFileHandle.lua
lldb/test/API/lua_api/TestLuaAPI.py
lldb/test/API/lua_api/TestProcessAPI.lua
lldb/test/API/lua_api/lua_lldb_test.lua
lldb/test/API/lua_api/main.c
Index: lldb/test/API/lua_api/main.c
===================================================================
--- /dev/null
+++ lldb/test/API/lua_api/main.c
@@ -0,0 +1,35 @@
+#include <stdio.h>
+
+void BFunction()
+{
+}
+
+void AFunction()
+{
+ printf("I am a function.\n");
+}
+
+int main(int argc, const char *argv[])
+{
+ int inited = 0xDEADBEEF;
+ int sum = 0;
+ if(argc > 1)
+ {
+ for(int i = 0; i < argc; i++)
+ {
+ puts(argv[i]);
+ }
+ if(argc > 2)
+ {
+ return argc;
+ }
+ }
+ AFunction();
+ for(int i = 1; i <= 100; i++)
+ {
+ BFunction();
+ sum += i;
+ }
+ printf("sum = %d\n", sum);
+ return 0;
+}
Index: lldb/test/API/lua_api/lua_lldb_test.lua
===================================================================
--- /dev/null
+++ lldb/test/API/lua_api/lua_lldb_test.lua
@@ -0,0 +1,107 @@
+-- Import all functions of luaunit
+EXPORT_ASSERT_TO_GLOBALS = true
+require('luaunit')
+
+-- Make lldb available in global
+lldb = require('lldb')
+
+-- Global helper functions
+function read_file_non_empty_lines(f)
+ local lines = {}
+ while true do
+ local line = f:read('*l')
+ if not line then break end
+ if line ~= '\n' then table.insert(lines, line) end
+ end
+ return lines
+end
+
+function split_lines(str)
+ local lines = {}
+ for line in str:gmatch("[^\r\n]+") do
+ table.insert(lines, line)
+ end
+ return lines
+end
+
+function get_stopped_threads(process, reason)
+ local threads = {}
+ for i = 0, process:GetNumThreads() - 1 do
+ local t = process:GetThreadAtIndex(i)
+ if t:IsValid() and t:GetStopReason() == reason then
+ table.insert(threads, t)
+ end
+ end
+ return threads
+end
+
+function get_stopped_thread(process, reason)
+ local threads = get_stopped_threads(process, reason)
+ if #threads ~= 0 then return threads[1]
+ else return nil end
+end
+
+-- Test helper
+
+local _M = {}
+local _m = {}
+
+local _mt = { __index = _m }
+
+function _M.create_test(name, exe, output, input)
+ print('[lldb/lua] Doing test ' .. name)
+ exe = exe or os.getenv('TEST_EXE')
+ output = output or os.getenv('TEST_OUTPUT')
+ input = input or os.getenv('TEST_INPUT')
+ lldb.SBDebugger.Initialize()
+ local debugger = lldb.SBDebugger.Create()
+ -- Ensure that debugger is created
+ assertNotNil(debugger)
+ assertTrue(debugger:IsValid())
+
+ debugger:SetAsync(false)
+
+ local lua_language = debugger:GetScriptingLanguage('lua')
+ assertNotNil(lua_language)
+ debugger:SetScriptLanguage(lua_language)
+
+ local test = setmetatable({
+ output = output,
+ input = input,
+ name = name,
+ exe = exe,
+ debugger = debugger
+ }, _mt)
+ _G[name] = test
+ return test
+end
+
+function _m:create_target(exe)
+ local target
+ if not exe then exe = self.exe end
+ target = self.debugger:CreateTarget(exe)
+ -- Ensure that target is created
+ assertNotNil(target)
+ assertTrue(target:IsValid())
+ return target
+end
+
+function _m:handle_command(command, collect)
+ if collect == nil then collect = true end
+ if collect then
+ local ret = lldb.SBCommandReturnObject()
+ local interpreter = self.debugger:GetCommandInterpreter()
+ assertTrue(interpreter:IsValid())
+ interpreter:HandleCommand(command, ret)
+ self.debugger:GetOutputFile():Flush()
+ self.debugger:GetErrorFile():Flush()
+ assertTrue(ret:Succeeded())
+ return ret:GetOutput()
+ else
+ self.debugger:HandleCommand(command)
+ self.debugger:GetOutputFile():Flush()
+ self.debugger:GetErrorFile():Flush()
+ end
+end
+
+return _M
Index: lldb/test/API/lua_api/TestProcessAPI.lua
===================================================================
--- /dev/null
+++ lldb/test/API/lua_api/TestProcessAPI.lua
@@ -0,0 +1,59 @@
+_T = require('lua_lldb_test').create_test('TestProcessAPI')
+
+function _T:TestProcessLaunchSimple()
+ local target = self:create_target()
+ local args = { 'arg1', 'arg2', 'arg3' }
+ local process = target:LaunchSimple(
+ -- argv
+ args,
+ -- envp
+ nil,
+ -- working directory
+ nil
+ )
+ assertTrue(process:IsValid())
+ local stdout = process:GetSTDOUT(1000)
+ assertEquals(split_lines(stdout), {self.exe, table.unpack(args)})
+end
+
+function _T:TestProcessLaunch()
+ local target = self:create_target()
+ local args = { 'arg1', 'arg2', 'arg3' }
+ local error = lldb.SBError()
+ local f = io.open(self.output, 'w')
+ f:write()
+ f:close()
+ local process = target:Launch(
+ -- listener
+ self.debugger:GetListener(),
+ -- argv
+ args,
+ -- envp
+ nil,
+ -- stdin
+ nil,
+ -- stdout
+ self.output,
+ -- stderr
+ nil,
+ -- working directory
+ nil,
+ -- launch flags
+ 0,
+ -- stop at entry
+ true,
+ -- error
+ error
+ )
+ assertTrue(error:Success())
+ assertTrue(process:IsValid())
+ local threads = get_stopped_threads(process, lldb.eStopReasonSignal)
+ assertTrue(#threads ~= 0)
+ local continue = process:Continue()
+ assertTrue(continue:Success())
+ local f = io.open(self.output, 'r')
+ assertEquals(read_file_non_empty_lines(f), {self.exe, table.unpack(args)})
+ f:close()
+end
+
+os.exit(LuaUnit.run())
Index: lldb/test/API/lua_api/TestLuaAPI.py
===================================================================
--- /dev/null
+++ lldb/test/API/lua_api/TestLuaAPI.py
@@ -0,0 +1,65 @@
+"""
+Test Lua API wrapper
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+import lit.util
+
+
+class TestLuaAPI(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+ NO_DEBUG_INFO_TESTCASE = True
+
+ def get_tests(self):
+ tests = []
+ for filename in os.listdir():
+ # Ignore dot files and excluded tests.
+ if filename.startswith('.'):
+ continue
+
+ # Ignore files that don't start with 'Test'.
+ if not filename.startswith('Test'):
+ continue
+
+ if not os.path.isdir(filename):
+ base, ext = os.path.splitext(filename)
+ if ext == '.lua':
+ tests.append(filename)
+ return tests
+
+ def test_lua_api(self):
+ if "LUA_EXECUTABLE" not in os.environ or len(os.environ["LUA_EXECUTABLE"]) == 0:
+ self.skipTest("Lua API tests could not find Lua executable.")
+ return
+ lua_executable = os.environ["LUA_EXECUTABLE"]
+
+ self.build()
+ test_exe = self.getBuildArtifact("a.out")
+ test_output = self.getBuildArtifact("output")
+ test_input = self.getBuildArtifact("input")
+
+ lua_lldb_cpath = "%s/lua/?.so" % configuration.lldb_libs_dir
+
+ lua_prelude = "package.cpath = '%s;' .. package.cpath" % lua_lldb_cpath
+
+ lua_env = {
+ "TEST_EXE": os.path.join(self.getBuildDir(), test_exe),
+ "TEST_OUTPUT": os.path.join(self.getBuildDir(), test_output),
+ "TEST_INPUT": os.path.join(self.getBuildDir(), test_input)
+ }
+
+ for lua_test in self.get_tests():
+ cmd = [lua_executable] + ["-e", lua_prelude] + [lua_test]
+ out, err, exitCode = lit.util.executeCommand(cmd, env=lua_env)
+
+ # Redirect Lua output
+ print(out)
+ print(err, file=sys.stderr)
+
+ self.assertTrue(
+ exitCode == 0,
+ "Lua test '%s' failure." % lua_test
+ )
Index: lldb/test/API/lua_api/TestFileHandle.lua
===================================================================
--- /dev/null
+++ lldb/test/API/lua_api/TestFileHandle.lua
@@ -0,0 +1,37 @@
+_T = require('lua_lldb_test').create_test('TestFileHandle')
+
+function _T:TestLegacyFileOutScript()
+ local f = io.open(self.output, 'w')
+ self.debugger:SetOutputFile(f)
+ self:handle_command('script print(1+1)')
+ self.debugger:GetOutputFileHandle():write('FOO\n')
+ self.debugger:GetOutputFileHandle():flush()
+ f:close()
+
+ f = io.open(self.output, 'r')
+ assertEquals(read_file_non_empty_lines(f), {'2', 'FOO'})
+ f:close()
+end
+
+function _T:TestLegacyFileOut()
+ local f = io.open(self.output, 'w')
+ self.debugger:SetOutputFile(f)
+ self:handle_command('p/x 3735928559', false)
+ f:close()
+
+ f = io.open(self.output, 'r')
+ assertStrContains(f:read('*l'), 'deadbeef')
+ f:close()
+end
+
+function _T:TestLegacyFileErr()
+ local f = io.open(self.output, 'w')
+ self.debugger:SetErrorFile(f)
+ self:handle_command('lol', false)
+
+ f = io.open(self.output, 'r')
+ assertStrContains(f:read('*l'), 'is not a valid command')
+ f:close()
+end
+
+os.exit(LuaUnit.run())
Index: lldb/test/API/lua_api/TestComprehensive.lua
===================================================================
--- /dev/null
+++ lldb/test/API/lua_api/TestComprehensive.lua
@@ -0,0 +1,96 @@
+_T = require('lua_lldb_test').create_test('TestComprehensive')
+
+function _T:Test0_CreateTarget()
+ self.target = self:create_target()
+ assertTrue(self.target:IsValid())
+end
+
+function _T:Test1_Breakpoint()
+ self.main_bp = self.target:BreakpointCreateByName('main', 'a.out')
+ self.loop_bp = self.target:BreakpointCreateByLocation('main.c', 28)
+ assertTrue(self.main_bp:IsValid() and self.main_bp:GetNumLocations() == 1)
+ assertTrue(self.loop_bp:IsValid() and self.loop_bp:GetNumLocations() == 1)
+end
+
+function _T:Test2_Launch()
+ local error = lldb.SBError()
+ self.args = { 'arg' }
+ self.process = self.target:Launch(
+ self.debugger:GetListener(),
+ self.args,
+ nil,
+ nil,
+ self.output,
+ nil,
+ nil,
+ 0,
+ false,
+ error
+ )
+ assert(error:Success())
+ assertTrue(self.process:IsValid())
+end
+
+function _T:Test3_BreakpointFindVariables()
+ -- checking "argc" value
+ local thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
+ assertNotNil(thread)
+ assertTrue(thread:IsValid())
+ local frame = thread:GetFrameAtIndex(0)
+ assertTrue(frame:IsValid())
+ local error = lldb.SBError()
+ local var_argc = frame:FindVariable('argc')
+ assertTrue(var_argc:IsValid())
+ local var_argc_value = var_argc:GetValueAsSigned(error, 0)
+ assertTrue(error:Success())
+ assertEquals(var_argc_value, 2)
+
+ -- checking "inited" value
+ local continue = self.process:Continue()
+ assertTrue(continue:Success())
+ thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
+ assertNotNil(thread)
+ assertTrue(thread:IsValid())
+ frame = thread:GetFrameAtIndex(0)
+ assertTrue(frame:IsValid())
+ error = lldb.SBError()
+ local var_inited = frame:FindVariable('inited')
+ assertTrue(var_inited:IsValid())
+ self.var_inited = var_inited
+ local var_inited_value = var_inited:GetValueAsUnsigned(error, 0)
+ assertTrue(error:Success())
+ assertEquals(var_inited_value, 0xDEADBEEF)
+end
+
+function _T:Test3_RawData()
+ local error = lldb.SBError()
+ local address = self.var_inited:GetAddress()
+ assertTrue(address:IsValid())
+ local size = self.var_inited:GetByteSize()
+ local raw_data = self.process:ReadMemory(address:GetOffset(), size, error)
+ assertTrue(error:Success())
+ assertTrue(raw_data == "\xEF\xBE\xAD\xDE" or raw_data == "\xDE\xAD\xBE\xEF")
+end
+
+function _T:Test4_ProcessExit()
+ self.loop_bp:SetAutoContinue(true)
+ local continue = self.process:Continue()
+ assertTrue(continue:Success())
+ assertTrue(self.process:GetExitStatus() == 0)
+end
+
+function _T:Test5_FileOutput()
+ local f = io.open(self.output, 'r')
+ assertEquals(
+ read_file_non_empty_lines(f),
+ {
+ self.exe,
+ table.unpack(self.args),
+ 'I am a function.',
+ 'sum = 5050'
+ }
+ )
+ f:close()
+end
+
+os.exit(LuaUnit.run())
Index: lldb/test/API/lua_api/TestBreakpointAPI.lua
===================================================================
--- /dev/null
+++ lldb/test/API/lua_api/TestBreakpointAPI.lua
@@ -0,0 +1,52 @@
+_T = require('lua_lldb_test').create_test('TestBreakpointAPI')
+
+function _T:TestBreakpointIsValid()
+ local target = self:create_target()
+ local breakpoint = target:BreakpointCreateByName('AFunction', 'a.out')
+ assertTrue(breakpoint:IsValid() and breakpoint:GetNumLocations() == 1)
+ local did_delete = target:BreakpointDelete(breakpoint:GetID())
+ assertTrue(did_delete)
+ local del_bkpt = target:FindBreakpointByID(breakpoint:GetID())
+ assertFalse(del_bkpt:IsValid())
+ assertFalse(breakpoint:IsValid())
+end
+
+function _T:TestTargetDelete()
+ local target = self:create_target()
+ local breakpoint = target:BreakpointCreateByName('AFunction', 'a.out')
+ assertTrue(breakpoint:IsValid() and breakpoint:GetNumLocations() == 1)
+ local location = breakpoint:GetLocationAtIndex(0)
+ assertTrue(location:IsValid())
+ assertEquals(target, breakpoint:GetTarget())
+ assertTrue(self.debugger:DeleteTarget(target))
+ assertFalse(breakpoint:IsValid())
+ assertFalse(location:IsValid())
+end
+
+function _T:TestBreakpointHitCount()
+ local target = self:create_target()
+ local breakpoint = target:BreakpointCreateByName('BFunction', 'a.out')
+ assertTrue(breakpoint:IsValid() and breakpoint:GetNumLocations() == 1)
+ breakpoint:SetAutoContinue(true)
+ target:LaunchSimple(nil, nil, nil)
+ assertEquals(breakpoint:GetHitCount(), 100)
+end
+
+function _T:TestBreakpointFrame()
+ local target = self:create_target()
+ local breakpoint = target:BreakpointCreateByName('main', 'a.out')
+ assertTrue(breakpoint:IsValid() and breakpoint:GetNumLocations() == 1)
+ local process = target:LaunchSimple({ 'arg1', 'arg2' }, nil, nil)
+ local thread = get_stopped_thread(process, lldb.eStopReasonBreakpoint)
+ assertNotNil(thread)
+ assertTrue(thread:IsValid())
+ local frame = thread:GetFrameAtIndex(0)
+ assertTrue(frame:IsValid())
+ local error = lldb.SBError()
+ local var_argc = frame:FindVariable('argc')
+ local var_argc_value = var_argc:GetValueAsSigned(error, 0)
+ assert(error:Success())
+ assertEquals(var_argc_value, 3)
+end
+
+os.exit(LuaUnit.run())
Index: lldb/test/API/lua_api/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/lua_api/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
Index: lldb/test/API/lldbtest.py
===================================================================
--- lldb/test/API/lldbtest.py
+++ lldb/test/API/lldbtest.py
@@ -50,11 +50,17 @@
# build with.
executable = test.config.python_executable
+ isLuaTest = testFile == test.config.lua_test_entry
+
# On Windows, the system does not always correctly interpret
# shebang lines. To make sure we can execute the tests, add
# python exe as the first parameter of the command.
cmd = [executable] + self.dotest_cmd + [testPath, '-p', testFile]
+ if isLuaTest:
+ luaExecutable = test.config.lua_executable
+ cmd.extend(['--env', 'LUA_EXECUTABLE=%s' % luaExecutable])
+
if 'lldb-repro-capture' in test.config.available_features or \
'lldb-repro-replay' in test.config.available_features:
reproducer_path = os.path.join(
Index: lldb/test/API/lit.site.cfg.py.in
===================================================================
--- lldb/test/API/lit.site.cfg.py.in
+++ lldb/test/API/lit.site.cfg.py.in
@@ -20,6 +20,8 @@
config.lldb_build_directory = "@LLDB_TEST_BUILD_DIRECTORY@"
config.lldb_reproducer_directory = os.path.join("@LLDB_TEST_BUILD_DIRECTORY@", "reproducers")
config.python_executable = "@Python3_EXECUTABLE@"
+config.lua_executable = "@Lua_EXECUTABLE@"
+config.lua_test_entry = "TestLuaAPI.py"
config.dotest_args_str = "@LLDB_DOTEST_ARGS@"
config.lldb_enable_python = @LLDB_ENABLE_PYTHON@
config.dotest_lit_args_str = None
Index: lldb/source/API/liblldb.exports
===================================================================
--- lldb/source/API/liblldb.exports
+++ lldb/source/API/liblldb.exports
@@ -2,3 +2,4 @@
_ZNK4lldb*
init_lld*
PyInit__lldb*
+luaopen_lldb*
Index: lldb/source/API/liblldb-private.exports
===================================================================
--- lldb/source/API/liblldb-private.exports
+++ lldb/source/API/liblldb-private.exports
@@ -4,3 +4,4 @@
_ZNK12lldb_private*
init_lld*
PyInit__lldb*
+luaopen_lldb*
Index: lldb/bindings/lua/lua.swig
===================================================================
--- lldb/bindings/lua/lua.swig
+++ lldb/bindings/lua/lua.swig
@@ -17,6 +17,10 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FormatVariadic.h"
#include "../bindings/lua/lua-swigsafecast.swig"
+
+// required headers for typemaps
+#include "lldb/Host/File.h"
+
using namespace lldb_private;
using namespace lldb;
%}
Index: lldb/bindings/lua/lua-wrapper.swig
===================================================================
--- lldb/bindings/lua/lua-wrapper.swig
+++ lldb/bindings/lua/lua-wrapper.swig
@@ -6,6 +6,19 @@
%}
+%runtime %{
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void LLDBSwigLuaCallLuaLogOutputCallback(const char *str, void *baton);
+int LLDBSwigLuaCloseFileHandle(lua_State *L);
+
+#ifdef __cplusplus
+}
+#endif
+%}
+
%wrapper %{
// This function is called from Lua::CallBreakpointCallback
@@ -88,5 +101,20 @@
return stop;
}
+SWIGEXPORT void
+LLDBSwigLuaCallLuaLogOutputCallback(const char *str, void *baton) {
+ lua_State *L = (lua_State *)baton;
+
+ lua_pushlightuserdata(L, (void *)&LLDBSwigLuaCallLuaLogOutputCallback);
+ lua_gettable(L, LUA_REGISTRYINDEX);
+
+ // FIXME: There's no way to report errors back to the user
+ lua_pushstring(L, str);
+ lua_pcall(L, 1, 0, 0);
+}
+
+int LLDBSwigLuaCloseFileHandle(lua_State *L) {
+ return luaL_error(L, "You cannot close a file handle used by lldb.");
+}
%}
Index: lldb/bindings/lua/lua-typemaps.swig
===================================================================
--- lldb/bindings/lua/lua-typemaps.swig
+++ lldb/bindings/lua/lua-typemaps.swig
@@ -12,7 +12,7 @@
// Primitive integer mapping
%typemap(in,checkfn="lua_isinteger") TYPE
-%{ $1 = (TYPE)lua_tointeger(L, $input); %}
+%{ $1 = ($type)lua_tointeger(L, $input); %}
%typemap(in,checkfn="lua_isinteger") const TYPE&($basetype temp)
%{ temp=($basetype)lua_tointeger(L,$input); $1=&temp;%}
%typemap(out) TYPE
@@ -54,6 +54,7 @@
LLDB_NUMBER_TYPEMAP(long long);
LLDB_NUMBER_TYPEMAP(unsigned long long);
LLDB_NUMBER_TYPEMAP(signed long long);
+LLDB_NUMBER_TYPEMAP(enum SWIGTYPE);
%apply unsigned long { size_t };
%apply const unsigned long & { const size_t & };
@@ -77,7 +78,7 @@
%typemap(in) (char *dst, size_t dst_len) {
$2 = luaL_checkinteger(L, $input);
if ($2 <= 0) {
- return luaL_error(L, "Positive integer expected");
+ return luaL_error(L, "Positive integer expected");
}
$1 = (char *) malloc($2);
}
@@ -86,6 +87,9 @@
// as char data instead of byte data.
%typemap(in) (void *char_buf, size_t size) = (char *dst, size_t dst_len);
+// Also SBProcess::ReadMemory.
+%typemap(in) (void *buf, size_t size) = (char *dst, size_t dst_len);
+
// Return the char buffer. Discarding any previous return result
%typemap(argout) (char *dst, size_t dst_len) {
lua_pop(L, 1); // Blow away the previous result
@@ -102,4 +106,195 @@
// as char data instead of byte data.
%typemap(argout) (void *char_buf, size_t size) = (char *dst, size_t dst_len);
+// Also SBProcess::ReadMemory.
+%typemap(argout) (void *buf, size_t size) = (char *dst, size_t dst_len);
+
+//===----------------------------------------------------------------------===//
+
+// Typemap for handling a snprintf-like API like SBThread::GetStopDescription.
+
+%typemap(in) (char *dst_or_null, size_t dst_len) {
+ $2 = luaL_checkinteger(L, $input);
+ if ($2 <= 0) {
+ return luaL_error(L, "Positive integer expected");
+ }
+ $1 = (char *)malloc($2);
+}
+
+%typemap(argout) (char *dst_or_null, size_t dst_len) {
+ lua_pop(L, 1); // Blow away the previous result
+ lua_pushlstring(L, (const char *)$1, $result);
+ free($1);
+ // SWIG_arg was already incremented
+}
+
+//===----------------------------------------------------------------------===//
+
+// Typemap for handling SBModule::GetVersion
+
+%typemap(in) (uint32_t *versions, uint32_t num_versions) {
+ $2 = 99;
+ $1 = (uint32_t *)malloc(sizeof(uint32_t) * $2);
+}
+
+%typemap(argout) (uint32_t *versions, uint32_t num_versions) {
+ uint32_t count = result;
+ if (count >= $2)
+ count = $2;
+ lua_newtable(L);
+ int i = 0;
+ while (i++ < count) {
+ lua_pushinteger(L, $1[i - 1]);
+ lua_seti(L, -2, i);
+ }
+ SWIG_arg++;
+ free($1);
+}
+
+//===----------------------------------------------------------------------===//
+
+// Typemap for handling SBDebugger::SetLoggingCallback
+
+%typemap(in) (lldb::LogOutputCallback log_callback, void *baton) {
+ $1 = LLDBSwigLuaCallLuaLogOutputCallback;
+ $2 = (void *)L;
+
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ lua_settop(L, 2);
+
+ lua_pushlightuserdata(L, (void *)&LLDBSwigLuaCallLuaLogOutputCallback);
+ lua_insert(L, 2);
+ lua_settable(L, LUA_REGISTRYINDEX);
+}
+
+//===----------------------------------------------------------------------===//
+
+// Typemap for handling SBEvent::SBEvent(uint32_t event, const char *cstr, uint32_t cstr_len)
+
+%typemap(in) (const char *cstr, uint32_t cstr_len) {
+ $1 = (char *)luaL_checklstring(L, $input, (size_t *)&$2);
+}
+
+// Typemap for handling SBProcess::PutSTDIN
+
+%typemap(in) (const char *src, size_t src_len) {
+ $1 = (char *)luaL_checklstring(L, $input, &$2);
+}
+
+// Typemap for handling SBProcess::WriteMemory, SBTarget::GetInstructions...
+
+%typemap(in) (const void *buf, size_t size),
+ (const void *data, size_t data_len) {
+ $1 = (void *)luaL_checklstring(L, $input, &$2);
+}
+
+//===----------------------------------------------------------------------===//
+
+// Typemap for handling char ** in SBTarget::LaunchSimple, SBTarget::Launch...
+
+%typemap(in) char ** {
+ if (lua_istable(L, $input)) {
+ size_t size = lua_rawlen(L, $input);
+ $1 = (char **)malloc((size + 1) * sizeof(char *));
+ int i = 0, j = 0;
+ while (i++ < size) {
+ lua_rawgeti(L, $input, i);
+ if (!lua_isstring(L, -1)) {
+ lua_pop(L, 1);
+ return luaL_error(L, "List should contains only strings");
+ }
+ $1[j++] = (char *)lua_tostring(L, -1);
+ lua_pop(L, 1);
+ }
+ $1[j] = 0;
+ } else if (lua_isnil(L, $input)) {
+ $1 = NULL;
+ }
+}
+
+%typemap(freearg) char ** {
+ free((char *) $1);
+}
+
+%typecheck(SWIG_TYPECHECK_STRING_ARRAY) char ** {
+ $1 = (lua_istable(L, $input) || lua_isnil(L, $input));
+}
+
+//===----------------------------------------------------------------------===//
+
+// Typemap for file handles (e.g. used in SBDebugger::SetOutputFile)
+
+%typemap(in) lldb::FileSP {
+ luaL_Stream *p = (luaL_Stream *)luaL_checkudata(L, $input, LUA_FILEHANDLE);
+ lldb::FileSP file_sp;
+ file_sp = std::make_shared<lldb_private::NativeFile>(p->f, false);
+ if (!file_sp->IsValid())
+ return luaL_error(L, "Invalid file");
+ $1 = file_sp;
+}
+
+%typecheck(SWIG_TYPECHECK_POINTER) lldb::FileSP {
+ $1 = (lua_isuserdata(L, $input)) &&
+ (luaL_testudata(L, $input, LUA_FILEHANDLE) != nullptr);
+}
+
+// Typemap for file handles (e.g. used in SBDebugger::GetOutputFileHandle)
+
+%typemap(out) lldb::FileSP {
+ lldb::FileSP &sp = $1;
+ if (sp && sp->IsValid()) {
+ luaL_Stream *p = (luaL_Stream *)lua_newuserdata(L, sizeof(luaL_Stream));
+ p->closef = &LLDBSwigLuaCloseFileHandle;
+ p->f = sp->GetStream();
+ luaL_setmetatable(L, LUA_FILEHANDLE);
+ SWIG_arg++;
+ }
+}
+
+//===----------------------------------------------------------------------===//
+
+// Typemap for SBData::CreateDataFromUInt64Array, SBData::SetDataFromUInt64Array ...
+
+%typemap(in) (uint64_t* array, size_t array_len),
+ (uint32_t* array, size_t array_len),
+ (int64_t* array, size_t array_len),
+ (int32_t* array, size_t array_len),
+ (double* array, size_t array_len) {
+ if (lua_istable(L, $input)) {
+ $2 = lua_rawlen(L, $input);
+ $1 = ($1_ltype)malloc(($2) * sizeof($*1_type));
+ int i = 0, j = 0;
+ while (i++ < $2) {
+ lua_rawgeti(L, $input, i);
+ $1[j++] = ($*1_ltype)lua_tonumber(L, -1);
+ lua_pop(L, 1);
+ }
+ } else if (lua_isnil(L, $input)) {
+ $1 = NULL;
+ $2 = 0;
+ }
+}
+
+%typemap(in) (uint64_t* array, size_t array_len),
+ (uint32_t* array, size_t array_len),
+ (int64_t* array, size_t array_len),
+ (int32_t* array, size_t array_len),
+ (double* array, size_t array_len) {
+ free($1);
+}
+
+//===----------------------------------------------------------------------===//
+
+// Typemap for SBCommandReturnObject::PutCString
+
+%typemap(in) (const char *string, int len) {
+ if (lua_isnil(L, $input)) {
+ $1 = NULL;
+ $2 = 0;
+ }
+ else {
+ $1 = (char *)luaL_checklstring(L, $input, (size_t *)&$2);
+ }
+}
+
//===----------------------------------------------------------------------===//
Index: lldb/bindings/lua/CMakeLists.txt
===================================================================
--- lldb/bindings/lua/CMakeLists.txt
+++ lldb/bindings/lua/CMakeLists.txt
@@ -17,3 +17,34 @@
add_custom_target(swig_wrapper_lua ALL DEPENDS
${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapLua.cpp
)
+
+function(create_lua_package swig_target working_dir pkg_dir)
+ cmake_parse_arguments(ARG "NOINIT" "" "FILES" ${ARGN})
+ add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${pkg_dir}
+ WORKING_DIRECTORY ${working_dir})
+endfunction()
+
+function(finish_swig_lua swig_target lldb_lua_bindings_dir lldb_lua_target_dir)
+ add_custom_target(${swig_target} ALL VERBATIM
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${lldb_lua_target_dir}
+ DEPENDS swig_wrapper_lua
+ COMMENT "Lua LLDB Python API")
+ create_relative_symlink(${swig_target}
+ "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}"
+ ${lldb_lua_target_dir}
+ "lldb.so")
+ set(lldb_lua_library_target "${swig_target}-library")
+ add_custom_target(${lldb_lua_library_target})
+ add_dependencies(${lldb_lua_library_target} ${swig_target})
+ install(DIRECTORY ${lldb_lua_target_dir}/
+ DESTINATION ${LLDB_LUA_INSTALL_PATH}
+ COMPONENT ${lldb_lua_library_target})
+ # Ensure we do the Lua post-build step when building lldb.
+ add_dependencies(lldb ${swig_target})
+
+ set(lldb_lua_library_install_target "install-${lldb_lua_library_target}")
+ add_llvm_install_targets(${lldb_lua_library_install_target}
+ COMPONENT ${lldb_lua_library_target}
+ DEPENDS ${lldb_lua_library_target})
+endfunction()
Index: lldb/CMakeLists.txt
===================================================================
--- lldb/CMakeLists.txt
+++ lldb/CMakeLists.txt
@@ -51,6 +51,24 @@
CACHE STRING "Path where Python modules are installed, relative to install prefix")
endif ()
+if (LLDB_ENABLE_LUA)
+ # FIXME: Lua 5.3 is hardcoded but it should support 5.3+!
+ find_program(Lua_EXECUTABLE lua5.3)
+ if (NOT Lua_EXECUTABLE)
+ message(FATAL_ERROR "Lua executable not found")
+ else ()
+ execute_process(
+ COMMAND ${Lua_EXECUTABLE}
+ -e "for w in string.gmatch(package.cpath, ';?([^;]+);?') do \
+ if string.match(w, '%?%.so') then print(string.sub(w, 1, #w - 4)) break end end"
+ OUTPUT_VARIABLE LLDB_LUA_DEFAULT_INSTALL_PATH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+ file(TO_CMAKE_PATH ${LLDB_LUA_DEFAULT_INSTALL_PATH} LLDB_LUA_DEFAULT_INSTALL_PATH)
+ set(LLDB_LUA_INSTALL_PATH ${LLDB_LUA_DEFAULT_INSTALL_PATH}
+ CACHE STRING "Path where Lua modules are installed")
+ endif ()
+endif ()
+
if (LLDB_ENABLE_PYTHON OR LLDB_ENABLE_LUA)
add_subdirectory(bindings)
endif ()
@@ -94,6 +112,12 @@
finish_swig_python("lldb-python" "${lldb_python_bindings_dir}" "${lldb_python_target_dir}")
endif()
+if (LLDB_ENABLE_LUA)
+ set(lldb_lua_target_dir "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${CMAKE_INSTALL_LIBDIR}/lua")
+ get_target_property(lldb_lua_bindings_dir swig_wrapper_lua BINARY_DIR)
+ finish_swig_lua("lldb-lua" "${lldb_lua_bindings_dir}" "${lldb_lua_target_dir}")
+endif()
+
option(LLDB_INCLUDE_TESTS "Generate build targets for the LLDB unit tests." ${LLVM_INCLUDE_TESTS})
if(LLDB_INCLUDE_TESTS)
add_subdirectory(test)
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits