Sign in to follow this  
Silvo

Lua: More detailed error information

Recommended Posts

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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 this post


Link to post
Share on other sites
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 instance

TrackExecLine = false
local IgnoreList = {
['[C]']=true,
}

if TrackExecLine then
function linetrace (event, line)
print("Executing Line: " .. line)
end
end

function 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)
end
end

function 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)
end
end

if TrackExecLine then
debug.sethook(linetrace, "l")
end
debug.sethook(startfunc, "c")
debug.sethook(endfunc, "r")

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this