Blame view

lib/hexdump.c 6.06 KB
99eaf3c45   Randy Dunlap   lib/hexdump
1
2
3
4
5
6
7
8
9
10
11
12
13
  /*
   * lib/hexdump.c
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation. See README and COPYING for
   * more details.
   */
  
  #include <linux/types.h>
  #include <linux/ctype.h>
  #include <linux/kernel.h>
  #include <linux/module.h>
3fc957721   Harvey Harrison   lib: create commo...
14
15
  const char hex_asc[] = "0123456789abcdef";
  EXPORT_SYMBOL(hex_asc);
99eaf3c45   Randy Dunlap   lib/hexdump
16
17
18
19
  /**
   * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
   * @buf: data blob to dump
   * @len: number of bytes in the @buf
c79092349   Randy Dunlap   hexdump: more out...
20
21
   * @rowsize: number of bytes to print per line; must be 16 or 32
   * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
99eaf3c45   Randy Dunlap   lib/hexdump
22
23
   * @linebuf: where to put the converted data
   * @linebuflen: total size of @linebuf, including space for terminating NUL
c79092349   Randy Dunlap   hexdump: more out...
24
   * @ascii: include ASCII after the hex output
99eaf3c45   Randy Dunlap   lib/hexdump
25
26
   *
   * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
c79092349   Randy Dunlap   hexdump: more out...
27
   * 16 or 32 bytes of input data converted to hex + ASCII output.
99eaf3c45   Randy Dunlap   lib/hexdump
28
29
30
31
32
33
   *
   * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
   * to a hex + ASCII dump at the supplied memory location.
   * The converted output is always NUL-terminated.
   *
   * E.g.:
c79092349   Randy Dunlap   hexdump: more out...
34
35
   *   hex_dump_to_buffer(frame->data, frame->len, 16, 1,
   *			linebuf, sizeof(linebuf), 1);
99eaf3c45   Randy Dunlap   lib/hexdump
36
37
   *
   * example output buffer:
c79092349   Randy Dunlap   hexdump: more out...
38
   * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
99eaf3c45   Randy Dunlap   lib/hexdump
39
   */
c79092349   Randy Dunlap   hexdump: more out...
40
41
42
  void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
  			int groupsize, char *linebuf, size_t linebuflen,
  			bool ascii)
99eaf3c45   Randy Dunlap   lib/hexdump
43
44
45
46
  {
  	const u8 *ptr = buf;
  	u8 ch;
  	int j, lx = 0;
c79092349   Randy Dunlap   hexdump: more out...
47
  	int ascii_column;
99eaf3c45   Randy Dunlap   lib/hexdump
48

c79092349   Randy Dunlap   hexdump: more out...
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
  	if (rowsize != 16 && rowsize != 32)
  		rowsize = 16;
  
  	if (!len)
  		goto nil;
  	if (len > rowsize)		/* limit to one line at a time */
  		len = rowsize;
  	if ((len % groupsize) != 0)	/* no mixed size output */
  		groupsize = 1;
  
  	switch (groupsize) {
  	case 8: {
  		const u64 *ptr8 = buf;
  		int ngroups = len / groupsize;
  
  		for (j = 0; j < ngroups; j++)
  			lx += scnprintf(linebuf + lx, linebuflen - lx,
  				"%16.16llx ", (unsigned long long)*(ptr8 + j));
  		ascii_column = 17 * ngroups + 2;
  		break;
  	}
  
  	case 4: {
  		const u32 *ptr4 = buf;
  		int ngroups = len / groupsize;
  
  		for (j = 0; j < ngroups; j++)
  			lx += scnprintf(linebuf + lx, linebuflen - lx,
  				"%8.8x ", *(ptr4 + j));
  		ascii_column = 9 * ngroups + 2;
  		break;
  	}
  
  	case 2: {
  		const u16 *ptr2 = buf;
  		int ngroups = len / groupsize;
  
  		for (j = 0; j < ngroups; j++)
  			lx += scnprintf(linebuf + lx, linebuflen - lx,
  				"%4.4x ", *(ptr2 + j));
  		ascii_column = 5 * ngroups + 2;
  		break;
  	}
  
  	default:
  		for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
  		     j++) {
  			ch = ptr[j];
3fc957721   Harvey Harrison   lib: create commo...
97
98
  			linebuf[lx++] = hex_asc_hi(ch);
  			linebuf[lx++] = hex_asc_lo(ch);
99eaf3c45   Randy Dunlap   lib/hexdump
99
  			linebuf[lx++] = ' ';
c79092349   Randy Dunlap   hexdump: more out...
100
101
102
  		}
  		ascii_column = 3 * rowsize + 2;
  		break;
99eaf3c45   Randy Dunlap   lib/hexdump
103
  	}
c79092349   Randy Dunlap   hexdump: more out...
104
105
106
107
  	if (!ascii)
  		goto nil;
  
  	while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
99eaf3c45   Randy Dunlap   lib/hexdump
108
  		linebuf[lx++] = ' ';
c79092349   Randy Dunlap   hexdump: more out...
109
  	for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
d0eec99ce   Randy Dunlap   hexdump: don't pr...
110
111
  		linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j]
  				: '.';
c79092349   Randy Dunlap   hexdump: more out...
112
  nil:
99eaf3c45   Randy Dunlap   lib/hexdump
113
114
115
116
117
118
119
  	linebuf[lx++] = '\0';
  }
  EXPORT_SYMBOL(hex_dump_to_buffer);
  
  /**
   * print_hex_dump - print a text hex dump to syslog for a binary blob of data
   * @level: kernel log level (e.g. KERN_DEBUG)
c79092349   Randy Dunlap   hexdump: more out...
120
121
   * @prefix_str: string to prefix each line with;
   *  caller supplies trailing spaces for alignment if desired
99eaf3c45   Randy Dunlap   lib/hexdump
122
123
   * @prefix_type: controls whether prefix of an offset, address, or none
   *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
c79092349   Randy Dunlap   hexdump: more out...
124
125
   * @rowsize: number of bytes to print per line; must be 16 or 32
   * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
99eaf3c45   Randy Dunlap   lib/hexdump
126
127
   * @buf: data blob to dump
   * @len: number of bytes in the @buf
c79092349   Randy Dunlap   hexdump: more out...
128
   * @ascii: include ASCII after the hex output
99eaf3c45   Randy Dunlap   lib/hexdump
129
130
131
132
133
   *
   * 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
   * leading prefix.
   *
c79092349   Randy Dunlap   hexdump: more out...
134
135
136
137
138
   * print_hex_dump() works on one "line" of output at a time, i.e.,
   * 16 or 32 bytes of input data converted to hex + ASCII output.
   * print_hex_dump() iterates over the entire input @buf, breaking it into
   * "line size" chunks to format and print.
   *
99eaf3c45   Randy Dunlap   lib/hexdump
139
   * E.g.:
c79092349   Randy Dunlap   hexdump: more out...
140
141
   *   print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS,
   *		16, 1, frame->data, frame->len, 1);
99eaf3c45   Randy Dunlap   lib/hexdump
142
   *
c79092349   Randy Dunlap   hexdump: more out...
143
144
145
146
   * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode:
   * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
   * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode:
   * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c  pqrstuvwxyz{|}~.
99eaf3c45   Randy Dunlap   lib/hexdump
147
   */
c79092349   Randy Dunlap   hexdump: more out...
148
149
  void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
  			int rowsize, int groupsize,
6a0ed91e3   Artem Bityutskiy   hexdump: use cons...
150
  			const void *buf, size_t len, bool ascii)
99eaf3c45   Randy Dunlap   lib/hexdump
151
  {
6a0ed91e3   Artem Bityutskiy   hexdump: use cons...
152
  	const u8 *ptr = buf;
99eaf3c45   Randy Dunlap   lib/hexdump
153
  	int i, linelen, remaining = len;
c79092349   Randy Dunlap   hexdump: more out...
154
  	unsigned char linebuf[200];
99eaf3c45   Randy Dunlap   lib/hexdump
155

c79092349   Randy Dunlap   hexdump: more out...
156
157
158
159
160
161
162
163
  	if (rowsize != 16 && rowsize != 32)
  		rowsize = 16;
  
  	for (i = 0; i < len; i += rowsize) {
  		linelen = min(remaining, rowsize);
  		remaining -= rowsize;
  		hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
  				linebuf, sizeof(linebuf), ascii);
99eaf3c45   Randy Dunlap   lib/hexdump
164
165
166
  
  		switch (prefix_type) {
  		case DUMP_PREFIX_ADDRESS:
c79092349   Randy Dunlap   hexdump: more out...
167
168
  			printk("%s%s%*p: %s
  ", level, prefix_str,
99eaf3c45   Randy Dunlap   lib/hexdump
169
170
171
  				(int)(2 * sizeof(void *)), ptr + i, linebuf);
  			break;
  		case DUMP_PREFIX_OFFSET:
c79092349   Randy Dunlap   hexdump: more out...
172
173
  			printk("%s%s%.8x: %s
  ", level, prefix_str, i, linebuf);
99eaf3c45   Randy Dunlap   lib/hexdump
174
175
  			break;
  		default:
c79092349   Randy Dunlap   hexdump: more out...
176
177
  			printk("%s%s%s
  ", level, prefix_str, linebuf);
99eaf3c45   Randy Dunlap   lib/hexdump
178
179
180
181
182
  			break;
  		}
  	}
  }
  EXPORT_SYMBOL(print_hex_dump);
c79092349   Randy Dunlap   hexdump: more out...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
  
  /**
   * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params
   * @prefix_str: string to prefix each line with;
   *  caller supplies trailing spaces for alignment if desired
   * @prefix_type: controls whether prefix of an offset, address, or none
   *  is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
   * @buf: data blob to dump
   * @len: number of bytes in the @buf
   *
   * Calls print_hex_dump(), with log level of KERN_DEBUG,
   * rowsize of 16, groupsize of 1, and ASCII output included.
   */
  void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
eb9a9a563   Alan Stern   hex_dump: add mis...
197
  			const void *buf, size_t len)
c79092349   Randy Dunlap   hexdump: more out...
198
199
200
201
202
  {
  	print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1,
  			buf, len, 1);
  }
  EXPORT_SYMBOL(print_hex_dump_bytes);