printk-formats.rst (16551B)
1.. include:: ../disclaimer-zh_CN.rst 2 3:Original: Documentation/core-api/printk-formats.rst 4 5:翻译: 6 7 司延腾 Yanteng Si <siyanteng@loongson.cn> 8 9.. _cn_printk-formats.rst: 10 11============================== 12如何获得正确的printk格式占位符 13============================== 14 15 16 17:作者: Randy Dunlap <rdunlap@infradead.org> 18:作者: Andrew Murray <amurray@mpc-data.co.uk> 19 20 21整数类型 22======== 23 24:: 25 26 若变量类型是Type,则使用printk格式占位符。 27 ------------------------------------------- 28 char %d 或 %x 29 unsigned char %u 或 %x 30 short int %d 或 %x 31 unsigned short int %u 或 %x 32 int %d 或 %x 33 unsigned int %u 或 %x 34 long %ld 或 %lx 35 unsigned long %lu 或 %lx 36 long long %lld 或 %llx 37 unsigned long long %llu 或 %llx 38 size_t %zu 或 %zx 39 ssize_t %zd 或 %zx 40 s8 %d 或 %x 41 u8 %u 或 %x 42 s16 %d 或 %x 43 u16 %u 或 %x 44 s32 %d 或 %x 45 u32 %u 或 %x 46 s64 %lld 或 %llx 47 u64 %llu 或 %llx 48 49 50如果 <type> 的大小依赖于配置选项 (例如 sector_t, blkcnt_t) 或其大小依赖于架构 51(例如 tcflag_t),则使用其可能的最大类型的格式占位符并显式强制转换为它。 52 53例如 54 55:: 56 57 printk("test: sector number/total blocks: %llu/%llu\n", 58 (unsigned long long)sector, (unsigned long long)blockcount); 59 60提醒:sizeof()返回类型为size_t。 61 62内核的printf不支持%n。显而易见,浮点格式(%e, %f, %g, %a)也不被识别。使用任何不 63支持的占位符或长度限定符都会导致一个WARN并且终止vsnprintf()执行。 64 65指针类型 66======== 67 68一个原始指针值可以用%p打印,它将在打印前对地址进行哈希处理。内核也支持扩展占位符来打印 69不同类型的指针。 70 71一些扩展占位符会打印给定地址上的数据,而不是打印地址本身。在这种情况下,以下错误消息可能 72会被打印出来,而不是无法访问的消息:: 73 74 (null) data on plain NULL address 75 (efault) data on invalid address 76 (einval) invalid data on a valid address 77 78普通指针 79---------- 80 81:: 82 83 %p abcdef12 or 00000000abcdef12 84 85没有指定扩展名的指针(即没有修饰符的%p)被哈希(hash),以防止内核内存布局消息的泄露。这 86样还有一个额外的好处,就是提供一个唯一的标识符。在64位机器上,前32位被清零。当没有足够的 87熵进行散列处理时,内核将打印(ptrval)代替 88 89如果可能的话,使用专门的修饰符,如%pS或%pB(如下所述),以避免打印一个必须事后解释的非哈 90希地址。如果不可能,而且打印地址的目的是为调试提供更多的消息,使用%p,并在调试过程中 91用 ``no_hash_pointers`` 参数启动内核,这将打印所有未修改的%p地址。如果你 *真的* 想知 92道未修改的地址,请看下面的%px。 93 94如果(也只有在)你将地址作为虚拟文件的内容打印出来,例如在procfs或sysfs中(使用 95seq_printf(),而不是printk())由用户空间进程读取,使用下面描述的%pK修饰符,不 96要用%p或%px。 97 98 99错误指针 100-------- 101 102:: 103 104 %pe -ENOSPC 105 106用于打印错误指针(即IS_ERR()为真的指针)的符号错误名。不知道符号名的错误值会以十进制打印, 107而作为%pe参数传递的非ERR_PTR会被视为普通的%p。 108 109符号/函数指针 110------------- 111 112:: 113 114 %pS versatile_init+0x0/0x110 115 %ps versatile_init 116 %pSR versatile_init+0x9/0x110 117 (with __builtin_extract_return_addr() translation) 118 %pB prev_fn_of_versatile_init+0x88/0x88 119 120 121``S`` 和 ``s`` 占位符用于打印符号格式的指针。它们的结果是符号名称带有(S)或不带有(s)偏移 122量。如果禁用KALLSYMS,则打印符号地址。 123 124``B`` 占位符的结果是带有偏移量的符号名,在打印堆栈回溯时应该使用。占位符将考虑编译器优化 125的影响,当使用尾部调用并使用noreturn GCC属性标记时,可能会发生这种优化。 126 127如果指针在一个模块内,模块名称和可选的构建ID将被打印在符号名称之后,并在说明符的末尾添加 128一个额外的 ``b`` 。 129 130:: 131 132 %pS versatile_init+0x0/0x110 [module_name] 133 %pSb versatile_init+0x0/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] 134 %pSRb versatile_init+0x9/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] 135 (with __builtin_extract_return_addr() translation) 136 %pBb prev_fn_of_versatile_init+0x88/0x88 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e] 137 138来自BPF / tracing追踪的探查指针 139---------------------------------- 140 141:: 142 143 %pks kernel string 144 %pus user string 145 146``k`` 和 ``u`` 指定符用于打印来自内核内存(k)或用户内存(u)的先前探测的内存。后面的 ``s`` 指 147定符的结果是打印一个字符串。对于直接在常规的vsnprintf()中使用时,(k)和(u)注释被忽略,但是,当 148在BPF的bpf_trace_printk()之外使用时,它会读取它所指向的内存,不会出现错误。 149 150内核指针 151-------- 152 153:: 154 155 %pK 01234567 or 0123456789abcdef 156 157用于打印应该对非特权用户隐藏的内核指针。%pK的行为取决于kptr_restrict sysctl——详见 158Documentation/admin-guide/sysctl/kernel.rst。 159 160未经修改的地址 161-------------- 162 163:: 164 165 %px 01234567 or 0123456789abcdef 166 167对于打印指针,当你 *真的* 想打印地址时。在用%px打印指针之前,请考虑你是否泄露了内核内 168存布局的敏感消息。%px在功能上等同于%lx(或%lu)。%px是首选,因为它在grep查找时更唯一。 169如果将来我们需要修改内核处理打印指针的方式,我们将能更好地找到调用点。 170 171在使用%px之前,请考虑使用%p并在调试过程中启用' ' no_hash_pointer ' '内核参数是否足 172够(参见上面的%p描述)。%px的一个有效场景可能是在panic发生之前立即打印消息,这样无论如何 173都可以防止任何敏感消息被利用,使用%px就不需要用no_hash_pointer来重现panic。 174 175指针差异 176-------- 177 178:: 179 180 %td 2560 181 %tx a00 182 183为了打印指针的差异,使用ptrdiff_t的%t修饰符。 184 185例如:: 186 187 printk("test: difference between pointers: %td\n", ptr2 - ptr1); 188 189结构体资源(Resources) 190----------------------- 191 192:: 193 194 %pr [mem 0x60000000-0x6fffffff flags 0x2200] or 195 [mem 0x0000000060000000-0x000000006fffffff flags 0x2200] 196 %pR [mem 0x60000000-0x6fffffff pref] or 197 [mem 0x0000000060000000-0x000000006fffffff pref] 198 199用于打印结构体资源。 ``R`` 和 ``r`` 占位符的结果是打印出的资源带有(R)或不带有(r)解码标志 200成员。 201 202通过引用传递。 203 204物理地址类型 phys_addr_t 205------------------------ 206 207:: 208 209 %pa[p] 0x01234567 or 0x0123456789abcdef 210 211用于打印phys_addr_t类型(以及它的衍生物,如resource_size_t),该类型可以根据构建选项而 212变化,无论CPU数据真实物理地址宽度如何。 213 214通过引用传递。 215 216DMA地址类型dma_addr_t 217--------------------- 218 219:: 220 221 %pad 0x01234567 or 0x0123456789abcdef 222 223用于打印dma_addr_t类型,该类型可以根据构建选项而变化,而不考虑CPU数据路径的宽度。 224 225通过引用传递。 226 227原始缓冲区为转义字符串 228---------------------- 229 230:: 231 232 %*pE[achnops] 233 234用于将原始缓冲区打印成转义字符串。对于以下缓冲区:: 235 236 1b 62 20 5c 43 07 22 90 0d 5d 237 238几个例子展示了如何进行转换(不包括两端的引号)。:: 239 240 %*pE "\eb \C\a"\220\r]" 241 %*pEhp "\x1bb \C\x07"\x90\x0d]" 242 %*pEa "\e\142\040\\\103\a\042\220\r\135" 243 244转换规则是根据可选的标志组合来应用的(详见:c:func:`string_escape_mem` 内核文档): 245 246 - a - ESCAPE_ANY 247 - c - ESCAPE_SPECIAL 248 - h - ESCAPE_HEX 249 - n - ESCAPE_NULL 250 - o - ESCAPE_OCTAL 251 - p - ESCAPE_NP 252 - s - ESCAPE_SPACE 253 254默认情况下,使用 ESCAPE_ANY_NP。 255 256ESCAPE_ANY_NP是许多情况下的明智选择,特别是对于打印SSID。 257 258如果字段宽度被省略,那么将只转义1个字节。 259 260原始缓冲区为十六进制字符串 261-------------------------- 262 263:: 264 265 %*ph 00 01 02 ... 3f 266 %*phC 00:01:02: ... :3f 267 %*phD 00-01-02- ... -3f 268 %*phN 000102 ... 3f 269 270对于打印小的缓冲区(最长64个字节),可以用一定的分隔符作为一个 271十六进制字符串。对于较大的缓冲区,可以考虑使用 272:c:func:`print_hex_dump` 。 273 274MAC/FDDI地址 275------------ 276 277:: 278 279 %pM 00:01:02:03:04:05 280 %pMR 05:04:03:02:01:00 281 %pMF 00-01-02-03-04-05 282 %pm 000102030405 283 %pmR 050403020100 284 285用于打印以十六进制表示的6字节MAC/FDDI地址。 ``M`` 和 ``m`` 占位符导致打印的 286地址有(M)或没有(m)字节分隔符。默认的字节分隔符是冒号(:)。 287 288对于FDDI地址,可以在 ``M`` 占位符之后使用 ``F`` 说明,以使用破折号(——)分隔符 289代替默认的分隔符。 290 291对于蓝牙地址, ``R`` 占位符应使用在 ``M`` 占位符之后,以使用反转的字节顺序,适 292合于以小尾端顺序的蓝牙地址的肉眼可见的解析。 293 294通过引用传递。 295 296IPv4地址 297-------- 298 299:: 300 301 %pI4 1.2.3.4 302 %pi4 001.002.003.004 303 %p[Ii]4[hnbl] 304 305用于打印IPv4点分隔的十进制地址。 ``I4`` 和 ``i4`` 占位符的结果是打印的地址 306有(i4)或没有(I4)前导零。 307 308附加的 ``h`` 、 ``n`` 、 ``b`` 和 ``l`` 占位符分别用于指定主机、网络、大 309尾端或小尾端地址。如果没有提供占位符,则使用默认的网络/大尾端顺序。 310 311通过引用传递。 312 313IPv6 地址 314--------- 315 316:: 317 318 %pI6 0001:0002:0003:0004:0005:0006:0007:0008 319 %pi6 00010002000300040005000600070008 320 %pI6c 1:2:3:4:5:6:7:8 321 322用于打印IPv6网络顺序的16位十六进制地址。 ``I6`` 和 ``i6`` 占位符的结果是 323打印的地址有(I6)或没有(i6)分号。始终使用前导零。 324 325额外的 ``c`` 占位符可与 ``I`` 占位符一起使用,以打印压缩的IPv6地址,如 326https://tools.ietf.org/html/rfc5952 所述 327 328通过引用传递。 329 330IPv4/IPv6地址(generic, with port, flowinfo, scope) 331-------------------------------------------------- 332 333:: 334 335 %pIS 1.2.3.4 or 0001:0002:0003:0004:0005:0006:0007:0008 336 %piS 001.002.003.004 or 00010002000300040005000600070008 337 %pISc 1.2.3.4 or 1:2:3:4:5:6:7:8 338 %pISpc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345 339 %p[Ii]S[pfschnbl] 340 341用于打印一个IP地址,不需要区分它的类型是AF_INET还是AF_INET6。一个指向有效结构 342体sockaddr的指针,通过 ``IS`` 或 ``IS`` 指定,可以传递给这个格式占位符。 343 344附加的 ``p`` 、 ``f`` 和 ``s`` 占位符用于指定port(IPv4, IPv6)、 345flowinfo (IPv6)和sope(IPv6)。port有一个 ``:`` 前缀,flowinfo是 ``/`` 和 346范围是 ``%`` ,每个后面都跟着实际的值。 347 348对于IPv6地址,如果指定了额外的指定符 ``c`` ,则使用 349https://tools.ietf.org/html/rfc5952 描述的压缩IPv6地址。 350如https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07 351所建议的,IPv6地址由'[',']'包围,以防止出现额外的占位符 ``p`` , ``f`` 或 ``s`` 。 352 353对于IPv4地址,也可以使用额外的 ``h`` , ``n`` , ``b`` 和 ``l`` 说 354明符,但对于IPv6地址则忽略。 355 356通过引用传递。 357 358更多例子:: 359 360 %pISfc 1.2.3.4 or [1:2:3:4:5:6:7:8]/123456789 361 %pISsc 1.2.3.4 or [1:2:3:4:5:6:7:8]%1234567890 362 %pISpfc 1.2.3.4:12345 or [1:2:3:4:5:6:7:8]:12345/123456789 363 364UUID/GUID地址 365------------- 366 367:: 368 369 %pUb 00010203-0405-0607-0809-0a0b0c0d0e0f 370 %pUB 00010203-0405-0607-0809-0A0B0C0D0E0F 371 %pUl 03020100-0504-0706-0809-0a0b0c0e0e0f 372 %pUL 03020100-0504-0706-0809-0A0B0C0E0E0F 373 374用于打印16字节的UUID/GUIDs地址。附加的 ``l`` , ``L`` , ``b`` 和 ``B`` 占位符用 375于指定小写(l)或大写(L)十六进制表示法中的小尾端顺序,以及小写(b)或大写(B)十六进制表 376示法中的大尾端顺序。 377 378如果没有使用额外的占位符,则将打印带有小写十六进制表示法的默认大端顺序。 379 380通过引用传递。 381 382目录项(dentry)的名称 383---------------------- 384 385:: 386 387 %pd{,2,3,4} 388 %pD{,2,3,4} 389 390用于打印dentry名称;如果我们用 :c:func:`d_move` 和它比较,名称可能是新旧混合的,但 391不会oops。 %pd dentry比较安全,其相当于我们以前用的%s dentry->d_name.name,%pd<n>打 392印 ``n`` 最后的组件。 %pD对结构文件做同样的事情。 393 394 395通过引用传递。 396 397块设备(block_device)名称 398-------------------------- 399 400:: 401 402 %pg sda, sda1 or loop0p1 403 404用于打印block_device指针的名称。 405 406va_format结构体 407--------------- 408 409:: 410 411 %pV 412 413用于打印结构体va_format。这些结构包含一个格式字符串 414和va_list如下 415 416:: 417 418 struct va_format { 419 const char *fmt; 420 va_list *va; 421 }; 422 423实现 "递归vsnprintf"。 424 425如果没有一些机制来验证格式字符串和va_list参数的正确性,请不要使用这个功能。 426 427通过引用传递。 428 429设备树节点 430---------- 431 432:: 433 434 %pOF[fnpPcCF] 435 436 437用于打印设备树节点结构。默认行为相当于%pOFf。 438 439 - f - 设备节点全称 440 - n - 设备节点名 441 - p - 设备节点句柄 442 - P - 设备节点路径规范(名称+@单位) 443 - F - 设备节点标志 444 - c - 主要兼容字符串 445 - C - 全兼容字符串 446 447当使用多个参数时,分隔符是':'。 448 449例如 450 451:: 452 453 %pOF /foo/bar@0 - Node full name 454 %pOFf /foo/bar@0 - Same as above 455 %pOFfp /foo/bar@0:10 - Node full name + phandle 456 %pOFfcF /foo/bar@0:foo,device:--P- - Node full name + 457 major compatible string + 458 node flags 459 D - dynamic 460 d - detached 461 P - Populated 462 B - Populated bus 463 464通过引用传递。 465 466Fwnode handles 467-------------- 468 469:: 470 471 %pfw[fP] 472 473用于打印fwnode_handles的消息。默认情况下是打印完整的节点名称,包括路径。 474这些修饰符在功能上等同于上面的%pOF。 475 476 - f - 节点的全名,包括路径。 477 - P - 节点名称,包括地址(如果有的话)。 478 479例如 (ACPI) 480 481:: 482 483 %pfwf \_SB.PCI0.CIO2.port@1.endpoint@0 - Full node name 484 %pfwP endpoint@0 - Node name 485 486例如 (OF) 487 488:: 489 490 %pfwf /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name 491 %pfwP endpoint - Node name 492 493时间和日期 494---------- 495 496:: 497 498 %pt[RT] YYYY-mm-ddTHH:MM:SS 499 %pt[RT]s YYYY-mm-dd HH:MM:SS 500 %pt[RT]d YYYY-mm-dd 501 %pt[RT]t HH:MM:SS 502 %pt[RT][dt][r][s] 503 504用于打印日期和时间:: 505 506 R struct rtc_time structure 507 T time64_t type 508 509以我们(人类)可读的格式。 510 511默认情况下,年将以1900为单位递增,月将以1为单位递增。 使用%pt[RT]r (raw) 512来抑制这种行为。 513 514%pt[RT]s(空格)将覆盖ISO 8601的分隔符,在日期和时间之间使用''(空格)而 515不是'T'(大写T)。当日期或时间被省略时,它不会有任何影响。 516 517通过引用传递。 518 519clk结构体 520--------- 521 522:: 523 524 %pC pll1 525 %pCn pll1 526 527用于打印clk结构。%pC 和 %pCn 打印时钟的名称(通用时钟框架)或唯一的32位 528ID(传统时钟框架)。 529 530通过引用传递。 531 532位图及其衍生物,如cpumask和nodemask 533----------------------------------- 534 535:: 536 537 %*pb 0779 538 %*pbl 0,3-6,8-10 539 540对于打印位图(bitmap)及其派生的cpumask和nodemask,%*pb输出以字段宽度为位数的位图, 541%*pbl输出以字段宽度为位数的范围列表。 542 543字段宽度用值传递,位图用引用传递。可以使用辅助宏cpumask_pr_args()和 544nodemask_pr_args()来方便打印cpumask和nodemask。 545 546标志位字段,如页标志、gfp_flags 547------------------------------- 548 549:: 550 551 %pGp referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff 552 %pGg GFP_USER|GFP_DMA32|GFP_NOWARN 553 %pGv read|exec|mayread|maywrite|mayexec|denywrite 554 555将flags位字段打印为构造值的符号常量集合。标志的类型由第三个字符给出。目前支持的 556是[p]age flags, [v]ma_flags(都期望 ``unsigned long *`` )和 557[g]fp_flags(期望 ``gfp_t *`` )。标志名称和打印顺序取决于特定的类型。 558 559注意,这种格式不应该直接用于跟踪点的:c:func:`TP_printk()` 部分。相反,应使 560用 <trace/events/mmflags.h>中的show_*_flags()函数。 561 562通过引用传递。 563 564网络设备特性 565------------ 566 567:: 568 569 %pNF 0x000000000000c000 570 571用于打印netdev_features_t。 572 573通过引用传递。 574 575V4L2和DRM FourCC代码(像素格式) 576------------------------------ 577 578:: 579 580 %p4cc 581 582打印V4L2或DRM使用的FourCC代码,包括格式端序及其十六进制的数值。 583 584通过引用传递。 585 586例如:: 587 588 %p4cc BG12 little-endian (0x32314742) 589 %p4cc Y10 little-endian (0x20303159) 590 %p4cc NV12 big-endian (0xb231564e) 591 592谢谢 593==== 594 595如果您添加了其他%p扩展,请在可行的情况下,用一个或多个测试用例扩展<lib/test_printf.c>。 596 597谢谢你的合作和关注。