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

hexdump: make it return number of bytes placed in buffer

This patch makes hexdump return the number of bytes placed in the buffer
excluding trailing NUL. In the case of overflow it returns the desired
amount of bytes to produce the entire dump. Thus, it mimics snprintf().

This will be useful for users that would like to repeat with a bigger
buffer.

[akpm@linux-foundation.org: fix printk warning]
Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andy Shevchenko and committed by
Linus Torvalds
114fc1af 5d909c8d

+103 -21
+3 -3
include/linux/printk.h
··· 417 417 DUMP_PREFIX_ADDRESS, 418 418 DUMP_PREFIX_OFFSET 419 419 }; 420 - extern void hex_dump_to_buffer(const void *buf, size_t len, 421 - int rowsize, int groupsize, 422 - char *linebuf, size_t linebuflen, bool ascii); 420 + extern int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, 421 + int groupsize, char *linebuf, size_t linebuflen, 422 + bool ascii); 423 423 #ifdef CONFIG_PRINTK 424 424 extern void print_hex_dump(const char *level, const char *prefix_str, 425 425 int prefix_type, int rowsize, int groupsize,
+55 -18
lib/hexdump.c
··· 97 97 * 98 98 * example output buffer: 99 99 * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO 100 + * 101 + * Return: 102 + * The amount of bytes placed in the buffer without terminating NUL. If the 103 + * output was truncated, then the return value is the number of bytes 104 + * (excluding the terminating NUL) which would have been written to the final 105 + * string if enough space had been available. 100 106 */ 101 - void hex_dump_to_buffer(const void *buf, size_t len, int rowsize, 102 - int groupsize, char *linebuf, size_t linebuflen, 103 - bool ascii) 107 + int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize, 108 + char *linebuf, size_t linebuflen, bool ascii) 104 109 { 105 110 const u8 *ptr = buf; 106 111 int ngroups; 107 112 u8 ch; 108 113 int j, lx = 0; 109 114 int ascii_column; 115 + int ret; 110 116 111 117 if (rowsize != 16 && rowsize != 32) 112 118 rowsize = 16; 113 119 114 - if (!len) 115 - goto nil; 116 120 if (len > rowsize) /* limit to one line at a time */ 117 121 len = rowsize; 118 122 if (!is_power_of_2(groupsize) || groupsize > 8) ··· 126 122 127 123 ngroups = len / groupsize; 128 124 ascii_column = rowsize * 2 + rowsize / groupsize + 1; 125 + 126 + if (!linebuflen) 127 + goto overflow1; 128 + 129 + if (!len) 130 + goto nil; 131 + 129 132 if (groupsize == 8) { 130 133 const u64 *ptr8 = buf; 131 134 132 - for (j = 0; j < ngroups; j++) 133 - lx += scnprintf(linebuf + lx, linebuflen - lx, 134 - "%s%16.16llx", j ? " " : "", 135 - (unsigned long long)*(ptr8 + j)); 135 + for (j = 0; j < ngroups; j++) { 136 + ret = snprintf(linebuf + lx, linebuflen - lx, 137 + "%s%16.16llx", j ? " " : "", 138 + (unsigned long long)*(ptr8 + j)); 139 + if (ret >= linebuflen - lx) 140 + goto overflow1; 141 + lx += ret; 142 + } 136 143 } else if (groupsize == 4) { 137 144 const u32 *ptr4 = buf; 138 145 139 - for (j = 0; j < ngroups; j++) 140 - lx += scnprintf(linebuf + lx, linebuflen - lx, 141 - "%s%8.8x", j ? " " : "", *(ptr4 + j)); 146 + for (j = 0; j < ngroups; j++) { 147 + ret = snprintf(linebuf + lx, linebuflen - lx, 148 + "%s%8.8x", j ? " " : "", 149 + *(ptr4 + j)); 150 + if (ret >= linebuflen - lx) 151 + goto overflow1; 152 + lx += ret; 153 + } 142 154 } else if (groupsize == 2) { 143 155 const u16 *ptr2 = buf; 144 156 145 - for (j = 0; j < ngroups; j++) 146 - lx += scnprintf(linebuf + lx, linebuflen - lx, 147 - "%s%4.4x", j ? " " : "", *(ptr2 + j)); 157 + for (j = 0; j < ngroups; j++) { 158 + ret = snprintf(linebuf + lx, linebuflen - lx, 159 + "%s%4.4x", j ? " " : "", 160 + *(ptr2 + j)); 161 + if (ret >= linebuflen - lx) 162 + goto overflow1; 163 + lx += ret; 164 + } 148 165 } else { 149 - for (j = 0; (j < len) && (lx + 3) <= linebuflen; j++) { 166 + for (j = 0; j < len; j++) { 167 + if (linebuflen < lx + 3) 168 + goto overflow2; 150 169 ch = ptr[j]; 151 170 linebuf[lx++] = hex_asc_hi(ch); 152 171 linebuf[lx++] = hex_asc_lo(ch); ··· 181 154 if (!ascii) 182 155 goto nil; 183 156 184 - while (lx < (linebuflen - 1) && lx < ascii_column) 157 + while (lx < ascii_column) { 158 + if (linebuflen < lx + 2) 159 + goto overflow2; 185 160 linebuf[lx++] = ' '; 186 - for (j = 0; (j < len) && (lx + 2) < linebuflen; j++) { 161 + } 162 + for (j = 0; j < len; j++) { 163 + if (linebuflen < lx + 2) 164 + goto overflow2; 187 165 ch = ptr[j]; 188 166 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.'; 189 167 } 190 168 nil: 169 + linebuf[lx] = '\0'; 170 + return lx; 171 + overflow2: 191 172 linebuf[lx++] = '\0'; 173 + overflow1: 174 + return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1; 192 175 } 193 176 EXPORT_SYMBOL(hex_dump_to_buffer); 194 177
+45
lib/test-hexdump.c
··· 114 114 test_hexdump(len, rowsize, 1, ascii); 115 115 } 116 116 117 + static void __init test_hexdump_overflow(bool ascii) 118 + { 119 + char buf[56]; 120 + const char *t = test_data_1_le[0]; 121 + size_t l = get_random_int() % sizeof(buf); 122 + bool a; 123 + int e, r; 124 + 125 + memset(buf, ' ', sizeof(buf)); 126 + 127 + r = hex_dump_to_buffer(data_b, 1, 16, 1, buf, l, ascii); 128 + 129 + if (ascii) 130 + e = 50; 131 + else 132 + e = 2; 133 + buf[e + 2] = '\0'; 134 + 135 + if (!l) { 136 + a = r == e && buf[0] == ' '; 137 + } else if (l < 3) { 138 + a = r == e && buf[0] == '\0'; 139 + } else if (l < 4) { 140 + a = r == e && !strcmp(buf, t); 141 + } else if (ascii) { 142 + if (l < 51) 143 + a = r == e && buf[l - 1] == '\0' && buf[l - 2] == ' '; 144 + else 145 + a = r == e && buf[50] == '\0' && buf[49] == '.'; 146 + } else { 147 + a = r == e && buf[e] == '\0'; 148 + } 149 + 150 + if (!a) { 151 + pr_err("Len: %zu rc: %u strlen: %zu\n", l, r, strlen(buf)); 152 + pr_err("Result: '%s'\n", buf); 153 + } 154 + } 155 + 117 156 static int __init test_hexdump_init(void) 118 157 { 119 158 unsigned int i; ··· 167 128 rowsize = (get_random_int() % 2 + 1) * 16; 168 129 for (i = 0; i < 16; i++) 169 130 test_hexdump_set(rowsize, true); 131 + 132 + for (i = 0; i < 16; i++) 133 + test_hexdump_overflow(false); 134 + 135 + for (i = 0; i < 16; i++) 136 + test_hexdump_overflow(true); 170 137 171 138 return -EINVAL; 172 139 }