151 lines
4.1 KiB
Lua
151 lines
4.1 KiB
Lua
local breakpoints = {}
|
|
local dbg_steps_mode = false
|
|
local dbg_step_into_func = false
|
|
local hook_lock = false
|
|
local current_func
|
|
local current_func_stack_size
|
|
|
|
local __parse_path = parse_path
|
|
local _debug_getinfo = debug.getinfo
|
|
local _debug_getlocal = debug.getlocal
|
|
local __pause = debug.pause
|
|
local __error = error
|
|
local __sethook = debug.sethook
|
|
|
|
-- 'return' hook not called for some functions
|
|
-- todo: speedup
|
|
local function calc_stack_size()
|
|
local s = debug.traceback("", 2)
|
|
local count = 0
|
|
for i in s:gmatch("\n") do
|
|
count = count + 1
|
|
end
|
|
return count
|
|
end
|
|
|
|
local is_debugging = debug.is_debugging()
|
|
if is_debugging then
|
|
__sethook(function (e, line)
|
|
if e == "return" then
|
|
local info = _debug_getinfo(2)
|
|
if info.func == current_func then
|
|
current_func = nil
|
|
end
|
|
end
|
|
if dbg_steps_mode and not hook_lock then
|
|
hook_lock = true
|
|
|
|
if not dbg_step_into_func then
|
|
local func = _debug_getinfo(2).func
|
|
if func ~= current_func then
|
|
return
|
|
end
|
|
if current_func_stack_size ~= calc_stack_size() then
|
|
return
|
|
end
|
|
end
|
|
current_func = func
|
|
__pause("step")
|
|
debug.pull_events()
|
|
end
|
|
hook_lock = false
|
|
local bps = breakpoints[line]
|
|
if not bps then
|
|
return
|
|
end
|
|
local source = _debug_getinfo(2).source
|
|
if not bps[source] then
|
|
return
|
|
end
|
|
current_func = _debug_getinfo(2).func
|
|
current_func_stack_size = calc_stack_size()
|
|
__pause("breakpoint")
|
|
while debug.pull_events() do
|
|
__pause()
|
|
end
|
|
end, "lr")
|
|
end
|
|
|
|
local DBG_EVENT_SET_BREAKPOINT = 1
|
|
local DBG_EVENT_RM_BREAKPOINT = 2
|
|
local DBG_EVENT_STEP = 3
|
|
local DBG_EVENT_STEP_INTO_FUNCTION = 4
|
|
local DBG_EVENT_RESUME = 5
|
|
local DBG_EVENT_GET_VALUE = 6
|
|
local __pull_events = debug.__pull_events
|
|
local __sendvalue = debug.__sendvalue
|
|
debug.__pull_events = nil
|
|
debug.__sendvalue = nil
|
|
|
|
function debug.get_pack_by_frame(func)
|
|
local prefix, _ = __parse_path(_debug_getinfo(func, "S").source)
|
|
return prefix
|
|
end
|
|
|
|
function debug.pull_events()
|
|
if not is_debugging then
|
|
return
|
|
end
|
|
if not debug.is_debugging() then
|
|
is_debugging = false
|
|
__sethook()
|
|
end
|
|
local events = __pull_events()
|
|
if not events then
|
|
return
|
|
end
|
|
local keepPaused = false
|
|
for i, event in ipairs(events) do
|
|
if event[1] == DBG_EVENT_SET_BREAKPOINT then
|
|
debug.set_breakpoint(event[2], event[3])
|
|
elseif event[1] == DBG_EVENT_RM_BREAKPOINT then
|
|
debug.remove_breakpoint(event[2], event[3])
|
|
elseif event[1] == DBG_EVENT_STEP then
|
|
dbg_steps_mode = true
|
|
dbg_step_into_func = false
|
|
elseif event[1] == DBG_EVENT_STEP_INTO_FUNCTION then
|
|
dbg_steps_mode = true
|
|
dbg_step_into_func = true
|
|
elseif event[1] == DBG_EVENT_RESUME then
|
|
dbg_steps_mode = false
|
|
dbg_step_into_func = false
|
|
elseif event[1] == DBG_EVENT_GET_VALUE then
|
|
local _, value = _debug_getlocal(event[2] + 3, event[3])
|
|
for _, key in ipairs(event[4]) do
|
|
if value == nil then
|
|
value = "error: index nil value"
|
|
break
|
|
end
|
|
value = value[key]
|
|
end
|
|
__sendvalue(value, event[2], event[3], event[4])
|
|
keepPaused = true
|
|
end
|
|
end
|
|
return keepPaused
|
|
end
|
|
|
|
function debug.set_breakpoint(source, line)
|
|
local bps = breakpoints[line]
|
|
if not bps then
|
|
bps = {}
|
|
breakpoints[line] = bps
|
|
end
|
|
bps[source] = true
|
|
end
|
|
|
|
function debug.remove_breakpoint(source, line)
|
|
local bps = breakpoints[line]
|
|
if not bps then
|
|
return
|
|
end
|
|
bps[source] = nil
|
|
end
|
|
|
|
function error(message, level)
|
|
if is_debugging then
|
|
__pause("exception", message)
|
|
end
|
|
__error(message, level)
|
|
end
|