Reprint printk debugging

5. Format characters of printk

The format characters of printk corresponding to common data types are as follows:

    int %d or %x
    unsigned int %u, %x
    long %ld, %lx
    unsigned long %lu, %lx
    long long %lld, %llx
    unsigned long long %llu, %llx
    size_t %zu, %zx
    ssize_t %zd, %zx

 

5.1 print pointer

Use% p to print the pointer, but this is extended in printk.

  • %PS,% pf print the corresponding symbol name / function name and offset
  • %PS,% pf print the corresponding symbol name / function name

5.2 print restricted kernel address

Use% pK to print restricted kernel addresses

  • %pK and / proc / sys / kernel / kptr_ When restrict = 0, it can be printed directly
  • %pK and / proc / sys / kernel / kptr_ When restrict = 1, all addresses are printed as 0 (unless CAP_SYSLOG is configured).
  • %pK and / proc / sys / kernel / kptr_ When restrict = 2, all addresses are printed as 0.

kptr_restrict = 0, all users can read the kernel symbol address.

kptr_restrict = 1. Ordinary users cannot read the kernel symbol address. root users can view it.

kptr_restrict = 2, all users cannot read the kernel symbol address.

5.3 print structure resources

  • %pr print structure resource
  • %pR print structure resource, including a decoding tag

Print physical address

  • %pa

5.4 print raw buffer (below 64 bytes, print_hex_dump should be used for larger buffer)

  • %*ph, space division, such as 00 01 02
  • %*phC, colon division, such as 00:01:02
  • %*phD, horizontal bar division, such as 00-01-02
  • %*phN, no delimiter, such as 000102

5.5 print MAC/FDDI

  • %pM, colon division, such as 00:01:02:03:04:05
  • %pMR, colon division, reverse order, such as 05:04; 03; 02: 01: 00
  • %pMF, horizontal bar division, such as 00-01-02-03-04-05
  • %pm, no segmentation, such as 000102030405
  • %pmR, no division, reverse order, such as 0504030201

5.6 printing ipv4 address

  • %pI4, form of 1.2.3.4
  • %pi4001.002.003.004 form
  • [hnbl] the additional 'h', 'n', 'b', 'l' is used to specify whether the byte order of the parameter is host byte order or network byte order, or large end alignment or small end alignment. The default address of printk is the network byte order, and it is automatically converted to the host byte order and then printed without additional byte order conversion

5.7 printing ipv6 address

  • %pI6 ,00010003; 0004; 0005; 0006; Form of 0007:0008
  • %pi6001002003004005006007008 form
  • %pI6C, 1; 2; 3: 4; 5; 6: 7:8 form

5.8 printing UUID/GUID

  • %pUb small letter large endian
  • %pUB capital letter large end order
  • %pUl small letter small end order
  • %pUL capital letter small end order

5.9 print structure

  • %pV print the name and value of each member of the structure

6. Macro based on printk

It is too troublesome to specify log level every time printk is used. The kernel defines a set of macros.

    #ifndef pr_fmt
    #define pr_fmt(fmt) fmt
    #endif
    #define pr_emerg(fmt, ...) \
    printk(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__)
    #define pr_alert(fmt, ...) \
    printk(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__)
    #define pr_crit(fmt, ...) \
    printk(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__)
    #define pr_err(fmt, ...) \
    printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
    #define pr_warning(fmt, ...) \
    printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
    #define pr_warn pr_warning
    #define pr_notice(fmt, ...) \
    printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
    #define pr_info(fmt, ...) \
    printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
    #define pr_cont(fmt, ...) \
    printk(KERN_CONT fmt, ##__VA_ARGS__)

 

7. pr_debug, pr_devel

The kernel also defines a set of print macros pr_devel is only effective when building the DEBUG kernel, but it can also be started with the DEBUG macro.

    #ifdef DEBUG
    #define pr_devel(fmt, ...) \
    printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    #else
    #define pr_devel(fmt, ...) \
    no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    #endif

 

There is also a set of macro pr_debug, and PR_ Compared with devel, it can also be used for dynamic debug.

    #if defined(DEBUG)
    #define pr_debug(fmt, ...) \
    printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    #elif defined(CONFIG_DYNAMIC_DEBUG)
    /@@* dynamic_pr_debug() uses pr_fmt() internally so we don't need it here */
    #define pr_debug(fmt, ...) \
    dynamic_pr_debug(fmt, ##__VA_ARGS__)
    #else
    #define pr_debug(fmt, ...) \
    no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    #endif

 

8. Prevent printk from swiping the screen

In places where printk is frequently executed, inserting printk will result in a large number of messages being output and other messages being brushed out. In order to control the number of times printk is output, printk can be used_ ratelimited(…).

'#include' required

printk_ratelimited(...) will ensure that the output times of each bar is no more than 10 times in 5 seconds. If more precise frequency control is required, you can set DEFINE_RATELIMIT_STATE macro and use__ ratelimit function.

"/ proc/sys/kernel/printk_ratelimit" defines the minimum time interval between messages, and "/ proc/sys/kernel/printk_ratelimit_burst" defines the number of messages, that is, in printk_ Maximum printk in ratelimit seconds_ ratelimit_ Burst message.

The printk of each level also has corresponding macros such as "pr_err_ratelimited", "pr_debug_ratelimited", "pr_info_ratelimited".

If you only need to print once, you can use printk_once(…) .

9. dev_xxx()

In the process of developing device drivers, when outputting messages, you often want to attach device related information, such as device name. You can use device_ printk().

  1. int dev_printk(const char *level, const struct device *dev, const char *fmt, ...);

dev_printk() can additionally output driver name or bus name, device name of the device. If you are not satisfied with these output contents, you can__ dev_printk() encapsulates a message output function, dev_printk() is based on the encapsulation of this function.

If you want to output messages only in the DEBUG version or dynamic debug, you can use dev_dbg().

    #if defined(CONFIG_DYNAMIC_DEBUG)
    #define dev_dbg(dev, format, ...) \
    do { \
    dynamic_dev_dbg(dev, format, ##__VA_ARGS__); \
    } while (0)
    #elif defined(DEBUG)
    #define dev_dbg(dev, format, arg...) \
    dev_printk(KERN_DEBUG, dev, format, ##arg)
    #else
    #define dev_dbg(dev, format, arg...) \
    ({ \
    if (0) \
    dev_printk(KERN_DEBUG, dev, format, ##arg); \
    0; \
    })
    #endif

 

Similarly, there are dev of different message levels that limit the output frequency_ XXX () macro.

    #define dev_emerg_ratelimited(dev, fmt, ...) \
    dev_level_ratelimited(dev_emerg, dev, fmt, ##__VA_ARGS__)
    #define dev_alert_ratelimited(dev, fmt, ...) \
    dev_level_ratelimited(dev_alert, dev, fmt, ##__VA_ARGS__)
    #define dev_crit_ratelimited(dev, fmt, ...) \
    dev_level_ratelimited(dev_crit, dev, fmt, ##__VA_ARGS__)
    #define dev_err_ratelimited(dev, fmt, ...) \
    dev_level_ratelimited(dev_err, dev, fmt, ##__VA_ARGS__)
    #define dev_warn_ratelimited(dev, fmt, ...) \
    dev_level_ratelimited(dev_warn, dev, fmt, ##__VA_ARGS__)
    #define dev_notice_ratelimited(dev, fmt, ...) \
    dev_level_ratelimited(dev_notice, dev, fmt, ##__VA_ARGS__)
    #define dev_info_ratelimited(dev, fmt, ...) \
    dev_level_ratelimited(dev_info, dev, fmt, ##__VA_ARGS__)

 

DEBUG and dynamic debug versions can also limit the output frequency, dev_dbg_ratelimited()

    #if defined(CONFIG_DYNAMIC_DEBUG) || defined(DEBUG)
    #define dev_dbg_ratelimited(dev, fmt, ...) \
    do { \
    static DEFINE_RATELIMIT_STATE(_rs, \
    DEFAULT_RATELIMIT_INTERVAL, \
    DEFAULT_RATELIMIT_BURST); \
    DEFINE_DYNAMIC_DEBUG_METADATA(descriptor, fmt); \
    if (unlikely(descriptor.flags & _DPRINTK_FLAGS_PRINT) && \
    __ratelimit(&_rs)) \
    __dynamic_pr_debug(&descriptor, pr_fmt(fmt), \
    ##__VA_ARGS__); \
    } while (0)
    #else
    #define dev_dbg_ratelimited(dev, fmt, ...) \
    no_printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__)
    #endif

 

10. Print kernel messages in user space

The "/ dev/kmsg" device provides a way to output kernel messages in user space, which can be created using the mknod -m 600 /dev/kmsg c 1 11 command.

 echo "Hello Kernel-World" > /dev/kmsg

 

Alternatively, a leading number can be used to indicate the message level.

# echo "2Writing critical printk messages from userspace" >/dev/kmsg

 

The number 2 equals Kern_ The level of crit.

Using dmesg -u, you can see all kernel messages printed from user space.

11. Encapsulate printk to create an exclusive printing function

It's too troublesome to add line number and function name for debugging every time. Why not encapsulate an exclusive print log function?

#define log_info(fmt, arg...) printk(KERN_INFO "[%s][%d] "fmt"", __func__, __LINE__, ##arg);

 

Among them_ func_ _LINE_ Represents the current function name and line number respectively.

12. View the message output by printk

In user space, you can view kernel messages in the following ways

  • dmesg command
  • cat /proc/kmsg (it will not return, it will always wait and output new kernel messages, and the previous messages will not be output again)
  • cat //var/log/syslog

Dmesg is the most commonly used method. Some control parameters can be added when using the dmesg command

  • -C empties the ring buffer for kernel messages
  • -c List kernel messages and empty the ring buffer
  • -k prints only kernel messages output from the kernel
  • -u prints only kernel messages printed from user space
  • -n adjust the level of messages to be printed to the console
  • -s sets the size of the ring buffer

Added by dannyb785 on Sat, 29 Jan 2022 11:10:30 +0200