# 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 gmail 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 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 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 []: Dump the backtrace of the specified Lua state. is a mask value, whose bit 1/2 controls the dump of locals/upvalues at each stack frame correspondingly. So set 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 : 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 : 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 : 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 : 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 : Dump all entries in call stack. end # vi:ft=gdb ts=4 sw=4