probeModule
Places kprobes on kernel functions and runs Lua handlers when they are hit.
A probe goes on a kernel symbol, or on an address as syscall.address, syscall.table and linux.lookup return one. Itspre handler runs before the
probed instruction and its post handler after it. What a handler returns is
ignored, so a probe observes the function and cannot skip it, and the error of a
handler that raises goes to the kernel log. A handler receives the registers of the
probed CPU as a probe.regs, whose dump() prints them to the kernel log.
A probe fires wherever the probed code runs, inside an interrupt handler too, with
preemption or interrupts off, so the script runs in a hardirq runtime,
lunatik run -c hardirq <script>, whose lock turns interrupts off, and its handlers
must not sleep. A probe must not be placed where the probed CPU holds a lock its handler’s
Lua takes again, since the handler then spins on it with interrupts off: a function the
scheduler runs under a runqueue lock, enqueue_task_fair or activate_task among them,
where an allocation the handler makes can wake kswapd and print can wake a console’s
waiter, and either wakeup takes that lock; a function that runs under the allocator’s own
locks, a zone’s lock or a slab node’s list_lock, where the handler’s allocation takes
them; and a function the timekeeping update runs while it holds the clock’s sequence for
write, update_vsyscall among them, where linux.time waits on that sequence. Nor may it
be placed on code that runs in NMI, the perf overflow path among it, where an allocation
can take a slab or zone lock the interrupted code holds.
See examples/systrack and examples/dropreason.
Usage
-- run with `lunatik run -c hardirq <script>`
local probe = require("probe")
local reported = false
local function pre(symbol, regs)
if not reported then
reported = true
print(symbol)
regs:dump()
end
end
probe.new("do_sys_openat2", {pre = pre})
Class probe
| probe:disable () | Disables the probe: it stays registered, and a hit runs no handler until enable. |
| probe:enable () | Enables the probe: a hit runs its handlers, as it does from new until a disable. |
| probe:stop () | Unregisters and stops the probe. |
Class probe_regs
| probe_regs:argument (n) | Reads an argument of the probed function. |
| probe_regs:dump () | Prints the registers to the kernel log. |
probe
| new (symbol, handlers) | Creates and registers a new kprobe. |
Class probe in detail
- probe:disable ()
-
Disables the probe: it stays registered, and a hit runs no handler until enable.
Raises
if the probe has been stopped, if the percpu object owns this probe,not allowed once the runtime is armed(its script body has returned): disable_kprobe sleeps, and an armed runtime runs with its lock held and interrupts off; or the error disable_kprobe returns - probe:enable ()
-
Enables the probe: a hit runs its handlers, as it does from new until a disable.
Raises
if the probe has been stopped, if the percpu object owns this probe,not allowed once the runtime is armed(its script body has returned): enable_kprobe sleeps, and an armed runtime runs with its lock held and interrupts off; or the error enable_kprobe returns - probe:stop ()
-
Unregisters and stops the probe.
From a handler this raises: the way to stop delivering there is to return early on a flag
the script owns, and the kprobe is unregistered when the runtime stops. A to-be-closed
variable holding the probe stops it the same way.
Raises
if the percpu object owns this probe, ornot allowed once the runtime is armed(its script body has returned): unregister_kprobe sleeps, and an armed runtime runs with its lock held and interrupts off
Class probe_regs in detail
- probe_regs:argument (n)
-
Reads an argument of the probed function.
Reads through
regs_get_kernel_argument(), which guesses the register mapping: what it returns is not the argument past the registers the architecture passes arguments in, nor after a parameter 16 bytes or larger.Parameters
- n integer position of the argument, counting from zero
Returns
-
integer
the argument, as the register holds it
Raises
closed objectoutside a handler;out of boundsifnis negative;EOPNOTSUPPwhere the architecture does not selectCONFIG_HAVE_FUNCTION_ARG_ACCESS_API - probe_regs:dump ()
-
Prints the registers to the kernel log.
Raises
closed objectoutside a handler
probe in detail
- new (symbol, handlers)
-
Creates and registers a new kprobe.
In a percpu script the runtimes share one kprobe per symbol or address: the first
registration installs it, the others attach their handlers, and a call reaches the
runtime of the CPU it ran on.
Probing a target another probe already holds does not fail: both handlers run on a hit,
so two symbols the kernel resolves to one address each count the other’s calls. In a
percpu script, repeating a target of the set is refused instead.
Parameters
- symbol string or lightuserdata kernel symbol name or address
- handlers
table
table with optional
preandpostcallback functions; each receives the symbol (string) or the address as given (lightuserdata), and theprobe.regsof the hit. The table is read once, to decide whether the kernel installs a post handler, so apostadded to it afterwards never fires; apreadded afterwards does
Returns
-
probe
the probe, which probe.new keeps for its runtime: dropping it stops
nothing, and the kprobe stays until stop or the end of the runtime, or of the set
in a percpu script
Raises
bad field '<field>' (function expected, got <type>)ifpreorpostis present and not a function;runtime context mismatchunless the runtime is hardirq;not allowed while the runtime closesfrom a finalizer that runs at its close; the kernel’s errno if it refuses the registration,ENOENTfor a symbol it does not have; in a percpu script, if this runtime already registered the same symbol or address, or if another runtime of the set registered this target with a different post handler; ornot allowed once the runtime is armed(its script body has returned): register_kprobe sleeps, and an armed runtime runs with its lock held and interrupts off