diff --git a/README.md b/README.md index 144d379..81856da 100644 --- a/README.md +++ b/README.md @@ -1,33 +1,30 @@ debugger.lua = -A simple, embedabble CLI debugger for Lua 5.1, Lua 5.2 and LuaJIT 2.0. Licensed under the very permissable MIT license. +A simple, embedabble CLI debugger for Lua 5.1+, and LuaJIT 2.0. Licensed under the very permissable MIT license. -Have you ever been working on an embedded Lua project and found yourself in need of a debugger? The lua-users wiki lists a [number of them](http://lua-users.org/wiki/DebuggingLuaCode). While clidebugger was closest to what I wanted, I ran into several compatibility issues. The rest of them are very large libraries that require you to integrate socket libraries or other native libraries and such into your program. I just wanted something simple that would work through stdin/out. I also decided that it sounded fun to try and make my own. +Have you ever been working on an embedded Lua project and found yourself in need of a debugger? The lua-users wiki lists a [number of them](http://lua-users.org/wiki/DebuggingLuaCode). While clidebugger was closest to what I wanted, I ran into several compatibility issues. The rest of them are very large libraries that require you to integrate socket libraries or other native libraries and such into your program. I just wanted something simple to integrate that would work through stdin/stdout. I also decided that it sounded fun to try and make my own. Features - -- Simple to "install". Simply copy debugger.lua into your project then load it using local dbg = require(). +- Simple to "install". Can be integrated as a single .lua _or_ .c file. - Conditional, assert-style breakpoints. - Colored output and GNU readline support where applicable. - Easy to set it up to break on assert() or error() - dbg.call() works similar to xpcall() but starts the debugger when an error occurs. -- Works with Lua 5.2, Lua 5.1, LuaJIT and probably other versions that I didn't bother to test. +- dbg_call() works as a drop-in replacement for lua_pcall() when using the C API. - The regular assortment of commands you'd expect from a debugger: continue, step, next, finish, print/eval expression, move up/down the stack, backtrace, print locals, inline help. -- Evaluate expressions and call functions interactively in the debugger with pretty printed output. Inspect locals, upvalues and globals. Even works with varargs ... (Lua 5.2 and LuaJIT only). +- Evaluate expressions and call functions interactively in the debugger with pretty printed output. Inspect locals, upvalues and globals. Even works with varargs ... (Lua 5.2+ and LuaJIT only). - Pretty printed output so you get {1 = 3, "a" = 5} instead of table: 0x10010cfa0 - Speed. The debugger hooks are only set when running the step/next/finish commands and shouldn't otherwise affect your program's performance. -- IO can easily be remapped to a socket or window by setting the dbg.write() and dbg.read() functions. +- IO can easily be remapped to a socket or window by overwriting the dbg.write() and dbg.read() functions. How to Use it: - First of all, there is nothing to install. Just drop debugger.lua into your project and load it using require(). It couldn't be simpler. - - -- MyBuggyProgram.lua - local dbg = require("debugger") function foo() @@ -62,6 +59,44 @@ First of all, there is nothing to install. Just drop debugger.lua into your proj local assert = dbg.assert local error = dbg.error +Super Simple C API: +- + +debugger.lua can be easily integrated into an embedded project by including a single .c file. First make sure to run the `lua debugger.c.lua` template to actually generate the C code. (It just inserts the debugger.lua source into a C string) + + int main(int argc, char **argv){ + lua_State *lua = luaL_newstate(); + luaL_openlibs(lua); + + // Register the debuggr module as "util.debugger" and store it in the global variable "dbg". + dbg_setup(lua, "debugger", "dbg", NULL, NULL); + + // Load some lua code and prepare to call the MyBuggyFunction() defined below... + + // dbg_pcall() is called exactly like lua_pcall(). + // Although note that passing a custom message handler disables the debugger. + if(dbg_pcall(lua, nargs, nresults, 0)){ + fprintf(stderr, "Lua Error: %s\n", lua_tostring(lua, -1)); + } + } + +Now you can go nuts adding all sorts of bugs in your Lua code! + + function MyBuggyFunction() + -- You can either load the debugger module the usual way using the module name passed to dbg_setup()... + local enterTheDebuggerREPL = require("debugger"); + enterTheDebuggerREPL() + + -- or if you defined a global name, you can use that instead. (highly recommended) + dbg() + + -- When lua is invoked from dbg_pcall() using the default message handler (0), + -- errors will cause the debugger to attach automatically! Nice! + error() + assert(false) + (nil)[0] + end + Debugger Commands: - @@ -84,23 +119,13 @@ If you've never used a CLI debugger before. Start a nice warm cozy fire, run tut Environment Variables: - - Want to disable ANSI color support or disable GNU readline? Set the DBG_NOCOLOR and/or DBG_NOREADLINE environment variables. Known Issues: - -- Lua 5.1 lacks the API to access varargs. The workaround is to do something like local args = {...} and then use unpack(args) when you want to access them. In Lua 5.2 and LuaJIT, you can simply use ... in your expressions with the print command. -- You can't add breakpoints to a running program or remove them. Currently the only way to set them is by explicitly calling the dbg() function explicitly in your code. -- The print command will only print out the first 256 return values of an expression. Darn! -- Untested with Lua versions other than Lua 5.1, Lua 5.2 and LuaJIT 2.x. +- Lua 5.1 lacks the API to access varargs. The workaround is to do something like local args = {...} and then use unpack(args) when you want to access them. In Lua 5.2+ and LuaJIT, you can simply use ... in your expressions with the print command. +- You can't add breakpoints to a running program or remove them. Currently the only way to set them is by explicitly calling the dbg() function explicitly in your code. (This is sort of by design and sort of because it's difficult.) - Different interpreters (and versions) print out different stack trace information. - Tail calls are handled silghtly differently in different interpreters. You may find that 1.) stepping into a function that does nothing but a tail call steps you into the tail called function. 2.) The interpreter gives you the wrong name of a tail called function (watch the line numbers). 3.) Stepping out of a tail called function also steps out of the function that performed the tail call. Mostly this is never a problem, but it is a little confusing if you don't know what is going on. -- Coroutines may or may not work as expected... I haven't tested them extensively yet. (Though I certainly will on my current project) - -Future Plans: -- - -debugger.lua basically does everything I want now, although I have some ideas for enhancements. - -- C API: Make the debugger easily embedable from C as a second option. I have a solution I'm mostly happy with in my current project. It exposes a dbg_setup() function to preload the debugger, and a dbg_call() function that works like lua_pcall(), but starts the debugger automaticall when an error occurs. Just needs some cleaning up. +- Coroutine support has not been tested extensively yet, and Lua vs. LuaJIT handle them differently anyway. -_-