[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: new features for remdebug
- From: "Guangxian Zou" <trueweck@...>
- Date: Fri, 23 Jun 2006 18:32:30 +0800
hi all,
remdebug can make debug lua script easily. but it didn't support
backtrace, which is a very useful feature. so i modified the source code of
remdebug, added some new features:backtrace,frame,list,print,info locals,
and assign value to variable by value=variable.
here is the difference:
diff --exclude=.svn --exclude=*.html -urN remdebug-1.0b/src/controller.lua
remdebug/src/controller.lua
--- remdebug-1.0b/src/controller.lua Tue Aug 23 22:46:30 2005
+++ remdebug/src/controller.lua Fri Jun 23 10:33:29 2006
@@ -32,11 +32,19 @@
local basedir = ""
+local
abbr={c="continue",b="setb",bt="backtrace",h="help",f="frame",l="list",p="print",si="step",s="step"}
+
while true do
io.write("> ")
local line = io.read("*line")
- local _, _, command = string.find(line, "^([a-z]+)")
- if command == "run" or command == "step" or command == "over" then
+ local _, _, command, symbol = string.find(line, "^([a-z]+)%s*(=?)")
+ if symbol ~= "=" then
+ if abbr[command] then
+ command = abbr[command]
+ end
+ end
+
+ if command == "continue" or command == "step" or command == "over" then
client:send(string.upper(command) .. "\n")
client:receive()
local breakpoint = client:receive()
@@ -128,7 +136,7 @@
if index then
client:send("DELW " .. index .. "\n")
if client:receive() == "200 OK" then
- watches[index] = nil
+ watches[index] = nil
else
print("Error: watch expression not removed")
end
@@ -139,7 +147,7 @@
for index, exp in pairs(watches) do
client:send("DELW " .. index .. "\n")
if client:receive() == "200 OK" then
- watches[index] = nil
+ watches[index] = nil
else
print("Error: watch expression at index " .. index .. " [" .. exp
.. "] not removed")
end
@@ -208,25 +216,84 @@
print(basedir)
end
elseif command == "help" then
- print("setb <file> <line> -- sets a breakpoint")
- print("delb <file> <line> -- removes a breakpoint")
- print("delallb -- removes all breakpoints")
- print("setw <exp> -- adds a new watch expression")
- print("delw <index> -- removes the watch expression at index")
- print("delallw -- removes all watch expressions")
- print("run -- run until next breakpoint")
- print("step -- run until next line, stepping into
function calls")
- print("over -- run until next line, stepping over
function calls")
- print("listb -- lists breakpoints")
- print("listw -- lists watch expressions")
- print("eval <exp> -- evaluates expression on the current
context and returns its value")
- print("exec <stmt> -- eexecutes statement on the current
context")
- print("basedir [<path>] -- sets the base path of the remote
application, or shows the current one")
- print("exit -- exits debugger")
- else
- local _, _, spaces = string.find(line, "^(%s*)$")
- if not spaces then
+ client:send("HELP\n")
+ local line = client:receive()
+ local _, _, size = string.find(line, "^200 OK (%d+)$")
+ if size then
+ msg = client:receive(tonumber(size))
+ print(msg)
+ end
+ elseif command == "backtrace" then
+ client:send("BACKTRACE\n")
+ local line = client:receive()
+ local _, _, size = string.find(line, "^200 OK (%d+)$")
+ if size then
+ msg = client:receive(tonumber(size))
+ print(msg)
+ end
+ elseif command == "print" then
+ local _, _, exp = string.find(line, "^[a-z]+%s+([_%w]+)$")
+ client:send("PRINT " .. exp .. "\n")
+ local line = client:receive()
+ local _, _, size = string.find(line, "^200 OK (%d+)$")
+ if size then
+ msg = client:receive(tonumber(size))
+ print(msg)
+ end
+ elseif command == "frame" then
+ local _, _, exp = string.find(line, "^[a-z]+%s+(%d+)$")
+ if exp then
+ client:send("FRAME " .. exp .. "\n")
+ local line = client:receive()
+ end
+ elseif command == "info" then
+ local _, _, exp = string.find(line, "^[a-z]+%s+(%w+)$")
+ if exp then
+ client:send("INFO " .. exp .. "\n")
+ local line = client:receive()
+ local _, _, size = string.find(line, "^200 OK (%d+)$")
+ if size then
+ msg = client:receive(tonumber(size))
+ print(msg)
+ end
+ end
+ elseif command == "list" then
+ local _, _, _, filename, line = string.find(line,
"^([a-z]+)%s+([%w%p]+)%s+(%d+)$")
+ if filename and line then
+ filename = basedir .. filename
+ client:send("LIST " .. filename .. " " .. line .. "\n")
+ local line = client:receive()
+ local _, _, size = string.find(line, "^200 OK (%d+)$")
+ if size then
+ msg = client:receive(tonumber(size))
+ print(msg)
+ end
+ else
print("Invalid command")
+ end
+ else
+ local _, _, exp,value = string.find(line, "^([_%a][%w]*)%s*=%s*(%w+)$")
+ if exp and value then
+ client:send("SET " .. exp .. "=" .. value .. "\n")
+ local line = client:receive()
+ local _, _, status, len = string.find(line, "^(%d+)[a-zA-Z ]+(%d+)$")
+ if status == "200" then
+ len = tonumber(len)
+ local res = client:receive(len)
+ print(res)
+ elseif status == "401" then
+ len = tonumber(len)
+ local res = client:receive(len)
+ print("Error in expression:")
+ print(res)
+ else
+ print("Unknown error")
+ end
+ else
+ local _, _, spaces = string.find(line, "^(%s*)$")
+ if not spaces then
+ print("Invalid command")
+ end
end
end
end
Binary files remdebug-1.0b/src/remdebug/.engine.lua.swp and
remdebug/src/remdebug/.engine.lua.swp differ
diff --exclude=.svn --exclude=*.html -urN
remdebug-1.0b/src/remdebug/engine.lua remdebug/src/remdebug/engine.lua
--- remdebug-1.0b/src/remdebug/engine.lua Tue Aug 30 06:27:57 2005
+++ remdebug/src/remdebug/engine.lua Fri Jun 23 10:27:09 2006
@@ -3,14 +3,14 @@
-- Copyright Kepler Project 2005 (http://www.keplerproject.org/remdebug)
--
-module("remdebug.engine")
+module("remdebug.engine",package.seeall)
+local lfs = require("lfs")
+local socket = require("socket")
_COPYRIGHT = "2005 - Kepler Project"
_DESCRIPTION = "Remote Debugger for the Lua programming language"
_VERSION = "1.0 Beta"
-local socket = require"socket"
-local lfs = require"lfs"
local debug = debug
local coro_debugger
@@ -42,49 +42,68 @@
return breakpoints[file] and breakpoints[file][line]
end
-local function restore_vars(vars)
- if type(vars) ~= 'table' then return end
- local func = debug.getinfo(3, "f").func
- local i = 1
- local written_vars = {}
- while true do
- local name = debug.getlocal(3, i)
- if not name then break end
- debug.setlocal(3, i, vars[name])
- written_vars[name] = true
- i = i + 1
- end
- i = 1
- while true do
- local name = debug.getupvalue(func, i)
- if not name then break end
- if not written_vars[name] then
- debug.setupvalue(func, i, vars[name])
+local function restore_vars(framevars)
+ local START_FRAME = 3
+ local cur_frame = START_FRAME
+ if type(framevars) ~= 'table' then return end
+ for iframe,vars in ipairs(framevars) do
+ cur_frame = START_FRAME + ( iframe - 1 )
+ local info = debug.getinfo(cur_frame, "Slf")
+ local func = info.func
+ local i = 1
+ local written_vars = {}
+ while true do
+ local name = debug.getlocal(cur_frame, i)
+ if not name then break end
+ -- print('-',i,name,vars[name])
+ debug.setlocal(cur_frame, i, vars[name])
written_vars[name] = true
+ i = i + 1
+ end
+ i = 1
+ while true do
+ local name = debug.getupvalue(func, i)
+ if not name then break end
+ if not written_vars[name] then
+ -- print('=',i,name,vars[name])
+ debug.setupvalue(func, i, vars[name])
+ written_vars[name] = true
+ end
+ i = i + 1
end
- i = i + 1
end
end
local function capture_vars()
- local vars = {}
- local func = debug.getinfo(3, "f").func
- local i = 1
- while true do
- local name, value = debug.getupvalue(func, i)
- if not name then break end
- vars[name] = value
- i = i + 1
- end
- i = 1
- while true do
- local name, value = debug.getlocal(3, i)
- if not name then break end
- vars[name] = value
- i = i + 1
+ local START_FRAME = 3
+ local cur_frame = START_FRAME
+ local retval = {}
+ while true do
+ local vars = {}
+ local info = debug.getinfo(cur_frame, "Slf")
+ if not info then break end
+ local func = info.func
+ local i = 1
+ while true do
+ local name, value = debug.getupvalue(func, i)
+ if not name then break end
+ vars[name] = value
+ i = i + 1
+ end
+ i = 1
+ while true do
+ local name, value = debug.getlocal(cur_frame, i)
+ if not name then break end
+ vars[name] = value
+ i = i + 1
+ end
+ vars['__FILE__'] = info.short_src
+ vars['__LINE__'] = info.currentline
+ setmetatable(vars, { __index = getfenv(func), __newindex =
getfenv(func) })
+ table.insert(retval, vars)
+ cur_frame = cur_frame + 1
end
- setmetatable(vars, { __index = getfenv(func), __newindex =
getfenv(func) })
- return vars
+ return retval
end
local function break_dir(path)
@@ -137,10 +156,41 @@
end
end
+local function help_msg()
+ local msg =
+ [[
+ backtrace(bt) -- show backtrace
+ frame(f) -- switch to certain frame
+ list(l) <file> <line> -- list the source file
+ print(p) -- show value of expr
+ info locals -- show local variables
+ setb(b) <file> <line> -- sets a breakpoint
+ delb <file> <line> -- removes a breakpoint
+ delallb -- removes all breakpoints
+ setw <exp> -- adds a new watch expression
+ delw <index> -- removes the watch expression at index
+ delallw -- removes all watch expressions
+ continue(c) -- run until next breakpoint
+ step(si) -- run until next line, stepping into function
calls
+ over(s) -- run until next line, stepping over function
calls
+ listb -- lists breakpoints
+ listw -- lists watch expressions
+ eval <exp> -- evaluates expression on the current context and
returns its value
+ exec <stmt> -- eexecutes statement on the current context
+ basedir [<path>] -- sets the base path of the remote application, or
shows the current one
+ exit -- exits debugger
+ help(h) -- help
+ ]]
+ return msg
+end
+
+local linecache = {}
+
local function debugger_loop(server)
local command
local eval_env = {}
-
+ local cur_frame = 1
+
while true do
local line, status = server:receive()
command = string.sub(line, string.find(line, "^[A-Z]+"))
@@ -166,7 +216,7 @@
local func = loadstring(chunk)
local status, res
if func then
- setfenv(func, eval_env)
+ setfenv(func, eval_env[cur_frame])
status, res = xpcall(func, debug.traceback)
end
res = tostring(res)
@@ -200,10 +250,11 @@
else
server:send("400 Bad Request\n")
end
- elseif command == "RUN" then
+ elseif command == "CONTINUE" then
server:send("200 OK\n")
local ev, vars, file, line, idx_watch = coroutine.yield()
eval_env = vars
+ cur_frame = 1
if ev == events.BREAK then
server:send("202 Paused " .. file .. " " .. line .. "\n")
elseif ev == events.WATCH then
@@ -217,6 +268,7 @@
step_into = true
local ev, vars, file, line, idx_watch = coroutine.yield()
eval_env = vars
+ cur_frame = 1
if ev == events.BREAK then
server:send("202 Paused " .. file .. " " .. line .. "\n")
elseif ev == events.WATCH then
@@ -231,6 +283,7 @@
step_level = stack_level
local ev, vars, file, line, idx_watch = coroutine.yield()
eval_env = vars
+ cur_frame = 1
if ev == events.BREAK then
server:send("202 Paused " .. file .. " " .. line .. "\n")
elseif ev == events.WATCH then
@@ -239,7 +292,122 @@
server:send("401 Error in Execution " .. string.len(file) .. "\n")
server:send(file)
end
+ elseif command == "HELP" then
+ local msg = help_msg()
+ server:send("200 OK " .. string.len(msg) .. "\n")
+ server:send(msg)
+ elseif command == "BACKTRACE" then
+ local items = {}
+ for i,v in ipairs(eval_env) do
+ if i == cur_frame then
+ table.insert(items, string.format("*%3d %s:%d", i,
tostring(v["__FILE__"]), v["__LINE__"]))
+ else
+ table.insert(items, string.format(" %3d %s:%d", i,
tostring(v["__FILE__"]), v["__LINE__"]))
+ end
+ end
+ local msg = table.concat(items,"\n")
+ if msg == nil then
+ server:send("200 OK " .. 0 .. "\n")
+ else
+ server:send("200 OK " .. string.len(msg) .. "\n")
+ server:send(msg)
+ end
+ elseif command == "PRINT" then
+ local _, _, _, exp = string.find(line, "^([A-Z]+)%s+([_%w]+)$")
+ local cur_env = eval_env[cur_frame]
+ local msg
+ if cur_env then
+ msg = cur_env[exp]
+ end
+ if msg == nil then
+ server:send("200 OK " .. 0 .. "\n")
+ else
+ server:send("200 OK " .. string.len(msg) .. "\n")
+ server:send(msg)
+ end
+ elseif command == "FRAME" then
+ local _, _, _, frame = string.find(line, "^([A-Z]+)%s+([%d]+)$")
+ frame = tonumber(frame)
+ if frame > #eval_env then
+ cur_frame = #eval_env
+ else
+ cur_frame = frame
+ end
+ server:send("200 OK\n")
+ elseif command == "INFO" then
+ local _, _, _, scope = string.find(line, "^([A-Z]+)%s+([%w]+)$")
+ local ignore = { __FILE__ = true, __LINE__ = true }
+ if string.lower(scope) == "locals" then
+ local vars = {}
+ local cur_env = eval_env[cur_frame]
+ if cur_env then
+ for k,v in pairs(cur_env) do
+ if k == "(*temporary)" or ignore[k] then
+ else
+ table.insert(vars, string.format("%s = %s",
tostring(k),tostring(v)))
+ end
+ end
+ end
+ local msg = table.concat(vars,"\n")
+ if msg == nil then
+ server:send("200 OK " .. 0 .. "\n")
+ else
+ server:send("200 OK " .. string.len(msg) .. "\n")
+ server:send(msg)
+ end
+ end
+ elseif command == "LIST" then
+ local _, _, _, filename, line = string.find(line,
"^([A-Z]+)%s+([%w%p]+)%s+(%d+)$")
+ if filename and line then
+ if not linecache[filename] then
+ local fin = io.open( filename, "r" )
+ if fin then
+ local s = fin:read("*all")
+ local i = 0
+ local lines = {}
+ while true do
+ i,j = string.find(s, "[^\n]*\n", i+1)
+ if i == nil then break end
+ table.insert(lines,string.sub(s,i,j))
+ i = j
+ end
+ linecache[filename] = lines
+ linecache[filename]["__curline__"] = 1
+ end
+ fin:close()
+ end
+ linecache[filename]["__curline__"] = tonumber(line)
+ local t = {}
+ local cur_line = linecache[filename]["__curline__"]
+ for i = 0, 9 do
+
table.insert(t,string.format("%d\t%s",cur_line+i,linecache[filename][cur_line+i]))
+ end
+ local msg = table.concat(t)
+ server:send("200 OK " .. string.len(msg) .. "\n")
+ server:send(msg)
+ else
+ server:send("400 Bad Request\n")
+ end
+ elseif command == "SET" then
+ local _, _, _, exp, value = string.find(line,
"^([A-Z]+)%s+([_%a][%w]*)%s*=%s*(%w+)$")
+ local cur_env = eval_env[cur_frame]
+ if cur_env then
+ local func = loadstring("return " .. value)
+ local status, res
+ if func then
+ setfenv(func, eval_env[cur_frame])
+ status, res = xpcall(func, debug.traceback)
+ if status then
+ cur_env[exp] = res
+ server:send("200 OK " .. 0 .. "\n")
+ else
+ server:send("401 Error in Expression " .. string.len(res) ..
"\n")
+ server:send(res)
+ end
+ end
+ end
else
+ print("BAD",line)
server:send("400 Bad Request\n")
end
end
diff --exclude=.svn --exclude=*.html -urN remdebug-1.0b/src/test.lua
remdebug/src/test.lua
--- remdebug-1.0b/src/test.lua Fri Aug 19 03:24:17 2005
+++ remdebug/src/test.lua Mon Jun 19 11:18:58 2006
@@ -1,7 +1,10 @@
require"remdebug.engine"
+a='11111111'
+local b='222222'
+print("before",b)
remdebug.engine.start()
-
+print("after",b)
local tab = {
foo = 1,
bar = 2
--
zou guangxian