直接看/proc/kallsyms是最准、最实时的内核符号表查看方式,但默认因kptr_restrict=2被掩码为全0;临时解禁需echo 0 > /proc/sys/kernel/kptr_restrict,永久生效则配置kernel.kptr_restrict=0并sysctl -p。

直接看 /proc/kallsyms 就是最准、最实时的方式,但它默认对非 root 用户隐藏地址——这不是“查不到”,而是被 kptr_restrict 主动掩码了。
为什么 cat /proc/kallsyms 全是 0?
这是内核从 2.6.38 起默认启用的安全机制:kptr_restrict=2,所有符号地址强制显示为 0000000000000000,哪怕你有 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 启动的调试工具)暴露真实地址
怎么快速定位函数或变量?注意符号类型和前缀
直接 grep 容易漏匹配,因为符号名常带下划线前缀(比如 __do_sys_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}'
/proc/kallsyms 和 System.map 到底该用哪个?
两者不是替代关系,是动态视图 vs 静态快照。选错会导致地址无效或找不到模块符号。
-
/proc/kallsyms包含所有已加载模块符号,实时更新,但受kptr_restrict控制 -
System.map是编译时生成的静态文件(路径如/boot/System.map-$(uname -r)),不含模块,地址固定但不反映 KASLR 实际偏移 - 调试 panic 日志里的地址时,先确认是否启用了 KASLR —— 若启用了,
System.map地址大概率对不上,必须用当时运行中的/proc/kallsyms - 模块开发中要定位本模块符号,
/proc/kallsyms更可靠;分析离线vmlinux文件,则用nm vmlinux
真正容易被忽略的是:即使你拿到了函数地址,也不代表能安全调用它——很多未导出函数(比如 __do_sys_openat)没有稳定 ABI,内核版本一升级就可能改名、删掉或行为变更;更关键的是,kallsyms_lookup_name() 自 5.12 起已彻底移出导出列表,依赖它的模块在新版发行版(如 RHEL 8.8+)上会直接失败。











