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