[PATCH 11/13] display_options: Split print_buffer() into two functions
Simon Glass
sjg at chromium.org
Wed Mar 17 19:18:38 CET 2021
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 at chromium.org>
---
include/display_options.h | 25 +++++++++
lib/display_options.c | 115 +++++++++++++++++++++++---------------
test/print_ut.c | 30 +++++++++-
3 files changed, 123 insertions(+), 47 deletions(-)
diff --git a/include/display_options.h b/include/display_options.h
index 049688e39e8..43810cbe22f 100644
--- a/include/display_options.h
+++ b/include/display_options.h
@@ -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
*
diff --git a/lib/display_options.c b/lib/display_options.c
index 7752baba2bd..c08a87e3162 100644
--- a/lib/display_options.c
+++ b/lib/display_options.c
@@ -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);
-
- /* 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;
- }
+ uint thislinelen;
+ char buf[HEXDUMP_MAX_BUF_LENGTH(width * linelen)];
- 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;
diff --git a/test/print_ut.c b/test/print_ut.c
index 3a3cdf323e1..079d3f7cb08 100644
--- a/test/print_ut.c
+++ b/test/print_ut.c
@@ -229,7 +229,33 @@ static int print_display_buffer(struct unit_test_state *uts)
}
PRINT_TEST(print_display_buffer, UT_TESTF_CONSOLE_REC);
-static int print_hex_dump(struct unit_test_state *uts)
+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_hexdump(struct unit_test_state *uts)
{
u8 *buf;
int i;
@@ -302,7 +328,7 @@ static int print_hex_dump(struct unit_test_state *uts)
return 0;
}
-PRINT_TEST(print_hex_dump, UT_TESTF_CONSOLE_REC);
+PRINT_TEST(print_hexdump, UT_TESTF_CONSOLE_REC);
int do_ut_print(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
{
--
2.31.0.rc2.261.g7f71774620-goog
More information about the U-Boot
mailing list