slembcke / debugger.lua翻译 / 编辑

最近提交:3月前
创建时间:2012.09.09

语言构成

Lua89.5%
C10.5%

README

debugger.lua

A simple, highly embedabble CLI debugger for Lua 5.x, and LuaJIT 2.0.

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. 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

  • Trivial to "install". Can be integrated as a single .lua or .c file.
  • 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).
  • 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.
  • Conditional, assert-style breakpoints.
  • Colored output and GNU readline support when possible.
  • Easy to set it up to break on Lua's assert() or error() functions.
  • dbg.call() works similar to xpcall() but starts the debugger when an error occurs.
  • From the C API, dbg_call() works as a drop-in replacement for lua_pcall().
  • IO can easily be remapped to a socket or window by overwriting the dbg.write() and dbg.read() functions.
  • Permissive MIT license.

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.

local dbg = require("debugger")

function foo()
	-- Calling dbg() will enter the debugger on the next executable line, right before it calls print().
	-- Once in the debugger, you will be able to step around and inspect things.
	dbg()
	print("Woo!")
	
	-- Maybe you only want to start the debugger on a certain condition.
	-- If you pass a value to dbg(), it works like an assert statement.
	-- The debugger only triggers if it's nil or false.
	dbg(5 == 5) -- Will be ignored
	
	print("Fooooo!")
end

foo()

-- You can also wrap a chunk of code in a dbg.call() block.
-- Any error that occurs will cause the debugger to attach.
-- Then you can inspect the cause.
-- (NOTE: dbg.call() expects a function that takes no parameters)
dbg.call(function()
	-- Put some buggy code in here:
	local err1 = "foo" + 5
	local err2 = (nil).bar
end)

-- Lastly, you can override the standard Lua error() and assert() functions if you want:
-- These variations will enter the debugger instead of aborting the program.
-- dbg.call() is generally more useful though.
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 (and .h) file. First, you'll need to run lua debugger.c.lua. This generates debugger.c by inserting the lua code into a template .c file.

int main(int argc, char **argv){
	lua_State *lua = luaL_newstate();
	luaL_openlibs(lua);
	
	// The 2nd parameter is the module name. (Ex: require("debugger") )
	// The 3rd parameter is the name of a global variable to bind it to, or NULL if you don't want one.
	// The last two are lua_CFunctions for overriding the I/O functions.
	// A NULL I/O function  means to use standard input or output respectively.
	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 using 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! When an error occurs inside dbg_call() it will automatically load, and connect the debugger on the line of the crash.

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:

If you have used other CLI debuggers, debugger.lua should present no surprises. All the commands are a single letter as writting a "real" command parser seemed like a waste of time. debugger.lua is simple, and there are only a small handful of commands anwyay.

[return] - re-run last command
c(ontinue) - contiue execution
s(tep) - step forward by one line (into functions)
n(ext) - step forward by one line (skipping over functions)
p(rint) [expression] - execute the expression and print the result
f(inish) - step forward until exiting the current function
u(p) - move up the stack by one frame
d(own) - move down the stack by one frame
t(race) - print the stack trace
l(ocals) - print the function arguments, locals and upvalues.
h(elp) - print this message
q(uit) - halt execution

If you've never used a CLI debugger before. Start a nice warm cozy fire, run tutorial.lua and open it up in your favorite editor so you can follow along.

Environment Variables:

Want to disabl

讨论区

说说你的看法