aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRandy Dunlap <randy.dunlap@oracle.com>2007-06-08 16:47:04 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-06-08 20:23:34 -0400
commitc7909234993973692414901055dfbebbca21e73f (patch)
treeb3c97eafa742f3170c01aadbf3295a2876b3bd6b
parentabb49202ff37bf2eca7296c62ad18c77f636ec8e (diff)
hexdump: more output formatting
Add a prefix string parameter. Callers are responsible for any string length/alignment that they want to see in the output. I.e., callers should pad strings to achieve alignment if they want that. Add rowsize parameter. This is the number of raw data bytes to be printed per line. Must be 16 or 32. Add a groupsize parameter. This allows callers to dump values as 1-byte, 2-byte, 4-byte, or 8-byte numbers. Default is 1-byte numbers. If the total length is not an even multiple of groupsize, 1-byte numbers are printed. Add an "ascii" output parameter. This causes ASCII data output following the hex data output. Clean up some doc examples. Align the ASCII output on all lines that are produced by one call. Add a new interface, print_hex_dump_bytes(), that is a shortcut to print_hex_dump(), using default parameter values to print 16 bytes in byte-size chunks of hex + ASCII output, using printk level KERN_DEBUG. Signed-off-by: Randy Dunlap <randy.dunlap@oracle.com> Cc: Christoph Lameter <clameter@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--include/linux/kernel.h12
-rw-r--r--lib/hexdump.c149
2 files changed, 129 insertions, 32 deletions
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 45353d757cd0..7a4852505914 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -218,10 +218,14 @@ enum {
218 DUMP_PREFIX_ADDRESS, 218 DUMP_PREFIX_ADDRESS,
219 DUMP_PREFIX_OFFSET 219 DUMP_PREFIX_OFFSET
220}; 220};
221extern void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf, 221extern void hex_dump_to_buffer(const void *buf, size_t len,
222 size_t linebuflen); 222 int rowsize, int groupsize,
223extern void print_hex_dump(const char *level, int prefix_type, 223 char *linebuf, size_t linebuflen, bool ascii);
224 void *buf, size_t len); 224extern void print_hex_dump(const char *level, const char *prefix_str,
225 int prefix_type, int rowsize, int groupsize,
226 void *buf, size_t len, bool ascii);
227extern void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
228 void *buf, size_t len);
225#define hex_asc(x) "0123456789abcdef"[x] 229#define hex_asc(x) "0123456789abcdef"[x]
226 230
227#ifdef DEBUG 231#ifdef DEBUG
diff --git a/lib/hexdump.c b/lib/hexdump.c
index e6da5b7fc29a..473f5aed6cae 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -16,42 +16,98 @@
16 * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory 16 * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
17 * @buf: data blob to dump 17 * @buf: data blob to dump
18 * @len: number of bytes in the @buf 18 * @len: number of bytes in the @buf
19 * @rowsize: number of bytes to print per line; must be 16 or 32
20 * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
19 * @linebuf: where to put the converted data 21 * @linebuf: where to put the converted data
20 * @linebuflen: total size of @linebuf, including space for terminating NUL 22 * @linebuflen: total size of @linebuf, including space for terminating NUL
23 * @ascii: include ASCII after the hex output
21 * 24 *
22 * hex_dump_to_buffer() works on one "line" of output at a time, i.e., 25 * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
23 * 16 bytes of input data converted to hex + ASCII output. 26 * 16 or 32 bytes of input data converted to hex + ASCII output.
24 * 27 *
25 * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data 28 * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
26 * to a hex + ASCII dump at the supplied memory location. 29 * to a hex + ASCII dump at the supplied memory location.
27 * The converted output is always NUL-terminated. 30 * The converted output is always NUL-terminated.
28 * 31 *
29 * E.g.: 32 * E.g.:
30 * hex_dump_to_buffer(frame->data, frame->len, linebuf, sizeof(linebuf)); 33 * hex_dump_to_buffer(frame->data, frame->len, 16, 1,
34 * linebuf, sizeof(linebuf), 1);
31 * 35 *
32 * example output buffer: 36 * example output buffer:
33 * 40414243 44454647 48494a4b 4c4d4e4f @ABCDEFGHIJKLMNO 37 * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
34 */ 38 */
35void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf, 39void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
36 size_t linebuflen) 40 int groupsize, char *linebuf, size_t linebuflen,
41 bool ascii)
37{ 42{
38 const u8 *ptr = buf; 43 const u8 *ptr = buf;
39 u8 ch; 44 u8 ch;
40 int j, lx = 0; 45 int j, lx = 0;
46 int ascii_column;
41 47
42 for (j = 0; (j < 16) && (j < len) && (lx + 3) < linebuflen; j++) { 48 if (rowsize != 16 && rowsize != 32)
43 if (j && !(j % 4)) 49 rowsize = 16;
50
51 if (!len)
52 goto nil;
53 if (len > rowsize) /* limit to one line at a time */
54 len = rowsize;
55 if ((len % groupsize) != 0) /* no mixed size output */
56 groupsize = 1;
57
58 switch (groupsize) {
59 case 8: {
60 const u64 *ptr8 = buf;
61 int ngroups = len / groupsize;
62
63 for (j = 0; j < ngroups; j++)
64 lx += scnprintf(linebuf + lx, linebuflen - lx,
65 "%16.16llx ", (unsigned long long)*(ptr8 + j));
66 ascii_column = 17 * ngroups + 2;
67 break;
68 }
69
70 case 4: {
71 const u32 *ptr4 = buf;
72 int ngroups = len / groupsize;
73
74 for (j = 0; j < ngroups; j++)
75 lx += scnprintf(linebuf + lx, linebuflen - lx,
76 "%8.8x ", *(ptr4 + j));
77 ascii_column = 9 * ngroups + 2;
78 break;
79 }
80
81 case 2: {
82 const u16 *ptr2 = buf;
83 int ngroups = len / groupsize;
84
85 for (j = 0; j < ngroups; j++)
86 lx += scnprintf(linebuf + lx, linebuflen - lx,
87 "%4.4x ", *(ptr2 + j));
88 ascii_column = 5 * ngroups + 2;
89 break;
90 }
91
92 default:
93 for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
94 j++) {
95 ch = ptr[j];
96 linebuf[lx++] = hex_asc(ch >> 4);
97 linebuf[lx++] = hex_asc(ch & 0x0f);
44 linebuf[lx++] = ' '; 98 linebuf[lx++] = ' ';
45 ch = ptr[j]; 99 }
46 linebuf[lx++] = hex_asc(ch >> 4); 100 ascii_column = 3 * rowsize + 2;
47 linebuf[lx++] = hex_asc(ch & 0x0f); 101 break;
48 } 102 }
49 if ((lx + 2) < linebuflen) { 103 if (!ascii)
50 linebuf[lx++] = ' '; 104 goto nil;
105
106 while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
51 linebuf[lx++] = ' '; 107 linebuf[lx++] = ' ';
52 } 108 for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
53 for (j = 0; (j < 16) && (j < len) && (lx + 2) < linebuflen; j++)
54 linebuf[lx++] = isprint(ptr[j]) ? ptr[j] : '.'; 109 linebuf[lx++] = isprint(ptr[j]) ? ptr[j] : '.';
110nil:
55 linebuf[lx++] = '\0'; 111 linebuf[lx++] = '\0';
56} 112}
57EXPORT_SYMBOL(hex_dump_to_buffer); 113EXPORT_SYMBOL(hex_dump_to_buffer);
@@ -59,46 +115,83 @@ EXPORT_SYMBOL(hex_dump_to_buffer);
59/** 115/**
60 * print_hex_dump - print a text hex dump to syslog for a binary blob of data 116 * print_hex_dump - print a text hex dump to syslog for a binary blob of data
61 * @level: kernel log level (e.g. KERN_DEBUG) 117 * @level: kernel log level (e.g. KERN_DEBUG)
118 * @prefix_str: string to prefix each line with;
119 * caller supplies trailing spaces for alignment if desired
62 * @prefix_type: controls whether prefix of an offset, address, or none 120 * @prefix_type: controls whether prefix of an offset, address, or none
63 * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) 121 * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
122 * @rowsize: number of bytes to print per line; must be 16 or 32
123 * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
64 * @buf: data blob to dump 124 * @buf: data blob to dump
65 * @len: number of bytes in the @buf 125 * @len: number of bytes in the @buf
126 * @ascii: include ASCII after the hex output
66 * 127 *
67 * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump 128 * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
68 * to the kernel log at the specified kernel log level, with an optional 129 * to the kernel log at the specified kernel log level, with an optional
69 * leading prefix. 130 * leading prefix.
70 * 131 *
132 * print_hex_dump() works on one "line" of output at a time, i.e.,
133 * 16 or 32 bytes of input data converted to hex + ASCII output.
134 * print_hex_dump() iterates over the entire input @buf, breaking it into
135 * "line size" chunks to format and print.
136 *
71 * E.g.: 137 * E.g.:
72 * print_hex_dump(KERN_DEBUG, DUMP_PREFIX_ADDRESS, frame->data, frame->len); 138 * print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS,
139 * 16, 1, frame->data, frame->len, 1);
73 * 140 *
74 * Example output using %DUMP_PREFIX_OFFSET: 141 * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode:
75 * 0009ab42: 40414243 44454647 48494a4b 4c4d4e4f @ABCDEFGHIJKLMNO 142 * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
76 * Example output using %DUMP_PREFIX_ADDRESS: 143 * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode:
77 * ffffffff88089af0: 70717273 74757677 78797a7b 7c7d7e7f pqrstuvwxyz{|}~. 144 * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.
78 */ 145 */
79void print_hex_dump(const char *level, int prefix_type, void *buf, size_t len) 146void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
147 int rowsize, int groupsize,
148 void *buf, size_t len, bool ascii)
80{ 149{
81 u8 *ptr = buf; 150 u8 *ptr = buf;
82 int i, linelen, remaining = len; 151 int i, linelen, remaining = len;
83 unsigned char linebuf[100]; 152 unsigned char linebuf[200];
84 153
85 for (i = 0; i < len; i += 16) { 154 if (rowsize != 16 && rowsize != 32)
86 linelen = min(remaining, 16); 155 rowsize = 16;
87 remaining -= 16; 156
88 hex_dump_to_buffer(ptr + i, linelen, linebuf, sizeof(linebuf)); 157 for (i = 0; i < len; i += rowsize) {
158 linelen = min(remaining, rowsize);
159 remaining -= rowsize;
160 hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
161 linebuf, sizeof(linebuf), ascii);
89 162
90 switch (prefix_type) { 163 switch (prefix_type) {
91 case DUMP_PREFIX_ADDRESS: 164 case DUMP_PREFIX_ADDRESS:
92 printk("%s%*p: %s\n", level, 165 printk("%s%s%*p: %s\n", level, prefix_str,
93 (int)(2 * sizeof(void *)), ptr + i, linebuf); 166 (int)(2 * sizeof(void *)), ptr + i, linebuf);
94 break; 167 break;
95 case DUMP_PREFIX_OFFSET: 168 case DUMP_PREFIX_OFFSET:
96 printk("%s%.8x: %s\n", level, i, linebuf); 169 printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
97 break; 170 break;
98 default: 171 default:
99 printk("%s%s\n", level, linebuf); 172 printk("%s%s%s\n", level, prefix_str, linebuf);
100 break; 173 break;
101 } 174 }
102 } 175 }
103} 176}
104EXPORT_SYMBOL(print_hex_dump); 177EXPORT_SYMBOL(print_hex_dump);
178
179/**
180 * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params
181 * @prefix_str: string to prefix each line with;
182 * caller supplies trailing spaces for alignment if desired
183 * @prefix_type: controls whether prefix of an offset, address, or none
184 * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
185 * @buf: data blob to dump
186 * @len: number of bytes in the @buf
187 *
188 * Calls print_hex_dump(), with log level of KERN_DEBUG,
189 * rowsize of 16, groupsize of 1, and ASCII output included.
190 */
191void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
192 void *buf, size_t len)
193{
194 print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1,
195 buf, len, 1);
196}
197EXPORT_SYMBOL(print_hex_dump_bytes);