Skip to content

Symbolize init functions - #21

Merged
tzussman merged 3 commits into
mainfrom
init-syms
Oct 10, 2026
Merged

tzussman merged 3 commits into
mainfrom
init-syms

Conversation

@tzussman

Copy link
Copy Markdown
Owner

No description provided.

Stack frames other than the first are return addresses, the address of
the instruction after a call. When the call is the last instruction of
a function, as it is for calls to noreturn functions, the return address
is the first byte of whatever function follows in memory, and looking it
up directly names that unrelated function at +0x0. Look up addr - 1
instead, which is what the kernel's %pB format does for backtraces, and
keep printing the offset relative to the address itself.
Functions marked __init live in the module's init text, which the kernel
unmaps once the module's init function returns. By the time userspace
reads /proc/kallsyms on the module_load event those symbols are usually
gone, so allocations made during init were attributed to whatever symbol
preceded the freed range.

Resolve them where the information still exists: in the BPF program, at
the time of the allocation. For each recorded allocation, walk the
captured stack and format every return address that falls in the
module's init text with bpf_snprintf("%pS"), storing the result in a
hash map keyed by address. Userspace consults that map before the
kallsyms snapshot when printing a frame. bpf_snprintf() does not accept
%pB, so the lookup is done on the preceding byte and userspace adds one
to the offset, which gives the same attribution as %pB.

Alternatives considered:

 - Reading the module's ELF in userspace and relocating its .init.text
   symbols with /sys/module/<name>/sections/.init.text, which persists
   after init. Works, but needs the .ko path and an ELF parser.
 - Copying struct module::kallsyms from the module_load tracepoint. Also
   works, but means iterating every symbol of the module from BPF and
   depends on module internals with no stable layout.
 - Reading /proc/kallsyms before the init function returns, which is a
   race userspace usually loses.

bpf_snprintf() was added in Linux 5.13, so this raises the minimum
kernel from 5.8 (BPF ring buffer) to 5.13.

Fixes #8
The stack traces now resolve the module's __init function and show the
current kernel's allocation path, and the verbose output no longer
mentions the renamed validate_stack program.
@tzussman
tzussman merged commit 7cf51d9 into main Oct 10, 2026
8 checks passed
@tzussman
tzussman deleted the init-syms branch October 10, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant