Skip to content

Instantly share code, notes, and snippets.

@Fingercomp Fingercomp/stacktrace.lua
Last active Jun 20, 2019

Embed
What would you like to do?
A simple stacktracer for lua.
local function insertNonNil(t, v)
if v then
v = tostring(v)
if #v > 0 then
table.insert(t, v)
end
end
end
local function traceback(c)
for level = 0, math.huge do
local info = debug.getinfo(c, level, "ufnSl")
if not info then
break
end
local funcType, name, args, exec, defined = {}, nil, nil, "", {}
insertNonNil(funcType, info.what)
insertNonNil(funcType, info.namewhat)
table.insert(funcType, "function")
name = info.name or "<anon>"
if info.nparams then
args = {}
for an = 1, info.nparams do
local argName, argValue = debug.getlocal(c, level, an)
if argValue ~= nil then
argName = argName .. "=" .. tostring(argValue)
end
table.insert(args, argName)
end
end
if info.isvararg then
local varargs = {n = 0}
local gotNonNilValue = false
for an = 1, math.huge, 1 do
local argName, argValue = debug.getlocal(c, level, -an)
if not argName then
break
end
if argValue ~= nil then
gotNonNilValue = true
end
varargs.n = varargs.n + 1
varargs[varargs.n] = argValue
end
if varargs.n == 0 then
table.insert(args, "...")
elseif gotNonNilValue then
for an = 1, varargs.n, 1 do
table.insert(args, tostring(varargs[an]))
end
else
table.insert(args,
("<... (%d arg%s)>"):format(varargs.n,
varargs.n == 1 and "" or "s"))
end
end
if info.currentline and info.currentline ~= -1 then
exec = ":" .. tostring(info.currentline)
end
insertNonNil(defined, info.short_src)
if info.linedefined and info.linedefined ~= -1 then
table.insert(defined, info.linedefined)
end
funcType = table.concat(funcType, " ")
args = args and ("(" .. table.concat(args, ", ") .. ")")
defined = (defined[1] and (" in " .. defined[1] .. "") or "") ..
(defined[2] and (" at L" .. defined[2]) or "")
local line = ("#%2d: %s %s%s%s%s"):format(
level,
funcType,
name,
args or "",
exec,
#defined > 0 and (" (defined" .. defined .. ")") or ""
)
print(line)
end
end
local c = coroutine.create(function()
local function outer(f, g, a, b, ...)
g("outer", a, b)
f(g, a, b, "vararg test", nil)
end
local function inner(f, a, b, ...)
coroutine.yield()
f("inner", a, b)
end
outer(inner, print, 42, 24, nil)
end)
coroutine.resume(c)
traceback(c)
--> # 0: C field function yield(...) (defined in [C])
--> # 1: Lua local function f(f=function: 0x55a46ea8c590, a=42, b=24, vararg test, nil):109 (defined in trace.lua at L108)
--> # 2: Lua local function outer(f=function: 0x55a46ee15230, g=function: 0x55a46ea8c590, a=42, b=24, <... (1 arg)>):105 (defined in trace.lua at L103)
--> # 3: Lua function <anon>():113 (defined in trace.lua at L102)
coroutine.resume(c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.