Written by Greenman#0001
Last Updated Thursday, 05-Sep-2019 11:59:24 GMT-0400
Before you continue, please understand these things:
- This guide is written based on Synapse X's debug functions
- Luau has changed how some of these functions work
- Some of these functions work differently or produce different results that differ from vanilla Lua
- If a new debug function is added to an exploit, it will not be here if it's not documented or I can't figure out what it does
Documentation is formatted like this:
return_type debug.function_name(<type> arg1 [,<type> arg2])
Arguments enclosed in square brackets are optional.
It's important to understand some terminology so you don't get confused when reading this guide.
Local means a local variable and the plural version is locals.
Example:
local x = 10 -- This is a local
y = 20 -- This is not a local
An upvalue is an external local variable. This means that you are accessing a local variable that is above the scope of the current block (in the case of the debug lib, a function).
Example:
local x = 10
y = 20
function test()
local z = 30
print(x) -- x is an upvalue
print(y) -- y is not an upvalue because it's a global
print(z) -- z is not an upvalue because it's an internal local variable
end
If you reassign or reference a local variable that was defined outside the function inside the function, it's an upvalue.
The stack level is a number that returns a specific function or thread.
0
- The debug function that was called1
- The thread that called this function2
- The thread calling the function you are in
Example (Levels 0-2):
local a = 10
-- stack level 2
function x()
local b = 20
-- stack level 1
debug.getinfo(0) -- stack level 0 = this function
end
x()
-- stack level 2
Note: There can technically be infinite stack levels but the idea with stack levels is that you are "moving up" threads/functions until you get to the last thread.
An object refers to a table, userdata, thread, or function.
Int is short for integer which means a whole number.
Example:
1 Int
1.4 Not an int
This guide will overview the following debug functions:
- debug.getconstant
- debug.getconstants
- debug.getfenv
- debug.getinfo
- debug.getlocal
- debug.getlocals
- debug.getmetatable
- debug.getproto
- debug.getprotos
- debug.getregistry
- debug.getstack
- debug.getupvalue
- debug.getupvalues
- debug.setconstant
- debug.setlocal
- debug.setmetatable
- debug.setproto
- debug.setstack
- debug.setupvalue
- debug.setupvaluename
- debug.traceback
Documentation:
any debug.getconstant(<function, int> f, <int> idx)
Returns the constant at the specified index in function or stack level f
.
Example:
function test()
print(10)
end
print(debug.getconstant(test,2)) -- 10
Keep in mind that function names count as constants and are returned as strings.
Example 2:
function test()
print(10)
end
local x = debug.getconstant(test,1)
print(x) -- print
print("Datatype of constant: "..type(x)) -- Datatype of constant: string
Documentation:
table debug.getconstants(<function, int> f)
Returns a table containing the constants of function or stack level f
.
Example:
function test()
print(10)
end
for k,v in pairs(debug.getconstants(test)) do
print(k,v)
end
-- Output
-- 1 print
-- 2 10
This function can be useful when you need to get the index for a constant.
Alias: getfenv
Documentation:
table getfenv(<function, int> f)
Returns the global environment table of function or stack level f
. Same as getfenv
except it ignores all the safety checks.
Example:
function timer()
print("5 Second Timer Started!")
wait(5)
print("Time's Up!")
end
debug.getfenv(timer).wait = function() end
timer()
This script will have no delay by adding a new function called wait to the global environment of timer
that does nothing.
Documentation:
table debug.getinfo(<function, int> f [,<string> what])
Returns a table with information about the function or stack level f
. The what
argument can be used to select specific pieces of information that will go in the returned table. For information on how to use it, read this page.
Example:
function test()
print("hi")
end
for k,v in pairs(debug.getinfo(test)) do
print(k,v)
end
-- Output
-- func function: 0xADDRESS
-- nups 0
-- source @NAME
-- what Lua
-- currentline -1
-- lastlinedefined NUMBER
-- linedefined NUMBER
-- short_src NAME
To understand what this information means, please read this (ignore the code and look for the part where it says "The fields of lua_Debug have the following meaning").
This will return an error due to a replacement function being made for Luau. debug.getstack
should be used instead.
This will return an error due to a replacement function being made for Luau. debug.getstack
should be used instead.
Alias: getrawmetatable
Documentation:
object debug.getmetatable(object o)
Returns the metatable of object o
or nil if o
has no metatable. This function is not the same as getmetatable
because it will always return the table even if there is __metatable
in the metatable.
Example:
local myTable = {1,2,3}
setmetatable(myTable,{
__index = function(t,k)
return "Could not access "..k
end,
__metatable = "No access" -- does not effect debug.getmetatable
})
print(myTable[4]) -- Could not access 4
local backup = {"backup1","backup2","backup3","backup4","backup5"}
debug.getmetatable(myTable).__index = backup
print(myTable[4]) --backup4
This function was recently added to Synapse X and doesn't seem to be working properly at the moment.
This function was recently added to Synapse X and doesn't seem to be working properly at the moment.
Alias: getreg
Documentation:
table debug.getregistry()
Returns the Lua registry table. This table contains all functions and threads created from any client-side scripts. Keep in mind that getgc()
is actually better for most purposes.
Example:
for k,v in pairs(debug.getregistry()) do
if type(v) == "function" then
--you can do stuff like getting upvalues, constants, environment, etc.
end
end
Documentation:
table debug.getstack(<int> lvl)
Returns a table containing the local variables at the stack level lvl
. Unfortunately, this function does not allow you to get the arguments of a function (probably because of Luau?).
Example:
for k,v in pairs(debug.getstack(1)) do -- level 1 is current thread
print(k,v)
end
This script will display all of the local variables inside the current thread.
Documentation:
any debug.getupvalue(<function, int> f, <int> idx)
Returns the upvalue inside the function or stack levelf
at index idx
. If an upvalue at idx
is not found, nil is returned.
Example:
local health = 100
function takeDamage()
health = health - 10
end
print(debug.getupvalue(takeDamage,1)) -- 100
Documentation:
table debug.getupvalues(<function, int> f)
Returns a table containing the upvalues of function or stack level f
. If the function is from a script inside the game, you will get number indices instead of names because of Luau.
Example:
local health = 10
local ammo = 100
local state = "standing"
function showStats()
print("Health: "..health.."\nAmmo: "..ammo.."\nState: "..state)
end
for k,v in pairs(debug.getupvalues(showStats)) do
print(k,v)
end
Documentation:
nil debug.setconstant(<function, int> f, <int> idx, <object> value)
Sets the constant at index idx
to value
inside function or stack level f
. It's recommended to use debug.getconstants
to see all of the constants available in a function before using this function.
Example:
function test()
local x = 10
print(x)
end
function hijack(...)
print("HIJACKED: ",...)
end
debug.setconstant(test,2,"hijack")
test() -- HIJACKED: 10
This will return an error due to a replacement function being made for Luau. debug.setstack
should be used instead.
Alias: setrawmetatable
Documentation:
bool debug.setmetatable(<object> o, <table> mt)
Sets o
's metatable to mt
even if the __metatable
field exists in o
's metatable. Keep in mind that this function will return a boolean in Synapse X even though the function is supposed to return o
according to the reference manual.
Example:
local t = {1,2,3}
local mt = {__metatable = "The metatable is locked!"}
setmetatable(t,mt)
--[[ This block will return an error
print(setmetatable(t,{
__index = {1,2,3,4,5,6}
}))
]]
print(debug.setmetatable(t,{
__index = {1,2,3,4,5,6}
})) -- true
This function was recently added to Synapse X and doesn't seem to be working properly at the moment.
Documentation:
nil debug.setstack(<int> lvl, <int> idx, <any> value)
Sets the local at index idx
to value
at stack level lvl
. Unfortunately, you cannot set the arguments of a function with this function (probably because of Luau?).
Example:
local x = 10
debug.setstack(1,1,100)
print(x) -- 100
Documentation:
nil debug.setupvalue(<function, int> f, <int> idx, <any> value)
Sets the upvalue at index idx
to value
in function or stack level f
.
Example:
local health = 100
function takeDamage()
health = health - 10
end
print(health) -- 100
debug.setupvalue(takeDamage,1,math.huge)
print(health) -- inf
Documentation:
nil debug.setupvaluename(<function, int> f, <int> idx, <string> name)
Sets the name of the upvalue at idx
to name
in function or stack level f
. This function is meant to be used when you are working with functions from a script inside the game that uses number indices instead of names.
Example:
local health = 100
function takeDamage()
health = health - 10
end
debug.setupvaluename(takeDamage,1,"hp")
print(debug.getupvalue(takeDamage,"hp")) -- 100
Documentation:
string debug.traceback([<string> message, <int> lvl])
Returns a full execution stack trace of stack level lvl
and starting with message message
before the logging. Both arguments are optional and the default value for lvl
is 1 which is the current thread.
Example:
print(debug.traceback())
-- @SCRIPTNAME:1
Example 2:
print(debug.traceback("Traceback test"))
-- Traceback test!
-- @SCRIPTNAME:1