tracing Lua API calls

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

tracing Lua API calls

Luiz Henrique de Figueiredo
Lua API errors are hard to find without a debugger.
Here is something that might help. I'm posting this to ask people whether this
is useful and if so how it can be improved.
If you find it useful, I'll probably write a LTN about this.
 
The Lua program at the end of the message reads lua.h and outputs two files,
t.c and t.h.
The file t.c contains a set of wrappers to the API.  Here is a typical wrapper:
 
  int Lua_callfunction (lua_Object f,
          const char* _FILE, int _LINE, const char* _FUNC) {
   int rc;
   Lua_tracein("lua_callfunction",_FILE,_LINE,_FUNC);
   rc=lua_callfunction(f);
   Lua_traceout("lua_callfunction",_FILE,_LINE,_FUNC);
   return rc;
  }
 
The file t.h redefines all calls to the official API to go through the wrapper.
Here is the entry for lua_callfunction in t.h:
 
  int Lua_callfunction (lua_Object f,
          const char* _FILE, int _LINE, const char* _FUNC);
 
  #define lua_callfunction(f) \
          Lua_callfunction(f,__FILE__,__LINE__,__FUNCTION__)
 
If you're not using gcc, then do
 
  #ifndef  __GNUC__
  #define __FUNCTION__ ""
  #endif
 
or change the Lua program below.
 
You have to write your own Lua_tracein and Lua_traceout.
Here is a simple implementation, which generates a lot of output.
 
  void Lua_tracein(char* func, char* file, int line, char* parent)
  {
   fprintf(stderr,"lua_trace: { %s:%d [%s] %s\n",file,line,parent,func);
  }
 
  void Lua_traceout(char* func, char* file, int line, char* parent)
  {
   fprintf(stderr,"lua_trace: } %s:%d [%s] %s\n",file,line,parent,func);
  }
 
Another possibility would be to save the args to Lua_tracein into static 
variables that are output when an error happens. You can do this by registering
a function with atexit.
 
Comments welcome.
--lhf

-- make APi wrappers: lua thisfile.lua <lua.h

$debug

function bodyC(l,t,f,p,a,A)
 write(t," Lua_",f," (",p,A,") {\n")
 if t~="void" then write(" ",t," rc;\n") end
 write(" Lua_tracein(\"lua_",f,"\",_FILE,_LINE,_FUNC);\n")
 if t~="void" then write(" rc=") else write(" ") end
 write("lua_",f,"(",a,");\n")
 write(" Lua_traceout(\"lua_",f,"\",_FILE,_LINE,_FUNC);\n")
 if t~="void" then write(" return rc;\n") end
 write("}\n\n")
end

function bodyH(l,t,f,p,a,A)
 write(t," Lua_",f," (",p,A,");\n\n")
 A="__FILE__,__LINE__,__FUNCTION__"
 if p~="" then A=","..A end
 write("#define\tlua_",f,"(",a,") \\\n\tLua_",f,"(",a,A,")\n\n\n")
end

function header(o,e,v)
 _OUTPUT=o
 write("/* luatrace.",e," -- automatically extracted from lua.h (",v,") */\n\n")
end

function body(l)
 l=gsub(l,"[\n\t ]+"," ")
 l=gsub(l," %*","* ")
 local a,b,t,f,p=strfind(l,"(.*) lua_(%w+) %((.*)%)")
 if a==nil or f=="newstate" then return end
 A="const char* _FILE, int _LINE, const char* _FUNC"
 if p=="void" then
  p=""
  a=""
 else
  a=gsub(p..",","%s*.-%s*(%w+),","%1,")
  a=gsub(a,",$","")
  A=",\n\t"..A
 end
 _OUTPUT=C_OUT bodyC(l,t,f,p,a,A)
 _OUTPUT=H_OUT bodyH(l,t,f,p,a,A)
end

C_OUT=openfile("t.c","w")
H_OUT=openfile("t.h","w")
local T=read"*a"
local _,_,v=strfind(T,'LUA_VERSION.-"Lua.- (.-)"')
header(C_OUT,"c",v)
header(H_OUT,"h",v)
gsub(T,'\n([^\n]-%b());',body)

Reply | Threaded
Open this post in threaded view
|

Re: tracing Lua API calls

Erik Hougaard
Luiz Henrique de Figueiredo wrote:
> 
> Lua API errors are hard to find without a debugger.
> Here is something that might help. I'm posting this to ask people whether this
> is useful and if so how it can be improved.
> If you find it useful, I'll probably write a LTN about this.

Looks very nice, what about showing stack before (Parameters) and after
(Return values) to give more information about the actual call ?

/Erik

Reply | Threaded
Open this post in threaded view
|

RE: tracing Lua API calls

Vincent Penquerc'h-2
In reply to this post by Luiz Henrique de Figueiredo
Luiz Henrique de Figueiredo wrote:
> Lua API errors are hard to find without a debugger.

It is nice indeed to have information on the higher levels
of calls from C.
I'd like to take this occasion to point out that, in my own
experience, some of the most troublesome errors are typos in
identifiers. Since Lua is interpreted, compiling a program
does not ensure all routines it will call are defined. This
is a Good Thing, as it allows a C program to register some
routines to be called by Lua afterwards.
Nonetheless, it would be nice to have some sort of bugtracking
program which would try to detect those typos. For the moment,
I'm using a plain and simple identifier filter, which scans
a Lua for them, and then pipes with sort and uniq. This is
error prone though. I don't see a way this could be done
automatically though...
Just a thought

-- 
Vincent Penquerc'h

Reply | Threaded
Open this post in threaded view
|

RE: tracing Lua API calls

Luiz Henrique de Figueiredo
In reply to this post by Luiz Henrique de Figueiredo
>From: "Vincent Penquerc'h" <[hidden email]>

>I'd like to take this occasion to point out that, in my own
>experience, some of the most troublesome errors are typos in
>identifiers. Since Lua is interpreted, compiling a program
>does not ensure all routines it will call are defined.

This issue has been discussed before.
Look for $global or something like that in the archives.

>Nonetheless, it would be nice to have some sort of bugtracking
>program which would try to detect those typos.

The "getglobal" tag method is useful for this.
See the FAQ 3.1: http://www.tecgraf.puc-rio.br/lua/faq.html#3.1

>For the moment,
>I'm using a plain and simple identifier filter, which scans
>a Lua for them, and then pipes with sort and uniq. This is
>error prone though. I don't see a way this could be done
>automatically though...

See lua/test/globals.lua.
--lhf

Reply | Threaded
Open this post in threaded view
|

RE: tracing Lua API calls

Russell Y. Webb
In reply to this post by Vincent Penquerc'h-2
> I'd like to take this occasion to point out that, in my own
> experience, some of the most troublesome errors are typos in
> identifiers. 

Right.  Typos leada to all kinds of spooky things in Lua like not finding 
functions and defining new global variables.

Extremely dynamic languages are just hard to define and use for large 
projects.  Having some sort of typo checking facility woudl help.  I 
suppose one could build-in some kind of token checking as you describe 
which would warn you it two tokens in your source were almost the same, 
but then I guess 'x' and 'c' would be almost the same.

Russ

Reply | Threaded
Open this post in threaded view
|

RE: tracing Lua API calls

Vincent Penquerc'h-2
In reply to this post by Luiz Henrique de Figueiredo
> >Nonetheless, it would be nice to have some sort of bugtracking
> >program which would try to detect those typos.
> 
> The "getglobal" tag method is useful for this.
> See the FAQ 3.1: http://www.tecgraf.puc-rio.br/lua/faq.html#3.1

Yes, but I meant at precompile time. Anyway, that's no big deal...

> >For the moment,
> >I'm using a plain and simple identifier filter, which scans
> >a Lua for them, and then pipes with sort and uniq. This is
> >error prone though. I don't see a way this could be done
> >automatically though...
> 
> See lua/test/globals.lua.

Oh, yes. Ahem, I must confess, that, er... I was using 3.1 :)
I was waiting for 3.3 to upgrade, since I'd have the use for
multiple states....
Sorry

-- 
Vincent Penquerc'h