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