Skip to content

Commit 67f94e5

Browse files
committed
[lldb/lua] Supplement Lua bindings for lldb module
Add necessary typemaps for Lua bindings, together with some other files. Signed-off-by: Siger Yang <[email protected]> Reviewed By: tammela Differential Revision: https://reviews.llvm.org/D108090
1 parent 40546cb commit 67f94e5

17 files changed

+950
-2
lines changed

lldb/CMakeLists.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,13 @@ if (LLDB_ENABLE_PYTHON)
5151
CACHE STRING "Path where Python modules are installed, relative to install prefix")
5252
endif ()
5353

54+
if (LLDB_ENABLE_LUA)
55+
find_program(Lua_EXECUTABLE lua5.3)
56+
set(LLDB_LUA_DEFAULT_RELATIVE_PATH "lib/lua/5.3")
57+
set(LLDB_LUA_RELATIVE_PATH ${LLDB_LUA_DEFAULT_RELATIVE_PATH}
58+
CACHE STRING "Path where Lua modules are installed, relative to install prefix")
59+
endif ()
60+
5461
if (LLDB_ENABLE_PYTHON OR LLDB_ENABLE_LUA)
5562
add_subdirectory(bindings)
5663
endif ()
@@ -94,6 +101,16 @@ if (LLDB_ENABLE_PYTHON)
94101
finish_swig_python("lldb-python" "${lldb_python_bindings_dir}" "${lldb_python_target_dir}")
95102
endif()
96103

104+
if (LLDB_ENABLE_LUA)
105+
if(LLDB_BUILD_FRAMEWORK)
106+
set(lldb_lua_target_dir "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/Resources/Lua")
107+
else()
108+
set(lldb_lua_target_dir "${CMAKE_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${LLDB_LUA_RELATIVE_PATH}")
109+
endif()
110+
get_target_property(lldb_lua_bindings_dir swig_wrapper_lua BINARY_DIR)
111+
finish_swig_lua("lldb-lua" "${lldb_lua_bindings_dir}" "${lldb_lua_target_dir}")
112+
endif()
113+
97114
option(LLDB_INCLUDE_TESTS "Generate build targets for the LLDB unit tests." ${LLVM_INCLUDE_TESTS})
98115
if(LLDB_INCLUDE_TESTS)
99116
add_subdirectory(test)

lldb/bindings/lua/CMakeLists.txt

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,55 @@ add_custom_command(
1717
add_custom_target(swig_wrapper_lua ALL DEPENDS
1818
${CMAKE_CURRENT_BINARY_DIR}/LLDBWrapLua.cpp
1919
)
20+
21+
function(create_lua_package swig_target working_dir pkg_dir)
22+
cmake_parse_arguments(ARG "NOINIT" "" "FILES" ${ARGN})
23+
add_custom_command(TARGET ${swig_target} POST_BUILD VERBATIM
24+
COMMAND ${CMAKE_COMMAND} -E make_directory ${pkg_dir}
25+
WORKING_DIRECTORY ${working_dir})
26+
endfunction()
27+
28+
function(finish_swig_lua swig_target lldb_lua_bindings_dir lldb_lua_target_dir)
29+
add_custom_target(${swig_target} ALL VERBATIM
30+
COMMAND ${CMAKE_COMMAND} -E make_directory ${lldb_lua_target_dir}
31+
DEPENDS swig_wrapper_lua
32+
COMMENT "LLDB Lua API")
33+
if(LLDB_BUILD_FRAMEWORK)
34+
set(LIBLLDB_SYMLINK_DEST "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}/LLDB.framework/LLDB")
35+
else()
36+
set(LIBLLDB_SYMLINK_DEST "${LLVM_SHLIB_OUTPUT_INTDIR}/liblldb${CMAKE_SHARED_LIBRARY_SUFFIX}")
37+
endif()
38+
if(WIN32)
39+
if(CMAKE_BUILD_TYPE STREQUAL Debug)
40+
set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb_d.pyd")
41+
else()
42+
set(LIBLLDB_SYMLINK_OUTPUT_FILE "_lldb.pyd")
43+
endif()
44+
else()
45+
set(LIBLLDB_SYMLINK_OUTPUT_FILE "lldb.so")
46+
endif()
47+
create_relative_symlink(${swig_target} ${LIBLLDB_SYMLINK_DEST}
48+
${lldb_lua_target_dir} ${LIBLLDB_SYMLINK_OUTPUT_FILE})
49+
set(lldb_lua_library_target "${swig_target}-library")
50+
add_custom_target(${lldb_lua_library_target})
51+
add_dependencies(${lldb_lua_library_target} ${swig_target})
52+
53+
# Ensure we do the Lua post-build step when building lldb.
54+
add_dependencies(lldb ${swig_target})
55+
56+
if(LLDB_BUILD_FRAMEWORK)
57+
set(LLDB_LUA_INSTALL_PATH ${LLDB_FRAMEWORK_INSTALL_DIR}/LLDB.framework/Resources/Python)
58+
else()
59+
set(LLDB_LUA_INSTALL_PATH ${LLDB_LUA_RELATIVE_PATH})
60+
endif()
61+
install(DIRECTORY ${lldb_lua_target_dir}/
62+
DESTINATION ${LLDB_LUA_INSTALL_PATH}
63+
COMPONENT ${lldb_lua_library_target})
64+
65+
set(lldb_lua_library_install_target "install-${lldb_lua_library_target}")
66+
if (NOT LLVM_ENABLE_IDE)
67+
add_llvm_install_targets(${lldb_lua_library_install_target}
68+
COMPONENT ${lldb_lua_library_target}
69+
DEPENDS ${lldb_lua_library_target})
70+
endif()
71+
endfunction()

lldb/bindings/lua/lua-typemaps.swig

Lines changed: 213 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
// Primitive integer mapping
1414
%typemap(in,checkfn="lua_isinteger") TYPE
15-
%{ $1 = (TYPE)lua_tointeger(L, $input); %}
15+
%{ $1 = ($type)lua_tointeger(L, $input); %}
1616
%typemap(in,checkfn="lua_isinteger") const TYPE&($basetype temp)
1717
%{ temp=($basetype)lua_tointeger(L,$input); $1=&temp;%}
1818
%typemap(out) TYPE
@@ -54,6 +54,7 @@ LLDB_NUMBER_TYPEMAP(signed long);
5454
LLDB_NUMBER_TYPEMAP(long long);
5555
LLDB_NUMBER_TYPEMAP(unsigned long long);
5656
LLDB_NUMBER_TYPEMAP(signed long long);
57+
LLDB_NUMBER_TYPEMAP(enum SWIGTYPE);
5758

5859
%apply unsigned long { size_t };
5960
%apply const unsigned long & { const size_t & };
@@ -77,7 +78,7 @@ LLDB_NUMBER_TYPEMAP(signed long long);
7778
%typemap(in) (char *dst, size_t dst_len) {
7879
$2 = luaL_checkinteger(L, $input);
7980
if ($2 <= 0) {
80-
return luaL_error(L, "Positive integer expected");
81+
return luaL_error(L, "Positive integer expected");
8182
}
8283
$1 = (char *) malloc($2);
8384
}
@@ -86,6 +87,9 @@ LLDB_NUMBER_TYPEMAP(signed long long);
8687
// as char data instead of byte data.
8788
%typemap(in) (void *char_buf, size_t size) = (char *dst, size_t dst_len);
8889

90+
// Also SBProcess::ReadMemory.
91+
%typemap(in) (void *buf, size_t size) = (char *dst, size_t dst_len);
92+
8993
// Return the char buffer. Discarding any previous return result
9094
%typemap(argout) (char *dst, size_t dst_len) {
9195
lua_pop(L, 1); // Blow away the previous result
@@ -102,4 +106,211 @@ LLDB_NUMBER_TYPEMAP(signed long long);
102106
// as char data instead of byte data.
103107
%typemap(argout) (void *char_buf, size_t size) = (char *dst, size_t dst_len);
104108

109+
// Also SBProcess::ReadMemory.
110+
%typemap(argout) (void *buf, size_t size) = (char *dst, size_t dst_len);
111+
112+
//===----------------------------------------------------------------------===//
113+
114+
// Typemap for handling a snprintf-like API like SBThread::GetStopDescription.
115+
116+
%typemap(in) (char *dst_or_null, size_t dst_len) {
117+
$2 = luaL_checkinteger(L, $input);
118+
if ($2 <= 0) {
119+
return luaL_error(L, "Positive integer expected");
120+
}
121+
$1 = (char *)malloc($2);
122+
}
123+
124+
%typemap(argout) (char *dst_or_null, size_t dst_len) {
125+
lua_pop(L, 1); // Blow away the previous result
126+
lua_pushlstring(L, (const char *)$1, $result);
127+
free($1);
128+
// SWIG_arg was already incremented
129+
}
130+
131+
//===----------------------------------------------------------------------===//
132+
133+
// Typemap for handling SBModule::GetVersion
134+
135+
%typemap(in) (uint32_t *versions, uint32_t num_versions) {
136+
$2 = 99;
137+
$1 = (uint32_t *)malloc(sizeof(uint32_t) * $2);
138+
}
139+
140+
%typemap(argout) (uint32_t *versions, uint32_t num_versions) {
141+
uint32_t count = result;
142+
if (count >= $2)
143+
count = $2;
144+
lua_newtable(L);
145+
int i = 0;
146+
while (i++ < count) {
147+
lua_pushinteger(L, $1[i - 1]);
148+
lua_seti(L, -2, i);
149+
}
150+
SWIG_arg++;
151+
free($1);
152+
}
153+
154+
//===----------------------------------------------------------------------===//
155+
156+
// Typemap for handling SBDebugger::SetLoggingCallback
157+
158+
%typemap(in) (lldb::LogOutputCallback log_callback, void *baton) {
159+
$1 = LLDBSwigLuaCallLuaLogOutputCallback;
160+
$2 = (void *)L;
161+
162+
luaL_checktype(L, 2, LUA_TFUNCTION);
163+
lua_settop(L, 2);
164+
165+
lua_pushlightuserdata(L, (void *)&LLDBSwigLuaCallLuaLogOutputCallback);
166+
lua_insert(L, 2);
167+
lua_settable(L, LUA_REGISTRYINDEX);
168+
}
169+
170+
//===----------------------------------------------------------------------===//
171+
172+
// Typemap for handling SBEvent::SBEvent(uint32_t event, const char *cstr, uint32_t cstr_len)
173+
174+
%typemap(in) (const char *cstr, uint32_t cstr_len) {
175+
$1 = (char *)luaL_checklstring(L, $input, (size_t *)&$2);
176+
}
177+
178+
// Typemap for handling SBProcess::PutSTDIN
179+
180+
%typemap(in) (const char *src, size_t src_len) {
181+
$1 = (char *)luaL_checklstring(L, $input, &$2);
182+
}
183+
184+
// Typemap for handling SBProcess::WriteMemory, SBTarget::GetInstructions...
185+
186+
%typemap(in) (const void *buf, size_t size),
187+
(const void *data, size_t data_len) {
188+
$1 = (void *)luaL_checklstring(L, $input, &$2);
189+
}
190+
191+
//===----------------------------------------------------------------------===//
192+
193+
// Typemap for handling char ** in SBTarget::LaunchSimple, SBTarget::Launch...
194+
195+
// It should accept a Lua table of strings, for stuff like "argv" and "envp".
196+
197+
%typemap(in) char ** {
198+
if (lua_istable(L, $input)) {
199+
size_t size = lua_rawlen(L, $input);
200+
$1 = (char **)malloc((size + 1) * sizeof(char *));
201+
int i = 0, j = 0;
202+
while (i++ < size) {
203+
lua_rawgeti(L, $input, i);
204+
if (!lua_isstring(L, -1)) {
205+
// if current element cannot be converted to string, raise an error
206+
lua_pop(L, 1);
207+
return luaL_error(L, "List should only contain strings");
208+
}
209+
$1[j++] = (char *)lua_tostring(L, -1);
210+
lua_pop(L, 1);
211+
}
212+
$1[j] = 0;
213+
} else if (lua_isnil(L, $input)) {
214+
// "nil" is also acceptable, equivalent as an empty table
215+
$1 = NULL;
216+
} else {
217+
return luaL_error(L, "A list of strings expected");
218+
}
219+
}
220+
221+
%typemap(freearg) char ** {
222+
free((char *) $1);
223+
}
224+
225+
%typecheck(SWIG_TYPECHECK_STRING_ARRAY) char ** {
226+
$1 = (lua_istable(L, $input) || lua_isnil(L, $input));
227+
}
228+
229+
//===----------------------------------------------------------------------===//
230+
231+
// Typemap for file handles (e.g. used in SBDebugger::SetOutputFile)
232+
233+
%typemap(in) lldb::FileSP {
234+
luaL_Stream *p = (luaL_Stream *)luaL_checkudata(L, $input, LUA_FILEHANDLE);
235+
lldb::FileSP file_sp;
236+
file_sp = std::make_shared<lldb_private::NativeFile>(p->f, false);
237+
if (!file_sp->IsValid())
238+
return luaL_error(L, "Invalid file");
239+
$1 = file_sp;
240+
}
241+
242+
%typecheck(SWIG_TYPECHECK_POINTER) lldb::FileSP {
243+
$1 = (lua_isuserdata(L, $input)) &&
244+
(luaL_testudata(L, $input, LUA_FILEHANDLE) != nullptr);
245+
}
246+
247+
// Typemap for file handles (e.g. used in SBDebugger::GetOutputFileHandle)
248+
249+
%typemap(out) lldb::FileSP {
250+
lldb::FileSP &sp = $1;
251+
if (sp && sp->IsValid()) {
252+
luaL_Stream *p = (luaL_Stream *)lua_newuserdata(L, sizeof(luaL_Stream));
253+
p->closef = &LLDBSwigLuaCloseFileHandle;
254+
p->f = sp->GetStream();
255+
luaL_setmetatable(L, LUA_FILEHANDLE);
256+
SWIG_arg++;
257+
}
258+
}
259+
260+
//===----------------------------------------------------------------------===//
261+
262+
// Typemap for SBData::CreateDataFromUInt64Array, SBData::SetDataFromUInt64Array ...
263+
264+
%typemap(in) (uint64_t* array, size_t array_len),
265+
(uint32_t* array, size_t array_len),
266+
(int64_t* array, size_t array_len),
267+
(int32_t* array, size_t array_len),
268+
(double* array, size_t array_len) {
269+
if (lua_istable(L, $input)) {
270+
// It should accept a table of numbers.
271+
$2 = lua_rawlen(L, $input);
272+
$1 = ($1_ltype)malloc(($2) * sizeof($*1_type));
273+
int i = 0, j = 0;
274+
while (i++ < $2) {
275+
lua_rawgeti(L, $input, i);
276+
if (!lua_isnumber(L, -1)) {
277+
// if current element cannot be converted to number, raise an error
278+
lua_pop(L, 1);
279+
return luaL_error(L, "List should only contain numbers");
280+
}
281+
$1[j++] = ($*1_ltype)lua_tonumber(L, -1);
282+
lua_pop(L, 1);
283+
}
284+
} else if (lua_isnil(L, $input)) {
285+
// "nil" is also acceptable, equivalent as an empty table
286+
$1 = NULL;
287+
$2 = 0;
288+
} else {
289+
// else raise an error
290+
return luaL_error(L, "A list of numbers expected.");
291+
}
292+
}
293+
294+
%typemap(freearg) (uint64_t* array, size_t array_len),
295+
(uint32_t* array, size_t array_len),
296+
(int64_t* array, size_t array_len),
297+
(int32_t* array, size_t array_len),
298+
(double* array, size_t array_len) {
299+
free($1);
300+
}
301+
302+
//===----------------------------------------------------------------------===//
303+
304+
// Typemap for SBCommandReturnObject::PutCString
305+
306+
%typemap(in) (const char *string, int len) {
307+
if (lua_isnil(L, $input)) {
308+
$1 = NULL;
309+
$2 = 0;
310+
}
311+
else {
312+
$1 = (char *)luaL_checklstring(L, $input, (size_t *)&$2);
313+
}
314+
}
315+
105316
//===----------------------------------------------------------------------===//

lldb/bindings/lua/lua-wrapper.swig

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,19 @@ PushSBClass(lua_State* L, T* obj);
66

77
%}
88

9+
%runtime %{
10+
#ifdef __cplusplus
11+
extern "C" {
12+
#endif
13+
14+
void LLDBSwigLuaCallLuaLogOutputCallback(const char *str, void *baton);
15+
int LLDBSwigLuaCloseFileHandle(lua_State *L);
16+
17+
#ifdef __cplusplus
18+
}
19+
#endif
20+
%}
21+
922
%wrapper %{
1023

1124
// This function is called from Lua::CallBreakpointCallback
@@ -88,5 +101,20 @@ LLDBSwigLuaWatchpointCallbackFunction
88101
return stop;
89102
}
90103

104+
SWIGEXPORT void
105+
LLDBSwigLuaCallLuaLogOutputCallback(const char *str, void *baton) {
106+
lua_State *L = (lua_State *)baton;
107+
108+
lua_pushlightuserdata(L, (void *)&LLDBSwigLuaCallLuaLogOutputCallback);
109+
lua_gettable(L, LUA_REGISTRYINDEX);
110+
111+
// FIXME: There's no way to report errors back to the user
112+
lua_pushstring(L, str);
113+
lua_pcall(L, 1, 0, 0);
114+
}
115+
116+
int LLDBSwigLuaCloseFileHandle(lua_State *L) {
117+
return luaL_error(L, "You cannot close a file handle used by lldb.");
118+
}
91119

92120
%}

lldb/bindings/lua/lua.swig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@
1717
#include "llvm/Support/Error.h"
1818
#include "llvm/Support/FormatVariadic.h"
1919
#include "../bindings/lua/lua-swigsafecast.swig"
20+
21+
// required headers for typemaps
22+
#include "lldb/Host/File.h"
23+
2024
using namespace lldb_private;
2125
using namespace lldb;
2226
%}

lldb/source/API/liblldb-private.exports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ _ZN12lldb_private*
44
_ZNK12lldb_private*
55
init_lld*
66
PyInit__lldb*
7+
luaopen_lldb*

lldb/source/API/liblldb.exports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ _ZN4lldb*
22
_ZNK4lldb*
33
init_lld*
44
PyInit__lldb*
5+
luaopen_lldb*

0 commit comments

Comments
 (0)