smaeul-u-boot/lib/hexdump.c
Simon Glass 2f410fe557 hexdump: Move API to header file
Move the comments to the header file so people can find the function info
without digging in the implementation. Fix up the code style and add an
enum for the first arg.

Signed-off-by: Simon Glass <sjg@chromium.org>
2021-06-08 11:39:09 -04:00

174 lines
4.1 KiB
C

// SPDX-License-Identifier: GPL-2.0+
/*
* lib/hexdump.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See README and COPYING for
* more details.
*/
#include <common.h>
#include <hexdump.h>
#include <linux/ctype.h>
#include <linux/compat.h>
#include <linux/log2.h>
#include <asm/unaligned.h>
const char hex_asc[] = "0123456789abcdef";
const char hex_asc_upper[] = "0123456789ABCDEF";
#if CONFIG_IS_ENABLED(HEXDUMP)
int hex_dump_to_buffer(const void *buf, size_t len, int rowsize, int groupsize,
char *linebuf, size_t linebuflen, bool ascii)
{
const u8 *ptr = buf;
int ngroups;
u8 ch;
int j, lx = 0;
int ascii_column;
int ret;
if (rowsize != 16 && rowsize != 32)
rowsize = 16;
if (len > rowsize) /* limit to one line at a time */
len = rowsize;
if (!is_power_of_2(groupsize) || groupsize > 8)
groupsize = 1;
if ((len % groupsize) != 0) /* no mixed size output */
groupsize = 1;
ngroups = len / groupsize;
ascii_column = rowsize * 2 + rowsize / groupsize + 1;
if (!linebuflen)
goto overflow1;
if (!len)
goto nil;
if (groupsize == 8) {
const u64 *ptr8 = buf;
for (j = 0; j < ngroups; j++) {
ret = snprintf(linebuf + lx, linebuflen - lx,
"%s%16.16llx", j ? " " : "",
get_unaligned(ptr8 + j));
if (ret >= linebuflen - lx)
goto overflow1;
lx += ret;
}
} else if (groupsize == 4) {
const u32 *ptr4 = buf;
for (j = 0; j < ngroups; j++) {
ret = snprintf(linebuf + lx, linebuflen - lx,
"%s%8.8x", j ? " " : "",
get_unaligned(ptr4 + j));
if (ret >= linebuflen - lx)
goto overflow1;
lx += ret;
}
} else if (groupsize == 2) {
const u16 *ptr2 = buf;
for (j = 0; j < ngroups; j++) {
ret = snprintf(linebuf + lx, linebuflen - lx,
"%s%4.4x", j ? " " : "",
get_unaligned(ptr2 + j));
if (ret >= linebuflen - lx)
goto overflow1;
lx += ret;
}
} else {
for (j = 0; j < len; j++) {
if (linebuflen < lx + 2)
goto overflow2;
ch = ptr[j];
linebuf[lx++] = hex_asc_hi(ch);
if (linebuflen < lx + 2)
goto overflow2;
linebuf[lx++] = hex_asc_lo(ch);
if (linebuflen < lx + 2)
goto overflow2;
linebuf[lx++] = ' ';
}
if (j)
lx--;
}
if (!ascii)
goto nil;
while (lx < ascii_column) {
if (linebuflen < lx + 2)
goto overflow2;
linebuf[lx++] = ' ';
}
for (j = 0; j < len; j++) {
if (linebuflen < lx + 2)
goto overflow2;
ch = ptr[j];
linebuf[lx++] = (isascii(ch) && isprint(ch)) ? ch : '.';
}
nil:
linebuf[lx] = '\0';
return lx;
overflow2:
linebuf[lx++] = '\0';
overflow1:
return ascii ? ascii_column + len : (groupsize * 2 + 1) * ngroups - 1;
}
void print_hex_dump(const char *prefix_str, int prefix_type, int rowsize,
int groupsize, const void *buf, size_t len, bool ascii)
{
const u8 *ptr = buf;
int i, linelen, remaining = len;
char linebuf[32 * 3 + 2 + 32 + 1];
if (rowsize != 16 && rowsize != 32)
rowsize = 16;
for (i = 0; i < len; i += rowsize) {
linelen = min(remaining, rowsize);
remaining -= rowsize;
hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
linebuf, sizeof(linebuf), ascii);
switch (prefix_type) {
case DUMP_PREFIX_ADDRESS:
printf("%s%p: %s\n", prefix_str, ptr + i, linebuf);
break;
case DUMP_PREFIX_OFFSET:
printf("%s%.8x: %s\n", prefix_str, i, linebuf);
break;
default:
printf("%s%s\n", prefix_str, linebuf);
break;
}
}
}
void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
const void *buf, size_t len)
{
print_hex_dump(prefix_str, prefix_type, 16, 1, buf, len, true);
}
#else
/*
* Some code in U-Boot copy-pasted from Linux kernel uses both
* functions below so to keep stuff compilable we keep these stubs here.
*/
void print_hex_dump(const char *prefix_str, int prefix_type, int rowsize,
int groupsize, const void *buf, size_t len, bool ascii)
{
}
void print_hex_dump_bytes(const char *prefix_str, int prefix_type,
const void *buf, size_t len)
{
}
#endif /* CONFIG_HEXDUMP */