Blame view

lib/hexdump.c 6 KB
99eaf3c45   Randy Dunlap   lib/hexdump
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * 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>
  
  /**
   * 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...
19
20
   * @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
21
22
   * @linebuf: where to put the converted data
   * @linebuflen: total size of @linebuf, including space for terminating NUL
c79092349   Randy Dunlap   hexdump: more out...
23
   * @ascii: include ASCII after the hex output
99eaf3c45   Randy Dunlap   lib/hexdump
24
25
   *
   * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
c79092349   Randy Dunlap   hexdump: more out...
26
   * 16 or 32 bytes of input data converted to hex + ASCII output.
99eaf3c45   Randy Dunlap   lib/hexdump
27
28
29
30
31
32
   *
   * 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...
33
34
   *   hex_dump_to_buffer(frame->data, frame->len, 16, 1,
   *			linebuf, sizeof(linebuf), 1);
99eaf3c45   Randy Dunlap   lib/hexdump
35
36
   *
   * example output buffer:
c79092349   Randy Dunlap   hexdump: more out...
37
   * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f  @ABCDEFGHIJKLMNO
99eaf3c45   Randy Dunlap   lib/hexdump
38
   */
c79092349   Randy Dunlap   hexdump: more out...
39
40
41
  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
42
43
44
45
  {
  	const u8 *ptr = buf;
  	u8 ch;
  	int j, lx = 0;
c79092349   Randy Dunlap   hexdump: more out...
46
  	int ascii_column;
99eaf3c45   Randy Dunlap   lib/hexdump
47

c79092349   Randy Dunlap   hexdump: more out...
48
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
97
  	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];
  			linebuf[lx++] = hex_asc(ch >> 4);
  			linebuf[lx++] = hex_asc(ch & 0x0f);
99eaf3c45   Randy Dunlap   lib/hexdump
98
  			linebuf[lx++] = ' ';
c79092349   Randy Dunlap   hexdump: more out...
99
100
101
  		}
  		ascii_column = 3 * rowsize + 2;
  		break;
99eaf3c45   Randy Dunlap   lib/hexdump
102
  	}
c79092349   Randy Dunlap   hexdump: more out...
103
104
105
106
  	if (!ascii)
  		goto nil;
  
  	while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
99eaf3c45   Randy Dunlap   lib/hexdump
107
  		linebuf[lx++] = ' ';
c79092349   Randy Dunlap   hexdump: more out...
108
  	for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
d0eec99ce   Randy Dunlap   hexdump: don't pr...
109
110
  		linebuf[lx++] = (isascii(ptr[j]) && isprint(ptr[j])) ? ptr[j]
  				: '.';
c79092349   Randy Dunlap   hexdump: more out...
111
  nil:
99eaf3c45   Randy Dunlap   lib/hexdump
112
113
114
115
116
117
118
  	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...
119
120
   * @prefix_str: string to prefix each line with;
   *  caller supplies trailing spaces for alignment if desired
99eaf3c45   Randy Dunlap   lib/hexdump
121
122
   * @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...
123
124
   * @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
125
126
   * @buf: data blob to dump
   * @len: number of bytes in the @buf
c79092349   Randy Dunlap   hexdump: more out...
127
   * @ascii: include ASCII after the hex output
99eaf3c45   Randy Dunlap   lib/hexdump
128
129
130
131
132
   *
   * 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...
133
134
135
136
137
   * 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
138
   * E.g.:
c79092349   Randy Dunlap   hexdump: more out...
139
140
   *   print_hex_dump(KERN_DEBUG, "raw data: ", DUMP_PREFIX_ADDRESS,
   *		16, 1, frame->data, frame->len, 1);
99eaf3c45   Randy Dunlap   lib/hexdump
141
   *
c79092349   Randy Dunlap   hexdump: more out...
142
143
144
145
   * 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
146
   */
c79092349   Randy Dunlap   hexdump: more out...
147
148
  void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
  			int rowsize, int groupsize,
6a0ed91e3   Artem Bityutskiy   hexdump: use cons...
149
  			const void *buf, size_t len, bool ascii)
99eaf3c45   Randy Dunlap   lib/hexdump
150
  {
6a0ed91e3   Artem Bityutskiy   hexdump: use cons...
151
  	const u8 *ptr = buf;
99eaf3c45   Randy Dunlap   lib/hexdump
152
  	int i, linelen, remaining = len;
c79092349   Randy Dunlap   hexdump: more out...
153
  	unsigned char linebuf[200];
99eaf3c45   Randy Dunlap   lib/hexdump
154

c79092349   Randy Dunlap   hexdump: more out...
155
156
157
158
159
160
161
162
  	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
163
164
165
  
  		switch (prefix_type) {
  		case DUMP_PREFIX_ADDRESS:
c79092349   Randy Dunlap   hexdump: more out...
166
167
  			printk("%s%s%*p: %s
  ", level, prefix_str,
99eaf3c45   Randy Dunlap   lib/hexdump
168
169
170
  				(int)(2 * sizeof(void *)), ptr + i, linebuf);
  			break;
  		case DUMP_PREFIX_OFFSET:
c79092349   Randy Dunlap   hexdump: more out...
171
172
  			printk("%s%s%.8x: %s
  ", level, prefix_str, i, linebuf);
99eaf3c45   Randy Dunlap   lib/hexdump
173
174
  			break;
  		default:
c79092349   Randy Dunlap   hexdump: more out...
175
176
  			printk("%s%s%s
  ", level, prefix_str, linebuf);
99eaf3c45   Randy Dunlap   lib/hexdump
177
178
179
180
181
  			break;
  		}
  	}
  }
  EXPORT_SYMBOL(print_hex_dump);
c79092349   Randy Dunlap   hexdump: more out...
182
183
184
185
186
187
188
189
190
191
192
193
194
195
  
  /**
   * 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...
196
  			const void *buf, size_t len)
c79092349   Randy Dunlap   hexdump: more out...
197
198
199
200
201
  {
  	print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1,
  			buf, len, 1);
  }
  EXPORT_SYMBOL(print_hex_dump_bytes);