Linux kernel printk 占位符 %p 和 %px
1. %p
Linux 内核里的 printk 可以打印指针地址,这和 printf() 是一样的:
void *p = 0x1234;
printk("p = %p\n", p);
这里是想打印所指向的地址。实际运行起来后,看到的输出却是这样的:
p = (____ptrval____)
或者是这样的(并不是真实的地址):
p = 000000008a425fc2
通过查询代码和文档,内核打印这样实现目的,是为了避免内核地址的泄漏。
而显示内核地址,很可能仅仅是出于开发和调试的目的。对于研发过程中的这种需求,从文档中可以看到,可以在 bootargs 里加上参数 no_hash_pointers
来解决。
即使是这样,内核里也有非常明确的提醒,除非是调试,一定要避免使用这个选项。
[ 0.000000] **********************************************************
[ 0.000000] ** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **
[ 0.000000] ** **
[ 0.000000] ** This system shows unhashed kernel memory addresses **
[ 0.000000] ** via the console, logs, and other interfaces. This **
[ 0.000000] ** might reduce the security of your system. **
[ 0.000000] ** **
[ 0.000000] ** If you see this message and you are not debugging **
[ 0.000000] ** the kernel, report this immediately to your system **
[ 0.000000] ** administrator! **
[ 0.000000] ** **
[ 0.000000] ** NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE **
[ 0.000000] **********************************************************
2. %px
当然,如果实在是想打印内核地址,可以用 %px 占位符,比如:
void *p = 0x1234;
printk("p = %px\n", p);
同样的,按文档里的使用约定,这种用法是不合理的,应该尽量避免。
3. %p 的扩展
从 lib/vsprintf.c
里的 pointer()
函数可以看到,%p 后面还可以跟更多占位符,来实现多种内核数据类型的格式化,比如字符串、MAC 地址、IP 地址、UUID、struct clk 名字、fourcc 等等。因为功能太多了,确实不容易记忆,所以在需要使用的时候,参考 pointer()
函数里详细的注释说明,就可以了。
参考资料
- lib/vsprintf.c
- Documentation/core-api/printk-formats.rst