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