1
2
3
4
5
6
7
8
9
10#include <linux/types.h>
11#include <linux/ctype.h>
12#include <linux/errno.h>
13#include <linux/kernel.h>
14#include <linux/minmax.h>
15#include <linux/export.h>
16#include <asm/unaligned.h>
17
18const char hex_asc[] = "0123456789abcdef";
19EXPORT_SYMBOL(hex_asc);
20const char hex_asc_upper[] = "0123456789ABCDEF";
21EXPORT_SYMBOL(hex_asc_upper);
22
23
24
25
26
27
28
29
30int hex_to_bin(char ch)
31{
32 if ((ch >= '0') && (ch <= '9'))
33 return ch - '0';
34 ch = tolower(ch);
35 if ((ch >= 'a') && (ch <= 'f'))
36 return ch - 'a' + 10;
37 return -1;
38}
39EXPORT_SYMBOL(hex_to_bin);
40
41
42
43
44
45
46
47
48
49int hex2bin(u8 *dst, const char *src, size_t count)
50{
51 while (count--) {
52 int hi = hex_to_bin(*src++);
53 int lo = hex_to_bin(*src++);
54
55 if ((hi < 0) || (lo < 0))
56 return -EINVAL;
57
58 *dst++ = (hi << 4) | lo;
59 }
60 return 0;
61}
62EXPORT_SYMBOL(hex2bin);
63
64
65
66
67
68
69
70char *bin2hex(char *dst, const void *src, size_t count)
71{
72 const unsigned char *_src = src;
73
74 while (count--)
75 dst = hex_byte_pack(dst, *_src++);
76 return dst;
77}
78EXPORT_SYMBOL(bin2hex);
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
111 char *linebuf, size_t linebuflen, bool ascii)
112{
113 const u8 *ptr = buf;
114 int ngroups;
115 u8 ch;
116 int j, lx = 0;
117 int ascii_column;
118 int ret;
119
120 if (rowsize != 16 && rowsize != 32)
121 rowsize = 16;
122
123 if (len > rowsize)
124 len = rowsize;
125 if (!is_power_of_2(groupsize) || groupsize > 8)
126 groupsize = 1;
127 if ((len % groupsize) != 0)
128 groupsize = 1;
129
130 ngroups = len / groupsize;
131 ascii_column = rowsize * 2 + rowsize / groupsize + 1;
132
133 if (!linebuflen)
134 goto overflow1;
135
136 if (!len)
137 goto nil;
138
139 if (groupsize == 8) {
140 const u64 *ptr8 = buf;
141
142 for (j = 0; j < ngroups; j++) {
143 ret = snprintf(linebuf + lx, linebuflen - lx,
144 "%s%16.16llx", j ? " " : "",
145 get_unaligned(ptr8 + j));
146 if (ret >= linebuflen - lx)
147 goto overflow1;
148 lx += ret;
149 }
150 } else if (groupsize == 4) {
151 const u32 *ptr4 = buf;
152
153 for (j = 0; j < ngroups; j++) {
154 ret = snprintf(linebuf + lx, linebuflen - lx,
155 "%s%8.8x", j ? " " : "",
156 get_unaligned(ptr4 + j));
157 if (ret >= linebuflen - lx)
158 goto overflow1;
159 lx += ret;
160 }
161 } else if (groupsize == 2) {
162 const u16 *ptr2 = buf;
163
164 for (j = 0; j < ngroups; j++) {
165 ret = snprintf(linebuf + lx, linebuflen - lx,
166 "%s%4.4x", j ? " " : "",
167 get_unaligned(ptr2 + j));
168 if (ret >= linebuflen - lx)
169 goto overflow1;
170 lx += ret;
171 }
172 } else {
173 for (j = 0; j < len; j++) {
174 if (linebuflen < lx + 2)
175 goto overflow2;
176 ch = ptr[j];
177 linebuf[lx++] = hex_asc_hi(ch);
178 if (linebuflen < lx + 2)
179 goto overflow2;
180 linebuf[lx++] = hex_asc_lo(ch);
181 if (linebuflen < lx + 2)
182 goto overflow2;
183 linebuf[lx++] = ' ';
184 }
185 if (j)
186 lx--;
187 }
188 if (!ascii)
189 goto nil;
190
191 while (lx < ascii_column) {
192 if (linebuflen < lx + 2)
193 goto overflow2;
194 linebuf[lx++] = ' ';
195 }
196 for (j = 0; j < len; j++) {
197 if (linebuflen < lx + 2)
198 goto overflow2;
199 ch = ptr[j];
200 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
201 }
202nil:
203 linebuf[lx] = '\0';
204 return lx;
205overflow2:
206 linebuf[lx++] = '\0';
207overflow1:
208 return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
209}
210EXPORT_SYMBOL(hex_dump_to_buffer);
211
212#ifdef CONFIG_PRINTK
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
245 int rowsize, int groupsize,
246 const void *buf, size_t len, bool ascii)
247{
248 const u8 *ptr = buf;
249 int i, linelen, remaining = len;
250 unsigned char linebuf[32 * 3 + 2 + 32 + 1];
251
252 if (rowsize != 16 && rowsize != 32)
253 rowsize = 16;
254
255 for (i = 0; i < len; i += rowsize) {
256 linelen = min(remaining, rowsize);
257 remaining -= rowsize;
258
259 hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
260 linebuf, sizeof(linebuf), ascii);
261
262 switch (prefix_type) {
263 case DUMP_PREFIX_ADDRESS:
264 printk("%s%s%p: %s\n",
265 level, prefix_str, ptr + i, linebuf);
266 break;
267 case DUMP_PREFIX_OFFSET:
268 printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
269 break;
270 default:
271 printk("%s%s%s\n", level, prefix_str, linebuf);
272 break;
273 }
274 }
275}
276EXPORT_SYMBOL(print_hex_dump);
277
278#if !defined(CONFIG_DYNAMIC_DEBUG)
279
280
281
282
283
284
285
286
287
288
289
290
291void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
292 const void *buf, size_t len)
293{
294 print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, 16, 1,
295 buf, len, true);
296}
297EXPORT_SYMBOL(print_hex_dump_bytes);
298#endif
299#endif
300