一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Linux 如何查看系统的内核符号表

时间:2026-07-07 08:02:57 编辑:袖梨 来源:一聚教程网

cat /proc/kallsyms 全是 0 是因内核默认启用 kptr_restrict=2,主动将所有符号地址掩码为 0000000000000000,连 root 也看不到;临时解决需 echo 0 > /proc/sys/kernel/kptr_restrict,永久生效则配置 kernel.kptr_restrict=0 并 sysctl -p。

cat /proc/kallsyms 为什么全是 0?

这不是查不到,是内核故意把地址掩码成 0000000000000000。从 2.6.38 开始,默认 kptr_restrict=2,连 root 都看不到真实地址。

  • 临时放开:运行 echo 0 > /proc/sys/kernel/kptr_restrict(需 root)
  • 永久生效:在 /etc/sysctl.confkernel.kptr_restrict = 0,再执行 sysctl -p
  • kptr_restrict=1 时,只有具备 CAP_SYSLOG 能力的进程(如 syslogd 或 root 启动的某些调试工具)能见真实地址

grep 查函数或变量时总漏匹配?

符号名常带下划线前缀(比如 __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}'

System.map 和 /proc/kallsyms 到底该用哪个?

两者不是替代关系,是静态快照 vs 动态视图。选错会导致地址无效或找不到模块符号。

  • /proc/kallsyms 包含所有已加载模块符号,实时更新,但受 kptr_restrict 控制
  • System.map 是编译时生成的静态文件(路径如 /boot/System.map-$(uname -r)),不含模块,地址固定但不反映 KASLR 实际偏移
  • 调试 panic 日志里的地址时,先看当时是否启用了 KASLR —— 若启用了,System.map 地址大概率对不上,必须用当时运行中的 /proc/kallsyms
  • 模块开发中要定位本模块符号,/proc/kallsyms 更可靠;分析离线 vmlinux 文件,则用 nm vmlinux

kallsyms_lookup_name() 在模块里调用失败?

这个函数自 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 接口(如果可用)
真正麻烦的不是“怎么查”,而是查到的地址能不能用。KASLR、模块热插拔、kptr_restrict 级别、内核版本对 kallsyms_lookup_name 的策略变化——这些因素叠加起来,让一次看似简单的符号查找,可能在不同机器、不同启动状态下给出完全不同的结果。

热门栏目