415 lines
8.5 KiB
Text
415 lines
8.5 KiB
Text
# 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
|
|
|