new interface for debug hooks

This commit is contained in:
Roberto Ierusalimschy 2002-07-08 15:21:33 -03:00
parent d2d24f0971
commit 39b2d58c39
10 changed files with 165 additions and 129 deletions

View file

@ -1,5 +1,5 @@
/*
** $Id: ldblib.c,v 1.60 2002/06/18 17:42:52 roberto Exp roberto $
** $Id: ldblib.c,v 1.61 2002/06/25 19:16:44 roberto Exp roberto $
** Interface from Lua to its debug API
** See Copyright Notice in lua.h
*/
@ -108,65 +108,70 @@ static int setlocal (lua_State *L) {
static const char KEY_CALLHOOK = 'c';
static const char KEY_LINEHOOK = 'l';
static const char KEY_HOOK = 'h';
static void hookf (lua_State *L, void *key) {
lua_pushudataval(L, key);
static void hookf (lua_State *L, lua_Debug *ar) {
static const char *const hooknames[] = {"call", "return", "line", "count"};
lua_pushudataval(L, (void *)&KEY_HOOK);
lua_rawget(L, LUA_REGISTRYINDEX);
if (lua_isfunction(L, -1)) {
lua_pushvalue(L, -2); /* original argument (below function) */
lua_call(L, 1, 0);
lua_pushstring(L, hooknames[(int)ar->event]);
if (ar->currentline >= 0) lua_pushnumber(L, ar->currentline);
else lua_pushnil(L);
lua_assert(lua_getinfo(L, "lS", ar));
lua_call(L, 2, 0);
}
else
lua_pop(L, 1); /* pop result from gettable */
}
static void callf (lua_State *L, lua_Debug *ar) {
lua_pushstring(L, ar->event);
lua_assert(lua_getinfo(L, "lS", ar) && ar->currentline == -1);
hookf(L, (void *)&KEY_CALLHOOK);
static int makemask (const char *smask, int count) {
int mask = 0;
if (strchr(smask, 'c')) mask |= LUA_MASKCALL;
if (strchr(smask, 'r')) mask |= LUA_MASKRET;
if (strchr(smask, 'l')) mask |= LUA_MASKLINE;
return mask | lua_maskcount(count);
}
static void linef (lua_State *L, lua_Debug *ar) {
lua_pushnumber(L, ar->currentline);
lua_assert((ar->currentline = ar->linedefined = -1,
lua_getinfo(L, "lS", ar) &&
ar->currentline == lua_tonumber(L, -1) &&
ar->linedefined >= 0));
hookf(L, (void *)&KEY_LINEHOOK);
static char *unmakemask (int mask, char *smask) {
int i = 0;
if (mask & LUA_MASKCALL) smask[i++] = 'c';
if (mask & LUA_MASKRET) smask[i++] = 'r';
if (mask & LUA_MASKLINE) smask[i++] = 'l';
smask[i] = '\0';
return smask;
}
static void sethook (lua_State *L, void *key, lua_Hook hook,
lua_Hook (*sethookf)(lua_State * L, lua_Hook h)) {
lua_settop(L, 1);
if (lua_isnoneornil(L, 1))
(*sethookf)(L, NULL);
else if (lua_isfunction(L, 1))
(*sethookf)(L, hook);
else
luaL_argerror(L, 1, "function expected");
lua_pushudataval(L, key);
lua_rawget(L, LUA_REGISTRYINDEX); /* get old value */
lua_pushudataval(L, key);
static int sethook (lua_State *L) {
if (lua_isnoneornil(L, 1)) {
lua_settop(L, 1);
lua_sethook(L, NULL, 0); /* turn off hooks */
}
else {
const char *smask = luaL_check_string(L, 2);
int count = luaL_opt_int(L, 3, 0);
luaL_check_type(L, 1, LUA_TFUNCTION);
lua_sethook(L, hookf, makemask(smask, count));
}
lua_pushudataval(L, (void *)&KEY_HOOK);
lua_pushvalue(L, 1);
lua_rawset(L, LUA_REGISTRYINDEX); /* set new value */
lua_rawset(L, LUA_REGISTRYINDEX); /* set new hook */
return 0;
}
static int setcallhook (lua_State *L) {
sethook(L, (void *)&KEY_CALLHOOK, callf, lua_setcallhook);
return 1;
}
static int setlinehook (lua_State *L) {
sethook(L, (void *)&KEY_LINEHOOK, linef, lua_setlinehook);
return 1;
static int gethook (lua_State *L) {
char buff[5];
int mask = lua_gethookmask(L);
lua_pushudataval(L, (void *)&KEY_HOOK);
lua_rawget(L, LUA_REGISTRYINDEX); /* get hook */
lua_pushstring(L, unmakemask(mask, buff));
lua_pushnumber(L, lua_getmaskcount(mask));
return 3;
}
@ -245,8 +250,8 @@ static int errorfb (lua_State *L) {
static const luaL_reg dblib[] = {
{"getlocal", getlocal},
{"getinfo", getinfo},
{"setcallhook", setcallhook},
{"setlinehook", setlinehook},
{"gethook", gethook},
{"sethook", sethook},
{"setlocal", setlocal},
{"debug", debug},
{"traceback", errorfb},

View file

@ -1,5 +1,5 @@
/*
** $Id: ldebug.c,v 1.122 2002/06/20 20:39:44 roberto Exp roberto $
** $Id: ldebug.c,v 1.123 2002/06/24 15:07:21 roberto Exp roberto $
** Debug Interface
** See Copyright Notice in lua.h
*/
@ -53,26 +53,31 @@ static int currentline (lua_State *L, CallInfo *ci) {
}
LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func) {
lua_Hook oldhook;
lua_lock(L);
oldhook = L->callhook;
L->callhook = func;
lua_unlock(L);
return oldhook;
}
LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func) {
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask) {
CallInfo *ci;
lua_Hook oldhook;
int allow;
lua_lock(L);
oldhook = L->linehook;
L->linehook = func;
allow = allowhook(L);
if (func == NULL) mask = 0;
else if (mask == 0) func = NULL;
L->hook = func;
L->hookmask = mask;
setallowhook(L, allow);
resethookcount(L);
for (ci = L->base_ci; ci <= L->ci; ci++)
currentpc(L, ci); /* update `savedpc' */
lua_unlock(L);
return oldhook;
return 1;
}
LUA_API lua_Hook lua_gethook (lua_State *L) {
return L->hook;
}
LUA_API int lua_gethookmask (lua_State *L) {
return L->hookmask;
}
@ -396,6 +401,10 @@ static Instruction luaG_symbexec (const Proto *pt, int lastpc, int reg) {
return pt->code[last];
}
#undef check
#undef checkjump
#undef checkreg
/* }====================================================== */

View file

@ -1,5 +1,5 @@
/*
** $Id: ldebug.h,v 1.22 2002/06/18 15:19:27 roberto Exp roberto $
** $Id: ldebug.h,v 1.23 2002/06/24 15:07:21 roberto Exp roberto $
** Auxiliary functions from Debug Interface module
** See Copyright Notice in lua.h
*/
@ -16,6 +16,13 @@
#define getline(f,pc) (((f)->lineinfo) ? (f)->lineinfo[pc] : 0)
#define resethookcount(L) \
(L->hookcount = (1 << lua_getmaskcount(L->hookmask)) >> 1)
#define setallowhook(L,cond) ((L->hookmask) = ((L->hookmask) & ~1) | (cond))
#define allowhook(L) ((L->hookmask) & 1)
void luaG_typeerror (lua_State *L, const TObject *o, const char *opname);
void luaG_concaterror (lua_State *L, StkId p1, StkId p2);
void luaG_aritherror (lua_State *L, StkId p1, const TObject *p2);

67
ldo.c
View file

@ -1,5 +1,5 @@
/*
** $Id: ldo.c,v 1.184 2002/06/26 16:37:23 roberto Exp roberto $
** $Id: ldo.c,v 1.185 2002/07/04 12:29:32 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@ -135,40 +135,29 @@ static void luaD_openstack (lua_State *L, StkId pos) {
}
static void dohook (lua_State *L, lua_Debug *ar, lua_Hook hook) {
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, L->ci->top);
ar->i_ci = L->ci - L->base_ci;
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
L->ci->top = L->top + LUA_MINSTACK;
L->allowhooks = 0; /* cannot call hooks inside a hook */
lua_unlock(L);
(*hook)(L, ar);
lua_lock(L);
lua_assert(L->allowhooks == 0);
L->allowhooks = 1;
L->ci->top = restorestack(L, ci_top);
L->top = restorestack(L, top);
}
void luaD_lineHook (lua_State *L, int line) {
if (L->allowhooks) {
lua_Debug ar;
ar.event = "line";
ar.currentline = line;
dohook(L, &ar, L->linehook);
}
}
static void luaD_callHook (lua_State *L, lua_Hook callhook, const char *event) {
if (L->allowhooks) {
void luaD_callhook (lua_State *L, lua_Hookevent event, int line) {
lua_Hook hook = L->hook;
if (hook && allowhook(L)) {
ptrdiff_t top = savestack(L, L->top);
ptrdiff_t ci_top = savestack(L, L->ci->top);
lua_Debug ar;
ar.event = event;
L->ci->pc = NULL; /* function is not active */
L->ci->top = L->ci->base; /* `top' may not have a valid value yet */
dohook(L, &ar, callhook);
ar.currentline = line;
ar.i_ci = L->ci - L->base_ci;
if (event <= LUA_HOOKRET) { /* `call' or `return' event? */
L->ci->pc = NULL; /* function is not active */
L->ci->top = L->ci->base; /* `top' may not have a valid value yet */
}
luaD_checkstack(L, LUA_MINSTACK); /* ensure minimum stack size */
L->ci->top = L->top + LUA_MINSTACK;
setallowhook(L, 0); /* cannot call hooks inside a hook */
lua_unlock(L);
(*hook)(L, &ar);
lua_lock(L);
lua_assert(!allowhook(L));
setallowhook(L, 1);
L->ci->top = restorestack(L, ci_top);
L->top = restorestack(L, top);
}
}
@ -219,8 +208,8 @@ StkId luaD_precall (lua_State *L, StkId func) {
if (ttype(func) != LUA_TFUNCTION) /* `func' is not a function? */
func = tryfuncTM(L, func); /* check the `function' tag method */
cl = &clvalue(func)->l;
if (L->callhook) {
luaD_callHook(L, L->callhook, "call");
if (L->hookmask & LUA_MASKCALL) {
luaD_callhook(L, LUA_HOOKCALL, -1);
ci = L->ci; /* previous call may realocate `ci' */
}
if (!cl->isC) { /* Lua function? prepare its call */
@ -252,9 +241,9 @@ StkId luaD_precall (lua_State *L, StkId func) {
void luaD_poscall (lua_State *L, int wanted, StkId firstResult) {
StkId res;
if (L->callhook) {
if (L->hookmask & LUA_MASKRET) {
ptrdiff_t fr = savestack(L, firstResult); /* next call may change stack */
luaD_callHook(L, L->callhook, "return");
luaD_callhook(L, LUA_HOOKRET, -1);
firstResult = restorestack(L, fr);
}
res = L->ci->base - 1; /* res == final position of 1st result */
@ -483,7 +472,7 @@ int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud) {
struct lua_longjmp lj;
lj.ci = L->ci;
lj.top = L->top;
lj.allowhooks = L->allowhooks;
lj.allowhooks = allowhook(L);
lj.status = 0;
lj.err = ud;
lj.previous = L->errorJmp; /* chain new error handler */
@ -493,7 +482,7 @@ int luaD_runprotected (lua_State *L, Pfunc f, TObject *ud) {
else { /* an error occurred */
L->ci = lj.ci; /* restore the state */
L->top = lj.top;
L->allowhooks = lj.allowhooks;
setallowhook(L, lj.allowhooks);
restore_stack_limit(L);
}
L->errorJmp = lj.previous; /* restore old error handler */

4
ldo.h
View file

@ -1,5 +1,5 @@
/*
** $Id: ldo.h,v 1.46 2002/06/18 15:19:27 roberto Exp roberto $
** $Id: ldo.h,v 1.47 2002/06/18 17:10:43 roberto Exp roberto $
** Stack and Call structure of Lua
** See Copyright Notice in lua.h
*/
@ -32,7 +32,7 @@
typedef void (*Pfunc) (lua_State *L, void *v);
int luaD_protectedparser (lua_State *L, ZIO *z, int bin);
void luaD_lineHook (lua_State *L, int line);
void luaD_callhook (lua_State *L, lua_Hookevent event, int line);
StkId luaD_precall (lua_State *L, StkId func);
void luaD_call (lua_State *L, StkId func, int nResults);
int luaD_pcall (lua_State *L, int nargs, int nresults);

8
lgc.c
View file

@ -1,5 +1,5 @@
/*
** $Id: lgc.c,v 1.140 2002/07/01 17:06:58 roberto Exp roberto $
** $Id: lgc.c,v 1.141 2002/07/04 17:57:42 roberto Exp $
** Garbage Collector
** See Copyright Notice in lua.h
*/
@ -451,8 +451,8 @@ static void do1gcTM (lua_State *L, Udata *udata) {
static void callGCTM (lua_State *L) {
int oldah = L->allowhooks;
L->allowhooks = 0; /* stop debug hooks during GC tag methods */
int oldah = allowhook(L);
setallowhook(L, 0); /* stop debug hooks during GC tag methods */
L->top++; /* reserve space to keep udata while runs its gc method */
while (G(L)->tmudata != NULL) {
Udata *udata = G(L)->tmudata;
@ -465,7 +465,7 @@ static void callGCTM (lua_State *L) {
do1gcTM(L, udata);
}
L->top--;
L->allowhooks = oldah; /* restore hooks */
setallowhook(L, oldah); /* restore hooks */
}

View file

@ -1,5 +1,5 @@
/*
** $Id: lstate.c,v 1.96 2002/06/06 18:17:33 roberto Exp roberto $
** $Id: lstate.c,v 1.97 2002/06/18 15:19:27 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@ -92,12 +92,13 @@ static void preinit_state (lua_State *L) {
L->stack = NULL;
L->stacksize = 0;
L->errorJmp = NULL;
L->callhook = NULL;
L->linehook = NULL;
L->hook = NULL;
L->hookmask = 0;
setallowhook(L, 1);
resethookcount(L);
L->openupval = NULL;
L->size_ci = 0;
L->base_ci = NULL;
L->allowhooks = 1;
}

View file

@ -1,5 +1,5 @@
/*
** $Id: lstate.h,v 1.85 2002/05/08 17:34:23 roberto Exp roberto $
** $Id: lstate.h,v 1.86 2002/07/02 16:43:28 roberto Exp roberto $
** Global State
** See Copyright Notice in lua.h
*/
@ -130,8 +130,9 @@ struct lua_State {
CallInfo *end_ci; /* points after end of ci array*/
CallInfo *base_ci; /* array of CallInfo's */
global_State *l_G;
lua_Hook linehook;
lua_Hook callhook;
int hookmask;
int hookcount;
lua_Hook hook;
TObject globs[NUMGLOBS]; /* registry, table of globals, etc. */
struct lua_longjmp *errorJmp; /* current error recover point */
UpVal *openupval; /* list of open upvalues in this stack */
@ -139,7 +140,6 @@ struct lua_State {
lua_State *previous;
int stacksize;
int size_ci; /* size of array `base_ci' */
int allowhooks;
};

View file

@ -1,5 +1,5 @@
/*
** $Id: luadebug.h,v 1.27 2002/04/04 17:21:31 roberto Exp roberto $
** $Id: luadebug.h,v 1.28 2002/06/18 17:10:43 roberto Exp roberto $
** Debugging API
** See Copyright Notice in lua.h
*/
@ -11,6 +11,18 @@
#include "lua.h"
typedef enum lua_Hookevent {
LUA_HOOKCALL, LUA_HOOKRET, LUA_HOOKLINE, LUA_HOOKCOUNT
} lua_Hookevent;
#define LUA_MASKCALL (2 << LUA_HOOKCALL)
#define LUA_MASKRET (2 << LUA_HOOKRET)
#define LUA_MASKLINE (2 << LUA_HOOKLINE)
#define lua_maskcount(count) ((count) << (LUA_HOOKCOUNT+1))
#define lua_getmaskcount(mask) ((mask) >> (LUA_HOOKCOUNT+1))
#define LUA_MASKCOUNT (lua_maskcount(1))
typedef struct lua_Debug lua_Debug; /* activation record */
typedef void (*lua_Hook) (lua_State *L, lua_Debug *ar);
@ -21,14 +33,15 @@ LUA_API int lua_getinfo (lua_State *L, const char *what, lua_Debug *ar);
LUA_API const char *lua_getlocal (lua_State *L, const lua_Debug *ar, int n);
LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n);
LUA_API lua_Hook lua_setcallhook (lua_State *L, lua_Hook func);
LUA_API lua_Hook lua_setlinehook (lua_State *L, lua_Hook func);
LUA_API int lua_sethook (lua_State *L, lua_Hook func, int mask);
LUA_API lua_Hook lua_gethook (lua_State *L);
LUA_API int lua_gethookmask (lua_State *L);
#define LUA_IDSIZE 60
struct lua_Debug {
const char *event; /* `call', `return', `line' */
lua_Hookevent event;
const char *name; /* (n) */
const char *namewhat; /* (n) `global', `local', `field', `method' */
const char *what; /* (S) `Lua' function, `C' function, Lua `main' */

38
lvm.c
View file

@ -1,5 +1,5 @@
/*
** $Id: lvm.c,v 1.243 2002/06/24 15:07:21 roberto Exp roberto $
** $Id: lvm.c,v 1.244 2002/07/05 18:27:39 roberto Exp roberto $
** Lua virtual machine
** See Copyright Notice in lua.h
*/
@ -69,17 +69,28 @@ int luaV_tostring (lua_State *L, TObject *obj) {
static void traceexec (lua_State *L) {
CallInfo *ci = L->ci;
Proto *p = ci_func(ci)->l.p;
int newline = getline(p, pcRel(*ci->pc, p));
if (pcRel(*ci->pc, p) == 0) /* tracing may be starting now? */
ci->savedpc = *ci->pc; /* initialize `savedpc' */
/* calls linehook when enters a new line or jumps back (loop) */
if (*ci->pc <= ci->savedpc || newline != getline(p, pcRel(ci->savedpc, p))) {
luaD_lineHook(L, newline);
ci = L->ci; /* previous call may reallocate `ci' */
int mask = L->hookmask;
if (mask >= LUA_MASKCOUNT) { /* instruction hook set? */
if (L->hookcount == 0) {
luaD_callhook(L, LUA_HOOKCOUNT, -1);
resethookcount(L);
return;
}
}
if (mask & LUA_MASKLINE) {
CallInfo *ci = L->ci;
Proto *p = ci_func(ci)->l.p;
int newline = getline(p, pcRel(*ci->pc, p));
if (pcRel(*ci->pc, p) == 0) /* tracing may be starting now? */
ci->savedpc = *ci->pc; /* initialize `savedpc' */
/* calls linehook when enters a new line or jumps back (loop) */
if (*ci->pc <= ci->savedpc ||
newline != getline(p, pcRel(ci->savedpc, p))) {
luaD_callhook(L, LUA_HOOKLINE, newline);
ci = L->ci; /* previous call may reallocate `ci' */
}
ci->savedpc = *ci->pc;
}
ci->savedpc = *ci->pc;
}
@ -370,8 +381,9 @@ StkId luaV_execute (lua_State *L) {
for (;;) {
const Instruction i = *pc++;
StkId ra;
if (L->linehook)
traceexec(L);
if (L->hookmask >= LUA_MASKLINE &&
(--L->hookcount == 0 || L->hookmask & LUA_MASKLINE))
traceexec(L);
ra = RA(i);
lua_assert(L->top <= L->stack + L->stacksize && L->top >= L->ci->base);
lua_assert(L->top == L->ci->top ||