Recovering Symbols from a Stripped Linux Kernel

Quick Reference:
# Install vmlinux-to-elf
pipx install vmlinux-to-elf
# Convert stripped kernel to analyzable ELF
vmlinux-to-elf vmlinuz output.elf
# Extract from compressed kernel
vmlinux-to-elf bzImage output.elf
# Extract from Android boot image
vmlinux-to-elf boot.img output.elf
When debugging kernel panics or analyzing embedded firmware, you often encounter stripped kernel binaries with no debug symbols. Stack traces show hex addresses instead of function names. Traditional tools like nm and objdump report nothing useful.
But there's a hidden treasure inside almost every Linux kernel: kallsyms, a compressed symbol table that survives stripping.
What is kallsyms?
The Linux kernel maintains an internal symbol table called kallsyms (kernel all symbols). It exists primarily for:
- Printing readable kernel oops/panic messages
/proc/kallsymsfor debugging and profiling tools- Stack trace symbolization
Even when distributors strip debug symbols from the kernel binary, kallsyms remains embedded because it's needed at runtime.
The vmlinux-to-elf Tool
vmlinux-to-elf is a Python tool that extracts kallsyms from any kernel image and produces a proper ELF file with symbols restored.
Installation
# Using pipx (recommended)
pipx install vmlinux-to-elf
# Using uv
uv tool install vmlinux-to-elf
# From source
git clone https://github.com/marin-m/vmlinux-to-elf
cd vmlinux-to-elf
pip install -e .
Basic Usage
Convert a stripped kernel to an analyzable ELF:
# From raw vmlinux
vmlinux-to-elf /boot/vmlinuz-$(uname -r) kernel.elf
# From compressed bzImage
vmlinux-to-elf /boot/bzImage kernel.elf
# From Android boot.img
vmlinux-to-elf boot.img kernel.elf
The output ELF file contains all recovered symbols and can be loaded into:
- IDA Pro for static analysis
- Ghidra for free reverse engineering
- GDB for debugging
- addr2line for crash analysis
How kallsyms Works
The kallsyms table contains tuples of:
- Symbol address
- Symbol type (T for text, D for data, etc.)
- Symbol name (compressed)
The compression is simple: common substrings in symbol names are replaced with single-byte tokens. A token table maps these bytes back to string fragments.
kallsyms Structure
| Array | Purpose |
|---|---|
| kallsyms_addresses | Array of symbol addresses |
| kallsyms_num_syms | Total symbol count |
| kallsyms_names | Compressed symbol names |
| kallsyms_markers | Lookup table for fast access |
| kallsyms_token_table | String fragments for decompression |
| kallsyms_token_index | Offsets into token table |
vmlinux-to-elf finds these structures through heuristics, handles various kernel versions (including 6.4+ layout changes), and correctly decompresses the symbol names.
Practical Use Cases
Debugging Kernel Panics
When you get a panic with raw addresses:
[ 123.456789] BUG: unable to handle kernel NULL pointer dereference
[ 123.456790] IP: 0xffffffffa1234567
[ 123.456791] Call Trace:
[ 123.456792] 0xffffffffa1234890
[ 123.456793] 0xffffffffa1234abc
Extract symbols and resolve:
# Extract symbols
vmlinux-to-elf /boot/vmlinuz-$(uname -r) kernel.elf
# Resolve addresses
addr2line -e kernel.elf 0xffffffffa1234567
# Output: do_something+0x47/0x100
# Or use nm to find nearby symbols
nm kernel.elf | grep -i "a123"
Firmware Analysis
Embedded devices ship with stripped kernels. Extract from firmware:
# Extract kernel from firmware image
binwalk -e firmware.bin
# Find the kernel
file _firmware.bin.extracted/*
# Look for: Linux kernel ARM boot executable
# Convert to ELF
vmlinux-to-elf _firmware.bin.extracted/vmlinux kernel.elf
# Analyze in Ghidra
ghidraRun kernel.elf
Security Research
Analyzing kernel exploits requires understanding the kernel's memory layout:
# Get symbol addresses for ROP gadgets
nm kernel.elf | grep prepare_kernel_cred
# ffffffff810a1234 T prepare_kernel_cred
nm kernel.elf | grep commit_creds
# ffffffff810a5678 T commit_creds
Reading /proc/kallsyms Directly
On a running system with root access, you can read symbols directly:
# All kernel symbols
sudo cat /proc/kallsyms
# Find a specific function
sudo cat /proc/kallsyms | grep do_sys_open
# ffffffff812345678 T do_sys_open
# Count symbols by type
sudo cat /proc/kallsyms | awk '{print $2}' | sort | uniq -c
Symbol types follow the nm convention:
| Type | Meaning |
|---|---|
| T/t | Text (code) section |
| D/d | Data section |
| B/b | BSS (uninitialized data) |
| R/r | Read-only data |
| A | Absolute address |
Uppercase means global, lowercase means local.
Kernel Configuration
kallsyms is controlled by kernel config options:
CONFIG_KALLSYMS=y # Enable kallsyms
CONFIG_KALLSYMS_ALL=y # Include all symbols (not just functions)
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y # Use absolute addresses
CONFIG_KALLSYMS_BASE_RELATIVE=y # Use relative offsets (saves space)
Most distributions enable CONFIG_KALLSYMS by default. Check your kernel:
zcat /proc/config.gz | grep KALLSYMS
# Or
cat /boot/config-$(uname -r) | grep KALLSYMS
Limitations
kallsyms has some limitations:
- No type information: Only names and addresses, no function signatures
- No local variables: Only global symbols
- May be disabled: Some hardened kernels disable kallsyms
- Address randomization: KASLR shifts addresses at boot (use
/proc/kallsymsfor runtime addresses)
For full debug info, you need the original vmlinux with DWARF symbols, typically from kernel debuginfo packages:
# Debian/Ubuntu
apt install linux-image-$(uname -r)-dbgsym
# RHEL/CentOS
debuginfo-install kernel
# Fedora
dnf debuginfo-install kernel
Automating Symbol Resolution
Create a script for batch address resolution:
#!/bin/bash
# resolve-addrs.sh - Resolve kernel addresses from log
KERNEL_ELF=${1:-kernel.elf}
LOG_FILE=${2:-/var/log/kern.log}
grep -oE '0x[0-9a-f]+' "$LOG_FILE" | sort -u | while read addr; do
symbol=$(addr2line -f -e "$KERNEL_ELF" "$addr" 2>/dev/null | head -1)
if [ "$symbol" != "??" ]; then
echo "$addr -> $symbol"
fi
done
Related Tools
- crash - Kernel crash dump analyzer
- drgn - Programmable debugger for kernel analysis
- bpftrace - Dynamic tracing using eBPF
- perf - Performance analysis with symbol resolution
Conclusion
kallsyms is a powerful feature that enables kernel debugging even on stripped binaries. Tools like vmlinux-to-elf make it accessible for security researchers, SRE teams, and embedded developers who need to understand kernel behavior without source access.
Next time you face a cryptic kernel panic, remember: the symbols are probably still in there.
Need to automate kernel debugging and incident response? Akmatori AI agents can analyze crash dumps, resolve symbols, and diagnose issues automatically.
