内核中的格式化打印
背景
最近在调试个异常卡死的问题时,需要打印某个pcie link的,故学习了下内核里的打印,特此记录。
printk(“acpi_pci_link_set–>%pfwf, irq: %d\n”, &link->device->fwnode, irq);
内核中的格式化打印主要分为整型和指针。
整型
signed char		%d or %hhx
unsigned char		%u or %x
char			%u or %x
short int		%d or %hx
unsigned short int	%u or %x
int			%d or %x
unsigned int		%u or %x
long			%ld or %lx
unsigned long		%lu or %lx
long long		%lld or %llx
unsigned long long	%llu or %llx
size_t			%zu or %zx
ssize_t			%zd or %zx
s8			%d or %hhx
u8			%u or %x
s16			%d or %hx
u16			%u or %x
s32			%d or %x
u32			%u or %x
s64			%lld or %llx
u64			%llu or %llx
内核的printf不支持%n,浮点型(%e, %f, %g, %a)等。
有些类型的大小依赖配置选项如(如sector_t, blkcnt_t)或架构(如 tcflag_t),这时使用其可能的最大类型的格式占位符并显式强制转换为它。
指针类型
内核支持扩展占位符来打印不同类型的指针,有些不止能够打印指针地址,还能打印给定地址上的数据,名称或者相关提示等。
目前支持的指针类型如下:
- 普通指针
 - 错误指针
 - 符号/函数指针
 - 来自BPF / tracing追踪的探查指针
 - 内核指针
 - 未修改的地址
 - 指针差异
 - 结构体资源
 - 物理地址类型phys_addr_t
 - DMA地址类型dma_addr_t
 - 原始缓冲区为转义字符串
 - 原始缓冲区为hex字符串
 - MAC/FDDI 地址
 - IPv4 地址
 - IPv6 地址
 - IPv4/IPv6 地址 (generic, with port, flowinfo, scope)
 - UUID/GUID 地址
 - 目录项(dentry)的名称
 - 块设备(block_device)名称
 - va_format结构体
 - 设备树节点
 - Fwnode handles
 - 时间和日期
 - clk结构体
 - 位图及其扩展,如cpumask和nodemask
 - 标志位字段,如页标志、gfp_flags
 - 网络设备特性
 - V4L2和DRM FourCC代码(像素格式)
 - Rust
 
下面展开几个可能比较常用的
符号/函数指针
%pS	versatile_init+0x0/0x110
%ps	versatile_init
%pSR	versatile_init+0x9/0x110
	(with __builtin_extract_return_addr() translation)
%pB	prev_fn_of_versatile_init+0x88/0x88
S 和 s 用于打印符号格式的指针。(S)带有偏移量,(s)不带。如果禁用KALLSYMS,则打印符号地址。
如果指针在一个模块内,模块名称将被打印在符号名称之后,如果再添加一个额外的 b,后面还会打印构建ID。
例如:
%pS	versatile_init+0x0/0x110 [module_name]
%pSb	versatile_init+0x0/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
%pSRb	versatile_init+0x9/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
	(with __builtin_extract_return_addr() translation)
%pBb	prev_fn_of_versatile_init+0x88/0x88 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
MAC/FDDI地址
%pM	00:01:02:03:04:05
%pMR	05:04:03:02:01:00
%pMF	00-01-02-03-04-05
%pm	000102030405
%pmR	050403020100
用于打印以十六进制表示的6字节MAC/FDDI地址。 M带有分隔符, m则不带 。默认的字节分隔符是冒号(:)。
对于FDDI地址,可以在 M 占位符之后使用 F ,以使用破折号(——)分隔符代替默认的分隔符。
对于蓝牙地址, R 占位符应用在 M 占位符之后,以使用反转的字节顺序,适合于以小尾端顺序的蓝牙地址。
IPv4 地址
%pI4	1.2.3.4
%pi4	001.002.003.004
%p[Ii]4[hnbl]
用于打印IPv4点分隔的十进制地址。 I4 和 i4 占位符是打印的地址有(i4)或没有(I4)前导零。
附加的 h 、 n 、 b 和 l 占位符分别用于指定主机、网络、大端或小端地址。如果没有提供占位符,则使用默认的网络/大尾端顺序。
IPv6 地址
%pI6	0001:0002:0003:0004:0005:0006:0007:0008
%pi6	00010002000300040005000600070008
%pI6c	1:2:3:4:5:6:7:8
用于打印IPv6网络顺序的16位十六进制地址。 I6 和 i6 占位符是打印的地址有(I6)或没有(i6)分号,始终使用前导零。
额外的 c 占位符可与 I 占位符一起使用,以打印压缩的IPv6地址,如https://tools.ietf.org/html/rfc5952 所述
UUID/GUID地址
%pUb	00010203-0405-0607-0809-0a0b0c0d0e0f
%pUB	00010203-0405-0607-0809-0A0B0C0D0E0F
%pUl	03020100-0504-0706-0809-0a0b0c0e0e0f
%pUL	03020100-0504-0706-0809-0A0B0C0E0E0F
用于打印16字节的UUID/GUIDs地址。附加的 l , L , b 和 B 占位符用于指定小写(l)或大写(L)十六进制的小端顺序,以及小写(b)或大写(B)十六进制的大端顺序。
如果没有使用额外的占位符,则默认打印小写十六进制的大端顺序
块设备(block_device)名称
%pg	sda, sda1 or loop0p1
用于打印block_device指针的名称。
设备树节点
%pOF[fnpPcCF]
用于打印设备树节点结构,默认为%pOFf。
其余参数说明:
- f - 设备节点全称
 - n - 设备节点名
 - p - 设备节点句柄
 - P - 设备节点路径规范(名称+@单位)
 - F - 设备节点标志位
 - c - 主要兼容字符串
 - C - 全兼容字符串
 
当使用多个参数时,分隔符是’:’,例如:
%pOF	/foo/bar@0			- Node full name
%pOFf	/foo/bar@0			- Same as above
%pOFfp	/foo/bar@0:10			- Node full name + phandle
%pOFfcF	/foo/bar@0:foo,device:--P-	- Node full name + major compatible string + node flags
节点标志位(node flags)说明:
- D - dynamic
 - d - detached
 - P - Populated
 - B - Populated bus
 
Fwnode handles
%pfw[fP]
用于打印fwnode_handles的消息。默认情况打印完整的节点名称,包括路径。
其余参数说明:
- f - 节点的全名,包括路径。
 - P - 节点名称,包括地址(如果有的话)。
 
- (ACPI)例子:
%pfwf \_SB.PCI0.CIO2.port@1.endpoint@0 - Full node name %pfwP endpoint@0 - Node name - (OF)设备树例子:
%pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name %pfwP endpoint - Node name时间和日期
用于以我们(人类)可读的格式打印日期和时间:%pt[RT] YYYY-mm-ddTHH:MM:SS %pt[RT]s YYYY-mm-dd HH:MM:SS %pt[RT]d YYYY-mm-dd %pt[RT]t HH:MM:SS %pt[RT][dt][r][s]
默认情况下,年将以1900为单位递增,月将以1为单位递增。R struct rtc_time structure T time64_t type%pt[RT]s(空格)将覆盖ISO 8601的分隔符,在日期和时间之间使用’’(空格)而不是’T’(大写T)。当日期或时间被省略时,它不会有任何影响。 
V4L2和DRM FourCC代码(像素格式)
打印V4L2或DRM使用的FourCC代码,包括格式端序及其十六进制的数值
%p4cc	BG12 little-endian (0x32314742)
%p4cc	Y10  little-endian (0x20303159)
%p4cc	NV12 big-endian (0xb231564e)
参考
- 内核文档:Documentation/core-api/printk-formats.rst
 


 
