1*f8c987f8SAlexey Brodkin // SPDX-License-Identifier: GPL-2.0+
2*f8c987f8SAlexey Brodkin /*
3*f8c987f8SAlexey Brodkin * lib/hexdump.c
4*f8c987f8SAlexey Brodkin *
5*f8c987f8SAlexey Brodkin * This program is free software; you can redistribute it and/or modify
6*f8c987f8SAlexey Brodkin * it under the terms of the GNU General Public License version 2 as
7*f8c987f8SAlexey Brodkin * published by the Free Software Foundation. See README and COPYING for
8*f8c987f8SAlexey Brodkin * more details.
9*f8c987f8SAlexey Brodkin */
10*f8c987f8SAlexey Brodkin
11*f8c987f8SAlexey Brodkin #include <common.h>
12*f8c987f8SAlexey Brodkin #include <hexdump.h>
13*f8c987f8SAlexey Brodkin #include <linux/ctype.h>
14*f8c987f8SAlexey Brodkin #include <linux/compat.h>
15*f8c987f8SAlexey Brodkin #include <linux/log2.h>
16*f8c987f8SAlexey Brodkin #include <asm/unaligned.h>
17*f8c987f8SAlexey Brodkin
18*f8c987f8SAlexey Brodkin const char hex_asc[] = "0123456789abcdef";
19*f8c987f8SAlexey Brodkin const char hex_asc_upper[] = "0123456789ABCDEF";
20*f8c987f8SAlexey Brodkin
21*f8c987f8SAlexey Brodkin #ifdef CONFIG_HEXDUMP
22*f8c987f8SAlexey Brodkin /**
23*f8c987f8SAlexey Brodkin * hex_dump_to_buffer - convert a blob of data to "hex ASCII" in memory
24*f8c987f8SAlexey Brodkin * @buf: data blob to dump
25*f8c987f8SAlexey Brodkin * @len: number of bytes in the @buf
26*f8c987f8SAlexey Brodkin * @rowsize: number of bytes to print per line; must be 16 or 32
27*f8c987f8SAlexey Brodkin * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
28*f8c987f8SAlexey Brodkin * @linebuf: where to put the converted data
29*f8c987f8SAlexey Brodkin * @linebuflen: total size of @linebuf, including space for terminating NUL
30*f8c987f8SAlexey Brodkin * @ascii: include ASCII after the hex output
31*f8c987f8SAlexey Brodkin *
32*f8c987f8SAlexey Brodkin * hex_dump_to_buffer() works on one "line" of output at a time, i.e.,
33*f8c987f8SAlexey Brodkin * 16 or 32 bytes of input data converted to hex + ASCII output.
34*f8c987f8SAlexey Brodkin *
35*f8c987f8SAlexey Brodkin * Given a buffer of u8 data, hex_dump_to_buffer() converts the input data
36*f8c987f8SAlexey Brodkin * to a hex + ASCII dump at the supplied memory location.
37*f8c987f8SAlexey Brodkin * The converted output is always NUL-terminated.
38*f8c987f8SAlexey Brodkin *
39*f8c987f8SAlexey Brodkin * E.g.:
40*f8c987f8SAlexey Brodkin * hex_dump_to_buffer(frame->data, frame->len, 16, 1,
41*f8c987f8SAlexey Brodkin * linebuf, sizeof(linebuf), true);
42*f8c987f8SAlexey Brodkin *
43*f8c987f8SAlexey Brodkin * example output buffer:
44*f8c987f8SAlexey Brodkin * 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
45*f8c987f8SAlexey Brodkin *
46*f8c987f8SAlexey Brodkin * Return:
47*f8c987f8SAlexey Brodkin * The amount of bytes placed in the buffer without terminating NUL. If the
48*f8c987f8SAlexey Brodkin * output was truncated, then the return value is the number of bytes
49*f8c987f8SAlexey Brodkin * (excluding the terminating NUL) which would have been written to the final
50*f8c987f8SAlexey Brodkin * string if enough space had been available.
51*f8c987f8SAlexey Brodkin */
hex_dump_to_buffer(const void * buf,size_t len,int rowsize,int groupsize,char * linebuf,size_t linebuflen,bool ascii)52*f8c987f8SAlexey Brodkin int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
53*f8c987f8SAlexey Brodkin char *linebuf, size_t linebuflen, bool ascii)
54*f8c987f8SAlexey Brodkin {
55*f8c987f8SAlexey Brodkin const u8 *ptr = buf;
56*f8c987f8SAlexey Brodkin int ngroups;
57*f8c987f8SAlexey Brodkin u8 ch;
58*f8c987f8SAlexey Brodkin int j, lx = 0;
59*f8c987f8SAlexey Brodkin int ascii_column;
60*f8c987f8SAlexey Brodkin int ret;
61*f8c987f8SAlexey Brodkin
62*f8c987f8SAlexey Brodkin if (rowsize != 16 && rowsize != 32)
63*f8c987f8SAlexey Brodkin rowsize = 16;
64*f8c987f8SAlexey Brodkin
65*f8c987f8SAlexey Brodkin if (len > rowsize) /* limit to one line at a time */
66*f8c987f8SAlexey Brodkin len = rowsize;
67*f8c987f8SAlexey Brodkin if (!is_power_of_2(groupsize) || groupsize > 8)
68*f8c987f8SAlexey Brodkin groupsize = 1;
69*f8c987f8SAlexey Brodkin if ((len % groupsize) != 0) /* no mixed size output */
70*f8c987f8SAlexey Brodkin groupsize = 1;
71*f8c987f8SAlexey Brodkin
72*f8c987f8SAlexey Brodkin ngroups = len / groupsize;
73*f8c987f8SAlexey Brodkin ascii_column = rowsize * 2 + rowsize / groupsize + 1;
74*f8c987f8SAlexey Brodkin
75*f8c987f8SAlexey Brodkin if (!linebuflen)
76*f8c987f8SAlexey Brodkin goto overflow1;
77*f8c987f8SAlexey Brodkin
78*f8c987f8SAlexey Brodkin if (!len)
79*f8c987f8SAlexey Brodkin goto nil;
80*f8c987f8SAlexey Brodkin
81*f8c987f8SAlexey Brodkin if (groupsize == 8) {
82*f8c987f8SAlexey Brodkin const u64 *ptr8 = buf;
83*f8c987f8SAlexey Brodkin
84*f8c987f8SAlexey Brodkin for (j = 0; j < ngroups; j++) {
85*f8c987f8SAlexey Brodkin ret = snprintf(linebuf + lx, linebuflen - lx,
86*f8c987f8SAlexey Brodkin "%s%16.16llx", j ? " " : "",
87*f8c987f8SAlexey Brodkin get_unaligned(ptr8 + j));
88*f8c987f8SAlexey Brodkin if (ret >= linebuflen - lx)
89*f8c987f8SAlexey Brodkin goto overflow1;
90*f8c987f8SAlexey Brodkin lx += ret;
91*f8c987f8SAlexey Brodkin }
92*f8c987f8SAlexey Brodkin } else if (groupsize == 4) {
93*f8c987f8SAlexey Brodkin const u32 *ptr4 = buf;
94*f8c987f8SAlexey Brodkin
95*f8c987f8SAlexey Brodkin for (j = 0; j < ngroups; j++) {
96*f8c987f8SAlexey Brodkin ret = snprintf(linebuf + lx, linebuflen - lx,
97*f8c987f8SAlexey Brodkin "%s%8.8x", j ? " " : "",
98*f8c987f8SAlexey Brodkin get_unaligned(ptr4 + j));
99*f8c987f8SAlexey Brodkin if (ret >= linebuflen - lx)
100*f8c987f8SAlexey Brodkin goto overflow1;
101*f8c987f8SAlexey Brodkin lx += ret;
102*f8c987f8SAlexey Brodkin }
103*f8c987f8SAlexey Brodkin } else if (groupsize == 2) {
104*f8c987f8SAlexey Brodkin const u16 *ptr2 = buf;
105*f8c987f8SAlexey Brodkin
106*f8c987f8SAlexey Brodkin for (j = 0; j < ngroups; j++) {
107*f8c987f8SAlexey Brodkin ret = snprintf(linebuf + lx, linebuflen - lx,
108*f8c987f8SAlexey Brodkin "%s%4.4x", j ? " " : "",
109*f8c987f8SAlexey Brodkin get_unaligned(ptr2 + j));
110*f8c987f8SAlexey Brodkin if (ret >= linebuflen - lx)
111*f8c987f8SAlexey Brodkin goto overflow1;
112*f8c987f8SAlexey Brodkin lx += ret;
113*f8c987f8SAlexey Brodkin }
114*f8c987f8SAlexey Brodkin } else {
115*f8c987f8SAlexey Brodkin for (j = 0; j < len; j++) {
116*f8c987f8SAlexey Brodkin if (linebuflen < lx + 2)
117*f8c987f8SAlexey Brodkin goto overflow2;
118*f8c987f8SAlexey Brodkin ch = ptr[j];
119*f8c987f8SAlexey Brodkin linebuf[lx++] = hex_asc_hi(ch);
120*f8c987f8SAlexey Brodkin if (linebuflen < lx + 2)
121*f8c987f8SAlexey Brodkin goto overflow2;
122*f8c987f8SAlexey Brodkin linebuf[lx++] = hex_asc_lo(ch);
123*f8c987f8SAlexey Brodkin if (linebuflen < lx + 2)
124*f8c987f8SAlexey Brodkin goto overflow2;
125*f8c987f8SAlexey Brodkin linebuf[lx++] = ' ';
126*f8c987f8SAlexey Brodkin }
127*f8c987f8SAlexey Brodkin if (j)
128*f8c987f8SAlexey Brodkin lx--;
129*f8c987f8SAlexey Brodkin }
130*f8c987f8SAlexey Brodkin if (!ascii)
131*f8c987f8SAlexey Brodkin goto nil;
132*f8c987f8SAlexey Brodkin
133*f8c987f8SAlexey Brodkin while (lx < ascii_column) {
134*f8c987f8SAlexey Brodkin if (linebuflen < lx + 2)
135*f8c987f8SAlexey Brodkin goto overflow2;
136*f8c987f8SAlexey Brodkin linebuf[lx++] = ' ';
137*f8c987f8SAlexey Brodkin }
138*f8c987f8SAlexey Brodkin for (j = 0; j < len; j++) {
139*f8c987f8SAlexey Brodkin if (linebuflen < lx + 2)
140*f8c987f8SAlexey Brodkin goto overflow2;
141*f8c987f8SAlexey Brodkin ch = ptr[j];
142*f8c987f8SAlexey Brodkin linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
143*f8c987f8SAlexey Brodkin }
144*f8c987f8SAlexey Brodkin nil:
145*f8c987f8SAlexey Brodkin linebuf[lx] = '\0';
146*f8c987f8SAlexey Brodkin return lx;
147*f8c987f8SAlexey Brodkin overflow2:
148*f8c987f8SAlexey Brodkin linebuf[lx++] = '\0';
149*f8c987f8SAlexey Brodkin overflow1:
150*f8c987f8SAlexey Brodkin return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
151*f8c987f8SAlexey Brodkin }
152*f8c987f8SAlexey Brodkin
153*f8c987f8SAlexey Brodkin /**
154*f8c987f8SAlexey Brodkin * print_hex_dump - print a text hex dump to syslog for a binary blob of data
155*f8c987f8SAlexey Brodkin * @prefix_str: string to prefix each line with;
156*f8c987f8SAlexey Brodkin * caller supplies trailing spaces for alignment if desired
157*f8c987f8SAlexey Brodkin * @prefix_type: controls whether prefix of an offset, address, or none
158*f8c987f8SAlexey Brodkin * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
159*f8c987f8SAlexey Brodkin * @rowsize: number of bytes to print per line; must be 16 or 32
160*f8c987f8SAlexey Brodkin * @groupsize: number of bytes to print at a time (1, 2, 4, 8; default = 1)
161*f8c987f8SAlexey Brodkin * @buf: data blob to dump
162*f8c987f8SAlexey Brodkin * @len: number of bytes in the @buf
163*f8c987f8SAlexey Brodkin * @ascii: include ASCII after the hex output
164*f8c987f8SAlexey Brodkin *
165*f8c987f8SAlexey Brodkin * Given a buffer of u8 data, print_hex_dump() prints a hex + ASCII dump
166*f8c987f8SAlexey Brodkin * to the stdio, with an optional leading prefix.
167*f8c987f8SAlexey Brodkin *
168*f8c987f8SAlexey Brodkin * print_hex_dump() works on one "line" of output at a time, i.e.,
169*f8c987f8SAlexey Brodkin * 16 or 32 bytes of input data converted to hex + ASCII output.
170*f8c987f8SAlexey Brodkin * print_hex_dump() iterates over the entire input @buf, breaking it into
171*f8c987f8SAlexey Brodkin * "line size" chunks to format and print.
172*f8c987f8SAlexey Brodkin *
173*f8c987f8SAlexey Brodkin * E.g.:
174*f8c987f8SAlexey Brodkin * print_hex_dump("raw data: ", DUMP_PREFIX_ADDRESS, 16, 1, frame->data,
175*f8c987f8SAlexey Brodkin * frame->len, true);
176*f8c987f8SAlexey Brodkin *
177*f8c987f8SAlexey Brodkin * Example output using %DUMP_PREFIX_OFFSET and 1-byte mode:
178*f8c987f8SAlexey Brodkin * 0009ab42: 40 41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f @ABCDEFGHIJKLMNO
179*f8c987f8SAlexey Brodkin * Example output using %DUMP_PREFIX_ADDRESS and 4-byte mode:
180*f8c987f8SAlexey Brodkin * ffffffff88089af0: 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.
181*f8c987f8SAlexey Brodkin */
print_hex_dump(const char * prefix_str,int prefix_type,int rowsize,int groupsize,const void * buf,size_t len,bool ascii)182*f8c987f8SAlexey Brodkin void print_hex_dump(const char *prefix_str, int prefix_type, int rowsize,
183*f8c987f8SAlexey Brodkin int groupsize, const void *buf, size_t len, bool ascii)
184*f8c987f8SAlexey Brodkin {
185*f8c987f8SAlexey Brodkin const u8 *ptr = buf;
186*f8c987f8SAlexey Brodkin int i, linelen, remaining = len;
187*f8c987f8SAlexey Brodkin char linebuf[32 * 3 + 2 + 32 + 1];
188*f8c987f8SAlexey Brodkin
189*f8c987f8SAlexey Brodkin if (rowsize != 16 && rowsize != 32)
190*f8c987f8SAlexey Brodkin rowsize = 16;
191*f8c987f8SAlexey Brodkin
192*f8c987f8SAlexey Brodkin for (i = 0; i < len; i += rowsize) {
193*f8c987f8SAlexey Brodkin linelen = min(remaining, rowsize);
194*f8c987f8SAlexey Brodkin remaining -= rowsize;
195*f8c987f8SAlexey Brodkin
196*f8c987f8SAlexey Brodkin hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
197*f8c987f8SAlexey Brodkin linebuf, sizeof(linebuf), ascii);
198*f8c987f8SAlexey Brodkin
199*f8c987f8SAlexey Brodkin switch (prefix_type) {
200*f8c987f8SAlexey Brodkin case DUMP_PREFIX_ADDRESS:
201*f8c987f8SAlexey Brodkin printf("%s%p: %s\n", prefix_str, ptr + i, linebuf);
202*f8c987f8SAlexey Brodkin break;
203*f8c987f8SAlexey Brodkin case DUMP_PREFIX_OFFSET:
204*f8c987f8SAlexey Brodkin printf("%s%.8x: %s\n", prefix_str, i, linebuf);
205*f8c987f8SAlexey Brodkin break;
206*f8c987f8SAlexey Brodkin default:
207*f8c987f8SAlexey Brodkin printf("%s%s\n", prefix_str, linebuf);
208*f8c987f8SAlexey Brodkin break;
209*f8c987f8SAlexey Brodkin }
210*f8c987f8SAlexey Brodkin }
211*f8c987f8SAlexey Brodkin }
212*f8c987f8SAlexey Brodkin
213*f8c987f8SAlexey Brodkin /**
214*f8c987f8SAlexey Brodkin * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params
215*f8c987f8SAlexey Brodkin * @prefix_str: string to prefix each line with;
216*f8c987f8SAlexey Brodkin * caller supplies trailing spaces for alignment if desired
217*f8c987f8SAlexey Brodkin * @prefix_type: controls whether prefix of an offset, address, or none
218*f8c987f8SAlexey Brodkin * is printed (%DUMP_PREFIX_OFFSET, %DUMP_PREFIX_ADDRESS, %DUMP_PREFIX_NONE)
219*f8c987f8SAlexey Brodkin * @buf: data blob to dump
220*f8c987f8SAlexey Brodkin * @len: number of bytes in the @buf
221*f8c987f8SAlexey Brodkin *
222*f8c987f8SAlexey Brodkin * Calls print_hex_dump(), rowsize of 16, groupsize of 1,
223*f8c987f8SAlexey Brodkin * and ASCII output included.
224*f8c987f8SAlexey Brodkin */
print_hex_dump_bytes(const char * prefix_str,int prefix_type,const void * buf,size_t len)225*f8c987f8SAlexey Brodkin void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
226*f8c987f8SAlexey Brodkin const void *buf, size_t len)
227*f8c987f8SAlexey Brodkin {
228*f8c987f8SAlexey Brodkin print_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true);
229*f8c987f8SAlexey Brodkin }
230*f8c987f8SAlexey Brodkin #else
231*f8c987f8SAlexey Brodkin /*
232*f8c987f8SAlexey Brodkin * Some code in U-Boot copy-pasted from Linux kernel uses both
233*f8c987f8SAlexey Brodkin * functions below so to keep stuff compilable we keep these stubs here.
234*f8c987f8SAlexey Brodkin */
print_hex_dump(const char * prefix_str,int prefix_type,int rowsize,int groupsize,const void * buf,size_t len,bool ascii)235*f8c987f8SAlexey Brodkin void print_hex_dump(const char *prefix_str, int prefix_type,
236*f8c987f8SAlexey Brodkin int rowsize, int groupsize, const void *buf,
237*f8c987f8SAlexey Brodkin size_t len, bool ascii)
238*f8c987f8SAlexey Brodkin {
239*f8c987f8SAlexey Brodkin }
240*f8c987f8SAlexey Brodkin
print_hex_dump_bytes(const char * prefix_str,int prefix_type,const void * buf,size_t len)241*f8c987f8SAlexey Brodkin void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
242*f8c987f8SAlexey Brodkin const void *buf, size_t len)
243*f8c987f8SAlexey Brodkin {
244*f8c987f8SAlexey Brodkin }
245*f8c987f8SAlexey Brodkin #endif /* CONFIG_HEXDUMP */
246