# Lua: More detailed error information

## Recommended Posts

Silvo    166
G'day! I was wondering whether it is possible to get more detailed error information from Lua. I am embedding Lua in my C++ application, and when something goes wrong with Lua I print the Lua error. However, if (hypothetically) my error is that I call an object's method using a dot instead of a colon (Object.Method() instead of Object:Method()), Lua says that the method is trying to access the local 'self', but can't. I would like a more detailed error message, such as from where that function was called, and if possible, from where the function that called the erroneous function was called as well (is this a call-stack? Something tells me it is). So, essentially, what I would like to know is how to get more debug information from Lua when it is embedded in an application. Thank you!

##### Share on other sites
Silvo    166
After much Googleing, I think what i need to do is use debug.traceback in lua_pcall. But how do I do that?

##### Share on other sites
Silvo    166
Well, if this can't be done, could someone tell me what kind of debugging methods they used for their program (involving Lua)?

##### Share on other sites
CmpDev    100
You really must have looked very hard for this information :)
http://www.lua.org/pil/8.5.html
Quote:
 When pcall returns its error message, it destroys part of the stack (the part that went from it to the error point). Consequently, if we want a traceback, we must build it before pcall returns. To do that, Lua provides the xpcall function. Besides the function to be called, it receives a second argument, an error handler function.

http://www.lua.org/manual/5.1/manual.html#pdf-xpcall

##### Share on other sites
Silvo    166
Thank you for that!

I am sorry, this was not clear. I was referring to the C API end of Lua, not the Lua scripts themselves (so, the C/C++ functions: lua_pcall(), etc.).

For lua_pcall (http://www.lua.org/manual/5.1/manual.html#lua_pcall), the manual says:
Quote:
 int lua_pcall (lua_State *L, int nargs, int nresults, int errfunc);Calls a function in protected mode.[...]If errfunc is 0, then the error message returned on the stack is exactly the original error message. Otherwise, errfunc is the stack index of an error handler function.[...]Typically, the error handler function is used to add more debug information to the error message, such as a stack traceback. Such information cannot be gathered after the return of lua_pcall, since by then the stack has unwound.

So, it refers to "indexing" the debug function to use (I am assuming that this would be debug.traceback()?), how can I specify this function? i.e. how do I make debug.traceback get onto the stack and find the index for it? ("errfunc is the stack index of an error handler function")

Thank you!

Silvo    166
Nobody knows?

##### Share on other sites
Zorbfish    214
lua_pcall's standard behavior when no error function is given is to call debug.traceback and leave that string on the stack. So If you are simply trying to get the stack traceback if a lua_pcall fails its as simple as this:

lua_pushcfunction(L, foo);lua_pushnumber(L, 5.3);if (lua_pcall(L, 1, 0, 0) != 0) lua_error(L);

As far as indexing is concerned it means you pass the stack position of where you pushed an error function.

/* stack the debug.traceback function */lua_getglobal(L, "debug");lua_getfield(L, -1, "traceback");lua_remove(L, -2);lua_pushcfunction(L, foo);lua_pushnumber(L, 5.3);if (lua_pcall(L, 1, 0, -3) != 0) {  /* do something */}

If the pcall fails debug.traceback (at stack pos -3) will get called. Hope that helps.

##### Share on other sites
Silvo    166
Thank you so much!

I understand what you have said (or at least I think I do), but I am unable to put it into practice.

This is the relevant code:
	luaL_loadfile(lua, name);	lua_getglobal(lua, "debug");	lua_getfield(lua, -1, "traceback");	lua_remove(lua, -2);	if (lua_pcall(lua, 0, 0, -1) != 0) {		lua_error(lua);	}

"lua" is what is normally "L" - the lua instance thingo.
"name" is the filename to execute.
What I would like it to do is to load the file, put the traceback function onto the stack and run the file. When an error occurs, it should run the traceback function. I have made some Lua code that has errors, but there is no message generated at all - not even just a simple Lua PANIC thing.

Could you please tell me what is wrong? Thank you.

##### Share on other sites
Sneftel    1788
The only real problem I can see is that you're screwing up your stack. The called function and arguments need to be at the top of the stack. The error function, if there is one, needs to be somewhere under them.

##### Share on other sites
Silvo    166
But what will the stack index be if I do this:
	lua_getglobal(lua, "debug");	lua_getfield(lua, -1, "traceback");	lua_remove(lua, -2);	luaL_loadfile(lua, name);	if (lua_pcall(lua, 0, 0, ???????) != 0) {		lua_error(lua);	}

##### Share on other sites
Sneftel    1788
Well, 1, it looks like. Isn't it the bottom thing on the stack at that point?

##### Share on other sites
jdarling    232
Make sure that you have loaded the debug library first:
  luaopen_debug(L);

Next read Chapter 23 of the PIL and notice the differences between 5.0 and 5.1, better yet buy PIL for 5.1 and read the section about the debug libarary. (http://www.lua.org/pil/index.html#23)

Decide what type of debugger your going to want, a hook based or Introspective based. Hook is the easiest starting point in my experience.

Here is a very simple sample from one of the engines I use to just dump whats going on while the app is running.

EnableDebugLib() -- Make a call to luaopen_debug for this instanceTrackExecLine = falselocal IgnoreList = {   ['[C]']=true,}if TrackExecLine then  function linetrace (event, line)    print("Executing Line: " .. line)  endendfunction startfunc(event, line)  local info = debug.getinfo(2) --.short_src  local s = info.short_src  if IgnoreList[s]==true then    return  end  if info.name ~=nil then    print('Entering function: '..s..'.'..info.name)  else    print('Entering unknown function: '..s)  endendfunction endfunc(event, line)  local info = debug.getinfo(2) --.short_src  local s = info.short_src  if IgnoreList[s]==true then    return  end  if info.name ~=nil then    print('Exiting function: '..s..'.'..info.name)  else    print('Exiting unknown function: '..s)  endendif TrackExecLine then  debug.sethook(linetrace, "l")enddebug.sethook(startfunc, "c")debug.sethook(endfunc, "r")