lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


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