git: 719721ca4b4e - stable/14 - LinuxKPI: add seq_hex_dump()

From: Bjoern A. Zeeb <bz_at_FreeBSD.org>
Date: Fri, 18 Apr 2025 14:36:57 UTC
The branch stable/14 has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=719721ca4b4e03f9e4945fb6ba31a18023a45a0c

commit 719721ca4b4e03f9e4945fb6ba31a18023a45a0c
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-04-02 18:06:05 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-04-18 14:35:58 +0000

    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
    Reviewed by:    dumbbell
    Differential Revision: https://reviews.freebsd.org/D49637
    
    (cherry picked from commit 4359672e656af5e6758d0aae147212e58f445f5b)
---
 sys/compat/linuxkpi/common/include/linux/printk.h  | 54 +++------------
 .../linuxkpi/common/include/linux/seq_file.h       | 14 ++++
 sys/compat/linuxkpi/common/src/linux_compat.c      | 80 ++++++++++++++++++++++
 3 files changed, 102 insertions(+), 46 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/printk.h b/sys/compat/linuxkpi/common/include/linux/printk.h
index 3840a6e5fb8a..da9d45122d4d 100644
--- a/sys/compat/linuxkpi/common/include/linux/printk.h
+++ b/sys/compat/linuxkpi/common/include/linux/printk.h
@@ -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
diff --git a/sys/compat/linuxkpi/common/include/linux/seq_file.h b/sys/compat/linuxkpi/common/include/linux/seq_file.h
index d8b327f59538..876ef9e8dfe5 100644
--- a/sys/compat/linuxkpi/common/include/linux/seq_file.h
+++ b/sys/compat/linuxkpi/common/include/linux/seq_file.h
@@ -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_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_compat.c b/sys/compat/linuxkpi/common/src/linux_compat.c
index a30523e88864..a2c2d18c8185 100644
--- a/sys/compat/linuxkpi/common/src/linux_compat.c
+++ b/sys/compat/linuxkpi/common/src/linux_compat.c
@@ -95,6 +95,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>
@@ -1917,6 +1919,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)
 {