| # This gdb script provides several useful routines for debugging ngx_lua or |
| # standalone Lua/LuaJIT. |
| # |
| # You need gdb >= v7.3 to make this script working correctly. |
| # |
| # Installation: place it at $HOME/.gdbinit |
| # |
| # -- chaoslawful <at> gmail <dot> com |
| |
| #### Lua type defines #### |
| |
| set $__LUA_TNONE = -1 |
| set $__LUA_TNIL = 0 |
| set $__LUA_TBOOLEAN = 1 |
| set $__LUA_TLIGHTUSERDATA = 2 |
| set $__LUA_TNUMBER = 3 |
| set $__LUA_TSTRING = 4 |
| set $__LUA_TTABLE = 5 |
| set $__LUA_TFUNCTION = 6 |
| set $__LUA_TUSERDATA = 7 |
| set $__LUA_TTHREAD = 8 |
| |
| #### Lua constants #### |
| |
| set $__LUA_GLOBALSINDEX = -10002 |
| set $__LUA_ENVIRONINDEX = -10001 |
| set $__LUA_REGISTRYINDEX = -10000 |
| |
| #### Auxiliary methods #### |
| |
| define __lua_debug_instance |
| if !$__lua_debug_instance |
| set $__lua_debug_instance = (lua_Debug*)malloc(sizeof(lua_Debug)) |
| end |
| end |
| |
| define __free_lua_debug_instance |
| if $__lua_debug_instance |
| set $rc = free($__lua_debug_instance) |
| set $__lua_debug_instance = 0 |
| end |
| end |
| |
| set $__BUCKET_SIZE = 16 |
| define __set_instance |
| if !$__set_instance |
| set $__set_instance = (void*(*(*))[2])malloc($__BUCKET_SIZE*sizeof(void*(*)[2])) |
| set $rc = memset($__set_instance, 0, $__BUCKET_SIZE*sizeof(void*(*)[2])) |
| end |
| end |
| |
| define __free_set_instance |
| if $__set_instance |
| __set_clean |
| set $rc = free($__set_instance) |
| set $__set_instance = 0 |
| end |
| end |
| |
| define __set_add |
| set $p = (void*)$arg0 |
| set $__bkt_idx = (int)$p%$__BUCKET_SIZE |
| |
| __set_instance |
| set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] |
| set $__found = 0 |
| while $__elem |
| if (*$__elem)[0] == $p |
| set $__found = 1 |
| loop_break |
| end |
| set $__elem = (void*(*)[2])(*$__elem)[1] |
| end |
| if $__found |
| set $existed_in_set = 1 |
| else |
| set $existed_in_set = 0 |
| |
| set $rc = (void*(*)[2])calloc(1, sizeof(void*)*2) |
| set (*$rc)[0] = $p |
| set (*$rc)[1] = $__set_instance[$__bkt_idx] |
| set $__set_instance[$__bkt_idx] = $rc |
| end |
| end |
| |
| define __set_is_exist |
| set $p = (void*)$arg0 |
| set $__bkt_idx = (int)$p%$__BUCKET_SIZE |
| |
| __set_instance |
| set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] |
| set $__found = 0 |
| while $__elem |
| if (*$__elem)[0] == $p |
| set $__found = 1 |
| loop_break |
| end |
| set $__elem = (void*(*)[2])(*$__elem)[1] |
| end |
| if $__found |
| set $existed_in_set = 1 |
| else |
| set $existed_in_set = 0 |
| end |
| end |
| |
| define __set_clean |
| __set_instance |
| |
| set $__bkt_idx = 0 |
| while $__bkt_idx < $__BUCKET_SIZE |
| set $__elem = (void*(*)[2])$__set_instance[$__bkt_idx] |
| while $__elem |
| set $__next = (void*(*)[2])(*$__elem)[1] |
| set $rc = free($__elem) |
| set $__elem = $__next |
| end |
| set $__set_instance[$__bkt_idx] = 0 |
| set $__bkt_idx = $__bkt_idx+1 |
| end |
| end |
| |
| define hook-quit |
| __free_lua_debug_instance |
| __free_set_instance |
| end |
| |
| define hook-detach |
| __free_lua_debug_instance |
| __free_set_instance |
| end |
| |
| define hook-disconnect |
| __free_lua_debug_instance |
| __free_set_instance |
| end |
| |
| define _lua_pop |
| set $l = (lua_State*)$arg0 |
| set $_n = (int)$arg1 |
| set $_rc = lua_settop($l, -$_n-1) |
| end |
| |
| define _lua_dump_locals |
| set $l = (lua_State*)$arg0 |
| set $dbg = (lua_Debug*)$arg1 |
| set $idx = 1 |
| |
| set $rc = lua_getlocal($l, $dbg, $idx) |
| if $rc |
| printf "\t----[[ Locals ]]----\n" |
| while $rc |
| printf "\t%d:\t'%s' = ", $idx, $rc |
| __lua_dump_stack $l -1 |
| printf "\n" |
| |
| _lua_pop $l 1 |
| set $idx = $idx + 1 |
| set $rc = lua_getlocal($l, $dbg, $idx) |
| end |
| else |
| printf "\tNo locals!\n" |
| end |
| printf "\n" |
| end |
| |
| define _lua_dump_upvalues |
| set $l = (lua_State*)$arg0 |
| set $dbg = (lua_Debug*)$arg1 |
| set $idx = 1 |
| |
| set $rc = lua_getinfo($l, "f", $dbg) |
| if $rc |
| set $rc = lua_getupvalue($l, -1, $idx) |
| if $rc |
| printf "\t----[[ Upvalues ]]----\n" |
| while $rc |
| printf "\t%d:\t'%s' = ", $idx, $rc |
| __lua_dump_stack $l -1 |
| printf "\n" |
| |
| _lua_pop $l 1 |
| set $idx = $idx + 1 |
| set $rc = lua_getupvalue($l, -1, $idx) |
| end |
| else |
| printf "\tNo upvalues!\n" |
| end |
| _lua_pop $l 1 |
| else |
| printf "\tFailed to get function closure!\n" |
| end |
| printf "\n" |
| end |
| |
| define __lua_dump_stack |
| __set_clean |
| __lua_dump_stack_aux $arg0 $arg1 0 |
| end |
| |
| define __lua_dump_stack_aux |
| set $l = (lua_State*)$arg0 |
| set $nidx_$arg2 = (int)$arg1 |
| set $cidx_$arg2 = (int)$arg2+1 |
| |
| # relative stack index to absolute index |
| if $nidx_$arg2 < 0 && $nidx_$arg2 > $__LUA_REGISTRYINDEX |
| set $nidx_$arg2 = $nidx_$arg2 + (int)lua_gettop($l) + 1 |
| end |
| |
| set $vt_$arg2 = (int)lua_type($l, $nidx_$arg2) |
| |
| if $vt_$arg2 == $__LUA_TNONE |
| echo <invalid index> |
| end |
| if $vt_$arg2 == $__LUA_TNIL |
| echo (nil) |
| end |
| if $vt_$arg2 == $__LUA_TBOOLEAN |
| printf "(bool) %d", lua_toboolean($l, $nidx_$arg2) |
| end |
| if $vt_$arg2 == $__LUA_TLIGHTUSERDATA |
| printf "(ludata) %p", lua_touserdata($l, $nidx_$arg2) |
| end |
| if $vt_$arg2 == $__LUA_TNUMBER |
| printf "%g", lua_tonumber($l, $nidx_$arg2) |
| end |
| if $vt_$arg2 == $__LUA_TSTRING |
| set $tmplen = (size_t*)malloc(sizeof(size_t)) |
| set $tmp = lua_pushvalue($l, $nidx_$arg2) |
| set $tmp = lua_tolstring($l, -1, $tmplen) |
| #printf "(string:%d) ", *$tmplen |
| eval "output/r *(const char (*)[%d])$tmp", *$tmplen |
| _lua_pop $l 1 |
| set $tmp = free($tmplen) |
| end |
| if $vt_$arg2 == $__LUA_TTABLE |
| set $rc = lua_topointer($l, $nidx_$arg2) |
| #printf "(table) %p { ", $rc |
| printf "{ " |
| __set_add $rc |
| if $existed_in_set |
| printf "... " |
| else |
| set $rc = lua_pushnil($l) |
| set $rc = lua_next($l, $nidx_$arg2) |
| while $rc != 0 |
| printf "[" |
| __lua_dump_stack_aux $l -2 $cidx_$arg2 |
| printf "]" |
| printf " = " |
| __lua_dump_stack_aux $l -1 $cidx_$arg2 |
| printf ", " |
| _lua_pop $l 1 |
| set $rc = lua_next($l, $nidx_$arg2) |
| end |
| end |
| printf "}" |
| end |
| if $vt_$arg2 == $__LUA_TFUNCTION |
| printf "(func) %p", lua_topointer($l, $nidx_$arg2) |
| end |
| if $vt_$arg2 == $__LUA_TUSERDATA |
| printf "(udata) %p", lua_topointer($l, $nidx_$arg2) |
| end |
| if $vt_$arg2 == $__LUA_TTHREAD |
| printf "(thread) %p", lua_topointer($l, $nidx_$arg2) |
| else |
| if $vt_$arg2 > $__LUA_TTHREAD || $vt_$arg2 < 0 |
| echo <unknown type> |
| end |
| end |
| end |
| |
| #### Command methods #### |
| |
| define lbt |
| if $argc < 1 |
| echo Please specify Lua state and/or dump flag!\n |
| else |
| set $l = (lua_State*)$arg0 |
| if $argc > 1 |
| set $dump_local = ($arg1&1)==1 |
| set $dump_upvalue = ($arg1&2)==2 |
| else |
| set $dump_local = 0 |
| set $dump_upvalue = 0 |
| end |
| |
| __lua_debug_instance |
| set $dbg = $__lua_debug_instance |
| |
| set $level = 0 |
| set $rc = lua_getstack($l, $level, $dbg) |
| while $rc > 0 |
| set $rc = lua_getinfo($l, "Sln", $dbg) |
| set $name = $dbg->name |
| if !$name |
| set $name = "???" |
| end |
| |
| printf "#%d\t%s\t[%s]\tat %s:%d\n", $level, $name, $dbg->what, $dbg->source, $dbg->currentline |
| |
| if $dump_local |
| _lua_dump_locals $l $dbg |
| end |
| if $dump_upvalue |
| _lua_dump_upvalues $l $dbg |
| end |
| |
| set $level = $level+1 |
| set $rc = lua_getstack($l, $level, $dbg) |
| end |
| end |
| end |
| |
| document lbt |
| lbt <lua state> [<dump>]: Dump the backtrace of the specified Lua state. <dump> is a mask value, whose bit 1/2 controls the dump of locals/upvalues at each stack frame correspondingly. So set <dump> to 1 dumps only locals; set to 2 dumps only upvalues; and set to 3 dumps both locals and upvalues. |
| end |
| |
| define ll |
| if $argc != 2 |
| echo Please specify Lua state and stack frame number (0-based)!\n |
| else |
| set $l = (lua_State*)$arg0 |
| set $level = (int)$arg1 |
| |
| __lua_debug_instance |
| set $dbg = $__lua_debug_instance |
| |
| set $rc = lua_getstack($l, $level, $dbg) |
| if $rc > 0 |
| _lua_dump_locals $l $dbg |
| else |
| echo Failed to get Lua stack frame!\n |
| end |
| end |
| end |
| |
| document ll |
| ll <lua state> <frameno>: Dump all local vars in the specified Lua stack frame (0-based). |
| end |
| |
| define lu |
| if $argc != 2 |
| echo Please specify Lua state and stack frame number (0-based)!\n |
| else |
| set $l = (lua_State*)$arg0 |
| set $level = (int)$arg1 |
| |
| __lua_debug_instance |
| set $dbg = $__lua_debug_instance |
| |
| set $rc = lua_getstack($l, $level, $dbg) |
| if $rc > 0 |
| _lua_dump_upvalues $l $dbg |
| else |
| echo Failed to get Lua stack frame!\n |
| end |
| end |
| end |
| |
| document lu |
| lu <lua state> <frameno>: Dump all upvalues in the specified Lua stack frame (0-based). |
| end |
| |
| define lg |
| if $argc != 1 |
| echo Please specify Lua state!\n |
| else |
| set $l = (lua_State*)$arg0 |
| __lua_dump_stack $l $__LUA_GLOBALSINDEX |
| printf "\n" |
| end |
| end |
| |
| document lg |
| lg <lua state>: Dump all entries in Lua global table. |
| end |
| |
| define lr |
| if $argc != 1 |
| echo Please specify Lua state!\n |
| else |
| set $l = (lua_State*)$arg0 |
| __lua_dump_stack $l $__LUA_REGISTRYINDEX |
| printf "\n" |
| end |
| end |
| |
| document lr |
| lr <lua state>: Dump all entries in Lua registry table. |
| end |
| |
| define ls |
| if $argc != 1 |
| echo Please specify Lua state!\n |
| else |
| set $l = (lua_State*)$arg0 |
| set $idx = lua_gettop($l) |
| while $idx >= 1 |
| printf "#%d ", $idx |
| __lua_dump_stack $l $idx |
| printf "\n" |
| set $idx = $idx - 1 |
| end |
| end |
| end |
| |
| document ls |
| ls <lua state>: Dump all entries in call stack. |
| end |
| |
| # vi:ft=gdb ts=4 sw=4 |
| |