Detailed usage instructions and command reference for dLua, a dynamic GDB-like Lua debugger on Linux.
dLua attaches to an already running Lua process using dynamic library injection (hookso). It allows developers to set breakpoints, inspect variables, view stack traces, and modify execution state on the fly with zero modifications to source code.
+------------------+ +--------------------+
| Target Process | <====== | dlua (CLI) |
| (running Lua VM) | IPC Msg | (interact via GDB- |
| +dluaagent.so | Queue | style commands) |
+------------------+ +--------------------+
-
Launch your target Lua script:
lua test.lua
Assume the process PID is
1234. -
Attach using dlua:
./dlua 1234
Once attached, you will see:
attach to 1234 ok, use ctrl+c to input command, eg: h -
Interact with the debugger:
- Press
Ctrl+Cto interrupt the target and enter the(dlua)interactive prompt. - Enter commands (e.g.
h,bt,b,p, etc.). - Press
Ctrl+Cwhenever you want to issue new commands while running.
- Press
-
Detach and exit:
(dlua) q
| Command | Arguments | Description | Example |
|---|---|---|---|
h |
None | Display help message and list of supported commands | h |
q |
None | Detach from target process and exit | q |
bt |
None | Show current call stack backtrace | bt |
b |
<file:line> / <file line> / <line> / <func> [if ...] |
Add a line, function, or conditional breakpoint | b test.lua:34b test.lua 34b 34b my_funcb test.lua:34 if [a,b] a+b==10 |
i b |
None | List current breakpoints and hit counts | i b |
n |
None | Step over to next line | n |
s |
None | Step into next line / function call | s |
c |
None | Continue program execution | c |
fin |
None | Finish execution of current function call | fin |
dis |
[id] |
Disable specific breakpoint (or all if omitted) | dis 1dis |
en |
[id] |
Enable specific breakpoint (or all if omitted) | en 1en |
d |
[id] |
Delete specific breakpoint (or all if omitted) | d 1d |
p |
[expr] / [vars] expr |
Print expression / variable value | p yearp _G.testp [tmp] tmp.abc |
l |
[count] |
List source code around current line | ll 20 |
f |
<frame_id> |
Select stack frame index (from bt) |
f 0f 1 |
set |
var = val / [vars] expr = val |
Set variable value | set year=1234set _G.test=1set [tmp] tmp.a=2 |
r |
<code> / [vars] <code> |
Run arbitrary Lua code snippet | r print("hello")r [tmp] tmp[1]=2 |
dLua supports flexible spacing between filenames and line numbers:
(dlua) b test.lua:23
Breakpoint 0 at file test.lua, line 23, if
code: local tmp = { 1, 2, { 4, 5 } }
(dlua) b test.lua 23
Breakpoint 1 at file test.lua, line 23, if
code: local tmp = { 1, 2, { 4, 5 } }
(dlua) b test.lua : 23
Breakpoint 2 at file test.lua, line 23, if
code: local tmp = { 1, 2, { 4, 5 } }
Variables needed for condition calculation must be declared in square brackets [...] to be retrieved from local/upvalue scopes:
(dlua) b string_time_to_unix_time_with_tz if [tz] tz == 800
(dlua) b test.lua:44 if [time_sec, tz] time_sec > 0 and tz ~= nil
(dlua) bt
0 in string_time_to_unix_time at test.lua:23
1 in ? at test.lua:59
2 in ? at [C]:-1
(dlua) f 1
#1 ? at test.lua:59
59 local begin_time1 = string_time_to_unix_time("2020-11-02 00:00:00")
(dlua) p year
"2020"
(dlua) p _G.test
[table: 0x55d7b5ca8150]
1: 'test1'
2: 'test2'
3: 'test3'
4: 'a\tb\tc'
(dlua) set year = 2026
(dlua) set [tmp] tmp[1] = 99
(dlua) r print("debugging PID:", os.getenv("PID"))