siger-young created this revision.
Herald added a subscriber: arphaman.
siger-young requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
Add a basic reference page for Lua scripting, as a counterpart to section
"Python Reference".
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D104281
Files:
lldb/docs/index.rst
lldb/docs/use/lua-reference.rst
Index: lldb/docs/use/lua-reference.rst
===================================================================
--- /dev/null
+++ lldb/docs/use/lua-reference.rst
@@ -0,0 +1,190 @@
+Lua Reference
+================
+
+.. default-role:: samp
+
+Lua is a lightweight but powerful language. At present, Lua is only serving as
+an embedded interpreter in LLDB.
+
+.. contents::
+ :local:
+
+Embedded Lua Interpreter
+---------------------------
+
+The embedded Lua interpreter can be accessed in a variety of ways from
+within LLDB. The easiest way is to use the lldb command script with no
+arguments at the lldb command prompt:
+
+::
+
+ (lldb) script
+ >>> t = { 1, 2, 3 }
+ >>> print(t[1])
+ 1
+ >>> print(t[1] + t[2])
+ 3
+ >>>
+
+This drops you into the embedded Lua interpreter. When running under the
+script command, lldb sets some convenience variables that give you quick access
+to the currently selected entities that characterize the program and debugger
+state. In each case, if there is no currently selected entity of the
+appropriate type, the variable's IsValid method will return false. These
+variables are:
+
++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+
+| Variable | Type | Equivalent | Description |
++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+
+| `lldb.debugger` | `lldb.SBDebugger` | `SBTarget:GetDebugger` | Contains the debugger object whose `script` command was invoked. |
+| | | | The `lldb.SBDebugger` object owns the command interpreter |
+| | | | and all the targets in your debug session. There will always be a |
+| | | | Debugger in the embedded interpreter. |
++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+
+| `lldb.target` | `lldb.SBTarget` | `SBDebugger:GetSelectedTarget` | Contains the currently selected target - for instance the one made with the |
+| | | | `file` or selected by the `target select <target-index>` command. |
+| | | `SBProcess:GetTarget` | The `lldb.SBTarget` manages one running process, and all the executable |
+| | | | and debug files for the process. |
++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+
+| `lldb.process` | `lldb.SBProcess` | `SBTarget:GetProcess` | Contains the process of the currently selected target. |
+| | | | The `lldb.SBProcess` object manages the threads and allows access to |
+| | | `SBThread:GetProcess` | memory for the process. |
++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+
+| `lldb.thread` | `lldb.SBThread` | `SBProcess:GetSelectedThread` | Contains the currently selected thread. |
+| | | | The `lldb.SBThread` object manages the stack frames in that thread. |
+| | | `SBFrame:GetThread` | A thread is always selected in the command interpreter when a target stops. |
+| | | | The `thread select <thread-index>` command can be used to change the |
+| | | | currently selected thread. So as long as you have a stopped process, there will be |
+| | | | some selected thread. |
++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+
+| `lldb.frame` | `lldb.SBFrame` | `SBThread:GetSelectedFrame` | Contains the currently selected stack frame. |
+| | | | The `lldb.SBFrame` object manage the stack locals and the register set for |
+| | | | that stack. |
+| | | | A stack frame is always selected in the command interpreter when a target stops. |
+| | | | The `frame select <frame-index>` command can be used to change the |
+| | | | currently selected frame. So as long as you have a stopped process, there will |
+| | | | be some selected frame. |
++-------------------+---------------------+-------------------------------------+-------------------------------------------------------------------------------------+
+
+While extremely convenient, these variables have a couple caveats that you
+should be aware of. First of all, they hold the values of the selected objects
+on entry to the embedded interpreter. They do not update as you use the LLDB
+API's to change, for example, the currently selected stack frame or thread.
+
+Moreover, they are only defined and meaningful while in the interactive Lua
+interpreter. There is no guarantee on their value in any other situation, hence
+you should not use them when defining Lua formatters, breakpoint scripts and
+commands (or any other Lua extension point that LLDB provides). For the
+latter you'll be passed an `SBDebugger`, `SBTarget`, `SBProcess`, `SBThread` or
+`SBframe` instance and you can use the functions from the "Equivalent" column
+to navigate between them.
+
+As a rationale for such behavior, consider that lldb can run in a multithreaded
+environment, and another thread might call the "script" command, changing the
+value out from under you.
+
+To get started with these objects and LLDB scripting, please note that almost
+all of the lldb Lua objects are able to briefly describe themselves when you
+pass them to the Lua print function:
+
+::
+
+ (lldb) script
+ >>> print(lldb.debugger)
+ Debugger (instance: "debugger_1", id: 1)
+ >>> print(lldb.target)
+ a.out
+ >>> print(lldb.process)
+ SBProcess: pid = 3385871, state = stopped, threads = 1, executable = a.out
+ >>> print(lldb.thread)
+ thread #1: tid = 3385871, 0x000055555555514f a.out`main at test.c:5:3, name = 'a.out', stop reason = breakpoint 1.1
+ >>> print(lldb.frame)
+ frame #0: 0x000055555555514f a.out`main at test.c:5:3
+
+
+Running a Lua script when a breakpoint gets hit
+--------------------------------------------------
+
+One very powerful use of the lldb Lua API is to have a Lua script run
+when a breakpoint gets hit. Adding Lua scripts to breakpoints provides a way
+to create complex breakpoint conditions and also allows for smart logging and
+data gathering.
+
+When your process hits a breakpoint to which you have attached some Lua
+code, the code is executed as the body of a function which takes three
+arguments:
+
+::
+
+ function breakpoint_function_wrapper(frame, bp_loc, ...):
+ -- Your code goes here
+
+
++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
+| Argument | Type | Description |
++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
+| `frame` | `lldb.SBFrame` | The current stack frame where the breakpoint got hit. |
+| | | The object will always be valid. |
+| | | This `frame` argument might *not* match the currently selected stack frame found in the `lldb` module global variable `lldb.frame`. |
++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
+| `bp_loc` | `lldb.SBBreakpointLocation` | The breakpoint location that just got hit. Breakpoints are represented by `lldb.SBBreakpoint` |
+| | | objects. These breakpoint objects can have one or more locations. These locations |
+| | | are represented by `lldb.SBBreakpointLocation` objects. |
++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
+| `extra_args` | `lldb.SBStructuredData` | `Optional` If your breakpoint callback function takes this extra parameter, then when the callback gets added to a breakpoint, its |
+| | | contents can parametrize this use of the callback. For instance, instead of writing a callback that stops when the caller is "Foo", |
+| | | you could take the function name from a field in the `extra_args`, making the callback more general. The `-k` and `-v` options |
+| | | to `breakpoint command add` will be passed as a Dictionary in the `extra_args` parameter, or you can provide it with the SB API's. |
++-------------------+-------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------+
+
+Optionally, a Lua breakpoint command can return a value. Returning `false`
+tells LLDB that you do not want to stop at the breakpoint. Any other return
+value (including None or leaving out the return statement altogether) is akin
+to telling LLDB to actually stop at the breakpoint. This can be useful in
+situations where a breakpoint only needs to stop the process when certain
+conditions are met, and you do not want to inspect the program state manually
+at every stop and then continue.
+
+An example will show how simple it is to write some Lua code and attach it
+to a breakpoint. The following example will allow you to track the order in
+which the functions in a given shared library are first executed during one run
+of your program. This is a simple method to gather an order file which can be
+used to optimize function placement within a binary for execution locality.
+
+We do this by setting a regular expression breakpoint that will match every
+function in the shared library. The regular expression '.' will match any
+string that has at least one character in it, so we will use that. This will
+result in one lldb.SBBreakpoint object that contains an
+lldb.SBBreakpointLocation object for each function. As the breakpoint gets hit,
+we use a counter to track the order in which the function at this particular
+breakpoint location got hit. Since our code is passed the location that was
+hit, we can get the name of the function from the location, disable the
+location so we won't count this function again; then log some info and continue
+the process.
+
+Note we also have to initialize our counter, which we do with the simple
+one-line version of the script command.
+
+Here is the code:
+
+::
+
+ (lldb) breakpoint set --func-regex=. --shlib=libfoo.dylib
+ Breakpoint created: 1: regex = '.', module = libfoo.dylib, locations = 223
+ (lldb) script counter = 0
+ (lldb) breakpoint command add -s lua 1
+ Enter your Lua command(s). Type 'quit' to end.
+ The commands are compiled as the body of the following Lua function
+ function (frame, bp_loc, ...) end
+ ..> counter = counter + 1
+ ..> name = frame:GetFunctionName()
+ ..> print(string.format('[%i] %s', counter, name))
+ ..> bp_loc:SetEnabled(false)
+ ..> return false
+ ..> quit
+
+The breakpoint command add command above attaches a Lua script to breakpoint 1. To remove the breakpoint command:
+
+::
+
+ (lldb) breakpoint command delete 1
Index: lldb/docs/index.rst
===================================================================
--- lldb/docs/index.rst
+++ lldb/docs/index.rst
@@ -135,6 +135,7 @@
use/symbols
use/python
use/python-reference
+ use/lua-reference
use/remote
use/qemu-testing
use/troubleshooting
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits