返回
Featured image of post OpenResty Lua 代码执行实例跟踪

OpenResty Lua 代码执行实例跟踪

Lua 代码执行实例跟踪

实际跟踪 Lua 代码的执行情况(主要是出错情况)。

异常情况

由于使用 bpftrace 得到的堆栈不符合预期,直接用 gdb 来获取:

指令:

    # index a nil value
    init_by_lua 'return a.b';

对 nil 值进行索引。

错误输出:

nginx: [error] init_by_lua error: init_by_lua:1: attempt to index global 'a' (a nil value)
stack traceback:
        init_by_lua:1: in main chunk

命令:

$ gdb sbin/nginx
> set args -p /NGINX/CONFIG/PATH
> b ngx_http_lua_traceback
> run
> bt

从 init_by_lua 的文章中,已经知道了 ngx_http_lua_traceback 是错误处理函数,因此我们直接追踪它。

结果:

#0  ngx_http_lua_traceback (L=0x7ffff76f02e8) at ngx_lua-0.10.21/src/ngx_http_lua_util.c:3071
#1  0x00007ffff7eb1b83 in lj_BC_FUNCC () from luajit/lib/libluajit-5.1.so.2
#2  0x00007ffff7eb7098 in lj_err_run (L=L@entry=0x7ffff7717380) at lj_err.c:856
#3  0x00007ffff7eb72ed in err_msgv (L=L@entry=0x7ffff7717380, em=em@entry=LJ_ERR_BADOPRT) at lj_err.c:881
#4  0x00007ffff7eb7474 in lj_err_optype (L=L@entry=0x7ffff7717380, o=o@entry=0x7ffff770f380, opm=opm@entry=LJ_ERR_OPINDEX) at lj_err.c:915
#5  0x00007ffff7ebb967 in lj_meta_tget (L=0x7ffff7717380, o=0x7ffff770f380, k=0x7fffffffd2d0) at lj_meta.c:147
#6  0x00007ffff7eb2089 in lj_vmeta_tgetv () from luajit/lib/libluajit-5.1.so.2
#7  0x00007ffff7ecc1cd in lua_pcall (L=0x7ffff7717380, nargs=0, nresults=0, errfunc=<optimized out>) at lj_api.c:1145
#8  0x000055555570c0fb in ngx_http_lua_do_call (log=0x55555583d280 <ngx_log>, L=0x7ffff7717380) at ngx_lua-0.10.21/src/ngx_http_lua_util.c:4192
#9  0x000055555572bda3 in ngx_http_lua_init_by_inline (log=0x55555583d280 <ngx_log>, lmcf=0x555555890e80, L=0x7ffff7717380) at ngx_lua-0.10.21/src/ngx_http_lua_initby.c:24
#10 0x00005555556fb594 in ngx_http_lua_init (cf=0x7fffffffd7e0) at ngx_lua-0.10.21/src/ngx_http_lua_module.c:896
#11 0x00005555555f4ddc in ngx_http_block (cf=0x7fffffffd7e0, cmd=0x55555581a200 <ngx_http_commands>, conf=0x555555886a20) at src/http/ngx_http.c:310
#12 0x00005555555b9ec7 in ngx_conf_handler (cf=0x7fffffffd7e0, last=1) at src/core/ngx_conf_file.c:463
#13 0x00005555555b99cc in ngx_conf_parse (cf=0x7fffffffd7e0, filename=0x555555885958) at src/core/ngx_conf_file.c:319
#14 0x00005555555b4f87 in ngx_init_cycle (old_cycle=0x7fffffffd9b0) at src/core/ngx_cycle.c:284
#15 0x0000555555592fe8 in main (argc=3, argv=0x7fffffffdd58) at src/core/nginx.c:295

可以看到最终 ngx_http_lua_traceback 是被 Luajit 调用了,这是在 ngx_http_lua_do_call 中设置的。

  • ngx_http_lua_traceback 函数源码:
int
ngx_http_lua_traceback(lua_State *L)
{
    if (!lua_isstring(L, 1)) { /* 'message' not a string? */
        return 1;  /* keep it intact */
    }

    lua_getglobal(L, "debug");
    if (!lua_istable(L, -1)) {
        lua_pop(L, 1);
        return 1;
    }

    lua_getfield(L, -1, "traceback");
    if (!lua_isfunction(L, -1)) {
        lua_pop(L, 2);
        return 1;
    }

    lua_pushvalue(L, 1);  /* pass error message */
    lua_pushinteger(L, 2);  /* skip this function and traceback */
    lua_call(L, 2, 1);  /* call debug.traceback */
    return 1;
}

根据注释可以看到,主要做了:

  • 设置错误信息
  • 跳过 2 个栈帧:当前 Lua 函数和栈帧 [?, 猜测]
  • 调用 debug.traceback

因此,此函数看起来是获取调用栈,然后在后续打印到日志中(由 ngx_http_lua_report 调用 ngx_log_error)。

由于缺乏对 lua_* 相关函数的了解,还是没法继续深入,先作罢,后续再读下 luajit 源码去了解。

相信美好的事情即将发生。
Built with Hugo
Theme Stack designed by Jimmy