#Lua 的 Debug 模块
Debug 模块为 Lua 程序提供了调试接口。使用此模块时应格外小心,其中的一些函数违反了 Lua 代码的基本假设(例如,函数内部的变量不能从外部访问;用户数据元表不能被 Lua 代码修改;Lua 程序不会崩溃),因此可能会危及原本安全的代码。并且某些函数可能运行缓慢。
| 函数 | 说明 |
|---|---|
| debug.debug | 启动调试模式 |
| debug.getinfo | 获取函数信息 |
| debug.gethook | 获取调试钩子 |
| debug.sethook | 设置调试钩子 |
| debug.getlocal | 获取栈上局部变量 |
| debug.setlocal | 设置栈上局部变量 |
| debug.getmetatable | 获取元表 |
| debug.setmetatable | 设置元表 |
| debug.getregistry | 获取注册表 |
| debug.getupvalue | 获取闭包上值表 |
| debug.setupvalue | 设置闭包上值表 |
| debug.upvalueid | 获取闭包上值 ID |
| debug.upvaluejoin | 使闭包引用另一个闭包的上值 |
| debug.getuservalue | 获取用户值 |
| debug.setuservalue | 设置用户值 |
| debug.traceback | 获取栈的回溯信息 |
#debug.debug
debug.debug ()
说明
进入调试模式的交互式命令行,将用户输入的字符串作为 Lua 代码运行,输入 cont 即可退出调试模式继续运行程序。
参数
无
返回值
无
示例
local n = 10 -- 不能访问局部变量
text = "https://xplanc.org/" -- 可以访问全局变量
debug.debug ()
#debug.gethook
debug.gethook ([thread])
说明
获取线程 thread 的调试钩子函数。
参数
thread- 线程;默认为当前线程
返回值
- 返回调试钩子函数
#debug.getinfo
debug.getinfo ([thread,] f [, what])
说明
获取函数信息的表。
参数
thread- 线程;默认为当前线程f- 函数或函数在栈上的层级what- 指定想要的信息;默认为"nSluf"
what 接受的值 | 含义 |
|---|---|
| n | 函数名及调用方式(name, namewhat) |
| S | 源代码信息(short_src, linedefined, lastlinedefined, what, source) |
| l | 当前行号(currentline) |
| u | 函数的上值与参数信息(nups, nparams, isvararg) |
| f | 返回实际的函数本身(func) |
| L | 包含该函数中哪些行有可执行代码(activelines 表) |
返回值
- 返回函数信息表
示例
function level1()
print(debug.getinfo(0)['name']) -- 按栈上位置获取信息
print(debug.getinfo(1)['name'])
print(debug.getinfo(2)['name'])
print(debug.getinfo(3)['name'])
end
function level2()
level1()
end
function level3()
level2()
end
function main()
level3()
end
main()
local info = debug.getinfo(main, 'nl') -- 获取指定函数信息
for k,v in pairs(info) do
print(k, v)
end
#debug.getlocal
debug.getlocal ([thread,] f, local)
说明
获取栈上 f 层级中第 local 个局部变量。
参数
thread- 线程;默认为当前线程f- 栈上层级local- 局部变量的序号
返回值
- 成功时返回局部变量的名称和值
- 失败时返回
nil
示例
function demo()
local x = 10
local y = 20
local z = 30
print(debug.getlocal(1, 1))
print(debug.getlocal(1, 2))
print(debug.getlocal(1, 3))
end
demo()
#debug.getmetatable
debug.getmetatable (value)
说明
获取 value 的元表。
参数
value- 要获取元表的对象
返回值
- 返回对象的元表
示例
local metatable = debug.getmetatable("") -- 获取字符串的元表
for k,v in pairs(metatable) do
print(k, v)
end
#debug.getregistry
debug.getregistry ()
说明
获取注册表。
Lua 的注册表是一个由 C API 维护的全局表,用于在 C 和 Lua 之间安全地交换和保存数据,始终可以通过伪索引 LUA_REGISTRYINDEX 进行访问。
参数
无
返回值
- 返回 Lua 的注册表
示例
for k,v in pairs(debug.getregistry()) do
print(k, v)
end
#debug.getupvalue
debug.getupvalue (f, up)
说明
获取闭包 f 的第 up 个上值。
参数
f- 闭包up- 上值的序号
返回值
- 成功时返回上值的的名称和值
- 失败时返回
nil
示例
function demo()
local x = 10 -- 外层局部变量,即上值
local y = 20
local z = 30
-- 返回闭包
return function()
print(x, z) -- 只有被引用的外层变量才会被捕获为上值
end
end
-- 创建闭包
local closure = demo()
print(debug.getupvalue(closure, 1)) -- _ENV,调用函数时会创建这个局部变量
print(debug.getupvalue(closure, 2)) -- x
print(debug.getupvalue(closure, 3)) -- z
#debug.getuservalue
debug.getuservalue (u, n)
说明
获取与用户数据 u 关联的第 n 个用户值。
参数
u- 用户数据n- 用户值的序号
返回值
- 成功时返回用户的的名称和值
- 失败时返回
nil
#debug.sethook
debug.sethook ([thread,] hook, mask [, count])
说明
设置调试钩子函数,钩子函数在特定事件发生时被调用。
只有最后一个钩子是有效的,无法为不同的事件同时设置钩子。
参数
thread- 线程;默认为当前线程hook- 钩子函数mask- 事件掩码组合字符串'c'- 每次 Lua 调用函数时都会调用该钩子函数,参数为事件'r'- 每次 Lua 从函数返回时都会调用该钩子函数,参数为事件'l'- 每次 Lua 进入新行时该钩子函数,参数为事件和行号
count- 除事件外,每执行count条指令触发一次钩子函数;默认为 0 不触发
返回值
无
示例
local function hook(event, line)
print(event, line)
end
debug.sethook(hook, "l") -- 每行触发
-- 空行不会触发钩子
print("NOP")
print("NOP")
print("NOP")
#debug.setlocal
debug.setlocal ([thread,] level, local, value)
说明
将栈上 level 层级处的第 local 个局部变量的值设为 value。
参数
thread- 线程;默认为当前线程f- 栈上层级local- 局部变量的序号value- 要设为的值
返回值
- 成功时返回被修改的变量名
- 失败时返回
nil
示例
function inner()
debug.setlocal(2, 1, "Hello")
debug.setlocal(2, 2, "Primers")
debug.setlocal(2, 3, "编程伙伴")
end
function outer()
local x = 10
local y = 20
local z = 30
inner()
print(x, y, z)
end
outer()
#debug.setmetatable
debug.setmetatable (value, table)
说明
将对象 value 的元表设为 metatable;如果 value 已有的元表包含 __metatable 字段则会引发错误。
参数
value- 要设置元表的对象,可以时表或用户数据metatable- 要设置的元表,如果是nil则移除对象的元表
返回值
- 返回
value
示例
local t1 = {value = 10}
local t2 = {value = 20}
-- 元表,重载运算符
local metatable = {
__add = function(x, y) return {value = x.value + y.value} end,
__sub = function(x, y) return {value = x.value - y.value} end,
__mul = function(x, y) return {value = x.value * y.value} end,
__div = function(x, y) return {value = x.value / y.value} end,
}
-- 设置元表
debug.setmetatable(t1, metatable)
debug.setmetatable(t2, metatable)
-- 使用
print((t1 + t2).value)
print((t1 - t2).value)
print((t1 * t2).value)
print((t1 / t2).value)
#debug.setupvalue
debug.setupvalue (f, up, value)
说明
将闭包 f 的第 up 个上值设为 value。
参数
f- 闭包up- 上值的序号value- 要设为的值
返回值
- 被修改的上值变量名
示例
-- 外层局部变量,即上值
local x = 10
local y = 20
local z = 30
-- 创建闭包
local closure = function()
print(x, y, z) -- 只有被引用的外层变量才会被捕获为上值
end
-- 修改上值
debug.setupvalue(closure, 2, 'Hello')
debug.setupvalue(closure, 3, 'Primers')
debug.setupvalue(closure, 4, '编程伙伴')
-- 调用闭包
closure()
-- 外层变量也被改变
print(x, y, z)
#debug.setuservalue
debug.setuservalue (u, value, n)
说明
将与用户数据 u 关联的第 n 个用户值设置 value。
参数
u- 用户数据value- 要设为的值n- 用户数据的序号
返回值
- 返回
u
#debug.traceback
debug.traceback ([thread,] [message [, level]])
说明
生成调用栈回溯信息。
参数
thread- 线程;默认为当前线程message- 附加信息;如果这个参数不是字符串或nil则直接返回这个参数level- 从调用栈的第几层开始记录
返回值
- 返回生成的信息
示例
function level1()
print(debug.traceback("附加信息 https://xplanc.org/"))
end
function level2()
level1()
end
function level3()
level2()
end
function main()
level3()
end
main()
#debug.upvalueid
debug.upvalueid (f, n)
说明
获取闭包 f 的第 up 个上值的唯一 ID(类型为轻量用户数据)。
通过返回的 ID 可以检测不同的闭包是否引用同一个上值。
参数
f- 闭包up- 上值的序号
返回值
- 返回上值的唯一 ID(轻量用户数据)
示例
local function outer()
local a = 10
local b = 20
local function f1() return a end
local function f2() return a end
local function f3() return b end
return f1, f2, f3
end
local f1, f2, f3 = outer()
local id1 = debug.upvalueid(f1, 1)
local id2 = debug.upvalueid(f2, 1)
local id3 = debug.upvalueid(f3, 1)
print(id1 == id2) --> true (f1 和 f2 的上值 a 是同一个)
print(id1 == id3) --> false (f1 的 a 和 f3 的 b 不同)
#debug.upvaluejoin
debug.upvaluejoin (f1, n1, f2, n2)
说明
让闭包 f1 的第 n1 个上值引用闭包 f2 的第 n2 个上值。
参数
f1- 目标闭包n1- 目标上值序号f2- 源闭包n2- 源上值序号
返回值
无
示例
local function outer()
local a = 10
local b = 20
local function f1() return a end -- 引用 a
local function f2() return b end -- 引用 b
return f1, f2
end
local f1, f2 = outer()
-- 打印原始值
print(f1(), f2()) --> 10 20
-- 让 f2 的上值指向 f1 的上值
debug.upvaluejoin(f2, 1, f1, 1)
print(f1(), f2()) --> 10 10