hexdump: Add support for sandbox
[platform/kernel/u-boot.git] / lib / hexdump.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * lib/hexdump.c
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation. See README and COPYING for
8  * more details.
9  */
10
11 #include <common.h>
12 #include <hexdump.h>
13 #include <mapmem.h>
14 #include <linux/ctype.h>
15 #include <linux/compat.h>
16 #include <linux/log2.h>
17 #include <asm/unaligned.h>
18
19 const char hex_asc[] = "0123456789abcdef";
20 const char hex_asc_upper[] = "0123456789ABCDEF";
21
22 #if CONFIG_IS_ENABLED(HEXDUMP)
23 int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
24                        char *linebuf, size_t linebuflen, bool ascii)
25 {
26         const u8 *ptr = buf;
27         int ngroups;
28         u8 ch;
29         int j, lx = 0;
30         int ascii_column;
31         int ret;
32
33         if (rowsize != 16 && rowsize != 32)
34                 rowsize = 16;
35
36         if (len > rowsize)              /* limit to one line at a time */
37                 len = rowsize;
38         if (!is_power_of_2(groupsize) || groupsize > 8)
39                 groupsize = 1;
40         if ((len % groupsize) != 0)     /* no mixed size output */
41                 groupsize = 1;
42
43         ngroups = len / groupsize;
44         ascii_column = rowsize * 2 + rowsize / groupsize + 1;
45
46         if (!linebuflen)
47                 goto overflow1;
48
49         if (!len)
50                 goto nil;
51
52         if (groupsize == 8) {
53                 const u64 *ptr8 = buf;
54
55                 for (j = 0; j < ngroups; j++) {
56                         ret = snprintf(linebuf + lx, linebuflen - lx,
57                                        "%s%16.16llx", j ? " " : "",
58                                        get_unaligned(ptr8 + j));
59                         if (ret >= linebuflen - lx)
60                                 goto overflow1;
61                         lx += ret;
62                 }
63         } else if (groupsize == 4) {
64                 const u32 *ptr4 = buf;
65
66                 for (j = 0; j < ngroups; j++) {
67                         ret = snprintf(linebuf + lx, linebuflen - lx,
68                                        "%s%8.8x", j ? " " : "",
69                                        get_unaligned(ptr4 + j));
70                         if (ret >= linebuflen - lx)
71                                 goto overflow1;
72                         lx += ret;
73                 }
74         } else if (groupsize == 2) {
75                 const u16 *ptr2 = buf;
76
77                 for (j = 0; j < ngroups; j++) {
78                         ret = snprintf(linebuf + lx, linebuflen - lx,
79                                        "%s%4.4x", j ? " " : "",
80                                        get_unaligned(ptr2 + j));
81                         if (ret >= linebuflen - lx)
82                                 goto overflow1;
83                         lx += ret;
84                 }
85         } else {
86                 for (j = 0; j < len; j++) {
87                         if (linebuflen < lx + 2)
88                                 goto overflow2;
89                         ch = ptr[j];
90                         linebuf[lx++] = hex_asc_hi(ch);
91                         if (linebuflen < lx + 2)
92                                 goto overflow2;
93                         linebuf[lx++] = hex_asc_lo(ch);
94                         if (linebuflen < lx + 2)
95                                 goto overflow2;
96                         linebuf[lx++] = ' ';
97                 }
98                 if (j)
99                         lx--;
100         }
101         if (!ascii)
102                 goto nil;
103
104         while (lx < ascii_column) {
105                 if (linebuflen < lx + 2)
106                         goto overflow2;
107                 linebuf[lx++] = ' ';
108         }
109         for (j = 0; j < len; j++) {
110                 if (linebuflen < lx + 2)
111                         goto overflow2;
112                 ch = ptr[j];
113                 linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
114         }
115 nil:
116         linebuf[lx] = '\0';
117         return lx;
118 overflow2:
119         linebuf[lx++] = '\0';
120 overflow1:
121         return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
122 }
123
124 void print_hex_dump(const char *prefix_str, int prefix_type, int rowsize,
125                     int groupsize, const void *buf, size_t len, bool ascii)
126 {
127         const u8 *ptr = buf;
128         int i, linelen, remaining = len;
129         char linebuf[32 * 3 + 2 + 32 + 1];
130
131         if (rowsize != 16 && rowsize != 32)
132                 rowsize = 16;
133
134         for (i = 0; i < len; i += rowsize) {
135                 linelen = min(remaining, rowsize);
136                 remaining -= rowsize;
137
138                 hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
139                                    linebuf, sizeof(linebuf), ascii);
140
141                 switch (prefix_type) {
142                 case DUMP_PREFIX_ADDRESS:
143                         printf("%s%0*lx: %s\n", prefix_str,
144                                IS_ENABLED(CONFIG_PHYS_64BIT) ? 16 : 8,
145                                (ulong)map_to_sysmem(ptr) + i, linebuf);
146                         break;
147                 case DUMP_PREFIX_OFFSET:
148                         printf("%s%.8x: %s\n", prefix_str, i, linebuf);
149                         break;
150                 default:
151                         printf("%s%s\n", prefix_str, linebuf);
152                         break;
153                 }
154         }
155 }
156
157 void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
158                           const void *buf, size_t len)
159 {
160         print_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true);
161 }
162 #else
163 /*
164  * Some code in U-Boot copy-pasted from Linux kernel uses both
165  * functions below so to keep stuff compilable we keep these stubs here.
166  */
167 void print_hex_dump(const char *prefix_str, int prefix_type, int rowsize,
168                     int groupsize, const void *buf, size_t len, bool ascii)
169 {
170 }
171
172 void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
173                           const void *buf, size_t len)
174 {
175 }
176 #endif /* CONFIG_HEXDUMP */