The print_buffer() function is very useful for debugging. Add a version
of this in the log system also.

Signed-off-by: Simon Glass <s...@chromium.org>
---

 common/log.c        | 30 ++++++++++++++++++++++++++++++
 include/log.h       | 35 +++++++++++++++++++++++++++++++++++
 test/log/log_test.c | 27 +++++++++++++++++++++++++++
 3 files changed, 92 insertions(+)

diff --git a/common/log.c b/common/log.c
index ea407c6db9e..1aaa6c1527b 100644
--- a/common/log.c
+++ b/common/log.c
@@ -284,6 +284,36 @@ int _log(enum log_category_t cat, enum log_level_t level, 
const char *file,
        return 0;
 }
 
+#define MAX_LINE_LENGTH_BYTES          64
+#define DEFAULT_LINE_LENGTH_BYTES      16
+
+int _log_buffer(enum log_category_t cat, enum log_level_t level,
+               const char *file, int line, const char *func, 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;
+               char buf[HEXDUMP_MAX_BUF_LENGTH(width * linelen)];
+
+               thislinelen = hexdump_line(addr, data, width, count, linelen,
+                                          buf, sizeof(buf));
+               assert(thislinelen >= 0);
+               _log(cat, level, file, line, func, "%s\n", buf);
+
+               /* update references */
+               data += thislinelen * width;
+               addr += thislinelen * width;
+               count -= thislinelen;
+       }
+
+       return 0;
+}
+
 int log_add_filter_flags(const char *drv_name, enum log_category_t cat_list[],
                         enum log_level_t level, const char *file_list,
                         int flags)
diff --git a/include/log.h b/include/log.h
index 594a361c613..ed7ba6d705a 100644
--- a/include/log.h
+++ b/include/log.h
@@ -128,6 +128,24 @@ int _log(enum log_category_t cat, enum log_level_t level, 
const char *file,
         int line, const char *func, const char *fmt, ...)
                __attribute__ ((format (__printf__, 6, 7)));
 
+/**
+ * _log_buffer - Internal function to print data buffer in hex and ascii form
+ *
+ * @cat: Category of log record (indicating which subsystem generated it)
+ * @level: Level of log record (indicating its severity)
+ * @file: File name of file where log record was generated
+ * @line: Line number in file where log record was generated
+ * @func: Function where log record was generated
+ * @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
+ */
+int _log_buffer(enum log_category_t cat, enum log_level_t level,
+               const char *file, int line, const char *func, ulong addr,
+               const void *data, uint width, uint count, uint linelen);
+
 /* Define this at the top of a file to add a prefix to debug messages */
 #ifndef pr_fmt
 #define pr_fmt(fmt) fmt
@@ -177,6 +195,16 @@ int _log(enum log_category_t cat, enum log_level_t level, 
const char *file,
                     __LINE__, __func__, \
                      pr_fmt(_fmt), ##_args); \
        })
+
+/* Emit a dump if the level is less that the maximum */
+#define log_buffer(_cat, _level, _addr, _data, _width, _count, _linelen)  ({ \
+       int _l = _level; \
+       if (_LOG_DEBUG != 0 || _l <= _LOG_MAX_LEVEL) \
+               _log_buffer((enum log_category_t)(_cat), \
+                           (enum log_level_t)(_l | _LOG_DEBUG), __FILE__, \
+                           __LINE__, __func__, _addr, _data, \
+                           _width, _count, _linelen); \
+       })
 #else
 /* Note: _LOG_DEBUG != 0 avoids a warning with clang */
 #define log(_cat, _level, _fmt, _args...) ({ \
@@ -185,6 +213,13 @@ int _log(enum log_category_t cat, enum log_level_t level, 
const char *file,
            (_DEBUG && _l == LOGL_DEBUG)) \
                printf(_fmt, ##_args); \
        })
+
+#define log_buffer(_cat, _level, _addr, _data, _width, _count, _linelen)  ({ \
+       int _l = _level; \
+       if (_LOG_DEBUG != 0 || _l <= LOGL_INFO || \
+           (_DEBUG && _l == LOGL_DEBUG)) \
+               print_buffer(_addr, _data, _width, _count, _linelen); \
+       })
 #endif
 
 #ifdef DEBUG
diff --git a/test/log/log_test.c b/test/log/log_test.c
index 4a814ff4132..f1e67509c17 100644
--- a/test/log/log_test.c
+++ b/test/log/log_test.c
@@ -429,3 +429,30 @@ int log_test_dropped(struct unit_test_state *uts)
        return 0;
 }
 LOG_TEST_FLAGS(log_test_dropped, UT_TESTF_CONSOLE_REC);
+
+/* Check log_buffer() */
+int log_test_buffer(struct unit_test_state *uts)
+{
+       u8 *buf;
+       int i;
+
+       buf = malloc(0x20);
+       ut_assertnonnull(buf);
+       memset(buf, '\0', 0x20);
+       for (i = 0; i < 0x11; i++)
+               buf[i] = i * 0x11;
+
+       ut_assertok(console_record_reset_enable());
+       log_buffer(LOGC_BOOT, LOGL_INFO, 0, buf, 1, 0x12, 0);
+
+       /* This one should product no output due to the debug level */
+       log_buffer(LOGC_BOOT, LOGL_DEBUG, 0, buf, 1, 0x12, 0);
+
+       ut_assert_nextline("00000000: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd 
ee ff  ..\"3DUfw........");
+       ut_assert_nextline("00000010: 10 00                                     
       ..");
+       ut_assert_console_end();
+       free(buf);
+
+       return 0;
+}
+LOG_TEST_FLAGS(log_test_buffer, UT_TESTF_CONSOLE_REC);
-- 
2.31.0.rc2.261.g7f71774620-goog

Reply via email to