All Projects → slembcke → Debugger.lua

slembcke / Debugger.lua

A simple, embedabble CLI debugger for Lua.

Programming Languages

lua
6591 projects

Projects that are alternatives of or similar to Debugger.lua

Lua Resty Repl
Interactive console (REPL) for Openresty and luajit code
Stars: ✭ 165 (-61.27%)
Mutual labels:  luajit, debugger
Re Frisk
Take full control of re-frame app
Stars: ✭ 396 (-7.04%)
Mutual labels:  debugger
Nvim Dap
Debug Adapter Protocol client implementation for Neovim (>= 0.5)
Stars: ✭ 326 (-23.47%)
Mutual labels:  debugger
Laravel Tracy
A Laravel Package to integrate Nette Tracy Debugger
Stars: ✭ 384 (-9.86%)
Mutual labels:  debugger
Dlangide
D language IDE based on DlangUI
Stars: ✭ 358 (-15.96%)
Mutual labels:  debugger
Go Debug
🐛 A go debugger for atom using delve.
Stars: ✭ 390 (-8.45%)
Mutual labels:  debugger
Apioak
Full Lifecycle Management API Gateway.
Stars: ✭ 335 (-21.36%)
Mutual labels:  luajit
Lldb
Project moved to: https://github.com/llvm/llvm-project
Stars: ✭ 412 (-3.29%)
Mutual labels:  debugger
Powershelleditorservices
A common platform for PowerShell development support in any editor or application!
Stars: ✭ 394 (-7.51%)
Mutual labels:  debugger
Ply
CSS inspection aided by visual regression pruning
Stars: ✭ 370 (-13.15%)
Mutual labels:  debugger
Luaperfect
A pure C++ Lua IDE project, aimed to be the fastest and lightest Lua IDE in the world.
Stars: ✭ 368 (-13.62%)
Mutual labels:  debugger
Cocoadebug
iOS Debugging Tool 🚀
Stars: ✭ 3,769 (+784.74%)
Mutual labels:  debugger
Sysbench
Scriptable database and system performance benchmark
Stars: ✭ 4,268 (+901.88%)
Mutual labels:  luajit
Riscv vhdl
Portable RISC-V System-on-Chip implementation: RTL, debugger and simulators
Stars: ✭ 356 (-16.43%)
Mutual labels:  debugger
Various mcu debugger diy
各种LInk大合集
Stars: ✭ 402 (-5.63%)
Mutual labels:  debugger
Winappdbg
WinAppDbg Debugger
Stars: ✭ 338 (-20.66%)
Mutual labels:  debugger
Sayid
A debugger for Clojure
Stars: ✭ 367 (-13.85%)
Mutual labels:  debugger
Python Web Pdb
Web-based remote UI for Python's PDB debugger
Stars: ✭ 390 (-8.45%)
Mutual labels:  debugger
Winrepl
x86 and x64 assembly "read-eval-print loop" shell for Windows
Stars: ✭ 424 (-0.47%)
Mutual labels:  debugger
Ledge
An RFC compliant and ESI capable HTTP cache for Nginx / OpenResty, backed by Redis
Stars: ✭ 412 (-3.29%)
Mutual labels:  luajit

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.

ExampleLog

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")
-- Consider enabling auto_where to make stepping through code easier to follow.
dbg.auto_where = 2

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 embed/debugger.c.lua. This generates embed/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
w(here) [line count] - print source code around the current line
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.

Extras

There are several overloadable functions you can use to customize debugger.lua.

  • dbg.read(prompt) - Show the prompt and block for user input. (Defaults to read from stdin)
  • dbg.write(str) - Write a string to the output. (Defaults to write to stdout)
  • dbg.shorten_path(path) - Return a shortened version of a path. (Defaults to simply return path)
  • dbg.exit(err) - Stop debugging. (Defaults to os.exit(err))

Using these you can customize the debugger to work in your environment. For instance, you can divert the I/O over a network socket or to a GUI window.

There are also some goodies you can use to make debugging easier.

  • dbg.writeln(format, ...) - Basically the same as dbg.write(string.format(format.."\n", ...))
  • dbg.pretty_depth = int - Set how deep dbg.pretty() formats tables.
  • dbg.pretty(obj) - Will return a pretty print string of an object.
  • dbg.pp(obj) - Basically the same as dbg.writeln(dbg.pretty(obj))
  • dbg.auto_where = int_or_false - Set the where command to run automatically when the active line changes. The value is the number of context lines.
  • dbg.error(error, [level]) - Drop in replacement for error() that breaks in the debugger.
  • dbg.assert(error, [message]) - Drop in replacement for assert() that breaks in the debugger.
  • dbg.call(f, ...) - Drop in replacement for pcall() that breaks in the debugger.

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. (This is sort of by design and sort of because it's difficult/slow otherwise.)
  • Different interpreters (and versions) print out slightly 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.
  • Coroutine support has not been tested extensively yet, and Lua vs. LuaJIT handle them differently anyway. -_-

License:

Copyright (c) 2020 Scott Lembcke and Howling Moon Software

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].