feat(luau): expose native breakpoint and step debug API#705
Open
w4nderlust wants to merge 1 commit into
Open
Conversation
Wrap Luau's debug C API so embedders can build line-precise debuggers: lua_breakpoint, lua_singlestep, lua_getlocal/lua_setlocal, and the debugbreak/debugstep callbacks. The callbacks mirror set_interrupt and can return VmState::Yield to suspend the running coroutine. New surface (all gated on the luau feature): - Lua::set_debug_break / set_debug_step / set_single_step and their removers - Function::set_breakpoint - Debug::get_local / set_local / locals The debug callbacks need their own trampoline instead of callback_error_ext: the latter reserves its WrappedFailure at the running frame's base, which shifts the paused function's registers and makes lua_getlocal read the wrong slots. debug_callback reserves at the top of the stack instead.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
On the Luau backend there is currently no way to do line-precise debugging from mlua.
Lua::set_hookis#[cfg(not(feature = "luau"))],set_interruptonly fires at coarse safepoints (calls, loop back-edges, returns) so it cannot stop on an arbitrary line, and the Luau sandbox stripsdebug.getlocal/getfenvso even when you do pause you cannot read locals.Luau's C API already has everything needed for this, mlua just had not wrapped it. This PR adds safe wrappers following the existing
set_interruptpattern. Nomlua-syschanges, the ffi was already declared.New surface, all behind the
luaufeature:Lua::set_debug_break/set_debug_step(plus removers) andset_single_step. The callbacks receive a&Debugfor the paused frame and can returnVmState::Yieldto suspend the running coroutine, same semantics asset_interrupt.Function::set_breakpoint(line, enabled) -> Option<u32>, wrappinglua_breakpoint. Returns the line Luau actually placed it on (it snaps the breakpoint to the next executable line).Debug::get_local/set_local/locals, wrappinglua_getlocal/lua_setlocal. Luau keeps locals reachable here even though the sandbox removes thedebuglibrary equivalents.Two things worth knowing, both called out in the docs/comments:
VmState::Continueon resume to step past it. The tests exercise this.callback_error_ext. It reserves itsWrappedFailureuserdata at the base of the running frame (lua_insert(state, 1)), which shifts the paused function's registers up by one and makeslua_getlocalread the wrong slots. So there is a small dedicateddebug_callbacktrampoline that reserves at the top of the stack instead, keeping the same error/panic/yield handling.Tests in
tests/luau.rscover breakpoint pause with yield/resume in a coroutine, a breakpoint on a multi-line call expression, single-step over consecutive lines and disabling it, reading and writing locals at a breakpoint, and error propagation from a break callback. The chunks are compiled with optimization 0 / debug 2 so line and local mapping stays stable.