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