-- -- RemDebug 1.0 Beta -- Copyright Kepler Project 2005 (http://www.keplerproject.org/remdebug) -- local socket = require"socket" local global_print = print function print(...) global_print(...) io.stdout:flush() end --~ io.stdout:setvbuf("no") print("Lua Remote Debugger") print("Run the program you wish to debug") local server = socket.bind("*", 8171) local client = server:accept() local breakpoints = {} local watches = {} client:send("STEP\n") client:receive() local breakpoint = client:receive() local _, _, file, line = string.find(breakpoint, "^202 Paused%s+([%w%p]+)%s+(%d+)$") if file and line then print("Paused at file " .. file ) print("Type 'help' for commands") else local _, _, size = string.find(breakpoint, "^401 Error in Execution (%d+)$") if size then print("Error in remote application: ") print(client:receive(size)) end end local basedir = "" local display_expressions local function eval_error(client,len) len = tonumber(len) local res = client:receive(len) print("Error in expression:") --print(res) -- sjd I cd see no reason to print this bogus value end function any_command_args(line) local _, _, exp = string.find(line, "^[a-z]+%s+(.+)$") return exp end function remote_eval(exp) client:send("EXEC return remdebug.engine.expand_value(" .. exp .. ")\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) return true,res elseif status == "401" then eval_error(client,len) return false else print("Unknown error") return false end end function on_paused_execution() if display_expressions then for i,v in ipairs(display_expressions) do local ok,res = remote_eval(v) if ok then print(v .. " = " .. res) end end end end function process_line(line) local _, _, command = string.find(line, "^([a-z]+)") if command == "run" or command == "step" or command == "over" then client:send(string.upper(command) .. "\n") client:receive() -- always 'OK' local breakpoint = client:receive() if not breakpoint then -- client has terminated normally... print("Program finished") os.exit() end local _, _, status = string.find(breakpoint, "^(%d+)") if status == "202" then local _, _, file, line = string.find(breakpoint, "^202 Paused%s+([%w%p]+)%s+(%d+)$") if file and line then print("Paused at file " .. file .. " line " .. line) on_paused_execution() end elseif status == "203" then local _, _, file, line, watch_idx = string.find(breakpoint, "^203 Paused%s+([%w%p]+)%s+(%d+)%s+(%d+)$") if file and line and watch_idx then print("Paused at file " .. file .. " line " .. line .. " (watch expression " .. watch_idx .. ": [" .. watches[watch_idx] .. "])") on_paused_execution() end elseif status == "401" then local _, _, size = string.find(breakpoint, "^401 Error in Execution (%d+)$") if size then print("Error in remote application: ") print(client:receive(tonumber(size))) os.exit() end else print("Unknown error") os.exit() end elseif command == "exit" then client:close() os.exit() elseif command == "setb" then local _, _, _, filename, line = string.find(line, "^([a-z]+)%s+([%w%p]+)%s+(%d+)$") if filename and line then filename = basedir .. filename if not breakpoints[filename] then breakpoints[filename] = {} end client:send("SETB " .. filename .. " " .. line .. "\n") if client:receive() == "200 OK" then breakpoints[filename][line] = true else print("Error: breakpoint not inserted") end else print("Invalid command") end elseif command == "setw" then local _, _, exp = string.find(line, "^[a-z]+%s+(.+)$") if exp then client:send("SETW " .. exp .. "\n") local answer = client:receive() local _, _, watch_idx = string.find(answer, "^200 OK (%d+)$") if watch_idx then watches[watch_idx] = exp print("Inserted watch exp no. " .. watch_idx) else print("Error: Watch expression not inserted") end else print("Invalid command") end elseif command == "delb" then local _, _, _, filename, line = string.find(line, "^([a-z]+)%s+([%w%p]+)%s+(%d+)$") if filename and line then filename = basedir .. filename if not breakpoints[filename] then breakpoints[filename] = {} end client:send("DELB " .. filename .. " " .. line .. "\n") if client:receive() == "200 OK" then breakpoints[filename][line] = nil else print("Error: breakpoint not removed") end else print("Invalid command") end elseif command == "delallb" then for filename, breaks in pairs(breakpoints) do for line, _ in pairs(breaks) do client:send("DELB " .. filename .. " " .. line .. "\n") if client:receive() == "200 OK" then breakpoints[filename][line] = nil else print("Error: breakpoint at file " .. filename .. " line " .. line .. " not removed") end end end elseif command == "delw" then local _, _, index = string.find(line, "^[a-z]+%s+(%d+)$") if index then client:send("DELW " .. index .. "\n") if client:receive() == "200 OK" then watches[index] = nil else print("Error: watch expression not removed") end else print("Invalid command") end elseif command == "delallw" then for index, exp in pairs(watches) do client:send("DELW " .. index .. "\n") if client:receive() == "200 OK" then watches[index] = nil else print("Error: watch expression at index " .. index .. " [" .. exp .. "] not removed") end end elseif command == "locals" then --new-- client:send("LOCALS\n") local line = client:receive() local _, _, size = string.find(line, "^200 OK (%d+)$") if size then local msg = client:receive(tonumber(size)) print(msg) end elseif command == "detach" then --new-- client:send("DETACH\n") client:receive() elseif command == "display" then local exp = any_command_args(line) if not display_expressions then display_expressions = {} end table.insert(display_expressions,exp) elseif command == "eval" then local exp = any_command_args(line) if exp then local ok,res = remote_eval(exp) if ok then -- this pattern makes it a little easier for scite-gdb print('= '..res) end else print("Bad command") end elseif command == "exec" then local exp = any_command_args(line) if exp then client:send("EXEC " .. exp .. "\n") local line = client:receive() if not line then --sjd case where exp is 'os.exit(0)' print("Program killed") os.exit(0) end local _, _, status, len = string.find(line, "^(%d+)[%s%w]+(%d+)$") if status == "200" then len = tonumber(len) local res = client:receive(len) print(res) elseif status == "401" then eval_error(client,res) else print("Unknown error") end else print("Invalid command") end elseif command == "listb" then for k, v in pairs(breakpoints) do io.write(k .. ": ") for k, v in pairs(v) do io.write(k .. " ") end io.write("\n") end elseif command == "listw" then for i, v in pairs(watches) do print("Watch exp. " .. i .. ": " .. v) end elseif command == "basedir" then local _, _, dir = string.find(line, "^[a-z]+%s+(.+)$") if dir then if not string.find(dir, "/$") then dir = dir .. "/" end basedir = dir print("New base directory is " .. basedir) else print(basedir) end elseif command == "help" then print("setb -- sets a breakpoint") print("delb -- removes a breakpoint") print("delallb -- removes all breakpoints") print("setw -- adds a new watch expression") print("delw -- 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("locals -- lists local variables") print("detach -- stop debugging remote process") print("display -- add an expression to the display list") print("eval -- evaluates expression on the current context and returns its value") print("exec -- executes statement on the current context") print("basedir [] -- 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 print("Invalid command") end end end if table.getn(arg) == 1 then local f = io.open(arg[1],'r') for line in f:lines() do process_line(line) end end local prompt = "> " if _DPROMPT then prompt = _DPROMPT prompt = string.gsub(prompt,'\\n','\n') end while true do io.write(prompt) process_line(io.read("*line")) end