Fixes to debug.sethook, debug.gethook, and debug.getinfo functions.
This commit is contained in:
@@ -168,12 +168,12 @@ public class DebugLib extends LFunction {
|
||||
threadVm = vm.checkthread(2).vm;
|
||||
vm.remove(2);
|
||||
}
|
||||
LFunction func = vm.checkfunction(2);
|
||||
LString str = vm.checklstring(3);
|
||||
LFunction func = vm.isnoneornil(2)? null: vm.checkfunction(2);
|
||||
String str = vm.optstring(3,"");
|
||||
int count = vm.optint(4,0);
|
||||
int mask = 0;
|
||||
for ( int i=0; i<str.m_length; i++ )
|
||||
switch ( str.m_bytes[str.m_offset+i] ) {
|
||||
for ( int i=0; i<str.length(); i++ )
|
||||
switch ( str.charAt(i) ) {
|
||||
case 'c': mask |= LuaState.LUA_MASKCALL; break;
|
||||
case 'l': mask |= LuaState.LUA_MASKLINE; break;
|
||||
case 'r': mask |= LuaState.LUA_MASKRET; break;
|
||||
@@ -201,14 +201,11 @@ public class DebugLib extends LFunction {
|
||||
CallInfo ci = null;
|
||||
LFunction func = null;
|
||||
LClosure closure = null;
|
||||
String what = "";
|
||||
if ( vm.gettop() >= 4 ) {
|
||||
threadVm = vm.checkthread(2).vm;
|
||||
vm.remove(2);
|
||||
}
|
||||
if ( vm.gettop() >= 3 ) {
|
||||
what = vm.tostring(3);
|
||||
}
|
||||
String what = vm.optstring(3, "nSluf");
|
||||
if ( vm.isnumber(2) ) {
|
||||
ci = this.getcallinfo(vm, threadVm, vm.tointeger(2));
|
||||
closure = ci.closure;
|
||||
@@ -223,20 +220,20 @@ public class DebugLib extends LFunction {
|
||||
for (int i = 0, n = what.length(); i < n; i++) {
|
||||
switch (what.charAt(i)) {
|
||||
case 'S': {
|
||||
info.put("source", (closure!=null? closure.p.source: new LString("@?")));
|
||||
info.put("short_src", (closure!=null? closure.p.source.substring(1, closure.p.source.m_length-1): new LString("?")));
|
||||
String s = (closure!=null? closure.p.source.toJavaString(): "=?");
|
||||
info.put("source", new LString(s.replace('@','=')));
|
||||
info.put("short_src", new LString(s.substring(1)));
|
||||
info.put("linedefined", (closure!=null? closure.p.linedefined: 0));
|
||||
info.put("lastlinedefined", (closure!=null? closure.p.lastlinedefined: 0));
|
||||
info.put("what", new LString(what));
|
||||
info.put("what", new LString("Lua"));
|
||||
break;
|
||||
}
|
||||
case 'l': {
|
||||
info.put( "currentline", (ci!=null? ci.pc: 0) );
|
||||
info.put( "currentline", currentline(threadVm, ci, func) );
|
||||
break;
|
||||
}
|
||||
case 'u': {
|
||||
info.put("nups", (closure!=null? closure.p.nups: 0));
|
||||
info.put("what", new LString(what));
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
@@ -246,22 +243,40 @@ public class DebugLib extends LFunction {
|
||||
break;
|
||||
}
|
||||
case 'f': {
|
||||
if ( func != null )
|
||||
info.put( "func", func );
|
||||
info.put( "func", closure );
|
||||
break;
|
||||
}
|
||||
case 'L': {
|
||||
LTable lines = new LTable();
|
||||
info.put("activelines", lines);
|
||||
if ( closure != null )
|
||||
for ( int j=0, k=1; j<closure.p.lineinfo.length; j++, k++ )
|
||||
lines.put(k, LInteger.valueOf(closure.p.lineinfo[j]));
|
||||
for ( int j=threadVm.cc, k=1; j>=0; --j )
|
||||
if ( threadVm.calls[j].closure == func ) {
|
||||
int line = threadVm.debugGetLineNumber(ci);
|
||||
if ( line >= 0 )
|
||||
lines.put(k++, LInteger.valueOf(line));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int currentline(LuaState vm, CallInfo ci, LFunction func) {
|
||||
if ( ci == null ) {
|
||||
ci = findcallinfo(vm, func);
|
||||
if ( ci == null )
|
||||
return -1;
|
||||
}
|
||||
return vm.debugGetLineNumber(ci);
|
||||
}
|
||||
|
||||
private CallInfo findcallinfo(LuaState vm, LFunction func) {
|
||||
for ( int i=vm.cc; i>=0; --i )
|
||||
if ( vm.calls[i].closure == func )
|
||||
return vm.calls[i];
|
||||
return null;
|
||||
}
|
||||
|
||||
private LString getlocalname (LPrototype f, int local_number, int pc) {
|
||||
int i;
|
||||
for (i = 0; i<f.locvars.length && f.locvars[i].startpc <= pc; i++) {
|
||||
@@ -423,7 +438,6 @@ public class DebugLib extends LFunction {
|
||||
LuaState threadVm = vm;
|
||||
int level = 1;
|
||||
String message = "";
|
||||
StringBuffer sb = new StringBuffer();
|
||||
if ( vm.gettop() >= 4 ) {
|
||||
threadVm = vm.checkthread(2).vm;
|
||||
vm.remove(2);
|
||||
@@ -432,8 +446,10 @@ public class DebugLib extends LFunction {
|
||||
level = vm.optint(3,1);
|
||||
if ( vm.gettop() >= 2 )
|
||||
message = vm.tostring(2)+"\n";
|
||||
message += threadVm.getStackTrace(level);
|
||||
String trace = threadVm.getStackTrace(level-1);
|
||||
if ( trace.endsWith("\n") )
|
||||
trace = trace.substring(0,trace.length()-1);
|
||||
vm.resettop();
|
||||
vm.pushstring(sb.toString());
|
||||
vm.pushstring(message+trace);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ public class LuaState extends Lua {
|
||||
private int hookcount;
|
||||
private LFunction hookfunc;
|
||||
private int hookincr;
|
||||
private int hookline;
|
||||
private int hookline,hookcc;
|
||||
|
||||
protected void debugAssert(boolean b) {}
|
||||
|
||||
@@ -714,7 +714,7 @@ public class LuaState extends Lua {
|
||||
|
||||
// call hook
|
||||
if ( hooksenabled ) {
|
||||
debugCallHooks( ci.pc-1 );
|
||||
debugCallHooks( );
|
||||
}
|
||||
|
||||
// make or set up the call
|
||||
@@ -737,7 +737,7 @@ public class LuaState extends Lua {
|
||||
case LuaState.OP_TAILCALL: {
|
||||
// return hook
|
||||
if ( hooksenabled ) {
|
||||
debugTailReturnHooks( ci.pc-1 );
|
||||
debugTailReturnHooks( );
|
||||
}
|
||||
|
||||
// close up values
|
||||
@@ -785,7 +785,7 @@ public class LuaState extends Lua {
|
||||
case LuaState.OP_RETURN: {
|
||||
// return hook
|
||||
if ( hooksenabled ) {
|
||||
debugReturnHooks( ci.pc-1 );
|
||||
debugReturnHooks( );
|
||||
}
|
||||
|
||||
// close up values
|
||||
@@ -2414,8 +2414,9 @@ public class LuaState extends Lua {
|
||||
private void debugBytecodeHooks(int pc) {
|
||||
if ( hookfunc != null && (hookmask & LUA_MASKLINE) != 0 ) {
|
||||
int line = debugGetLineNumber(calls[cc]);
|
||||
if ( line != hookline ) {
|
||||
if ( (line != hookline || cc != hookcc) && line >= 0 ) {
|
||||
hookline = line;
|
||||
hookcc = cc;
|
||||
debugCallHook(LUA_HOOKLINE, line);
|
||||
}
|
||||
if (hookcount != 0) {
|
||||
@@ -2427,52 +2428,56 @@ public class LuaState extends Lua {
|
||||
}
|
||||
}
|
||||
|
||||
private void debugCallHooks(int pc) {
|
||||
private void debugCallHooks() {
|
||||
if ( hookfunc != null && ((hookmask & LUA_MASKCALL) != 0) ) {
|
||||
debugCallHook(LUA_HOOKCALL, debugGetLineNumber(calls[cc]));
|
||||
hookline = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void debugReturnHooks(int pc) {
|
||||
private void debugReturnHooks() {
|
||||
if ( hookfunc != null && ((hookmask & LUA_MASKRET) != 0) ) {
|
||||
debugCallHook(LUA_HOOKRET, debugGetLineNumber(calls[cc]));
|
||||
hookline = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void debugTailReturnHooks(int pc) {
|
||||
private void debugTailReturnHooks() {
|
||||
if ( hookfunc != null && ((hookmask & LUA_MASKRET) != 0) ) {
|
||||
debugCallHook(LUA_HOOKTAILRET, debugGetLineNumber(calls[cc]));
|
||||
hookline = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private int debugGetLineNumber(CallInfo ci) {
|
||||
int[] lineNumbers = ci.closure.p.lineinfo;
|
||||
int pc = getCurrentPc(ci);
|
||||
int line = (lineNumbers != null && lineNumbers.length > pc ?
|
||||
lineNumbers[pc] :
|
||||
-1);
|
||||
return line;
|
||||
public int debugGetLineNumber(CallInfo ci) {
|
||||
int[] li = ci.closure.p.lineinfo;
|
||||
int pc = ci.pc - 1;
|
||||
if ( li != null && pc >= 0 && pc < li.length )
|
||||
return li[pc];
|
||||
return -1;
|
||||
}
|
||||
|
||||
private void debugCallHook(int mask, int newline) {
|
||||
private void debugCallHook(int mask, int line) {
|
||||
int prevmask = hookmask;
|
||||
int oldtop = top;
|
||||
LValue lineval = LNil.NIL;
|
||||
try {
|
||||
if ( cc >= 0 )
|
||||
top = base + this.calls[cc].closure.p.maxstacksize;
|
||||
hookmask = 0;
|
||||
this.pushfunction(hookfunc);
|
||||
switch ( mask ) {
|
||||
default: this.pushstring("line"); break;
|
||||
case LUA_HOOKCOUNT: this.pushstring("count"); break;
|
||||
case LUA_HOOKCALL: this.pushstring("call"); break;
|
||||
case LUA_HOOKRET: this.pushstring("return"); break;
|
||||
case LUA_HOOKTAILRET: this.pushstring("tail return"); break;
|
||||
case LUA_HOOKTAILRET: this.pushstring("return"); break;
|
||||
default:
|
||||
lineval = LInteger.valueOf(line);
|
||||
this.pushstring("line");
|
||||
break;
|
||||
}
|
||||
this.pushinteger(newline);
|
||||
this.pushlvalue(lineval);
|
||||
this.pcall(2, 0, 0);
|
||||
} finally {
|
||||
hookmask = prevmask;
|
||||
top = oldtop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,29 +117,32 @@ print( pcall( debug.getmetatable, 1 ) )
|
||||
-- print( pcall( debug.setmetatable, 1, {} ) )
|
||||
-- print( pcall( debug.setmetatable, 1, nil ) )
|
||||
|
||||
|
||||
--[[
|
||||
local f = function(a)
|
||||
return 'f:'..tostring(a)..'|'..tostring(b)
|
||||
print( '----- debug.getinfo' )
|
||||
local printfield = function(tbl, field)
|
||||
local x = tbl[field]
|
||||
if x == nil then return end
|
||||
local typ = type(x)
|
||||
if typ=='table' then
|
||||
x = '{'..table.concat(x,',')..'}'
|
||||
elseif typ=='function' then
|
||||
x = typ
|
||||
end
|
||||
print( ' '..field..': '..tostring(x) )
|
||||
end
|
||||
local s,e
|
||||
|
||||
|
||||
local fields = { 'source', 'short_src', 'what',
|
||||
'currentline', 'linedefined', 'lastlinedefined',
|
||||
'nups', 'func', 'activelines' }
|
||||
local printinfo = function(...)
|
||||
for i,a in ipairs(arg) do
|
||||
if type(a) == 'table' then
|
||||
print( ' source: '..tostring(a.source) )
|
||||
print( ' short_src: '..tostring(a.short_src) )
|
||||
print( ' what: '..tostring(a.what) )
|
||||
print( ' currentline: '..tostring(a.currentline) )
|
||||
print( ' linedefined: '..tostring(a.linedefined) )
|
||||
print( ' lastlinedefined: '..tostring(a.lastlinedefined) )
|
||||
for j,field in ipairs(fields) do
|
||||
printfield( a, field)
|
||||
end
|
||||
else
|
||||
print( tostring(a) )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function test()
|
||||
local x = 5
|
||||
function f()
|
||||
@@ -148,6 +151,20 @@ function test()
|
||||
end
|
||||
function g()
|
||||
x = x - 1
|
||||
print( '---' )
|
||||
printinfo( 'debug.getinfo(1)', debug.getinfo(1) )
|
||||
printinfo( 'debug.getinfo(1,"l")', debug.getinfo(1, "l") )
|
||||
printinfo( 'debug.getinfo(1,"fL")', debug.getinfo(1, "fL") )
|
||||
printinfo( 'debug.getinfo(2)', debug.getinfo(2) )
|
||||
printinfo( 'debug.getinfo(2,"l")', debug.getinfo(2, "l") )
|
||||
printinfo( 'debug.getinfo(2,"fL")', debug.getinfo(2, "fL") )
|
||||
--[[
|
||||
for i=1,3 do
|
||||
printinfo( 'debug.traceback("msg")', debug.traceback('msg') )
|
||||
printinfo( 'debug.traceback("another",'..i..')', debug.traceback('another',i) )
|
||||
end
|
||||
--]]
|
||||
print( '---' )
|
||||
return x
|
||||
end
|
||||
print(f())
|
||||
@@ -155,10 +172,53 @@ function test()
|
||||
return f, g
|
||||
end
|
||||
|
||||
local options = "nSlufL"
|
||||
local e,f,g = pcall( test )
|
||||
print( 'e,f,g', e, type(f), type(g) )
|
||||
printinfo( 'debug.getinfo(f)', pcall(debug.getinfo, f) )
|
||||
printinfo( 'debug.getinfo(f,"'..options..'")', pcall(debug.getinfo, f, options) )
|
||||
for j=1,6 do
|
||||
local opts = options:sub(j,j)
|
||||
printinfo( 'debug.getinfo(f,"'..opts..'")', pcall(debug.getinfo, f, opts) )
|
||||
end
|
||||
printinfo( 'debug.getinfo(g)', pcall(debug.getinfo, g) )
|
||||
printinfo( 'debug.getinfo(test)', pcall(debug.getinfo, test) )
|
||||
|
||||
printinfo( 'debug.getinfo(f,"Sl")', pcall(debug.getinfo, f, "Sl") )
|
||||
printinfo( 'debug.getinfo(g,"Sl")', pcall(debug.getinfo, g, "Sl") )
|
||||
printinfo( 'debug.getinfo(test,"Sl")', pcall(debug.getinfo, test, "Sl") )
|
||||
print( '----- debug.sethook, debug.gethook' )
|
||||
f = function(x)
|
||||
g = function(y)
|
||||
return math.min(x,h)
|
||||
end
|
||||
local a = g(x)
|
||||
return a + a
|
||||
end
|
||||
local hook = function(...)
|
||||
print( ' ... in hook', ... )
|
||||
end
|
||||
local tryfunc = function(hook,mask,func,arg)
|
||||
local x,f,h,m
|
||||
pcall( function()
|
||||
debug.sethook(hook,mask)
|
||||
x = func(arg)
|
||||
f,h,m = debug.gethook()
|
||||
end )
|
||||
debug.sethook()
|
||||
return x,f,h,m
|
||||
end
|
||||
|
||||
local tryhooks = function(mask)
|
||||
local s1,a1,b1,c1,d1 = pcall( tryfunc, hook, mask, f, 333 )
|
||||
print( 'hook = '..mask..' -> '..
|
||||
'result='..tostring(s1)..','..tostring(a1)..','..
|
||||
type(b1)..','..type(c1)..','..
|
||||
tostring(b1==f)..','..tostring(c1==hook)..','..
|
||||
tostring(d1)..' ' )
|
||||
end
|
||||
--[[
|
||||
tryhooks("c")
|
||||
tryhooks("r")
|
||||
tryhooks("l")
|
||||
tryhooks("crl")
|
||||
--]]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user