[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: RE: Lua Digest, Vol 110, Issue 4
- From: "Dan Posluns" <dposluns@...>
- Date: Wed, 9 Jul 2008 10:23:57 -0700
> > I examined the code of lbci and used it to make my own static
analysis
> > routine. The requirements for getting all of the line numbers and
> > matching them to names of functions are non-trivial, but it works!
>
> Could you share your code if it only uses the lbci api?
>
> > The only thing I don't like about this is that it's tied to the
private
> > interface of Lua, ie. it is version-dependent and needs access to
the
> > complete Lua source in order to build. But things could be worse.
>
> Well, I can promise to keep lbci updated if there's enough interest.
I can share the code, but it's very task-specific and it needs some
extraction from its environment. It doesn't actually use the lbci API;
it just uses the techniques demonstrated in it.
My goal is to create a mapping of valid lines in a source file to a
structure of meta-information (currently only containing a pointer to a
function name). I can then query this map for the nearest valid line of
source to any arbitrary line supplied by the user by calling
lower_bound().
// Header-materials
#include <map>
struct LineMeta
{
const char *functionName;
};
struct SourceMeta
{
typedef std::map<int, LineMeta> LineMap;
LineMap lineMapping;
};
extern SourceMeta GetSourceMeta(lua_State *L, int stack);
// Implementation details
extern "C"
{
#include "lua.h"
#include "ldebug.h"
#include "lobject.h"
#include "lopcodes.h"
}
typedef std::map<int, const char *> FunctionNameMap;
static void RecurseOnPrototype(Proto *p, SourceMeta::LineMap *m,
FunctionNameMap *fnm)
{
int lastLine = 0;
// Iterate over the opcodes/set of valid lines
for (int i = 0; i < p->sizelineinfo; i++)
{
OpCode o = GET_OPCODE(p->code[i]);
int thisLine = p->lineinfo[i];
if (o == OP_SETGLOBAL)
{
// Store that this line possibly indicates the
start of a function definition
(*fnm)[thisLine] =
getstr(tsvalue(&p->k[GETARG_Bx(p->code[i])]));
}
if (lastLine == thisLine)
{
// We've visited this line already in a previous
opcode
continue;
}
// This is a new, valid line of source so create an
entry for it.
// Check to see if the linedefined field matches up to a
global name we've stored off.
LineMeta lm;
FunctionNameMap::iterator itr =
fnm->find(p->linedefined);
lm.functionName = (itr == fnm->end()) ? NULL :
itr->second;
m->insert(make_pair(thisLine, lm));
lastLine = thisLine; // This is the new most-recently
visited line
}
// Process any sub-functions in this definition
for (int i = 0; i < p->sizep; i++)
{
RecurseOnPrototype(p->p[i], m, fnm);
}
}
SourceMeta GetSourceMeta(lua_State *L, int stack)
{
Proto *p = ((Closure *)lua_topointer(L,
stack))->l.p;
FunctionNameMap fnm;
SourceMeta result;
RecurseOnPrototype(p, &result.lineMapping, &fnm);
return result;
}
If you call GetSourceMeta() with your Lua code loaded onto the stack
(eg. by calling luaL_loadbuffer) then it returns the complete mapping of
valid lines to function names.
Dan.