Scripting in LLDB
One thing that makes LLDB really powerful is how scriptable it is. It has a stable C++ API, called the SB API or Scripting Bridge API, which is accessible through Python. Following LLVM’s model of reusable components, most of LLDB constitutes a debugger library and the SB API is how tools like the command line driver interface with it. This means that the API is both powerful and extensive.
LLDB was always designed to support multiple scripting languages. However, since its inception, Python has been the main and only supported language. I wanted to see what it would take to extend scripting support to another language.
I picked Lua because it’s simple, lightweight and designed to be embedded. It’s used by a wide variety of software and especially popular in game engines. It also helped that SWIG, which we use to generate API bindings for Python, supports Lua.
I was able to get a prototype working after only a few hours of hacking. This really speaks to how easy it is to integrate Lua as well as to LLDB’s extensibility. So I sent out an RFC to the LLDB mailing list to gauge interest. Given that this was just a weekend project, I wanted to be very clear about the trade-offs. The reception was very positive, so I put up code reviews. Last week I started landing the first patches.
What follows is an overview of the progress we’ve made. This is by no means meant to be exhaustive. I’ll do my best to keep this up to date, but remember that the repository is the only real source of truth.
What Works in Lua?
- Both one-line and interactive scripting in Lua with the
(lldb) script print("Hello, World!") Hello, World! (lldb) script >>> print("Hello, World!") Hello, World!
- The script interpreter will maintain state. You have access to your previously defined variables between LLDB commands. For example if you leave and restart the interactive interpreter.
(lldb) script foo=1 (lldb) script print(foo) 1
- Accessing LLDB’s SB API from Lua within the embedded script interpreter.
(lldb) script >>> dbg = lldb.SBDebugger.Create() >>> print(dbg:IsValid()) true
- Accessing the current debugger, target, process, thread and frame with the convenience variables
(lldb) script >>> print(lldb.target) a.out
- Importing Lua packages with
command script import. (Under review)
(lldb) command script import /path/to/my/module.lua (lldb) script >>> module.foo() Hello World!
What Doens’t work in Lua?
- Redirection of
stderr. The result of an LLDB command like
scriptis represented by a
CommandReturnObjectwhich among other thins contains the output. Currently Lua write everything to standard out directly.
- Breakpoint callbacks. LLDB allows you to call some code when a breakpoint is hit. This code can either consist of regular LLDB commands or Python code. Lua is not (yet) supported.
- Watchpoint callbacks. Similar to breakpoint callbacks but for when a watchpoint is hit.
It’s worth pointing out that some things will remain different from Python. For example, you can use Python from withing LLDB and you can use LLDB from withing Python. The latter is currently not a goal for Lua.