diff options
-rw-r--r-- | include/linux/kernel.h | 11 | ||||
-rw-r--r-- | lib/Makefile | 2 | ||||
-rw-r--r-- | lib/hexdump.c | 104 |
3 files changed, 116 insertions, 1 deletions
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 8645181fca0f..eec0d13169a6 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -213,6 +213,17 @@ extern enum system_states { | |||
213 | 213 | ||
214 | extern void dump_stack(void); | 214 | extern void dump_stack(void); |
215 | 215 | ||
216 | enum { | ||
217 | DUMP_PREFIX_NONE, | ||
218 | DUMP_PREFIX_ADDRESS, | ||
219 | DUMP_PREFIX_OFFSET | ||
220 | }; | ||
221 | extern void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf, | ||
222 | size_t linebuflen); | ||
223 | extern void print_hex_dump(const char *level, int prefix_type, | ||
224 | void *buf, size_t len); | ||
225 | #define hex_asc(x) "0123456789abcdef"[x] | ||
226 | |||
216 | #ifdef DEBUG | 227 | #ifdef DEBUG |
217 | /* If you are writing a driver, please use dev_dbg instead */ | 228 | /* If you are writing a driver, please use dev_dbg instead */ |
218 | #define pr_debug(fmt,arg...) \ | 229 | #define pr_debug(fmt,arg...) \ |
diff --git a/lib/Makefile b/lib/Makefile index 1f65b4613e09..c8c8e20784ce 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
@@ -13,7 +13,7 @@ lib-$(CONFIG_SMP) += cpumask.o | |||
13 | lib-y += kobject.o kref.o kobject_uevent.o klist.o | 13 | lib-y += kobject.o kref.o kobject_uevent.o klist.o |
14 | 14 | ||
15 | obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ | 15 | obj-y += div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \ |
16 | bust_spinlocks.o | 16 | bust_spinlocks.o hexdump.o |
17 | 17 | ||
18 | ifeq ($(CONFIG_DEBUG_KOBJECT),y) | 18 | ifeq ($(CONFIG_DEBUG_KOBJECT),y) |
19 | CFLAGS_kobject.o += -DDEBUG | 19 | CFLAGS_kobject.o += -DDEBUG |
diff --git a/lib/hexdump.c b/lib/hexdump.c new file mode 100644 index 000000000000..e6da5b7fc29a --- /dev/null +++ b/lib/hexdump.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * lib/hexdump.c | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. See README and COPYING for | ||
7 | * more details. | ||
8 | */ | ||
9 | |||
10 | #include <linux/types.h> | ||
11 | #include <linux/ctype.h> | ||
12 | #include <linux/kernel.h> | ||
13 | #include <linux/module.h> | ||
14 | |||
15 | /** | ||
16 | * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory | ||
17 | * @buf: data blob to dump | ||
18 | * @len: number of bytes in the @buf | ||
19 | * @linebuf: where to put the converted data | ||
20 | * @linebuflen: total size of @linebuf, including space for terminating NUL | ||
21 | * | ||
22 | * 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. | ||
24 | * | ||
25 | * 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. | ||
27 | * The converted output is always NUL-terminated. | ||
28 | * | ||
29 | * E.g.: | ||
30 | * hex_dump_to_buffer(frame->data, frame->len, linebuf, sizeof(linebuf)); | ||
31 | * | ||
32 | * example output buffer: | ||
33 | * 40414243 44454647 48494a4b 4c4d4e4f @ABCDEFGHIJKLMNO | ||
34 | */ | ||
35 | void hex_dump_to_buffer(const void *buf, size_t len, char *linebuf, | ||
36 | size_t linebuflen) | ||
37 | { | ||
38 | const u8 *ptr = buf; | ||
39 | u8 ch; | ||
40 | int j, lx = 0; | ||
41 | |||
42 | for (j = 0; (j < 16) && (j < len) && (lx + 3) < linebuflen; j++) { | ||
43 | if (j && !(j % 4)) | ||
44 | linebuf[lx++] = ' '; | ||
45 | ch = ptr[j]; | ||
46 | linebuf[lx++] = hex_asc(ch >> 4); | ||
47 | linebuf[lx++] = hex_asc(ch & 0x0f); | ||
48 | } | ||
49 | if ((lx + 2) < linebuflen) { | ||
50 | linebuf[lx++] = ' '; | ||
51 | linebuf[lx++] = ' '; | ||
52 | } | ||
53 | for (j = 0; (j < 16) && (j < len) && (lx + 2) < linebuflen; j++) | ||
54 | linebuf[lx++] = isprint(ptr[j]) ? ptr[j] : '.'; | ||
55 | linebuf[lx++] = '\0'; | ||
56 | } | ||
57 | EXPORT_SYMBOL(hex_dump_to_buffer); | ||
58 | |||
59 | /** | ||
60 | * 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) | ||
62 | * @prefix_type: controls whether prefix of an offset, address, or none | ||
63 | * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE) | ||
64 | * @buf: data blob to dump | ||
65 | * @len: number of bytes in the @buf | ||
66 | * | ||
67 | * 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 | ||
69 | * leading prefix. | ||
70 | * | ||
71 | * E.g.: | ||
72 | * print_hex_dump(KERN_DEBUG, DUMP_PREFIX_ADDRESS, frame->data, frame->len); | ||
73 | * | ||
74 | * Example output using %DUMP_PREFIX_OFFSET: | ||
75 | * 0009ab42: 40414243 44454647 48494a4b 4c4d4e4f @ABCDEFGHIJKLMNO | ||
76 | * Example output using %DUMP_PREFIX_ADDRESS: | ||
77 | * ffffffff88089af0: 70717273 74757677 78797a7b 7c7d7e7f pqrstuvwxyz{|}~. | ||
78 | */ | ||
79 | void print_hex_dump(const char *level, int prefix_type, void *buf, size_t len) | ||
80 | { | ||
81 | u8 *ptr = buf; | ||
82 | int i, linelen, remaining = len; | ||
83 | unsigned char linebuf[100]; | ||
84 | |||
85 | for (i = 0; i < len; i += 16) { | ||
86 | linelen = min(remaining, 16); | ||
87 | remaining -= 16; | ||
88 | hex_dump_to_buffer(ptr + i, linelen, linebuf, sizeof(linebuf)); | ||
89 | |||
90 | switch (prefix_type) { | ||
91 | case DUMP_PREFIX_ADDRESS: | ||
92 | printk("%s%*p: %s\n", level, | ||
93 | (int)(2 * sizeof(void *)), ptr + i, linebuf); | ||
94 | break; | ||
95 | case DUMP_PREFIX_OFFSET: | ||
96 | printk("%s%.8x: %s\n", level, i, linebuf); | ||
97 | break; | ||
98 | default: | ||
99 | printk("%s%s\n", level, linebuf); | ||
100 | break; | ||
101 | } | ||
102 | } | ||
103 | } | ||
104 | EXPORT_SYMBOL(print_hex_dump); | ||