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