Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

seq_buf: Add printing formatted hex dumps

Provided function is an analogue of print_hex_dump().

Implementing this function in seq_buf allows using for multiple
purposes (e.g. for tracing) and therefore prevents from code duplication
in every layer that uses seq_buf.

print_hex_dump() is an essential part of logging data to dmesg. Adding
similar capability for other purposes is beneficial to all users.

Example usage:
seq_buf_hex_dump(seq, "", DUMP_PREFIX_OFFSET, 16, 4, buf,
ARRAY_SIZE(buf), true);
Example output:
00000000: 00000000 ffffff10 ffffff32 ffff3210 ........2....2..
00000010: ffff3210 83d00437 c0700000 00000000 .2..7.....p.....
00000020: 02010004 0000000f 0000000f 00004002 .............@..
00000030: 00000fff 00000000 ........

Link: http://lkml.kernel.org/r/1573130738-29390-1-git-send-email-piotrx.maziarz@linux.intel.com

Signed-off-by: Piotr Maziarz <piotrx.maziarz@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>

authored by

Piotr Maziarz and committed by
Steven Rostedt (VMware)
353cade3 c7411a1a

+65
+3
include/linux/seq_buf.h
··· 125 125 extern int seq_buf_putmem_hex(struct seq_buf *s, const void *mem, 126 126 unsigned int len); 127 127 extern int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc); 128 + extern int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, 129 + int prefix_type, int rowsize, int groupsize, 130 + const void *buf, size_t len, bool ascii); 128 131 129 132 #ifdef CONFIG_BINARY_PRINTF 130 133 extern int
+62
lib/seq_buf.c
··· 328 328 s->readpos += cnt; 329 329 return cnt; 330 330 } 331 + 332 + /** 333 + * seq_buf_hex_dump - print formatted hex dump into the sequence buffer 334 + * @s: seq_buf descriptor 335 + * @prefix_str: string to prefix each line with; 336 + * caller supplies trailing spaces for alignment if desired 337 + * @prefix_type: controls whether prefix of an offset, address, or none 338 + * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) 339 + * @rowsize: number of bytes to print per line; must be 16 or 32 340 + * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1) 341 + * @buf: data blob to dump 342 + * @len: number of bytes in the @buf 343 + * @ascii: include ASCII after the hex output 344 + * 345 + * Function is an analogue of print_hex_dump() and thus has similar interface. 346 + * 347 + * linebuf size is maximal length for one line. 348 + * 32 * 3 - maximum bytes per line, each printed into 2 chars + 1 for 349 + * separating space 350 + * 2 - spaces separating hex dump and ascii representation 351 + * 32 - ascii representation 352 + * 1 - terminating '\0' 353 + * 354 + * Returns zero on success, -1 on overflow 355 + */ 356 + int seq_buf_hex_dump(struct seq_buf *s, const char *prefix_str, int prefix_type, 357 + int rowsize, int groupsize, 358 + const void *buf, size_t len, bool ascii) 359 + { 360 + const u8 *ptr = buf; 361 + int i, linelen, remaining = len; 362 + unsigned char linebuf[32 * 3 + 2 + 32 + 1]; 363 + int ret; 364 + 365 + if (rowsize != 16 && rowsize != 32) 366 + rowsize = 16; 367 + 368 + for (i = 0; i < len; i += rowsize) { 369 + linelen = min(remaining, rowsize); 370 + remaining -= rowsize; 371 + 372 + hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize, 373 + linebuf, sizeof(linebuf), ascii); 374 + 375 + switch (prefix_type) { 376 + case DUMP_PREFIX_ADDRESS: 377 + ret = seq_buf_printf(s, "%s%p: %s\n", 378 + prefix_str, ptr + i, linebuf); 379 + break; 380 + case DUMP_PREFIX_OFFSET: 381 + ret = seq_buf_printf(s, "%s%.8x: %s\n", 382 + prefix_str, i, linebuf); 383 + break; 384 + default: 385 + ret = seq_buf_printf(s, "%s%s\n", prefix_str, linebuf); 386 + break; 387 + } 388 + if (ret) 389 + return ret; 390 + } 391 + return 0; 392 + }