Lua Debugging
Lua provides the debug library to facilitate the creation of custom debuggers. Lua itself does not have a built-in debugger, but many developers have shared their Lua debugger code.
The Lua debug library includes the following functions:
No. | Method & Purpose |
---|---|
1. | debug(): Enters an interactive mode where each string input by the user is executed. Users can review global and local variables, change variable values, evaluate expressions, etc., using simple commands and other debug settings. Inputting a string containing only "cont" will end this function, allowing the caller to continue execution. |
2. | getfenv(object): Returns the environment variables of the object. |
3. | gethook(optional thread): Returns three values representing the thread's hook settings: the current hook function, the current hook mask, and the current hook count. |
4. | getinfo([thread,] f[, what]): Returns a table with information about a function. You can provide the function directly or use a number f to represent it. The number f indicates the function at the corresponding level of the call stack in the specified thread: level 0 represents the current function (getinfo itself); level 1 represents the function that called getinfo (unless it's a tail call, which is not counted in the stack); and so on. If f is a number greater than the number of active functions, getinfo returns nil. |
5. | debug.getlocal([thread,] f, local): Returns the name and value of the local variable indexed by local at stack level f. This function can access not only explicitly defined local variables but also parameters and temporary variables. |
6. | getmetatable(value): Pushes the metatable of the value at the given index onto the stack. If the index is invalid or the value does not have a metatable, the function returns 0 and does not push anything onto the stack. |
7. | getregistry(): Returns the registry table, a predefined table that can be used to store any Lua values desired by C code. |
8. | getupvalue(f, up): Returns the name and value of the upvalue at index up for function f. If the function does not have that upvalue, it returns nil. Variables starting with '(' (opening parenthesis) represent unnamed variables (code blocks without debugging information). |
10. | sethook([thread,] hook, mask[, count]): Sets a function as the hook. The string mask and number count determine when the hook will be called. The mask is a string combining the following characters, each with a specific meaning: 'c': Calls the hook whenever Lua calls a function; 'r': Calls the hook whenever Lua returns from a function; 'l': Calls the hook whenever Lua enters a new line. |
11. | setlocal([thread,] level, local, value): Assigns value to the local variable indexed by local at the stack level level. If there is no such variable, the function returns nil. If the level is out of bounds, it throws an error. |
12. | setmetatable(value, table): Sets the metatable of value to table (which can be nil). Returns value. |
13. | setupvalue(f, up, value): Assigns value to the upvalue at index up for function f. If the function does not have that upvalue, it returns nil; otherwise, it returns the name of the upvalue. |
14. | traceback([thread,][message[, level]]): If message is provided and is not a string or nil, the function returns message without further processing. Otherwise, it returns a stack trace. The optional string message is added at the beginning of the stack trace. The optional number level specifies the stack level from which to start the traceback (default is 1, where traceback is called). |
The above table lists commonly used debugging functions. Next, let's look at some simple examples:
Example
function myfunction()
print(debug.traceback("Stack trace"))
print(debug.getinfo(1))
print("Stack trace end")
return 10
end
myfunction()
print(debug.getinfo(1))
Executing the above code outputs:
Stack trace
stack traceback:
test2.lua:2: in function 'myfunction'
test2.lua:8: in main chunk
[C]: ?
table: 0054C6C8
Stack trace end
In this example, we used the debug library's traceback and getinfo functions. The getinfo function is used to return a table with information about the function.
Another Example
Often, we need to debug local variables within a function. We can use the setupvalue function to set these local variables. Here is an example:
Example
function newCounter()
local n = 0
local k = 0
return function()
k = n
n = n + 1
return n
end
end
counter = newCounter()
print(counter())
print(counter())
local i = 1
repeat
name, val = debug.getupvalue(counter, i)
if name then
print("index", i, name, "=", val)
if name == "n" then
debug.setupvalue(counter, 2, 10)
end
i = i + 1
end -- if
until not name
print(counter())
Executing the above code outputs:
1
2
index 1 k = 1
index 2 n = 2
11
In this example, the counter increments by 1 with each call. We used the getupvalue function to check the current state of local variables. We can set local variables to new values. In the example, before setting, the value of n is 2, and we use the setupvalue function to set it to 10. Now, when we call the function, the output is 11 instead of 3.
Debugging Types
- Command-line debugging
- Graphical interface debugging
Command-line debuggers include: RemDebug, clidebugger, ctrace, xdbLua, LuaInterface - Debugger, Rldb, ModDebug.
Graphical interface debuggers include: SciTE, Decoda, ZeroBrane Studio, akdebugger, luaedit.