Let's make the code cleaner: Special vsnprintf () extensions in the Linux kernel

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

The Linux Device Drivers book is out of date, and the new version will not be available soon. Therefore, I want to fill in the gaps in the knowledge of those programmers who write code in the kernel.

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

So, I'll take the vanilla kernel version 4.0-rc2 as the basis . I will not consider standard qualifiers, anyone can read printf (3).

All special extensions fall on the % p specifier . By default, it prints the memory address referenced by the pointer. In the core, one often wants to do something much larger and more specific. To do this, we decided to go by adding modifiers to the specifier, so in the general case, the specifier looks like this:
%[длина поля]p[модификаторы в виде буквы, цифры или их сочетаний]

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

Pointers to special addresses

% pK

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

% pa [pd]

Prints a pointer to a physical memory or DMA address (phys_addr_t, dma_addr_t) and inherited types of resource_size_t. 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 passed by the pointer to the buffer. M - standard MAC address, m - without colons, an additional R modifier in reverse format (the last byte of the address is printed first).

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

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

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

Data buffer dump

% * pE [achnops]

Prints a string with escaped characters. Flags define the character classes to be escaped.

constchar *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 is a colon, D is a hyphen, and N is without a separator.

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

% pU [Ll] [Bb]

Intended for outputting UUIDs (16 bytes long buffer) in various formats. Modifiers determine the size of letters (large or small) and the order of writing UUID: B or b - high bytes at the beginning, L or l - low bytes at the beginning.

% * pb [l]

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

The contents of structures, their fields and special data types

% p [Rr]

Prints the contents of a struct resource.

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

% pV

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

% pNF Specifier

for type netdev_features_t.

% pd [234],% pD [234]

Prints the path and file name (struct dentry, field d_name.name). 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 specifier can be useful for printing the function name at the address, for example, to find out the calling function.

In a future release

It is planned to include additional extensions in 4.1-rc1 .

% pC [nr]

Designed to display the name and frequency of the oscillator stored in struct clk.

% pT

Print the name of the current executable process or task defined in struct task_struct.

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


To output large buffer dumps in hexadecimal format, the function is intended print_hex_dump().

To convert ASCII <—> binary data, a set of such functions is used:

/* В бинарный вид */
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() */

Have a good print!

Also popular now: