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 localAn 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
endIf 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 2Note: 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)) -- 10Keep 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: stringDocumentation:
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 10This 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 NAMETo 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]) --backup4This 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
endDocumentation:
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)
endThis 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)) -- 100Documentation:
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)
endDocumentation:
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: 10This 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}
})) -- trueThis 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) -- 100Documentation:
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) -- infDocumentation:
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")) -- 100Documentation:
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:1Example 2:
print(debug.traceback("Traceback test"))
-- Traceback test!
-- @SCRIPTNAME:1