| author | Julien Desgats | 2013-02-01 13:00:07 (EST) |
|---|---|---|
| committer | Simon Bernard | 2013-02-26 11:34:18 (EST) |
| commit | df6dc1287375fca5905a5b999e0fe62d008f9d41 (patch) (side-by-side diff) | |
| tree | 0d653145750f3c83f664adce1fd872d74739e0d2 | |
| parent | 84ceb600f76bf826788e4117d8e9158b1d3b06dd (diff) | |
| download | org.eclipse.koneki.ldt-df6dc1287375fca5905a5b999e0fe62d008f9d41.zip org.eclipse.koneki.ldt-df6dc1287375fca5905a5b999e0fe62d008f9d41.tar.gz org.eclipse.koneki.ldt-df6dc1287375fca5905a5b999e0fe62d008f9d41.tar.bz2 | |
Bug 398531 : Fixed error with LuaJIT 2.0 without 5.2 compatibility
Current debugging logic was based on the assumption that
coroutine.running()
can return main thread, which is the case only when LuaJIT is compiled
with LUAJIT_ENABLE_LUA52COMPAT. Now the debugger can be started on the
top of user code, just like with regular 5.1 (with some modifications
due
to different tail call handling)
| -rw-r--r-- | libraries/luadbgpclient/debugger/init.lua | 36 | ||||
| -rw-r--r-- | libraries/luadbgpclient/debugger/platform.lua | 2 | ||||
| -rw-r--r-- | libraries/luadbgpclient/debugger/util.lua | 72 |
3 files changed, 66 insertions, 44 deletions
diff --git a/libraries/luadbgpclient/debugger/init.lua b/libraries/luadbgpclient/debugger/init.lua index a228045..2f4530b 100644 --- a/libraries/luadbgpclient/debugger/init.lua +++ b/libraries/luadbgpclient/debugger/init.lua @@ -412,7 +412,7 @@ end if jit then debugger_hook = function(event, line) - local thread = corunning() + local thread = corunning() or "main" if event == "call" then if debug.getinfo(2, "S").what == "C" then return end stack_levels[thread] = stack_levels[thread] + 1 @@ -425,7 +425,12 @@ if jit then stack_levels[thread] = depth - 2 elseif event == "line" then active_session.coro = util.CurrentThread(corunning()) - assert(coresume(line_hook_coro, line)) + if active_session.coro[1] == "main" then + line_hook(line) + else + -- run the debugger loop in another thread on the other cases (simplifies stack handling) + assert(coresume(line_hook_coro, line)) + end active_session.coro = nil end end @@ -436,22 +441,22 @@ local function init(host, port, idekey, transport, executionplatform, workingdir local host = host or os.getenv "DBGP_IDEHOST" or "127.0.0.1" local port = port or os.getenv "DBGP_IDEPORT" or "10000" local idekey = idekey or os.getenv("DBGP_IDEKEY") or "luaidekey" - + -- init plaform module local executionplatform = executionplatform or os.getenv("DBGP_PLATFORM") or nil local workingdirectory = workingdirectory or os.getenv("DBGP_WORKINGDIR") or nil platform.init(executionplatform,workingdirectory) - + -- get transport layer local transportpath = transport or os.getenv("DBGP_TRANSPORT") or "debugger.transport.luasocket" local transport = require(transportpath) - + -- install base64 functions into util util.b64, util.rawb64, util.unb64 = transport.b64, transport.rawb64, transport.unb64 - + local skt = assert(transport.create()) skt:settimeout(nil) - + -- try to connect several times: if IDE launches both process and server at same time, first connect attempts may fail local ok, err for i=1, 5 do @@ -460,11 +465,11 @@ local function init(host, port, idekey, transport, executionplatform, workingdir transport.sleep(0.5) end if err then error(string.format("Cannot connect to %s:%d : %s", host, port, err)) end - + -- get the debugger and transport layer URI debugger_uri = platform.get_uri(debug.getinfo(1).source) transportmodule_uri = platform.get_uri(debug.getinfo(transport.create).source) - + -- get the root script path (the highest possible stack index) local source for i=2, math.huge do @@ -473,14 +478,14 @@ local function init(host, port, idekey, transport, executionplatform, workingdir source = platform.get_uri(info.source) or source end if not source then source = "unknown:/" end -- when loaded before actual script (with a command line switch) - + -- generate some kind of thread identifier local thread = corunning() or "main" stack_levels[thread] = 1 -- the return event will set the counter to 0 local sessionid = tostring(os.time()) .. "_" .. tostring(thread) - + dbgp.send_xml(skt, { tag = "init", attr = { - appid = "Lua DBGp", + appid = "Lua DBGp", idekey = idekey, session = sessionid, thread = tostring(thread), @@ -489,14 +494,15 @@ local function init(host, port, idekey, transport, executionplatform, workingdir protocol_version = "1.0", fileuri = source } }) - + + --FIXME util.CurrentThread(corunning) => util.CurrentThread(corunning()) WHAT DOES IT FIXES ?? local sess = { skt = skt, state = "starting", id = sessionid, coro = util.CurrentThread(corunning) } active_session = sess debugger_loop(sess) - + -- set debug hooks debug.sethook(debugger_hook, "rlc") - + -- install coroutine collecting functions. -- TODO: maintain a list of *all* coroutines can be overkill (for example, the ones created by copcall), make a extension point to -- customize debugged coroutines diff --git a/libraries/luadbgpclient/debugger/platform.lua b/libraries/luadbgpclient/debugger/platform.lua index c0035f4..7a1cb4e 100644 --- a/libraries/luadbgpclient/debugger/platform.lua +++ b/libraries/luadbgpclient/debugger/platform.lua @@ -148,7 +148,7 @@ function M.init(executionplatform,workingdirectory) return false end - status, iswin = pcall(iswindows) + local status, iswin = pcall(iswindows) if status and iswin then platform = "win" else diff --git a/libraries/luadbgpclient/debugger/util.lua b/libraries/luadbgpclient/debugger/util.lua index abc52e5..f7cdaa3 100644 --- a/libraries/luadbgpclient/debugger/util.lua +++ b/libraries/luadbgpclient/debugger/util.lua @@ -87,41 +87,57 @@ local CurrentThreadMT = { CurrentThreadMT.__index = CurrentThreadMT function M.CurrentThread(coro) return setmetatable({ coro }, CurrentThreadMT) end --- Fallback method to inspect running thread (only for main thread in 5.1 or for conditional breakpoints) ---- Gets a script stack level with additional debugger logic added --- @param l (number) stack level to get for debugged script (0 based) --- @return real Lua stack level suitable to be passed through deubg functions -local function get_script_level(l) - local hook = debug.gethook() - for i=2, math.huge do - if assert(debug.getinfo(i, "f")).func == hook then - return i + l -- the script to level is just below, but because of the extra call to this function, the level is ok for callee - end - end -end -M.MainThread = { - [1] = "main", -- as the raw thread object is used as table keys, provide a replacement. - getinfo = function(self, level, what) return getinfo(get_script_level(level), what:gsub("t", "", 1)) end, - getlocal = function(self, level, idx) return getlocal(get_script_level(level), idx) end, - setlocal = function(self, level, idx, val) return setlocal(get_script_level(level), idx, val) end, -} -- Some version dependant functions if _VERSION == "Lua 5.1" then - local loadstring, getfenv, setfenv, debug_getinfo = loadstring, getfenv, setfenv, debug.getinfo - + local loadstring, getfenv, setfenv, debug_getinfo, MainThread = + loadstring, getfenv, setfenv, debug.getinfo, nil + -- in 5.1 "t" flag does not exist and trigger an error so remove it from what CurrentThreadMT.getinfo = function(self, level, what) return getinfo(self[1], level + 2, what:gsub("t", "", 1)) end ForeignThreadMT.getinfo = function(self, level, what) return getinfo(self[1], level, what:gsub("t", "", 1)) end - - -- If the VM is vanilla Lua 5.1, there is no way to get a reference to the main coroutine, so fall back to direct mode: - -- the debugger loop is started on the top of main thread and the actual level is recomputed each time - if not jit then - -- allow CurrentThread to take a nil parameter - local oldCurrentThread = M.CurrentThread - M.CurrentThread = function(coro) return coro and oldCurrentThread(coro) or M.MainThread end + + -- when we're forced to start debug loop on top of program stack (when on main coroutine) + -- this requires some hackery to get right stack level + + -- Fallback method to inspect running thread (only for main thread in 5.1 or for conditional breakpoints) + --- Gets a script stack level with additional debugger logic added + -- @param l (number) stack level to get for debugged script (0 based) + -- @return real Lua stack level suitable to be passed through deubg functions + local function get_script_level(l) + local hook = debug.gethook() + for i=2, math.huge do + if assert(debug.getinfo(i, "f")).func == hook then + return i + l -- the script to level is just below, but because of the extra call to this function, the level is ok for callee + end + end end - + + if jit then + MainThread = { + [1] = "main", -- as the raw thread object is used as table keys, provide a replacement. + -- LuaJIT completely eliminates tail calls from stack, so get_script_level retunrs wrong result in this case + getinfo = function(self, level, what) return getinfo(get_script_level(level) - 1, what:gsub("t", "", 1)) end, + getlocal = function(self, level, idx) return getlocal(get_script_level(level) - 1, idx) end, + setlocal = function(self, level, idx, val) return setlocal(get_script_level(level) - 1, idx, val) end, + } + else + MainThread = { + [1] = "main", + getinfo = function(self, level, what) return getinfo(get_script_level(level) , what:gsub("t", "", 1)) end, + getlocal = function(self, level, idx) return getlocal(get_script_level(level), idx) end, + setlocal = function(self, level, idx, val) return setlocal(get_script_level(level), idx, val) end, + } + end + + + + -- If the VM is vanilla Lua 5.1 or LuaJIT 2 without 5.2 compatibility, there is no way to get a reference to + -- the main coroutine, so fall back to direct mode: the debugger loop is started on the top of main thread + -- and the actual level is recomputed each time + local oldCurrentThread = M.CurrentThread + M.CurrentThread = function(coro) return coro and oldCurrentThread(coro) or MainThread end + -- load a piece of code alog with its environment function M.loadin(code, env) local f = loadstring(code) |

