内核中的格式化打印
背景
最近在调试个异常卡死的问题时,需要打印某个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