Old scripts that still read /proc/ksyms have been broken since kernel 2.5.71: it moved to /proc/kallsyms. This guide reads the current kernel symbol table, explains why addresses sometimes show as zero, and shows how to spot code still chasing the retired path. Allow about ten minutes. You need a shell and a running Linux system with proc mounted. Every example only reads pseudo-files, so nothing here needs elevated privileges and nothing changes kernel or service state.
This guide follows the installed proc_ksyms(5) and proc_kallsyms(5) manual pages, from the manpages package version 6.7-2. The page is titled proc_kallsyms because that is the current interface; the retired name just gets a historical note.
Start by checking the path and the filesystem that provides it:
$ test -r /proc/kallsyms && echo readable
readable
$ findmnt -T /proc/kallsyms -o TARGET,FSTYPE,OPTIONS
TARGET FSTYPE OPTIONS
/proc proc rw,relatime
/proc/kallsyms is a procfs pseudo-file, not a normal file that you create or edit. Its contents describe the live kernel, so the result can differ after a reboot or after a kernel change. Do not use cp, an editor or output redirection against this path.
Checkpoint: If the test command prints nothing, check the mount without changing it:
$ findmnt /proc
$ mountpoint /proc
If procfs is not mounted, use the system's normal boot or container configuration process to restore it. Do not mount filesystems merely because a diagnostic script assumed this path would exist.
Read only the first few records while you are exploring. The file can be large and it represents kernel data, not a stable application API:
$ head -n 8 /proc/kallsyms
0000000000000000 A fixed_percpu_data
0000000000000000 A __per_cpu_start
0000000000000000 A cpu_debug_store
0000000000000000 A irq_stack_backing_store
0000000000000000 A cpu_tss_rw
0000000000000000 A gdt_page
0000000000000000 A exception_stacks
0000000000000000 A entry_stack_storage
Each line is a symbol record. In the common format, the first field is an address, the second is a symbol type, and the remaining text is the symbol name. The installed manual defines the file as the kernel's exported symbol definitions used by the modules tools to dynamically link and bind loadable modules. It does not promise that every line, type or address will have the same meaning across kernel builds.
The exact names and ordering above are from the running machine. Treat them as sample output, not values to hard-code in a portable script.
A readable symbol table does not guarantee readable addresses. On this machine the addresses are zeroed, while the records and names remain visible:
$ cat /proc/sys/kernel/kptr_restrict
1
kptr_restrict controls exposure of kernel pointer values. A value of 1 is a security boundary, not a read failure. Do not interpret zero addresses as evidence that the symbols are absent, and do not weaken the setting just to make a diagnostic display more attractive.
Compare the structure rather than expecting an address:
$ awk 'NF >= 3 { print "address=" $1, "type=" $2, "name=" $3; exit }' /proc/kallsyms
address=0000000000000000 type=A name=fixed_percpu_data
This is a read-only check and normally runs as an ordinary user. Some systems apply additional permission or namespace restrictions. If an application genuinely needs kernel addresses, establish the requirement and its security impact first, then follow the distribution and kernel policy for that host. Do not add broad privileges to a service simply to bypass an observation check.
For a known symbol, filter the stream with grep. Quote the pattern when it contains punctuation:
$ grep -m 5 -E '(^| )schedule$|^.* schedule$' /proc/kallsyms
0000000000000000 T schedule
The output depends on the kernel configuration and version. A missing match means that this running kernel did not expose a symbol with that exact name through this interface; it does not prove that a similarly named internal function, module symbol or debug symbol is absent.
For a quick count of records, use a streaming command:
$ awk 'END { print NR, "records" }' /proc/kallsyms
<record-count> records
The count is deliberately shown as a placeholder because it changes with the installed kernel and loaded modules. If a script consumes this file, validate fields defensively and expect an empty result, a permission error or a changed symbol set.
The installed history says that /proc/ksyms was the older interface on Linux 1.1.23 through 2.5.47. From Linux 2.5.71, the corresponding current path is /proc/kallsyms. Check both paths when diagnosing an old script:
$ for path in /proc/ksyms /proc/kallsyms; do
if test -e "$path"; then
printf '%s: present\n' "$path"
else
printf '%s: absent\n' "$path"
fi
done
/proc/ksyms: absent
/proc/kallsyms: present
Do not create a compatibility symlink in /proc. Procfs entries are controlled by the kernel, and the old file had slightly different syntax according to the manual. Update the consumer to use /proc/kallsyms and test its parser against the kernels you support.
/proc/kallsyms as a configuration file. There is nothing to save or restore.sudo./proc/kallsyms reads cleanly through procfs on the running system./proc/kallsyms, handle missing matches, and skip the retired /proc/ksyms syntax.