Back to home page

OSCL-LXR

 
 

    


0001 .. include:: ../disclaimer-zh_CN.rst
0002 
0003 :Original: Documentation/core-api/printk-formats.rst
0004 
0005 :翻译:
0006 
0007  司延腾 Yanteng Si <siyanteng@loongson.cn>
0008  周彬彬 Binbin Zhou <zhoubinbin@loongson.cn>
0009 
0010 .. _cn_printk-formats.rst:
0011 
0012 ==============================
0013 如何获得正确的printk格式占位符
0014 ==============================
0015 
0016 
0017 
0018 :作者: Randy Dunlap <rdunlap@infradead.org>
0019 :作者: Andrew Murray <amurray@mpc-data.co.uk>
0020 
0021 
0022 整数类型
0023 ========
0024 
0025 ::
0026 
0027                 若变量类型是Type,则使用printk格式占位符。
0028                 -------------------------------------------
0029                 char                    %d 或 %x
0030                 unsigned char           %u 或 %x
0031                 short int               %d 或 %x
0032                 unsigned short int      %u 或 %x
0033                 int                     %d 或 %x
0034                 unsigned int            %u 或 %x
0035                 long                    %ld 或 %lx
0036                 unsigned long           %lu 或 %lx
0037                 long long               %lld 或 %llx
0038                 unsigned long long      %llu 或 %llx
0039                 size_t                  %zu 或 %zx
0040                 ssize_t                 %zd 或 %zx
0041                 s8                      %d 或 %x
0042                 u8                      %u 或 %x
0043                 s16                     %d 或 %x
0044                 u16                     %u 或 %x
0045                 s32                     %d 或 %x
0046                 u32                     %u 或 %x
0047                 s64                     %lld 或 %llx
0048                 u64                     %llu 或 %llx
0049 
0050 
0051 如果 <type> 的大小依赖于配置选项 (例如 sector_t, blkcnt_t) 或其大小依赖于架构
0052 (例如 tcflag_t),则使用其可能的最大类型的格式占位符并显式强制转换为它。
0053 
0054 例如
0055 
0056 ::
0057 
0058         printk("test: sector number/total blocks: %llu/%llu\n",
0059                 (unsigned long long)sector, (unsigned long long)blockcount);
0060 
0061 提醒:sizeof()返回类型为size_t。
0062 
0063 内核的printf不支持%n。显而易见,浮点格式(%e, %f, %g, %a)也不被识别。使用任何不
0064 支持的占位符或长度限定符都会导致一个WARN并且终止vsnprintf()执行。
0065 
0066 指针类型
0067 ========
0068 
0069 一个原始指针值可以用%p打印,它将在打印前对地址进行哈希处理。内核也支持扩展占位符来打印
0070 不同类型的指针。
0071 
0072 一些扩展占位符会打印给定地址上的数据,而不是打印地址本身。在这种情况下,以下错误消息可能
0073 会被打印出来,而不是无法访问的消息::
0074 
0075         (null)   data on plain NULL address
0076         (efault) data on invalid address
0077         (einval) invalid data on a valid address
0078 
0079 普通指针
0080 ----------
0081 
0082 ::
0083 
0084         %p      abcdef12 or 00000000abcdef12
0085 
0086 没有指定扩展名的指针(即没有修饰符的%p)被哈希(hash),以防止内核内存布局消息的泄露。这
0087 样还有一个额外的好处,就是提供一个唯一的标识符。在64位机器上,前32位被清零。当没有足够的
0088 熵进行散列处理时,内核将打印(ptrval)代替
0089 
0090 如果可能的话,使用专门的修饰符,如%pS或%pB(如下所述),以避免打印一个必须事后解释的非哈
0091 希地址。如果不可能,而且打印地址的目的是为调试提供更多的消息,使用%p,并在调试过程中
0092 用 ``no_hash_pointers`` 参数启动内核,这将打印所有未修改的%p地址。如果你 *真的* 想知
0093 道未修改的地址,请看下面的%px。
0094 
0095 如果(也只有在)你将地址作为虚拟文件的内容打印出来,例如在procfs或sysfs中(使用
0096 seq_printf(),而不是printk())由用户空间进程读取,使用下面描述的%pK修饰符,不
0097 要用%p或%px。
0098 
0099 
0100 错误指针
0101 --------
0102 
0103 ::
0104 
0105         %pe     -ENOSPC
0106 
0107 用于打印错误指针(即IS_ERR()为真的指针)的符号错误名。不知道符号名的错误值会以十进制打印,
0108 而作为%pe参数传递的非ERR_PTR会被视为普通的%p。
0109 
0110 符号/函数指针
0111 -------------
0112 
0113 ::
0114 
0115         %pS     versatile_init+0x0/0x110
0116         %ps     versatile_init
0117         %pSR    versatile_init+0x9/0x110
0118                 (with __builtin_extract_return_addr() translation)
0119         %pB     prev_fn_of_versatile_init+0x88/0x88
0120 
0121 
0122 ``S`` 和 ``s`` 占位符用于打印符号格式的指针。它们的结果是符号名称带有(S)或不带有(s)偏移
0123 量。如果禁用KALLSYMS,则打印符号地址。
0124 
0125 ``B`` 占位符的结果是带有偏移量的符号名,在打印堆栈回溯时应该使用。占位符将考虑编译器优化
0126 的影响,当使用尾部调用并使用noreturn GCC属性标记时,可能会发生这种优化。
0127 
0128 如果指针在一个模块内,模块名称和可选的构建ID将被打印在符号名称之后,并在说明符的末尾添加
0129 一个额外的 ``b`` 。
0130 
0131 ::
0132 
0133         %pS     versatile_init+0x0/0x110 [module_name]
0134         %pSb    versatile_init+0x0/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
0135         %pSRb   versatile_init+0x9/0x110 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
0136                 (with __builtin_extract_return_addr() translation)
0137         %pBb    prev_fn_of_versatile_init+0x88/0x88 [module_name ed5019fdf5e53be37cb1ba7899292d7e143b259e]
0138 
0139 来自BPF / tracing追踪的探查指针
0140 ----------------------------------
0141 
0142 ::
0143 
0144         %pks    kernel string
0145         %pus    user string
0146 
0147 ``k`` 和 ``u`` 指定符用于打印来自内核内存(k)或用户内存(u)的先前探测的内存。后面的 ``s`` 指
0148 定符的结果是打印一个字符串。对于直接在常规的vsnprintf()中使用时,(k)和(u)注释被忽略,但是,当
0149 在BPF的bpf_trace_printk()之外使用时,它会读取它所指向的内存,不会出现错误。
0150 
0151 内核指针
0152 --------
0153 
0154 ::
0155 
0156         %pK     01234567 or 0123456789abcdef
0157 
0158 用于打印应该对非特权用户隐藏的内核指针。%pK的行为取决于kptr_restrict sysctl——详见
0159 Documentation/admin-guide/sysctl/kernel.rst。
0160 
0161 未经修改的地址
0162 --------------
0163 
0164 ::
0165 
0166         %px     01234567 or 0123456789abcdef
0167 
0168 对于打印指针,当你 *真的* 想打印地址时。在用%px打印指针之前,请考虑你是否泄露了内核内
0169 存布局的敏感消息。%px在功能上等同于%lx(或%lu)。%px是首选,因为它在grep查找时更唯一。
0170 如果将来我们需要修改内核处理打印指针的方式,我们将能更好地找到调用点。
0171 
0172 在使用%px之前,请考虑使用%p并在调试过程中启用' ' no_hash_pointer ' '内核参数是否足
0173 够(参见上面的%p描述)。%px的一个有效场景可能是在panic发生之前立即打印消息,这样无论如何
0174 都可以防止任何敏感消息被利用,使用%px就不需要用no_hash_pointer来重现panic。
0175 
0176 指针差异
0177 --------
0178 
0179 ::
0180 
0181         %td     2560
0182         %tx     a00
0183 
0184 为了打印指针的差异,使用ptrdiff_t的%t修饰符。
0185 
0186 例如::
0187 
0188         printk("test: difference between pointers: %td\n", ptr2 - ptr1);
0189 
0190 结构体资源(Resources)
0191 -----------------------
0192 
0193 ::
0194 
0195         %pr     [mem 0x60000000-0x6fffffff flags 0x2200] or
0196                 [mem 0x0000000060000000-0x000000006fffffff flags 0x2200]
0197         %pR     [mem 0x60000000-0x6fffffff pref] or
0198                 [mem 0x0000000060000000-0x000000006fffffff pref]
0199 
0200 用于打印结构体资源。 ``R`` 和 ``r`` 占位符的结果是打印出的资源带有(R)或不带有(r)解码标志
0201 成员。
0202 
0203 通过引用传递。
0204 
0205 物理地址类型 phys_addr_t
0206 ------------------------
0207 
0208 ::
0209 
0210         %pa[p]  0x01234567 or 0x0123456789abcdef
0211 
0212 用于打印phys_addr_t类型(以及它的衍生物,如resource_size_t),该类型可以根据构建选项而
0213 变化,无论CPU数据真实物理地址宽度如何。
0214 
0215 通过引用传递。
0216 
0217 DMA地址类型dma_addr_t
0218 ---------------------
0219 
0220 ::
0221 
0222         %pad    0x01234567 or 0x0123456789abcdef
0223 
0224 用于打印dma_addr_t类型,该类型可以根据构建选项而变化,而不考虑CPU数据路径的宽度。
0225 
0226 通过引用传递。
0227 
0228 原始缓冲区为转义字符串
0229 ----------------------
0230 
0231 ::
0232 
0233         %*pE[achnops]
0234 
0235 用于将原始缓冲区打印成转义字符串。对于以下缓冲区::
0236 
0237                 1b 62 20 5c 43 07 22 90 0d 5d
0238 
0239 几个例子展示了如何进行转换(不包括两端的引号)。::
0240 
0241                 %*pE            "\eb \C\a"\220\r]"
0242                 %*pEhp          "\x1bb \C\x07"\x90\x0d]"
0243                 %*pEa           "\e\142\040\\\103\a\042\220\r\135"
0244 
0245 转换规则是根据可选的标志组合来应用的(详见:c:func:`string_escape_mem` 内核文档):
0246 
0247         - a - ESCAPE_ANY
0248         - c - ESCAPE_SPECIAL
0249         - h - ESCAPE_HEX
0250         - n - ESCAPE_NULL
0251         - o - ESCAPE_OCTAL
0252         - p - ESCAPE_NP
0253         - s - ESCAPE_SPACE
0254 
0255 默认情况下,使用 ESCAPE_ANY_NP。
0256 
0257 ESCAPE_ANY_NP是许多情况下的明智选择,特别是对于打印SSID。
0258 
0259 如果字段宽度被省略,那么将只转义1个字节。
0260 
0261 原始缓冲区为十六进制字符串
0262 --------------------------
0263 
0264 ::
0265 
0266         %*ph    00 01 02  ...  3f
0267         %*phC   00:01:02: ... :3f
0268         %*phD   00-01-02- ... -3f
0269         %*phN   000102 ... 3f
0270 
0271 对于打印小的缓冲区(最长64个字节),可以用一定的分隔符作为一个
0272 十六进制字符串。对于较大的缓冲区,可以考虑使用
0273 :c:func:`print_hex_dump` 。
0274 
0275 MAC/FDDI地址
0276 ------------
0277 
0278 ::
0279 
0280         %pM     00:01:02:03:04:05
0281         %pMR    05:04:03:02:01:00
0282         %pMF    00-01-02-03-04-05
0283         %pm     000102030405
0284         %pmR    050403020100
0285 
0286 用于打印以十六进制表示的6字节MAC/FDDI地址。 ``M`` 和 ``m`` 占位符导致打印的
0287 地址有(M)或没有(m)字节分隔符。默认的字节分隔符是冒号(:)。
0288 
0289 对于FDDI地址,可以在 ``M`` 占位符之后使用 ``F`` 说明,以使用破折号(——)分隔符
0290 代替默认的分隔符。
0291 
0292 对于蓝牙地址, ``R`` 占位符应使用在 ``M`` 占位符之后,以使用反转的字节顺序,适
0293 合于以小尾端顺序的蓝牙地址的肉眼可见的解析。
0294 
0295 通过引用传递。
0296 
0297 IPv4地址
0298 --------
0299 
0300 ::
0301 
0302         %pI4    1.2.3.4
0303         %pi4    001.002.003.004
0304         %p[Ii]4[hnbl]
0305 
0306 用于打印IPv4点分隔的十进制地址。 ``I4`` 和 ``i4`` 占位符的结果是打印的地址
0307 有(i4)或没有(I4)前导零。
0308 
0309 附加的 ``h`` 、 ``n`` 、 ``b`` 和 ``l`` 占位符分别用于指定主机、网络、大
0310 尾端或小尾端地址。如果没有提供占位符,则使用默认的网络/大尾端顺序。
0311 
0312 通过引用传递。
0313 
0314 IPv6 地址
0315 ---------
0316 
0317 ::
0318 
0319         %pI6    0001:0002:0003:0004:0005:0006:0007:0008
0320         %pi6    00010002000300040005000600070008
0321         %pI6c   1:2:3:4:5:6:7:8
0322 
0323 用于打印IPv6网络顺序的16位十六进制地址。 ``I6`` 和 ``i6`` 占位符的结果是
0324 打印的地址有(I6)或没有(i6)分号。始终使用前导零。
0325 
0326 额外的 ``c`` 占位符可与 ``I`` 占位符一起使用,以打印压缩的IPv6地址,如
0327 https://tools.ietf.org/html/rfc5952 所述
0328 
0329 通过引用传递。
0330 
0331 IPv4/IPv6地址(generic, with port, flowinfo, scope)
0332 --------------------------------------------------
0333 
0334 ::
0335 
0336         %pIS    1.2.3.4         or 0001:0002:0003:0004:0005:0006:0007:0008
0337         %piS    001.002.003.004 or 00010002000300040005000600070008
0338         %pISc   1.2.3.4         or 1:2:3:4:5:6:7:8
0339         %pISpc  1.2.3.4:12345   or [1:2:3:4:5:6:7:8]:12345
0340         %p[Ii]S[pfschnbl]
0341 
0342 用于打印一个IP地址,不需要区分它的类型是AF_INET还是AF_INET6。一个指向有效结构
0343 体sockaddr的指针,通过 ``IS`` 或 ``IS`` 指定,可以传递给这个格式占位符。
0344 
0345 附加的 ``p`` 、  ``f`` 和 ``s`` 占位符用于指定port(IPv4, IPv6)、
0346 flowinfo (IPv6)和sope(IPv6)。port有一个 ``:`` 前缀,flowinfo是 ``/`` 和
0347 范围是 ``%`` ,每个后面都跟着实际的值。
0348 
0349 对于IPv6地址,如果指定了额外的指定符 ``c`` ,则使用
0350 https://tools.ietf.org/html/rfc5952 描述的压缩IPv6地址。
0351 如https://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-07
0352 所建议的,IPv6地址由'[',']'包围,以防止出现额外的占位符 ``p`` , ``f`` 或 ``s`` 。
0353 
0354 对于IPv4地址,也可以使用额外的 ``h`` , ``n`` , ``b`` 和 ``l`` 说
0355 明符,但对于IPv6地址则忽略。
0356 
0357 通过引用传递。
0358 
0359 更多例子::
0360 
0361         %pISfc          1.2.3.4         or [1:2:3:4:5:6:7:8]/123456789
0362         %pISsc          1.2.3.4         or [1:2:3:4:5:6:7:8]%1234567890
0363         %pISpfc         1.2.3.4:12345   or [1:2:3:4:5:6:7:8]:12345/123456789
0364 
0365 UUID/GUID地址
0366 -------------
0367 
0368 ::
0369 
0370         %pUb    00010203-0405-0607-0809-0a0b0c0d0e0f
0371         %pUB    00010203-0405-0607-0809-0A0B0C0D0E0F
0372         %pUl    03020100-0504-0706-0809-0a0b0c0e0e0f
0373         %pUL    03020100-0504-0706-0809-0A0B0C0E0E0F
0374 
0375 用于打印16字节的UUID/GUIDs地址。附加的 ``l`` , ``L`` , ``b`` 和 ``B`` 占位符用
0376 于指定小写(l)或大写(L)十六进制表示法中的小尾端顺序,以及小写(b)或大写(B)十六进制表
0377 示法中的大尾端顺序。
0378 
0379 如果没有使用额外的占位符,则将打印带有小写十六进制表示法的默认大端顺序。
0380 
0381 通过引用传递。
0382 
0383 目录项(dentry)的名称
0384 ----------------------
0385 
0386 ::
0387 
0388         %pd{,2,3,4}
0389         %pD{,2,3,4}
0390 
0391 用于打印dentry名称;如果我们用 :c:func:`d_move` 和它比较,名称可能是新旧混合的,但
0392 不会oops。 %pd dentry比较安全,其相当于我们以前用的%s dentry->d_name.name,%pd<n>打
0393 印 ``n`` 最后的组件。 %pD对结构文件做同样的事情。
0394 
0395 
0396 通过引用传递。
0397 
0398 块设备(block_device)名称
0399 --------------------------
0400 
0401 ::
0402 
0403         %pg     sda, sda1 or loop0p1
0404 
0405 用于打印block_device指针的名称。
0406 
0407 va_format结构体
0408 ---------------
0409 
0410 ::
0411 
0412         %pV
0413 
0414 用于打印结构体va_format。这些结构包含一个格式字符串
0415 和va_list如下
0416 
0417 ::
0418 
0419         struct va_format {
0420                 const char *fmt;
0421                 va_list *va;
0422         };
0423 
0424 实现 "递归vsnprintf"。
0425 
0426 如果没有一些机制来验证格式字符串和va_list参数的正确性,请不要使用这个功能。
0427 
0428 通过引用传递。
0429 
0430 设备树节点
0431 ----------
0432 
0433 ::
0434 
0435         %pOF[fnpPcCF]
0436 
0437 
0438 用于打印设备树节点结构。默认行为相当于%pOFf。
0439 
0440         - f - 设备节点全称
0441         - n - 设备节点名
0442         - p - 设备节点句柄
0443         - P - 设备节点路径规范(名称+@单位)
0444         - F - 设备节点标志
0445         - c - 主要兼容字符串
0446         - C - 全兼容字符串
0447 
0448 当使用多个参数时,分隔符是':'。
0449 
0450 例如
0451 
0452 ::
0453 
0454         %pOF    /foo/bar@0                      - Node full name
0455         %pOFf   /foo/bar@0                      - Same as above
0456         %pOFfp  /foo/bar@0:10                   - Node full name + phandle
0457         %pOFfcF /foo/bar@0:foo,device:--P-      - Node full name +
0458                                                   major compatible string +
0459                                                   node flags
0460                                                         D - dynamic
0461                                                         d - detached
0462                                                         P - Populated
0463                                                         B - Populated bus
0464 
0465 通过引用传递。
0466 
0467 Fwnode handles
0468 --------------
0469 
0470 ::
0471 
0472         %pfw[fP]
0473 
0474 用于打印fwnode_handles的消息。默认情况下是打印完整的节点名称,包括路径。
0475 这些修饰符在功能上等同于上面的%pOF。
0476 
0477         - f - 节点的全名,包括路径。
0478         - P - 节点名称,包括地址(如果有的话)。
0479 
0480 例如 (ACPI)
0481 
0482 ::
0483 
0484         %pfwf   \_SB.PCI0.CIO2.port@1.endpoint@0        - Full node name
0485         %pfwP   endpoint@0                              - Node name
0486 
0487 例如 (OF)
0488 
0489 ::
0490 
0491         %pfwf   /ocp@68000000/i2c@48072000/camera@10/port/endpoint - Full name
0492         %pfwP   endpoint                                - Node name
0493 
0494 时间和日期
0495 ----------
0496 
0497 ::
0498 
0499         %pt[RT]                 YYYY-mm-ddTHH:MM:SS
0500         %pt[RT]s                YYYY-mm-dd HH:MM:SS
0501         %pt[RT]d                YYYY-mm-dd
0502         %pt[RT]t                HH:MM:SS
0503         %pt[RT][dt][r][s]
0504 
0505 用于打印日期和时间::
0506 
0507         R  struct rtc_time structure
0508         T  time64_t type
0509 
0510 以我们(人类)可读的格式。
0511 
0512 默认情况下,年将以1900为单位递增,月将以1为单位递增。 使用%pt[RT]r (raw)
0513 来抑制这种行为。
0514 
0515 %pt[RT]s(空格)将覆盖ISO 8601的分隔符,在日期和时间之间使用''(空格)而
0516 不是'T'(大写T)。当日期或时间被省略时,它不会有任何影响。
0517 
0518 通过引用传递。
0519 
0520 clk结构体
0521 ---------
0522 
0523 ::
0524 
0525         %pC     pll1
0526         %pCn    pll1
0527 
0528 用于打印clk结构。%pC 和 %pCn 打印时钟的名称(通用时钟框架)或唯一的32位
0529 ID(传统时钟框架)。
0530 
0531 通过引用传递。
0532 
0533 位图及其衍生物,如cpumask和nodemask
0534 -----------------------------------
0535 
0536 ::
0537 
0538         %*pb    0779
0539         %*pbl   0,3-6,8-10
0540 
0541 对于打印位图(bitmap)及其派生的cpumask和nodemask,%*pb输出以字段宽度为位数的位图,
0542 %*pbl输出以字段宽度为位数的范围列表。
0543 
0544 字段宽度用值传递,位图用引用传递。可以使用辅助宏cpumask_pr_args()和
0545 nodemask_pr_args()来方便打印cpumask和nodemask。
0546 
0547 标志位字段,如页标志、gfp_flags
0548 -------------------------------
0549 
0550 ::
0551 
0552         %pGp    0x17ffffc0002036(referenced|uptodate|lru|active|private|node=0|zone=2|lastcpupid=0x1fffff)
0553         %pGg    GFP_USER|GFP_DMA32|GFP_NOWARN
0554         %pGv    read|exec|mayread|maywrite|mayexec|denywrite
0555 
0556 将flags位字段打印为构造值的符号常量集合。标志的类型由第三个字符给出。目前支持的
0557 是[p]age flags, [v]ma_flags(都期望 ``unsigned long *`` )和
0558 [g]fp_flags(期望 ``gfp_t *`` )。标志名称和打印顺序取决于特定的类型。
0559 
0560 注意,这种格式不应该直接用于跟踪点的:c:func:`TP_printk()` 部分。相反,应使
0561 用 <trace/events/mmflags.h>中的show_*_flags()函数。
0562 
0563 通过引用传递。
0564 
0565 网络设备特性
0566 ------------
0567 
0568 ::
0569 
0570         %pNF    0x000000000000c000
0571 
0572 用于打印netdev_features_t。
0573 
0574 通过引用传递。
0575 
0576 V4L2和DRM FourCC代码(像素格式)
0577 ------------------------------
0578 
0579 ::
0580 
0581         %p4cc
0582 
0583 打印V4L2或DRM使用的FourCC代码,包括格式端序及其十六进制的数值。
0584 
0585 通过引用传递。
0586 
0587 例如::
0588 
0589         %p4cc   BG12 little-endian (0x32314742)
0590         %p4cc   Y10  little-endian (0x20303159)
0591         %p4cc   NV12 big-endian (0xb231564e)
0592 
0593 谢谢
0594 ====
0595 
0596 如果您添加了其他%p扩展,请在可行的情况下,用一个或多个测试用例扩展<lib/test_printf.c>。
0597 
0598 谢谢你的合作和关注。