display_options: Split print_buffer() into two functions

At present print_buffer() outputs a hex dump but it is not possible to
place this dump in a string. Refactor it into a top-level function which
does the printing and a utility function that dumps a line into a string.
This makes the code more generally useful.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2021-05-08 07:00:05 -06:00 committed by Tom Rini
parent 735dd6ef89
commit 0cceb99ac5
3 changed files with 121 additions and 45 deletions

View File

@ -47,6 +47,31 @@ void print_freq(uint64_t freq, const char *suffix);
int print_buffer(ulong addr, const void *data, uint width, uint count,
uint linelen);
/*
* Maximum length of an output line is when width == 1
* 9 for address,
* a space, two hex digits and an ASCII character for each byte
* 2 spaces between the hex and ASCII
* \0 terminator
*/
#define HEXDUMP_MAX_BUF_LENGTH(bytes) (9 + (bytes) * 4 + 3)
/**
* hexdump_line() - Print out a single line of a hex dump
*
* @addr: Starting address to display at start of line
* @data: pointer to data buffer
* @width: data value width. May be 1, 2, or 4.
* @count: number of values to display
* @linelen: Number of values to print per line; specify 0 for default length
* @out: Output buffer to hold the dump
* @size: Size of output buffer in bytes
* @return number of bytes processed, if OK, -ENOSPC if buffer too small
*
*/
int hexdump_line(ulong addr, const void *data, uint width, uint count,
uint linelen, char *out, int size);
/**
* display_options() - display the version string / build tag
*

View File

@ -131,10 +131,11 @@ void print_size(uint64_t size, const char *s)
printf (" %ciB%s", c, s);
}
#define MAX_LINE_LENGTH_BYTES (64)
#define DEFAULT_LINE_LENGTH_BYTES (16)
int print_buffer(ulong addr, const void *data, uint width, uint count,
uint linelen)
#define MAX_LINE_LENGTH_BYTES 64
#define DEFAULT_LINE_LENGTH_BYTES 16
int hexdump_line(ulong addr, const void *data, uint width, uint count,
uint linelen, char *out, int size)
{
/* linebuf as a union causes proper alignment */
union linebuf {
@ -143,62 +144,86 @@ int print_buffer(ulong addr, const void *data, uint width, uint count,
uint16_t us[MAX_LINE_LENGTH_BYTES/sizeof(uint16_t) + 1];
uint8_t uc[MAX_LINE_LENGTH_BYTES/sizeof(uint8_t) + 1];
} lb;
uint thislinelen;
int i;
ulong x;
if (linelen * width > MAX_LINE_LENGTH_BYTES)
linelen = MAX_LINE_LENGTH_BYTES / width;
if (linelen < 1)
linelen = DEFAULT_LINE_LENGTH_BYTES / width;
/*
* Check the size here so that we don't need to use snprintf(). This
* helps to reduce code size
*/
if (size < HEXDUMP_MAX_BUF_LENGTH(linelen * width))
return -ENOSPC;
thislinelen = linelen;
out += sprintf(out, "%08lx:", addr);
/* check for overflow condition */
if (count < thislinelen)
thislinelen = count;
/* Copy from memory into linebuf and print hex values */
for (i = 0; i < thislinelen; i++) {
if (width == 4)
x = lb.ui[i] = *(volatile uint32_t *)data;
else if (MEM_SUPPORT_64BIT_DATA && width == 8)
x = lb.uq[i] = *(volatile ulong *)data;
else if (width == 2)
x = lb.us[i] = *(volatile uint16_t *)data;
else
x = lb.uc[i] = *(volatile uint8_t *)data;
if (CONFIG_IS_ENABLED(USE_TINY_PRINTF))
out += sprintf(out, " %x", (uint)x);
else
out += sprintf(out, " %0*lx", width * 2, x);
data += width;
}
/* fill line with whitespace for nice ASCII print */
for (i = 0; i < (linelen - thislinelen) * (width * 2 + 1); i++)
*out++ = ' ';
/* Print data in ASCII characters */
for (i = 0; i < thislinelen * width; i++) {
if (!isprint(lb.uc[i]) || lb.uc[i] >= 0x80)
lb.uc[i] = '.';
}
lb.uc[i] = '\0';
out += sprintf(out, " %s", lb.uc);
return thislinelen;
}
int print_buffer(ulong addr, const void *data, uint width, uint count,
uint linelen)
{
if (linelen*width > MAX_LINE_LENGTH_BYTES)
linelen = MAX_LINE_LENGTH_BYTES / width;
if (linelen < 1)
linelen = DEFAULT_LINE_LENGTH_BYTES / width;
while (count) {
uint thislinelen = linelen;
printf("%08lx:", addr);
uint thislinelen;
char buf[HEXDUMP_MAX_BUF_LENGTH(width * linelen)];
/* check for overflow condition */
if (count < thislinelen)
thislinelen = count;
/* Copy from memory into linebuf and print hex values */
for (i = 0; i < thislinelen; i++) {
if (width == 4)
x = lb.ui[i] = *(volatile uint32_t *)data;
else if (MEM_SUPPORT_64BIT_DATA && width == 8)
x = lb.uq[i] = *(volatile ulong *)data;
else if (width == 2)
x = lb.us[i] = *(volatile uint16_t *)data;
else
x = lb.uc[i] = *(volatile uint8_t *)data;
if (CONFIG_IS_ENABLED(USE_TINY_PRINTF))
printf(" %x", (uint)x);
else
printf(" %0*lx", width * 2, x);
data += width;
}
while (thislinelen < linelen) {
/* fill line with whitespace for nice ASCII print */
for (i=0; i<width*2+1; i++)
puts(" ");
linelen--;
}
/* Print data in ASCII characters */
for (i = 0; i < thislinelen * width; i++) {
if (!isprint(lb.uc[i]) || lb.uc[i] >= 0x80)
lb.uc[i] = '.';
}
lb.uc[i] = '\0';
printf(" %s\n", lb.uc);
thislinelen = hexdump_line(addr, data, width, count, linelen,
buf, sizeof(buf));
assert(thislinelen >= 0);
puts(buf);
putc('\n');
/* update references */
data += thislinelen * width;
addr += thislinelen * width;
count -= thislinelen;
#ifndef CONFIG_SPL_BUILD
if (ctrlc())
return -1;
#endif
if (!IS_ENABLED(CONFIG_SPL_BUILD) && ctrlc())
return -EINTR;
}
return 0;

View File

@ -227,6 +227,32 @@ static int print_display_buffer(struct unit_test_state *uts)
}
PRINT_TEST(print_display_buffer, UT_TESTF_CONSOLE_REC);
static int print_hexdump_line(struct unit_test_state *uts)
{
char *linebuf;
u8 *buf;
int i;
buf = map_sysmem(0, BUF_SIZE);
memset(buf, '\0', BUF_SIZE);
for (i = 0; i < 0x11; i++)
buf[i] = i * 0x11;
/* Check buffer size calculations */
linebuf = map_sysmem(0x400, BUF_SIZE);
memset(linebuf, '\xff', BUF_SIZE);
ut_asserteq(-ENOSPC, hexdump_line(0, buf, 1, 0x10, 0, linebuf, 75));
ut_asserteq(-1, linebuf[0]);
ut_asserteq(0x10, hexdump_line(0, buf, 1, 0x10, 0, linebuf, 76));
ut_asserteq(0, linebuf[75]);
ut_asserteq(-1, linebuf[76]);
unmap_sysmem(buf);
return 0;
}
PRINT_TEST(print_hexdump_line, UT_TESTF_CONSOLE_REC);
static int print_do_hex_dump(struct unit_test_state *uts)
{
u8 *buf;