At work I do games. Again not the usual kind but the slot ones. A good thing about where I work unlike others in the industry is that we actually have a bit of belief in technology and try to “catchup” with latest technology (usually mainstream – 5 years). Now while this may be astonishing to some outside the industry, it is quite advanced within! Anyhoo I am digressing.
Point was that with all this catching up we do, we recently (about 6months-1year ago) started using Lua to script a big chunk of the games so that only the core is handled by C++ and everything UI related is palmed off to Lua. Obvious advantage is that extra builds are not required as compileable source code is not changed and configuration is a lot easier and lot less time consuming. Again nothing new here.
The problem is that the lua scripts we invoke from C++ have no easy way of debugging them. So our engineers had been toiling with this by using the first-class technique of peppering the code with print statements. You would thing some methodologies would die eventually but nope.
So I figured why not simply have a debugger that takes advantage of Lua’s debug api and allow debugging of scripts remotely. So was born LunarProbe. My attemt at debugging lua scripts once embedded in a host language. Even at the beginning I figured that this was a very generic thing and has no specific code for our games. So I decided to release it on the Apache License. You can find the code on google code.
So far it only supports C/C++ but hope to have more languages supported with the appropriate bindings in place. The idea is simple:
- The lua_State object (ie the lua stack or the lua context) is god in Lua. Essentially it is what the interpreter uses to execute scripts and lua statements “on”.
- A new lua stack can be opened with the lua_open command.
- Usually following this command, you open all the standard libraries with the luaL_openlibs.
That is it. You do usual things like loading lua files on a particular stack. See the lua manual for more info on this.
So where does the debugging come in? Well each lua stack can be given a debug hook function that is called by the interpreter after certain points at runtime. eg after a line has been executed, after a function is invoked, after a function has returned etc.
What LunarProbe does is registers itself as a hook function and deals with each of the above debug events and presents it via tcp (port 9999 by default) to a remote client. The debug server is in fact api driven. It accepts commands from the client and returns responses (but not HTTP – to keep it simple). This means any UI could be written easily by simply following the debug server protocol. A reference client is provided (written in python). The python client is supposed to be like gdb (but no where near it!! GDB – please accept my apologies for even trying a comparison!! I know I dont deserve it.)
I wanted to write a GUI or an Eclipse plugin, but we dont use eclipse plugin at work and wx widget toolkits werent installed by default here at work. So doing either meant having all developers install extra packages which was a huge adminstrative overhead. At a later stage, I would like to see more coming up. Any helpers?
Again I digress. So how would one enable LunarProbe in stacks they are opening? Simple.
Instead of lua_open and luaL_openlibs, simply do this:
1. Include the lunarprobe header (ensure that lunarprobe/src is in the include path):
- #include “lpmain.h”
2. Instead of lua_open and luaL_openlibs simply do:
LUNARPROBE_NS::LuaUtils::NewLuaStack(true, true, “hello”)
This does a few things:
- Creates a lua stack using lua_open
- If the first parameter is true, then Opens standard libraries using luaL_openlibs.
- and if the second parameter is true, registers LunarProbe by calling LUNARPROBE_NS::LunarProbe::Attach(stack, name), where “stack” was opened in step 1.
- The fourth parameter (defaulting to “”) only gives a name to each of your stacks for debugging purposes. This is very useful in the debug client to identify which stack your dealing with when the address of a stack may not be very useful or very clear.
Alternatively, you can simply call the step 3 instead of NewLuaStack if you do not want to pull out your own versions of lua_open and luaL_openlibs.
That it. This is the embedding/attaching part of the debugger. Now the client.
lunarprobe/client includes a simple client – client.py.
I wont go into too much detail here as the “help” command is mostly self-explanatory. Just the brief stuff.
Invoke this with:
- python client run
or if you would like to run it from within an interpreter then:
- import client
This brings up the LDB prompt: type in “help” to show all commands and their usage.
One distinction (actually an inconvinience) is that since multiple stacks can be debugged at the same time, any context (LP calls stacks as contexts) specific commands must pass in the address of the context. This is not hard, just inconvinient.
To get a list of all the contexts simply type in the contexts at the prompt and press enter. This will show all context names and their addresses. Use these addresses with any context related commands (like step, next, continue etc).
Breakpoints at the moment can be set by filename (and linenumber) or by a function name. However at this stage member functions are not differentiated from global functions. So a function name breakpoint will affect ALL functions of the same name.
As mentioned this is very brief. Apologies for that. Il add more and more in as I improve this.
Well hopefully this project is useful for all Lua embedders out there. Please let me know how I can improve this. Also this project is on google code, so please let me know if you would like to contribute or extend LP.
Best of luck!!!