From: Alastair D'Silva <alast...@d-silva.org>

The behaviour of hexdump groups is to print the data out as if
it was a native-endian number.

This patch tweaks the documentation to make this clear, and also
adds the HEXDUMP_RETAIN_BYTE_ORDER flag to allow groups of
multiple bytes to be printed without affecting the ordering
of the printed bytes.

Signed-off-by: Alastair D'Silva <alast...@d-silva.org>
---
 include/linux/printk.h |  1 +
 lib/hexdump.c          | 30 +++++++++++++++++----
 lib/test_hexdump.c     | 60 +++++++++++++++++++++++++++++-------------
 3 files changed, 68 insertions(+), 23 deletions(-)

diff --git a/include/linux/printk.h b/include/linux/printk.h
index 04416e788802..ffc94bedd737 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -490,6 +490,7 @@ enum {
 #define HEXDUMP_2_GRP_SPACES           BIT(5)
 #define HEXDUMP_4_GRP_SPACES           BIT(6)
 #define HEXDUMP_8_GRP_SPACES           BIT(7)
+#define HEXDUMP_RETAIN_BYTE_ORDER      BIT(8)
 
 extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
                              int groupsize, char *linebuf, size_t linebuflen,
diff --git a/lib/hexdump.c b/lib/hexdump.c
index dc85ef0dbb0a..ce14abc7701f 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -127,7 +127,8 @@ static void separator_parameters(u64 flags, int groupsize, 
int *sep_chars,
  * @buf: data blob to dump
  * @len: number of bytes in the @buf
  * @rowsize: number of bytes to print per line; must be a multiple of groupsize
- * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
+ * @groupsize: number of bytes to convert to a native endian number and print:
+ *            1, 2, 4, 8; default = 1
  * @linebuf: where to put the converted data
  * @linebuflen: total size of @linebuf, including space for terminating NUL
  * @flags: A bitwise OR of the following flags:
@@ -138,6 +139,9 @@ static void separator_parameters(u64 flags, int groupsize, 
int *sep_chars,
  *     HEXDUMP_2_GRP_SPACES:           insert a ' ' after every 2 groups
  *     HEXDUMP_4_GRP_SPACES:           insert a ' ' after every 4 groups
  *     HEXDUMP_8_GRP_SPACES:           insert a ' ' after every 8 groups
+ *     HEXDUMP_RETAIN_BYTE_ORDER:      Retain the byte ordering of groups
+ *                                     instead of treating each group as a
+ *                                     native-endian number
  *
  * hex_dump_to_buffer() works on one "line" of output at a time, converting
  * <groupsize> bytes of input to hexadecimal (and optionally printable ASCII)
@@ -171,6 +175,7 @@ int hex_dump_to_buffer(const void *buf, size_t len, int 
rowsize, int groupsize,
        int ret;
        int sep_chars = 0;
        char sep = 0;
+       bool big_endian = (flags & HEXDUMP_RETAIN_BYTE_ORDER) ? 1 : 0;
 
        if (!is_power_of_2(groupsize) || groupsize > 8)
                groupsize = 1;
@@ -202,10 +207,13 @@ int hex_dump_to_buffer(const void *buf, size_t len, int 
rowsize, int groupsize,
                const u64 *ptr8 = buf;
 
                for (j = 0; j < ngroups; j++) {
+                       u64 val = big_endian ?
+                                       be64_to_cpu(get_unaligned(ptr8 + j)) :
+                                       get_unaligned(ptr8 + j);
                        ret = snprintf(linebuf + lx, linebuflen - lx,
                                       "%s%16.16llx",
                                       j ? group_separator(j, flags) : "",
-                                      get_unaligned(ptr8 + j));
+                                      val);
                        if (ret >= linebuflen - lx)
                                goto overflow1;
                        lx += ret;
@@ -214,10 +222,14 @@ int hex_dump_to_buffer(const void *buf, size_t len, int 
rowsize, int groupsize,
                const u32 *ptr4 = buf;
 
                for (j = 0; j < ngroups; j++) {
+                       u32 val = big_endian ?
+                                       be32_to_cpu(get_unaligned(ptr4 + j)) :
+                                       get_unaligned(ptr4 + j);
+
                        ret = snprintf(linebuf + lx, linebuflen - lx,
                                       "%s%8.8x",
                                       j ? group_separator(j, flags) : "",
-                                      get_unaligned(ptr4 + j));
+                                      val);
                        if (ret >= linebuflen - lx)
                                goto overflow1;
                        lx += ret;
@@ -226,10 +238,14 @@ int hex_dump_to_buffer(const void *buf, size_t len, int 
rowsize, int groupsize,
                const u16 *ptr2 = buf;
 
                for (j = 0; j < ngroups; j++) {
+                       u16 val = big_endian ?
+                                       be16_to_cpu(get_unaligned(ptr2 + j)) :
+                                       get_unaligned(ptr2 + j);
+
                        ret = snprintf(linebuf + lx, linebuflen - lx,
                                       "%s%4.4x",
                                       j ? group_separator(j, flags) : "",
-                                      get_unaligned(ptr2 + j));
+                                      val);
                        if (ret >= linebuflen - lx)
                                goto overflow1;
                        lx += ret;
@@ -331,7 +347,8 @@ static void announce_skipped(const char *level, const char 
*prefix_str,
  * @prefix_type: controls whether prefix of an offset, address, or none
  *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
  * @rowsize: number of bytes to print per line; must be a multiple of groupsize
- * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
+ * @groupsize: number of bytes to convert to a native endian number and print:
+ *            1, 2, 4, 8; default = 1
  * @buf: data blob to dump
  * @len: number of bytes in the @buf
  * @ascii: include ASCII after the hex output
@@ -342,6 +359,9 @@ static void announce_skipped(const char *level, const char 
*prefix_str,
  *     HEXDUMP_2_GRP_LINES:            insert a '|' after every 2 groups
  *     HEXDUMP_4_GRP_LINES:            insert a '|' after every 4 groups
  *     HEXDUMP_8_GRP_LINES:            insert a '|' after every 8 groups
+ *     HEXDUMP_RETAIN_BYTE_ORDER:      Retain the byte ordering of groups
+ *                                     instead of treating each group as a
+ *                                     native-endian number
  *
  * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
  * to the kernel log at the specified kernel log level, with an optional
diff --git a/lib/test_hexdump.c b/lib/test_hexdump.c
index ae340c5c1c6f..1e510e934568 100644
--- a/lib/test_hexdump.c
+++ b/lib/test_hexdump.c
@@ -98,14 +98,15 @@ static unsigned failed_tests __initdata;
 
 static void __init test_hexdump_prepare_test(size_t len, int rowsize,
                                             int groupsize, char *test,
-                                            size_t testlen, bool ascii)
+                                            size_t testlen, u64 flags)
 {
        char *p;
        const char * const *result;
        size_t l = len;
        int gs = groupsize, rs = rowsize;
        unsigned int i;
-       const bool is_be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN);
+       const bool is_be = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ||
+                       (flags & HEXDUMP_RETAIN_BYTE_ORDER);
 
        if (l > rs)
                l = rs;
@@ -142,7 +143,7 @@ static void __init test_hexdump_prepare_test(size_t len, 
int rowsize,
                p--;
 
        /* ASCII part */
-       if (ascii) {
+       if (flags & HEXDUMP_ASCII) {
                do {
                        *p++ = ' ';
                } while (p < test + rs * 2 + rs / gs + 1);
@@ -157,7 +158,7 @@ static void __init test_hexdump_prepare_test(size_t len, 
int rowsize,
 #define TEST_HEXDUMP_BUF_SIZE          (64 * 3 + 2 + 64 + 1)
 
 static void __init test_hexdump(size_t len, int rowsize, int groupsize,
-                               bool ascii)
+                               u64 flags)
 {
        char test[TEST_HEXDUMP_BUF_SIZE];
        char real[TEST_HEXDUMP_BUF_SIZE];
@@ -166,11 +167,11 @@ static void __init test_hexdump(size_t len, int rowsize, 
int groupsize,
 
        memset(real, FILL_CHAR, sizeof(real));
        hex_dump_to_buffer(data_b, len, rowsize, groupsize, real, sizeof(real),
-                          ascii ? HEXDUMP_ASCII : 0);
+                          flags);
 
        memset(test, FILL_CHAR, sizeof(test));
        test_hexdump_prepare_test(len, rowsize, groupsize, test, sizeof(test),
-                                 ascii);
+                                 flags);
 
        if (memcmp(test, real, TEST_HEXDUMP_BUF_SIZE)) {
                pr_err("Len: %zu row: %d group: %d\n", len, rowsize, groupsize);
@@ -193,7 +194,7 @@ static void __init test_hexdump_set(int rowsize, bool ascii)
 
 static void __init test_hexdump_overflow(size_t buflen, size_t len,
                                         int rowsize, int groupsize,
-                                        bool ascii)
+                                        u64 flags)
 {
        char test[TEST_HEXDUMP_BUF_SIZE];
        char buf[TEST_HEXDUMP_BUF_SIZE];
@@ -205,7 +206,7 @@ static void __init test_hexdump_overflow(size_t buflen, 
size_t len,
        memset(buf, FILL_CHAR, sizeof(buf));
 
        rc = hex_dump_to_buffer(data_b, len, rowsize, groupsize, buf, buflen,
-                               ascii ? HEXDUMP_ASCII : 0);
+                               flags);
 
        /*
         * Caller must provide the data length multiple of groupsize. The
@@ -222,12 +223,12 @@ static void __init test_hexdump_overflow(size_t buflen, 
size_t len,
                  - 1 /* no trailing space */;
        }
 
-       expected_len = (ascii) ? ascii_len : hex_len;
+       expected_len = (flags & HEXDUMP_ASCII) ? ascii_len : hex_len;
 
        fill_point = min_t(int, expected_len + 1, buflen);
        if (buflen) {
                test_hexdump_prepare_test(len, rowsize, groupsize, test,
-                                         sizeof(test), ascii);
+                                         sizeof(test), flags);
                test[fill_point - 1] = '\0';
        }
        memset(test + fill_point, FILL_CHAR, sizeof(test) - fill_point);
@@ -237,8 +238,8 @@ static void __init test_hexdump_overflow(size_t buflen, 
size_t len,
        buf[sizeof(buf) - 1] = '\0';
 
        if (!match) {
-               pr_err("rowsize: %u groupsize: %u ascii: %d Len: %zu buflen: 
%zu strlen: %zu\n",
-                       rowsize, groupsize, ascii, len, buflen,
+               pr_err("rowsize: %u groupsize: %u flags: %llx Len: %zu buflen: 
%zu strlen: %zu\n",
+                       rowsize, groupsize, flags, len, buflen,
                        strnlen(buf, sizeof(buf)));
                pr_err("Result: %d '%-.*s'\n", rc, (int)buflen, buf);
                pr_err("Expect: %d '%-.*s'\n", expected_len, (int)buflen, test);
@@ -247,7 +248,7 @@ static void __init test_hexdump_overflow(size_t buflen, 
size_t len,
        }
 }
 
-static void __init test_hexdump_overflow_set(size_t buflen, bool ascii)
+static void __init test_hexdump_overflow_set(size_t buflen, u64 flags)
 {
        unsigned int i = 0;
        int rs = (get_random_int() % 4 + 1) * 16;
@@ -256,7 +257,7 @@ static void __init test_hexdump_overflow_set(size_t buflen, 
bool ascii)
                int gs = 1 << i;
                size_t len = get_random_int() % rs + gs;
 
-               test_hexdump_overflow(buflen, rounddown(len, gs), rs, gs, 
ascii);
+               test_hexdump_overflow(buflen, rounddown(len, gs), rs, gs, 
flags);
        } while (i++ < 3);
 }
 
@@ -264,20 +265,43 @@ static int __init test_hexdump_init(void)
 {
        unsigned int i;
        int rowsize;
+       u64 flags;
 
+       flags = 0;
        rowsize = (get_random_int() % 4 + 1) * 16;
        for (i = 0; i < 16; i++)
-               test_hexdump_set(rowsize, false);
+               test_hexdump_set(rowsize, flags);
 
+       flags = HEXDUMP_ASCII;
        rowsize = (get_random_int() % 4 + 1) * 16;
        for (i = 0; i < 16; i++)
-               test_hexdump_set(rowsize, true);
+               test_hexdump_set(rowsize, flags);
 
+       flags = HEXDUMP_RETAIN_BYTE_ORDER;
+       rowsize = (get_random_int() % 2 + 1) * 16;
+       for (i = 0; i < 16; i++)
+               test_hexdump_set(rowsize, flags);
+
+       flags = HEXDUMP_ASCII | HEXDUMP_RETAIN_BYTE_ORDER;
+       rowsize = (get_random_int() % 2 + 1) * 16;
+       for (i = 0; i < 16; i++)
+               test_hexdump_set(rowsize, flags);
+
+       flags = 0;
+       for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
+               test_hexdump_overflow_set(i, flags);
+
+       flags = HEXDUMP_ASCII;
+       for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
+               test_hexdump_overflow_set(i, flags);
+
+       flags = HEXDUMP_RETAIN_BYTE_ORDER;
        for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
-               test_hexdump_overflow_set(i, false);
+               test_hexdump_overflow_set(i, flags);
 
+       flags = HEXDUMP_ASCII | HEXDUMP_RETAIN_BYTE_ORDER;
        for (i = 0; i <= TEST_HEXDUMP_BUF_SIZE; i++)
-               test_hexdump_overflow_set(i, true);
+               test_hexdump_overflow_set(i, flags);
 
        if (failed_tests == 0)
                pr_info("all %u tests passed\n", total_tests);
-- 
2.21.0

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to