LinuxKPI: add seq_hex_dump()

Move the implementation of print_hex_dump() into linux_compat.c as
lkpi_hex_dump() taking an extra function pointer and argument.
Add two internal wrappers for printf and sbuf_printf to get a common
function definition (sbuf_printf takes the extra argument).

Use these to implement print_hex_dump() and the newly added
seq_hex_dump().

This allows us to re-use the same implementation of print_hex_dump()
for both functions without duplicating the code.

Initial implementation:	D49381 by dumbbell
Sponsored by:	The FreeBSD Foundation
MFC after:	3 days
Reviewed by:	dumbbell
Differential Revision: https://reviews.freebsd.org/D49637
This commit is contained in:
Bjoern A. Zeeb 2025-04-02 18:06:05 +00:00
parent 2cb892c0b6
commit 4359672e65
3 changed files with 102 additions and 46 deletions

View file

@ -44,57 +44,19 @@ enum {
DUMP_PREFIX_OFFSET
};
int __lkpi_hexdump_printf(void *, const char *, ...) __printflike(2, 3);
void lkpi_hex_dump(int(*)(void *, const char *, ...), void *arg1,
const char *, const char *, const int, const int, const int,
const void *, size_t, const bool);
static inline void
print_hex_dump(const char *level, const char *prefix_str,
const int prefix_type, const int rowsize, const int groupsize,
const void *buf, size_t len, const bool ascii)
{
typedef const struct { long long value; } __packed *print_64p_t;
typedef const struct { uint32_t value; } __packed *print_32p_t;
typedef const struct { uint16_t value; } __packed *print_16p_t;
const void *buf_old = buf;
int row;
while (len > 0) {
if (level != NULL)
printf("%s", level);
if (prefix_str != NULL)
printf("%s ", prefix_str);
switch (prefix_type) {
case DUMP_PREFIX_ADDRESS:
printf("[%p] ", buf);
break;
case DUMP_PREFIX_OFFSET:
printf("[%#tx] ", ((const char *)buf -
(const char *)buf_old));
break;
default:
break;
}
for (row = 0; row != rowsize; row++) {
if (groupsize == 8 && len > 7) {
printf("%016llx ", ((print_64p_t)buf)->value);
buf = (const uint8_t *)buf + 8;
len -= 8;
} else if (groupsize == 4 && len > 3) {
printf("%08x ", ((print_32p_t)buf)->value);
buf = (const uint8_t *)buf + 4;
len -= 4;
} else if (groupsize == 2 && len > 1) {
printf("%04x ", ((print_16p_t)buf)->value);
buf = (const uint8_t *)buf + 2;
len -= 2;
} else if (len > 0) {
printf("%02x ", *(const uint8_t *)buf);
buf = (const uint8_t *)buf + 1;
len--;
} else {
break;
}
}
printf("\n");
}
lkpi_hex_dump(__lkpi_hexdump_printf, NULL, level, prefix_str, prefix_type,
rowsize, groupsize, buf, len, ascii);
}
static inline void

View file

@ -28,9 +28,13 @@
#ifndef _LINUXKPI_LINUX_SEQ_FILE_H_
#define _LINUXKPI_LINUX_SEQ_FILE_H_
#include <sys/types.h>
#include <sys/sbuf.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/string_helpers.h>
#include <linux/printk.h>
#undef file
#define inode vnode
@ -89,6 +93,16 @@ void lkpi_seq_printf(struct seq_file *m, const char *fmt, ...);
#define seq_vprintf(...) lkpi_seq_vprintf(__VA_ARGS__)
#define seq_printf(...) lkpi_seq_printf(__VA_ARGS__)
int __lkpi_hexdump_sbuf_printf(void *, const char *, ...) __printflike(2, 3);
static inline void
seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type,
int rowsize, int groupsize, const void *buf, size_t len, bool ascii)
{
lkpi_hex_dump(__lkpi_hexdump_sbuf_printf, m->buf, NULL, prefix_str, prefix_type,
rowsize, groupsize, buf, len, ascii);
}
#define file linux_file
#endif /* _LINUXKPI_LINUX_SEQ_FILE_H_ */

View file

@ -96,6 +96,8 @@
#include <linux/rcupdate.h>
#include <linux/interval_tree.h>
#include <linux/interval_tree_generic.h>
#include <linux/printk.h>
#include <linux/seq_file.h>
#if defined(__i386__) || defined(__amd64__)
#include <asm/smp.h>
@ -1969,6 +1971,84 @@ kasprintf(gfp_t gfp, const char *fmt, ...)
return (p);
}
int
__lkpi_hexdump_printf(void *arg1 __unused, const char *fmt, ...)
{
va_list ap;
int result;
va_start(ap, fmt);
result = vprintf(fmt, ap);
va_end(ap);
return (result);
}
int
__lkpi_hexdump_sbuf_printf(void *arg1, const char *fmt, ...)
{
va_list ap;
int result;
va_start(ap, fmt);
result = sbuf_vprintf(arg1, fmt, ap);
va_end(ap);
return (result);
}
void
lkpi_hex_dump(int(*_fpf)(void *, const char *, ...), void *arg1,
const char *level, const char *prefix_str,
const int prefix_type, const int rowsize, const int groupsize,
const void *buf, size_t len, const bool ascii)
{
typedef const struct { long long value; } __packed *print_64p_t;
typedef const struct { uint32_t value; } __packed *print_32p_t;
typedef const struct { uint16_t value; } __packed *print_16p_t;
const void *buf_old = buf;
int row;
while (len > 0) {
if (level != NULL)
_fpf(arg1, "%s", level);
if (prefix_str != NULL)
_fpf(arg1, "%s ", prefix_str);
switch (prefix_type) {
case DUMP_PREFIX_ADDRESS:
_fpf(arg1, "[%p] ", buf);
break;
case DUMP_PREFIX_OFFSET:
_fpf(arg1, "[%#tx] ", ((const char *)buf -
(const char *)buf_old));
break;
default:
break;
}
for (row = 0; row != rowsize; row++) {
if (groupsize == 8 && len > 7) {
_fpf(arg1, "%016llx ", ((print_64p_t)buf)->value);
buf = (const uint8_t *)buf + 8;
len -= 8;
} else if (groupsize == 4 && len > 3) {
_fpf(arg1, "%08x ", ((print_32p_t)buf)->value);
buf = (const uint8_t *)buf + 4;
len -= 4;
} else if (groupsize == 2 && len > 1) {
_fpf(arg1, "%04x ", ((print_16p_t)buf)->value);
buf = (const uint8_t *)buf + 2;
len -= 2;
} else if (len > 0) {
_fpf(arg1, "%02x ", *(const uint8_t *)buf);
buf = (const uint8_t *)buf + 1;
len--;
} else {
break;
}
}
_fpf(arg1, "\n");
}
}
static void
linux_timer_callback_wrapper(void *context)
{