cat /proc/kallsyms 全是 0 是因内核默认启用 kptr_restrict=2,主动将所有符号地址掩码为 0000000000000000,连 root 也看不到;临时解决需 echo 0 > /proc/sys/kernel/kptr_restrict,永久生效则配置 kernel.kptr_restrict=0 并 sysctl -p。
这不是查不到,是内核故意把地址掩码成 0000000000000000。从 2.6.38 开始,默认 kptr_restrict=2,连 root 都看不到真实地址。
echo 0 > /proc/sys/kernel/kptr_restrict(需 root)/etc/sysctl.conf 加 kernel.kptr_restrict = 0,再执行 sysctl -p
kptr_restrict=1 时,只有具备 CAP_SYSLOG 能力的进程(如 syslogd 或 root 启动的某些调试工具)能见真实地址符号名常带下划线前缀(比如 __do_sys_ioctl),直接搜 ioctl 会失败;大小写、符号类型字段也影响结果。
" T " 或 " t " 过滤: grep " T " /proc/kallsyms | grep -i ioctl
" D " 或 " d ": grep " D " /proc/kallsyms | grep jiffies
grep -E "(do_sys|__do_sys)_ioctl" /proc/kallsyms
grep -i "printk" /proc/kallsyms | awk '{print $1, $3}'
两者不是替代关系,是静态快照 vs 动态视图。选错会导致地址无效或找不到模块符号。
/proc/kallsyms 包含所有已加载模块符号,实时更新,但受 kptr_restrict 控制System.map 是编译时生成的静态文件(路径如 /boot/System.map-$(uname -r)),不含模块,地址固定但不反映 KASLR 实际偏移System.map 地址大概率对不上,必须用当时运行中的 /proc/kallsyms
/proc/kallsyms 更可靠;分析离线 vmlinux 文件,则用 nm vmlinux
这个函数自 5.7 起不再导出,5.12 起彻底移出导出列表,且部分发行版(如 RHEL 8.8+)默认禁用接口。
unsigned long addr = kallsyms_lookup_name("unexported_func"); if (!addr) return -EINVAL;
#include <linux>(注意不是 <linux/kallsyms.h>,后者在较新内核中可能不暴露该函数)NULL —— 不代表符号不存在,而是接口被内核配置禁用或未启用 CONFIG_KALLSYMS
/proc/kallsyms 解析 + 用户态预读,或依赖 debugfs 下的 kallsyms 接口(如果可用)kptr_restrict 级别、内核版本对 kallsyms_lookup_name 的策略变化——这些因素叠加起来,让一次看似简单的符号查找,可能在不同机器、不同启动状态下给出完全不同的结果。