如何将lua函数块转储到字符串?
function test(a, b)
local c = a + b
return c
end
print( type(test) ) --> function
print( test ) --> function: 0053B108
print( dumpToString(test) )
Run Code Online (Sandbox Code Playgroud)
我希望dumpToString结果如下:
function test(a, b)
local c = a + b
return c
end
Run Code Online (Sandbox Code Playgroud)
这该怎么做 ?
=== update1 ===
我想自动记录并注入代码.
你没有说出为什么要这样做,这可能很重要。您可以将函数转储为字符串,但它不会是一个非常可读的字符串;您可以通过这种方式存储和传输您的函数(在兼容的 Lua 引擎之间):
string.dump(function() print "Hello" end)
Run Code Online (Sandbox Code Playgroud)
没有简单的答案(尽管这么多年)。我将详细介绍替代方案。
1考古学教授的回答(以及一些反汇编):
这个问题的答案古老的问题在于内primodial一个。即luadec。可能当时是停机时间,但至少到目前为止,有一个更新的版本,可以处理lua 5.1-.3。
此外,并string.dump
没有提供完整的乱码,而是以机器指令的原始字节提供了程序代码,您可以使用更好地表示这些代码luac -l -p <filename>
。Vm代码没有得到很好的记录,但是人们确实在这里做了一些整理。Luajit在自己的说明集上有更好的文档。
从vm重建代码说明是luadec要做的。从理论上讲,您也可以将自己的指令直接拼接到转储的字符串中。
但是,无论您对字节码采取什么技巧,它都会遇到不同解释器之间的不兼容性,包括lua本身的不同发行版。
2.实际做X
将函数转换为字符串是一个非常特殊的愿望(除非您正在执行代码生成,在这种情况下,您首先已经拥有字符串)。
实际上,“日志和注入代码”是非常通用的X,这可以保证要解决Y。但是,单个案例可以通过单一措施来解决。Lua是一种非常灵活的语言,例如,您可以x
通过将其作为对象来跟踪示例中值的流程:
local to2number = tonumber
tonumber= function(o)
local r= to2number(o)
if not r then
local m= getmetatable(o)
if m and m.__tonumber then
r=m.__tonumber(o)
end
end
return r
end
local number
number={
new=function(n)
return setmetatable({n},number)
end,
__add=function(me,other)
print("I'm "..tostring(me).." and I'm being added to "..tostring(other))
local o=tonumber(other)
return number.new(me[1]+o)
end,
__tonumber=function(me) return me[1] end,
__tostring=function(me) return tostring(me[1]) end,
}
test(number.new(4), number.new(10))
Run Code Online (Sandbox Code Playgroud)
如上例所示,您可以通过更改函数的环境来注入行为。即,我在那里重新定义了全局函数tonumber
。您可能希望将函数完全打包在不同的环境中:
local test = function() print"hello" end
local newenv={print=function(s) print(s..'world') end}
setfenv(test,newenv)--this is lua 5.1, luajit, good luck with upvalues
local test = load(string.dump(test),nil,nil,newenv)--this is lua 5.2-5.3, good luck with upvalues
test()
Run Code Online (Sandbox Code Playgroud)
对于较旧的版本,您必须处理可能引用了您尝试重新定义的全局函数的升值。对于较新的版本,您必须处理在转储过程中会丢失的升值。
3.读取文件
最后,正如其他人所说,如果您有权访问源代码,则可以尝试从中查找函数定义。除非它是单个函数定义或单个返回文件,否则该任务可能最终等同于lua解析器的重新实现。其中不止一个,但是考虑到这些功能并没有完成,因此可能需要一些工作才能重新利用其代码。
如果所有功能都由您自己定义,并且您愿意稍加约束,则可以再次使用lua元表,在编码阶段解决问题:
local def=function(code,env)
env=env or _ENV
local compiled,q=load("return "..code,nil,nil,env)
if not compiled then error(q) end
local f=compiled()
return setmetatable({code=code},{__call=function(me,...) return f(...) end})
end
local test=def[[function(a,b)
return a+b
end]]
print(test(2,3))
Run Code Online (Sandbox Code Playgroud)
但是,定义升值将非常棘手。
你不知道。Lua 不会将编译后的 Lua 脚本作为原始文本存储在任何地方。而且,由于它旨在成为一种小型脚本语言,因此它也不提供反编译其自身字节码的机制。