debugger part 2

This commit is contained in:
kepler155c@gmail.com
2020-05-24 15:18:18 -06:00
parent f07302588c
commit 26b693d609
5 changed files with 116 additions and 43 deletions

View File

@@ -9,7 +9,7 @@ local dbg = { }
local function hookBreakpoint(info) local function hookBreakpoint(info)
if dbg.breakpoints then if dbg.breakpoints then
for _,v in pairs(dbg.breakpoints) do for _,v in pairs(dbg.breakpoints) do
if v.line == info.currentline and v.file == info.short_src then if v.line == info.currentline and v.file == info.short_src and not v.disabled then
return true return true
end end
end end
@@ -24,8 +24,8 @@ end
local function hookStep() local function hookStep()
local co = coroutine.running() local co = coroutine.running()
return function() return function(info)
return co == coroutine.running() return co == coroutine.running() or hookBreakpoint(info)
end end
end end
@@ -39,12 +39,13 @@ local function hookStepStacksize(n)
end end
i = i + 1 i = i + 1
end end
return function() return function(info)
if co == coroutine.running() then if co == coroutine.running() then
if not debug.getinfo(i - n) then if not debug.getinfo(i - n) then
return true return true
end end
end end
return hookBreakpoint(info)
end end
end end
@@ -63,13 +64,13 @@ local hookEval = function() end
local function local_bindings(offset, stack_inspect_offset) local function local_bindings(offset, stack_inspect_offset)
offset = offset + 1 + stack_inspect_offset -- add this function to the offset offset = offset + 1 + stack_inspect_offset -- add this function to the offset
local func = debug.getinfo(offset).func local func = debug.getinfo(offset).func
local bindings = {} local bindings = { }
-- Retrieve the upvalues -- Retrieve the upvalues
do local i = 1; while true do do local i = 1; while true do
local name, value = debug.getupvalue(func, i) local name, value = debug.getupvalue(func, i)
if not name then break end if not name then break end
bindings[name] = value bindings[name] = { type = 'U', raw = value }
i = i + 1 i = i + 1
end end end end
@@ -77,21 +78,32 @@ local function local_bindings(offset, stack_inspect_offset)
do local i = 1; while true do do local i = 1; while true do
local name, value = debug.getlocal(offset, i) local name, value = debug.getlocal(offset, i)
if not name then break end if not name then break end
bindings[name] = value bindings[name] = { type = 'L', raw = value }
i = i + 1 i = i + 1
end end end end
-- Retrieve the varargs (works in Lua 5.2 and LuaJIT) -- Retrieve the varargs (works in Lua 5.2 and LuaJIT)
local varargs = {} local varargs = { }
do local i = 1; while true do do local i = 1; while true do
local name, value = debug.getlocal(offset, -i) local name, value = debug.getlocal(offset, -i)
if not name then break end if not name then break end
varargs[i] = value varargs[i] = value
i = i + 1 i = i + 1
end end end end
if #varargs > 0 then bindings["..."] = varargs end if #varargs > 0 then
bindings["..."] = { type = 'V', value = varargs }
end
return bindings local t = { }
for k,v in pairs(bindings) do
if v.raw ~= nil then
v.name = k
v.value = tostring(v.raw)
table.insert(t, v)
end
end
return t
end end
local function get_trace(offset, stack_inspect_offset) local function get_trace(offset, stack_inspect_offset)
@@ -172,6 +184,17 @@ local function hook()
end end
end end
local cocreate = coroutine.create
_ENV.coroutine = { }
for k,v in pairs(_G.coroutine) do
_ENV.coroutine[k] = v
end
_ENV.coroutine.create = function(f, ...)
local co = cocreate(f, ...)
debug.sethook(co, dbg.hook, "l")
return co
end
debug.sethook(hook, 'l') debug.sethook(hook, 'l')
-- Expose the debugger's functions -- Expose the debugger's functions

View File

@@ -0,0 +1,4 @@
local completion = require('cc.shell.completion')
_ENV.shell.setCompletionFunction("packages/debugger/debug.lua",
completion.build(completion.program))

View File

@@ -16,12 +16,14 @@ if not filename then
error('file not found') error('file not found')
end end
UI:disableEffects()
local config = Config.load('debugger') local config = Config.load('debugger')
if not config.filename then if not config[filename] then
config.filename = { } config[filename] = { }
end end
local breakpoints = config.filename local breakpoints = config[filename]
local currentFile local currentFile
local debugFile, debugLine local debugFile, debugLine
@@ -37,14 +39,10 @@ local function startClient()
args = args, args = args,
fn = function(...) fn = function(...)
local dbg = require('debugger') local dbg = require('debugger')
local fn = loadfile(filename, env) local fn, msg = loadfile(filename, env)
local cocreate = coroutine.create if not fn then
env.coroutine = require('opus.util').shallowCopy(coroutine) error(msg, -1)
env.coroutine.create = function(f, ...)
local co = cocreate(f, ...)
debug.sethook(co, dbg.hook, "l")
return co
end end
dbg.debugger = debugger dbg.debugger = debugger
@@ -56,10 +54,32 @@ local function startClient()
client = kernel.find(clientId) client = kernel.find(clientId)
end end
local romFiles = {
load = function(self)
local function recurse(dir)
local files = fs.list(dir)
for _,f in ipairs(files) do
local fullName = fs.combine(dir, f)
if fs.isDir(fullName) then
recurse(fullName)
else
self.files[f] = fullName
end
end
end
recurse('rom/apis')
end,
get = function(self, file)
return self.files[file]
end,
files = { },
}
romFiles:load()
local function loadSource(file) local function loadSource(file)
currentFile = file:match('@?(.*)') currentFile = romFiles:get(file) or file:match('@?(.*)')
local src = { } local src = { }
local lines = Util.readLines(file:match('@?(.*)')) local lines = Util.readLines(currentFile)
if lines then if lines then
for i = 1, #lines do for i = 1, #lines do
@@ -77,11 +97,11 @@ end
local page = UI.Page { local page = UI.Page {
menuBar = UI.MenuBar { menuBar = UI.MenuBar {
buttons = { buttons = {
{ text = 'Continue', event = 'cmd', cmd = 'c' }, { text = 'Continue', event = 'cmd', cmd = 'c' },
{ text = 'Step', event = 'cmd', cmd = 's' }, { text = 'Step', event = 'cmd', cmd = 's' },
{ text = 'Step Over', event = 'cmd', cmd = 'n' }, { text = 'Over', event = 'cmd', cmd = 'n' },
{ text = 'Step Out', event = 'cmd', cmd = 'f' }, { text = 'Out', event = 'cmd', cmd = 'f' },
{ text = 'Restart', event = 'restart', width = 9, ex = -1 }, { text = 'Restart', event = 'restart', width = 9, ex = -1 },
}, },
}, },
@@ -94,11 +114,15 @@ local page = UI.Page {
{ heading = 'Key', key = 'name' }, { heading = 'Key', key = 'name' },
{ heading = 'Value', key = 'value', textColor = 'yellow' }, { heading = 'Value', key = 'value', textColor = 'yellow' },
}, },
--sortColumn = 'name',
autospace = true, autospace = true,
accelerators = { accelerators = {
grid_select = 'show_variable', grid_select = 'show_variable',
}, },
getRowTextColor = function(self, row, selected)
return row.type == 'U' and 'cyan'
or row.type == 'V' and 'lime'
or UI.Grid.getRowTextColor(self, row, selected)
end,
}, },
statusBar = UI.StatusBar { statusBar = UI.StatusBar {
ex = -7, y = -1, ex = -7, y = -1,
@@ -128,7 +152,7 @@ local page = UI.Page {
for _,v in pairs(breakpoints) do for _,v in pairs(breakpoints) do
if v.file == currentFile and v.line == row.line then if v.file == currentFile and v.line == row.line then
return { return {
marker = '!', marker = v.disabled and 'x' or '!',
line = row.line, line = row.line,
source = row.source, source = row.source,
} }
@@ -136,6 +160,9 @@ local page = UI.Page {
end end
return row return row
end, end,
accelerators = {
t = 'toggle_enabled'
},
getRowTextColor = function(self, row, selected) getRowTextColor = function(self, row, selected)
return row.line == debugLine and currentFile == debugFile and 'yellow' return row.line == debugLine and currentFile == debugFile and 'yellow'
or UI.Grid.getRowTextColor(self, row, selected) or UI.Grid.getRowTextColor(self, row, selected)
@@ -147,6 +174,17 @@ local page = UI.Page {
file = currentFile, file = currentFile,
line = event.selected.line, line = event.selected.line,
}) })
elseif event.type == 'toggle_enabled' then
local line = self:getSelected() and self:getSelected().line
if line then
for _,v in pairs(breakpoints) do
if v.file == currentFile and v.line == line then
v.disabled = not v.disabled
self:emit({ type = 'update_breakpoints' })
break
end
end
end
end end
return UI.Grid.eventHandler(self, event) return UI.Grid.eventHandler(self, event)
end, end,
@@ -157,6 +195,7 @@ local page = UI.Page {
title = 'Stack', title = 'Stack',
index = 3, index = 3,
grid = UI.ScrollingGrid { grid = UI.ScrollingGrid {
disableHeader = true,
columns = { columns = {
{ key = 'index', width = 2 }, { key = 'index', width = 2 },
{ heading = 'heading', key = 'desc' }, { heading = 'heading', key = 'desc' },
@@ -166,14 +205,14 @@ local page = UI.Page {
or UI.Grid.getRowTextColor(self, row, selected) or UI.Grid.getRowTextColor(self, row, selected)
end, end,
sortColumn = 'index', sortColumn = 'index',
eventHandler = function(self, event)
if event.type == 'grid_select' then
message('i', event.selected.index)
else
return UI.Grid.eventHandler(self, event)
end
end,
}, },
eventHandler = function(self, event)
if event.type == 'grid_select' then
message('r', event.selected.index)
else
return UI.Grid.eventHandler(self, event)
end
end,
}, },
env = UI.Tab { env = UI.Tab {
@@ -371,10 +410,10 @@ Event.on('debugger', function(_, cmd, data)
kernel.raise(debugger.uid) kernel.raise(debugger.uid)
-- local tab -- local tab
local t = { } local t = data.locals
for k,v in pairs(data.locals or { }) do -- for k,v in pairs(data.locals or { }) do
table.insert(t, { name = k, value = tostring(v), raw = v }) -- table.insert(t, { name = k, value = tostring(v), raw = v })
end -- end
table.sort(t, function(a, b) return a.name < b.name end) table.sort(t, function(a, b) return a.name < b.name end)
page.container.locals:setValues(t) page.container.locals:setValues(t)
page.container.locals.orig = Util.shallowCopy(t) page.container.locals.orig = Util.shallowCopy(t)
@@ -404,4 +443,6 @@ end)
UI:setPage(page) UI:setPage(page)
UI:start() UI:start()
message('d') if kernel.find(client.uid) then
client:resume('terminate')
end

View File

@@ -12,8 +12,7 @@ local function method(times)
end end
print('before') print('before')
-- breakpoint term.current().clear()
--dbg()
print('after') print('after')
local i = 2 local i = 2

6
debugger/help/debug.txt Normal file
View File

@@ -0,0 +1,6 @@
An interactive debugger for lua
debug must be enabled!
Run from a shell prompt
> debug FILE [ARGS]