前言
昨天更新了一下lfunctimer,主要把hook更改为c api的形式,并且初步加了util和config的扩展
想要试用的同学的话可以点击上面clone下来,或者安装luarocks后执行下面命令安装~
luarocks install --server=http://luarocks.org/manifests/utmhikari lfunctimer
言归正传,利用lua原生的c api做debug相关操作会比lua自带的debug.getinfo
来的快许多,我们可以来一探究竟
debug.getinfo源码分析
我们可以从官方下载源码搜索debug.getinfo
的实现,此处以版本5.3.5为例。
debug.getinfo
对应的源码是ldblib.c
的db_getinfo
函数,我们可以简单在ldblib.c
的末尾中查到~
1 | static const luaL_Reg dblib[] = { |
lua提供一个注册表(Registry)机制去把我们的函数名跟函数对应起来,然后最后要让lua识别这个模块的话,就定义一个函数,名称为luaopen_模块名
,然后通过luaL_newlib
方法读取前面的luaL_Reg
注册表数据变成一个函数名——函数的table就ok了。
像debug
之类的lua内置库,则在起lua的时候就调用linit.c
里的luaL_openlibs
方法就载入;而如果是第三方库,你在require的时候,则会通过loadlib.c
中的方法去寻找模块有无载入过,如果载入过则用载入过的模块(package.loaded
),如果没载入过就载入,并且加到载入过模块中。这部分不再细究啦,有兴趣的同学可以自行发掘,我有空的话也会自己再踩踩坑~
我们再回头看ldblib.c
的db_getinfo
函数,也就是debug.getinfo
对应的实现,代码如下:
1 | // debug.getinfo([thread,] f [,what]): 获取当前运行函数的信息 |
可以看到如果在每次调用debug.getinfo
会经历参数检验——获取func或CallInfo信息——获取附加信息(what)
的过程,每次都会创建一个lua_Debug
结构体,在lua中返回的是一个table,相对繁琐一些。为了提高效率,我们可以直接用db_getinfo
中的lua_getstack
跟lua_getinfo
方法去在我们的c hook中获取函数信息。
用C API重写lfunctimer的hook
在新版lfunctimer中,第一版C Hook实现如下:
1 |
|
在某些情况下(比如loadstring)时,我们希望能够不侵入lua原生api去获取函数名称信息。因此可以这样操作——在hook函数中去上一个栈层次(level=1)的caller,我们就可以getstack
后把函数信息暂存在一个lua_Debug
结构体中,并在后续依据需求getinfo
相应的内容。
获取函数名称的总体逻辑和上一版的lfunctimer(lua hook)基本类似,如果能获取到好书名称,就把函数名称push到lua_State
的栈上。在后边的逻辑中,call跟return事件的handler都被分离了出来,这样就显得更加模块化了。
1 | // debug hook of lfunctimer |
总结
过后真的要多抽空研读下各种源码,打好基础= =mlgb的,最近为了领导毕业论文的事情,都憔悴了。