📜 ⬆️ ⬇️

Making the code cleaner: Special vsnprintf () extensions in the Linux kernel

Looking at a bunch of source code that programmers send to the mailing lists of the Linux kernel subsystems sometimes you feel like crying. On the one hand, there is a terrible and indecent code, on the other - people may be trying to do something for the kernel for the first time, so they do not know all its features.

Book Linux Device Drivers is outdated, and the new version will be released soon. Therefore, I would like to fill in the gaps in the knowledge of those programmers who write code in the kernel.

In this article I will discuss the special extensions of the print function in the Linux kernel. Do not be embarrassed that I put out its traditional name in the header in the main C library, printk() and macros are used more often in the kernel.

So, I will take the vanilla kernel version 4.0-rc2 as a basis . I will not consider standard specifiers, anyone can read printf (3).
')
All special extensions fall within the % p specifier. By default, it prints the memory address referenced by the pointer. In the core, you often want to do something much more specific. To do this, we decided to go by adding modifiers to the specifier, so in general the specifier looks like this:
 %[ ]p[   ,    ] 


Below, I tried to break down all extensions into groups and give brief descriptions and sometimes examples.

Pointers to special addresses



% pK

Same as % p , but kptr_restrict sysctl is checked, 0'i are printed, if the user does not have enough rights.

% pa [pd]

Prints a pointer to a physical memory address or DMA (phys_addr_t, dma_addr_t) and inherited types resource_size_t. It is passed by reference, for example:

 phys_addr_t pa; dma_addr_t da; pr_debug("Phys: %pa DMA: %pad\n", &pa, &da); 


Network addresses



% p [Mm] [FR]

Prints the MAC address transmitted by the pointer to the buffer. M - standard MAC address, m - without colons, additional modifier R in reverse format (first the last byte of the address is printed).

 u8 mac[ETH_ALEN]; pr_debug("%pMR\n", mac); 


% p [Ii] 4 [hnbl],% p [Ii] 6 [c],% p [Ii] S [pfschnbl]

Prints in various combinations of IPv4 addresses (__be32 addr), IPv6 (__be32 addr [4]), and struct sockaddr (autodetection).

Data buffer dump



% * pE [achnops]

Prints a string with escapes. Flags define classes of characters that must be escaped.

 const char *buf; int len; pr_debug("Buffer: %*pE Buffer[0-5]: %6pE\n", len, buf, buf); 


% * ph [CDN]

Prints a memory dump (up to 64 bytes) in hexadecimal. Modifiers define a separator: the default space, C - colon, D - hyphens, N - without separator.

 u8 data[100]; pr_debug("Buf: %*phC\n", (int)sizeof(data), data); /* only first 64 bytes! */ 


% pU [Ll] [Bb]

Designed to output a UUID (16-byte buffer) in various formats. Modifiers determine the size of the letters (large or small) and the writing order of the UUID: B or b are high bytes at the beginning, L or l are low bytes at the beginning.

% * pb [l]

Dumps bitmaps and its heirs (cpumask, nodemask). The l modifier defines dump output by ranges. The length field determines how many bits are in one element of the bitmap.

Contents of structures, their fields and special data types



% p [Rr]

Prints the contents of the struct resource.

 struct resource res; pr_debug("%pR\n", &res); 


% pV

Outputting data defined by the va_format and va_list structures. Essentially a recursive vsnprintf() call from under itself. Be sure to check the validity of the parameters and arguments in va_format and va_list!

% pNF

Qualifier for type netdev_features_t.

% pd [234],% pD [234]

Prints the path and file name (struct dentry, d_name.name field). 2 , 3 or 4 limits the number of path elements (from the end). % pD is the same, but for struct file (f_path.dentry).

Print function name at



% p [Ff],% p [Ss] [R],% pB

The qualifier may be useful for printing the name of the function at the address, for example, to know the calling function.

In a future release



Additional extensions are planned for 4.1-rc1 .

% pC [nr]

It is intended to display the name and frequency of the oscillator stored in struct clk.

% pT

Displays the name of the currently running process or task defined in struct task_struct.

 struct task_struct *task = known_task; pr_debug("Current: %pT, given: %pT\n", NULL, task); 


Bonuses



The function print_hex_dump() intended to output large buffer dumps in hexadecimal format.

To convert ASCII <-> binary data, use a set of such functions:

 /*    */ hex_to_bin(); /*  */ hex2bin(); /*  */ 


To convert a MAC address from a text view, use mac_pton() .

 /*  ASCII  */ hex_asc_lo(); hex_asc_hi(); /*  */ hex_asc_upper_lo(); hex_asc_upper_hi(); /*  ,    */ hex_byte_pack(); hex_byte_pack_upper(); /*  */ bin2hex(); /*  */ hex_dump_to_buffer(); /*     print_hex_dump() */ 


Happy printing!

Source: https://habr.com/ru/post/252453/


All Articles