Skip to content

Debug

Extended debug library functions for inspecting and modifying function internals at runtime. These functions are available both as globals and under the debug table (e.g., debug.getstack and getstack).

debug.getstack

Returns the value(s) on the stack at the given level. Can optionally accept a thread as the first argument.

lua
debug.getstack(level: number, index: number?) -> any
debug.getstack(thread: thread, level: number, index: number?) -> any
ParameterTypeDescription
threadthread?Optional thread to inspect
levelnumberStack level to inspect
indexnumber?Specific stack index, or all values if omitted

Example

lua
local function test()
    local a = 10
    local b = "hello"
    print(debug.getstack(1))    --> 10, "hello"
    print(debug.getstack(1, 1)) --> 10
end
test()

-- With thread argument
local co = coroutine.create(function()
    local x = 42
    coroutine.yield()
end)
coroutine.resume(co)
print(debug.getstack(co, 1, 1)) --> 42

debug.setstack

Sets a value on the stack at the given level and index. Can optionally accept a thread as the first argument.

lua
debug.setstack(level: number, index: number, value: any) -> void
debug.setstack(thread: thread, level: number, index: number, value: any) -> void
ParameterTypeDescription
threadthread?Optional thread to modify
levelnumberStack level to modify
indexnumberStack index to set
valueanyThe new value

Example

lua
local function test()
    local x = 10
    debug.setstack(1, 1, 999)
    print(x) --> 999
end
test()

debug.getconstants

Returns a table of all constants in a function's bytecode.

lua
debug.getconstants(func: function | number) -> table
ParameterTypeDescription
funcfunction | numberThe function or stack level

Example

lua
local function test()
    local x = "hello"
    print(x)
end

local constants = debug.getconstants(test)
for i, v in pairs(constants) do
    print(i, v) --> 1 "hello", 2 "print"
end

debug.getconstant

Returns a specific constant at the given index.

lua
debug.getconstant(func: function | number, index: number) -> any
ParameterTypeDescription
funcfunction | numberThe function or stack level
indexnumberThe constant index

Example

lua
local function test()
    print("hello")
end

print(debug.getconstant(test, 1)) --> "print"

debug.setconstant

Sets a constant at the given index in a function's bytecode.

lua
debug.setconstant(func: function | number, index: number, value: any) -> void
ParameterTypeDescription
funcfunction | numberThe function or stack level
indexnumberThe constant index
valueanyThe new constant value

Example

lua
local function greet()
    print("hello")
end

debug.setconstant(greet, 2, "goodbye")
greet() --> goodbye

debug.getupvalues

Returns a table of all upvalues of a function.

lua
debug.getupvalues(func: function | number) -> table
ParameterTypeDescription
funcfunction | numberThe function or stack level

Example

lua
local secret = "password123"
local function getSecret()
    return secret
end

local upvalues = debug.getupvalues(getSecret)
for i, v in pairs(upvalues) do
    print(i, v) --> 1 "password123"
end

debug.getupvalue

Returns a specific upvalue at the given index.

lua
debug.getupvalue(func: function | number, index: number) -> any
ParameterTypeDescription
funcfunction | numberThe function or stack level
indexnumberThe upvalue index

Example

lua
local counter = 0
local function increment()
    counter = counter + 1
end

print(debug.getupvalue(increment, 1)) --> 0

debug.setupvalue

Sets a specific upvalue at the given index.

lua
debug.setupvalue(func: function | number, index: number, value: any) -> void
ParameterTypeDescription
funcfunction | numberThe function or stack level
indexnumberThe upvalue index
valueanyThe new value

Example

lua
local counter = 0
local function getCounter()
    return counter
end

debug.setupvalue(getCounter, 1, 100)
print(getCounter()) --> 100

debug.getprotos

Returns a table of all inner (proto) functions defined within a function.

lua
debug.getprotos(func: function | number) -> table
ParameterTypeDescription
funcfunction | numberThe function or stack level

Example

lua
local function outer()
    local function inner1() end
    local function inner2() end
end

local protos = debug.getprotos(outer)
print(#protos) --> 2

debug.getproto

Returns a specific proto (inner function) at the given index.

lua
debug.getproto(func: function | number, index: number) -> function
ParameterTypeDescription
funcfunction | numberThe function or stack level
indexnumberThe proto index

Example

lua
local function outer()
    local function inner()
        return "inner function"
    end
end

local proto = debug.getproto(outer, 1)
print(proto()) --> "inner function"

debug.getinfo

Returns a table of information about a function.

lua
debug.getinfo(func: function | number) -> table
ParameterTypeDescription
funcfunction | numberThe function or stack level

Returned Table

KeyTypeDescription
sourcestringSource file/chunk name
namestringFunction name (if available)
whatstring"Lua", "C", or "main"
currentlinenumberCurrent executing line
nupsnumberNumber of upvalues
numparamsnumberNumber of parameters
is_varargbooleanWhether function accepts varargs

Example

lua
local function myFunc(a, b, c)
    print(a, b, c)
end

local info = debug.getinfo(myFunc)
print(info.name)      --> "myFunc"
print(info.numparams) --> 3
print(info.nups)      --> 0

debug.validlevel

Returns true if the given stack level is valid (exists).

Aliases: isvalidlevel

lua
debug.validlevel(level: number) -> boolean

Example

lua
print(debug.validlevel(1)) --> true
print(debug.validlevel(999)) --> false

debug.getfenv

Gets the environment of a function or stack level. Works the same as getfenv, but is required inside oth hooks — when a stack level is provided, it automatically uses the original thread.

Global alias: dgetfenv

lua
debug.getfenv(func_or_level: function | number) -> table
ParameterTypeDescription
func_or_levelfunction | numberThe function or stack level to get the environment of

WARNING

Inside oth hooks, always use debug.getfenv instead of getfenv. When you pass a stack level, debug.getfenv will use the original thread rather than the hook thread, giving you the correct caller environment.

Example

lua
local function test()
    return "hello"
end

local env = debug.getfenv(test)
print(env == getfenv(0)) --> true (default environment)

-- Inside an oth hook:
oth.hook(some_func, function(...)
    -- Use debug.getfenv with a level - uses original thread automatically
    local caller_env = debug.getfenv(2)
    return oth.get_root_callback()(...)
end)