xref: /aosp_15_r20/external/bcc/src/lua/README.md (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1*387f9dfdSAndroid Build Coastguard WorkerLua Tools for BCC
2*387f9dfdSAndroid Build Coastguard Worker-----------------
3*387f9dfdSAndroid Build Coastguard Worker
4*387f9dfdSAndroid Build Coastguard WorkerThis directory contains Lua tooling for [BCC][bcc]
5*387f9dfdSAndroid Build Coastguard Worker(the BPF Compiler Collection).
6*387f9dfdSAndroid Build Coastguard Worker
7*387f9dfdSAndroid Build Coastguard WorkerBCC is a toolkit for creating userspace and kernel tracing programs. By
8*387f9dfdSAndroid Build Coastguard Workerdefault, it comes with a library `libbcc`, some example tooling and a Python
9*387f9dfdSAndroid Build Coastguard Workerfrontend for the library.
10*387f9dfdSAndroid Build Coastguard Worker
11*387f9dfdSAndroid Build Coastguard WorkerHere we present an alternate frontend for `libbcc` implemented in LuaJIT. This
12*387f9dfdSAndroid Build Coastguard Workerlets you write the userspace part of your tracer in Lua instead of Python.
13*387f9dfdSAndroid Build Coastguard Worker
14*387f9dfdSAndroid Build Coastguard WorkerSince LuaJIT is a JIT compiled language, tracers implemented in `bcc-lua`
15*387f9dfdSAndroid Build Coastguard Workerexhibit significantly reduced overhead compared to their Python equivalents.
16*387f9dfdSAndroid Build Coastguard WorkerThis is particularly noticeable in tracers that actively use the table APIs to
17*387f9dfdSAndroid Build Coastguard Workerget information from the kernel.
18*387f9dfdSAndroid Build Coastguard Worker
19*387f9dfdSAndroid Build Coastguard WorkerIf your tracer makes extensive use of `BPF_MAP_TYPE_PERF_EVENT_ARRAY` or
20*387f9dfdSAndroid Build Coastguard Worker`BPF_MAP_TYPE_HASH`, you may find the performance characteristics of this
21*387f9dfdSAndroid Build Coastguard Workerimplementation very appealing, as LuaJIT can compile to native code a lot of
22*387f9dfdSAndroid Build Coastguard Workerthe callchain to process the events, and this wrapper has been designed to
23*387f9dfdSAndroid Build Coastguard Workerbenefit from such JIT compilation.
24*387f9dfdSAndroid Build Coastguard Worker
25*387f9dfdSAndroid Build Coastguard Worker## Quickstart Guide
26*387f9dfdSAndroid Build Coastguard Worker
27*387f9dfdSAndroid Build Coastguard WorkerThe following instructions assume Ubuntu 18.04 LTS.
28*387f9dfdSAndroid Build Coastguard Worker
29*387f9dfdSAndroid Build Coastguard Worker1. Clone this repository
30*387f9dfdSAndroid Build Coastguard Worker
31*387f9dfdSAndroid Build Coastguard Worker    ```
32*387f9dfdSAndroid Build Coastguard Worker    $ git clone https://github.com/iovisor/bcc.git
33*387f9dfdSAndroid Build Coastguard Worker    $ cd bcc/
34*387f9dfdSAndroid Build Coastguard Worker    ```
35*387f9dfdSAndroid Build Coastguard Worker
36*387f9dfdSAndroid Build Coastguard Worker2. As per the [Ubuntu - Binary](https://github.com/iovisor/bcc/blob/master/INSTALL.md#ubuntu---binary) installation istructions, install the required upstream stable and signed packages
37*387f9dfdSAndroid Build Coastguard Worker
38*387f9dfdSAndroid Build Coastguard Worker    ```
39*387f9dfdSAndroid Build Coastguard Worker    $ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 4052245BD4284CDD
40*387f9dfdSAndroid Build Coastguard Worker    $ echo "deb https://repo.iovisor.org/apt/$(lsb_release -cs) $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/iovisor.list
41*387f9dfdSAndroid Build Coastguard Worker    $ sudo apt-get update
42*387f9dfdSAndroid Build Coastguard Worker    $ sudo apt-get install bcc-tools libbcc-examples linux-headers-$(uname -r)
43*387f9dfdSAndroid Build Coastguard Worker    ```
44*387f9dfdSAndroid Build Coastguard Worker
45*387f9dfdSAndroid Build Coastguard Worker3. Install LuaJit and the corresponding development files
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Worker    ```
48*387f9dfdSAndroid Build Coastguard Worker    $ sudo apt-get install luajit luajit-5.1-dev
49*387f9dfdSAndroid Build Coastguard Worker    ```
50*387f9dfdSAndroid Build Coastguard Worker
51*387f9dfdSAndroid Build Coastguard Worker4. Test one of the examples to ensure `libbcc` is properly installed
52*387f9dfdSAndroid Build Coastguard Worker
53*387f9dfdSAndroid Build Coastguard Worker    ```
54*387f9dfdSAndroid Build Coastguard Worker    $ sudo src/lua/bcc-probe examples/lua/task_switch.lua
55*387f9dfdSAndroid Build Coastguard Worker    ```
56*387f9dfdSAndroid Build Coastguard Worker
57*387f9dfdSAndroid Build Coastguard Worker## LuaJIT BPF compiler
58*387f9dfdSAndroid Build Coastguard Worker
59*387f9dfdSAndroid Build Coastguard WorkerNow it is also possible to write Lua functions and compile them transparently to BPF bytecode, here is a simple socket filter example:
60*387f9dfdSAndroid Build Coastguard Worker
61*387f9dfdSAndroid Build Coastguard Worker```lua
62*387f9dfdSAndroid Build Coastguard Workerlocal S = require('syscall')
63*387f9dfdSAndroid Build Coastguard Workerlocal bpf = require('bpf')
64*387f9dfdSAndroid Build Coastguard Workerlocal map = bpf.map('array', 256)
65*387f9dfdSAndroid Build Coastguard Worker-- Kernel-space part of the program
66*387f9dfdSAndroid Build Coastguard Workerlocal prog = assert(bpf(function ()
67*387f9dfdSAndroid Build Coastguard Worker    local proto = pkt.ip.proto  -- Get byte (ip.proto) from frame at [23]
68*387f9dfdSAndroid Build Coastguard Worker    xadd(map[proto], 1)         -- Increment packet count
69*387f9dfdSAndroid Build Coastguard Workerend))
70*387f9dfdSAndroid Build Coastguard Worker-- User-space part of the program
71*387f9dfdSAndroid Build Coastguard Workerlocal sock = assert(bpf.socket('lo', prog))
72*387f9dfdSAndroid Build Coastguard Workerfor i=1,10 do
73*387f9dfdSAndroid Build Coastguard Worker    local icmp, udp, tcp = map[1], map[17], map[6]
74*387f9dfdSAndroid Build Coastguard Worker    print('TCP', tcp, 'UDP', udp, 'ICMP', icmp, 'packets')
75*387f9dfdSAndroid Build Coastguard Worker    S.sleep(1)
76*387f9dfdSAndroid Build Coastguard Workerend
77*387f9dfdSAndroid Build Coastguard Worker```
78*387f9dfdSAndroid Build Coastguard Worker
79*387f9dfdSAndroid Build Coastguard WorkerThe other application of BPF programs is attaching to probes for [perf event tracing][tracing]. That means you can trace events inside the kernel (or user-space), and then collect results - for example histogram of `sendto()` latency, off-cpu time stack traces, syscall latency, and so on. While kernel probes and perf events have unstable ABI, with a dynamic language we can create and use proper type based on the tracepoint ABI on runtime.
80*387f9dfdSAndroid Build Coastguard Worker
81*387f9dfdSAndroid Build Coastguard WorkerRuntime automatically recognizes reads that needs a helper to be accessed. The type casts denote source of the objects, for example the [bashreadline][bashreadline] example that prints entered bash commands from all running shells:
82*387f9dfdSAndroid Build Coastguard Worker
83*387f9dfdSAndroid Build Coastguard Worker```lua
84*387f9dfdSAndroid Build Coastguard Workerlocal ffi = require('ffi')
85*387f9dfdSAndroid Build Coastguard Workerlocal bpf = require('bpf')
86*387f9dfdSAndroid Build Coastguard Worker-- Perf event map
87*387f9dfdSAndroid Build Coastguard Workerlocal sample_t = 'struct { uint64_t pid; char str[80]; }'
88*387f9dfdSAndroid Build Coastguard Workerlocal events = bpf.map('perf_event_array')
89*387f9dfdSAndroid Build Coastguard Worker-- Kernel-space part of the program
90*387f9dfdSAndroid Build Coastguard Workerbpf.uprobe('/bin/bash:readline' function (ptregs)
91*387f9dfdSAndroid Build Coastguard Worker    local sample = ffi.new(sample_t)
92*387f9dfdSAndroid Build Coastguard Worker    sample.pid = pid_tgid()
93*387f9dfdSAndroid Build Coastguard Worker    ffi.copy(sample.str, ffi.cast('char *', req.ax)) -- Cast `ax` to string pointer and copy to buffer
94*387f9dfdSAndroid Build Coastguard Worker    perf_submit(events, sample)                      -- Write sample to perf event map
95*387f9dfdSAndroid Build Coastguard Workerend, true, -1, 0)
96*387f9dfdSAndroid Build Coastguard Worker-- User-space part of the program
97*387f9dfdSAndroid Build Coastguard Workerlocal log = events:reader(nil, 0, sample_t) -- Must specify PID or CPU_ID to observe
98*387f9dfdSAndroid Build Coastguard Workerwhile true do
99*387f9dfdSAndroid Build Coastguard Worker    log:block()               -- Wait until event reader is readable
100*387f9dfdSAndroid Build Coastguard Worker    for _,e in log:read() do  -- Collect available reader events
101*387f9dfdSAndroid Build Coastguard Worker        print(tonumber(e.pid), ffi.string(e.str))
102*387f9dfdSAndroid Build Coastguard Worker    end
103*387f9dfdSAndroid Build Coastguard Workerend
104*387f9dfdSAndroid Build Coastguard Worker```
105*387f9dfdSAndroid Build Coastguard Worker
106*387f9dfdSAndroid Build Coastguard WorkerWhere cast to `struct pt_regs` flags the source of data as probe arguments, which means any pointer derived
107*387f9dfdSAndroid Build Coastguard Workerfrom this structure points to kernel and a helper is needed to access it. Casting `req.ax` to pointer is then required for `ffi.copy` semantics, otherwise it would be treated as `u64` and only it's value would be
108*387f9dfdSAndroid Build Coastguard Workercopied. The type detection is automatic most of the times (socket filters and `bpf.tracepoint`), but not with uprobes and kprobes.
109*387f9dfdSAndroid Build Coastguard Worker
110*387f9dfdSAndroid Build Coastguard Worker### Installation
111*387f9dfdSAndroid Build Coastguard Worker
112*387f9dfdSAndroid Build Coastguard Worker```bash
113*387f9dfdSAndroid Build Coastguard Worker$ luarocks install bpf
114*387f9dfdSAndroid Build Coastguard Worker```
115*387f9dfdSAndroid Build Coastguard Worker
116*387f9dfdSAndroid Build Coastguard Worker### Examples
117*387f9dfdSAndroid Build Coastguard Worker
118*387f9dfdSAndroid Build Coastguard WorkerSee `examples/lua` directory.
119*387f9dfdSAndroid Build Coastguard Worker
120*387f9dfdSAndroid Build Coastguard Worker### Helpers
121*387f9dfdSAndroid Build Coastguard Worker
122*387f9dfdSAndroid Build Coastguard Worker* `print(...)` is a wrapper for `bpf_trace_printk`, the output is captured in `cat /sys/kernel/debug/tracing/trace_pipe`
123*387f9dfdSAndroid Build Coastguard Worker* `bit.*` library **is** supported (`lshift, rshift, arshift, bnot, band, bor, bxor`)
124*387f9dfdSAndroid Build Coastguard Worker* `math.*` library *partially* supported (`log2, log, log10`)
125*387f9dfdSAndroid Build Coastguard Worker* `ffi.cast()` is implemented (including structures and arrays)
126*387f9dfdSAndroid Build Coastguard Worker* `ffi.new(...)` allocates memory on stack, initializers are NYI
127*387f9dfdSAndroid Build Coastguard Worker* `ffi.copy(...)` copies memory (possibly using helpers) between stack/kernel/registers
128*387f9dfdSAndroid Build Coastguard Worker* `ntoh(x[, width])` - convert from network to host byte order.
129*387f9dfdSAndroid Build Coastguard Worker* `hton(x[, width])` - convert from host to network byte order.
130*387f9dfdSAndroid Build Coastguard Worker* `xadd(dst, inc)` - exclusive add, a synchronous `*dst += b` if Lua had `+=` operator
131*387f9dfdSAndroid Build Coastguard Worker
132*387f9dfdSAndroid Build Coastguard WorkerBelow is a list of BPF-specific helpers:
133*387f9dfdSAndroid Build Coastguard Worker
134*387f9dfdSAndroid Build Coastguard Worker* `time()` - return current monotonic time in nanoseconds (uses `bpf_ktime_get_ns`)
135*387f9dfdSAndroid Build Coastguard Worker* `cpu()` - return current CPU number (uses `bpf_get_smp_processor_id`)
136*387f9dfdSAndroid Build Coastguard Worker* `pid_tgid()` - return caller `tgid << 32 | pid` (uses `bpf_get_current_pid_tgid`)
137*387f9dfdSAndroid Build Coastguard Worker* `uid_gid()` - return caller `gid << 32 | uid` (uses `bpf_get_current_uid_gid`)
138*387f9dfdSAndroid Build Coastguard Worker* `comm(var)` - write current process name (uses `bpf_get_current_comm`)
139*387f9dfdSAndroid Build Coastguard Worker* `perf_submit(map, var)` - submit variable to perf event array BPF map
140*387f9dfdSAndroid Build Coastguard Worker* `stack_id(map, flags)` - return stack trace identifier from stack trace BPF map
141*387f9dfdSAndroid Build Coastguard Worker* `load_bytes(off, var)` - helper for direct packet access with `skb_load_bytes()`
142*387f9dfdSAndroid Build Coastguard Worker
143*387f9dfdSAndroid Build Coastguard Worker### Current state
144*387f9dfdSAndroid Build Coastguard Worker
145*387f9dfdSAndroid Build Coastguard Worker* Not all LuaJIT bytecode opcodes are supported *(notable mentions below)*
146*387f9dfdSAndroid Build Coastguard Worker* Closures `UCLO` will probably never be supported, although you can use upvalues inside compiled function.
147*387f9dfdSAndroid Build Coastguard Worker* Type narrowing is opportunistic. Numbers are 64-bit by default, but 64-bit immediate loads are not supported (e.g. `local x = map[ffi.cast('uint64_t', 1000)]`)
148*387f9dfdSAndroid Build Coastguard Worker* Tail calls `CALLT`, and iterators `ITERI` are NYI (as of now)
149*387f9dfdSAndroid Build Coastguard Worker* Arbitrary ctype **is** supported both for map keys and values
150*387f9dfdSAndroid Build Coastguard Worker* Basic optimisations like: constant propagation, partial DCE, liveness analysis and speculative register allocation are implement, but there's no control flow analysis yet. This means the compiler has the visibility when things are used and dead-stores occur, but there's no rewriter pass to eliminate them.
151*387f9dfdSAndroid Build Coastguard Worker* No register sub-allocations, no aggressive use of caller-saved `R1-5`, no aggressive narrowing (this would require variable range assertions and variable relationships)
152*387f9dfdSAndroid Build Coastguard Worker* Slices with not 1/2/4/8 length are NYI (requires allocating a memory on stack and using pointer type)
153*387f9dfdSAndroid Build Coastguard Worker
154*387f9dfdSAndroid Build Coastguard Worker
155*387f9dfdSAndroid Build Coastguard Worker[bcc]: https://github.com/iovisor/bcc
156*387f9dfdSAndroid Build Coastguard Worker[tracing]: http://www.brendangregg.com/blog/2016-03-05/linux-bpf-superpowers.html
157*387f9dfdSAndroid Build Coastguard Worker[bashreadline]: http://www.brendangregg.com/blog/2016-02-08/linux-ebpf-bcc-uprobes.html