diff options
author | Evan Green <evgreen@chromium.org> | 2019-08-01 11:20:14 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-10-05 00:47:41 +0000 |
commit | b63e2a87a75dce8941d087c8736c5a35544ab3b0 (patch) | |
tree | 32a4bfe24554a38c6ad30dcb38911796d2acea50 /common/printf.c | |
parent | 60d66714d3b41d69942652650672fd5259815538 (diff) | |
download | chrome-ec-b63e2a87a75dce8941d087c8736c5a35544ab3b0.tar.gz |
printf: Convert %h to %ph
In order to make printf more standard, use %ph. Pass a pointer to
a struct describing the buffer, including its size. Add a convenience
macro so that conversion between the old style and new style is purely
mechanical. The old style of %h cannot be converted directly to %ph as-is
because the C standard doesn't allow flags, precision, or field width on
%p.
Ultimately the goal is to enable compile-time printf format checking.
This gets us one step closer to that.
BUG=chromium:984041
TEST=make -j buildall
BRANCH=None
Cq-Depend:chrome-internal:1559798,chrome-internal:1560598
Change-Id: I9c0ca124a048314c9b62d64bd55b36be55034e0e
Signed-off-by: Evan Green <evgreen@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1730605
Diffstat (limited to 'common/printf.c')
-rw-r--r-- | common/printf.c | 118 |
1 files changed, 73 insertions, 45 deletions
diff --git a/common/printf.c b/common/printf.c index 89ee004452..777c78b471 100644 --- a/common/printf.c +++ b/common/printf.c @@ -5,6 +5,7 @@ /* Printf-like functionality for Chrome EC */ +#include "console.h" #include "printf.h" #include "timer.h" #include "util.h" @@ -18,6 +19,7 @@ static inline int divmod(uint64_t *n, int d) { return uint64divmod(n, d); } + #else /* CONFIG_DEBUG_PRINTF */ /* if we are optimizing for size, remove the 64-bit support */ #define NO_UINT64_SUPPORT @@ -48,7 +50,55 @@ static int hexdigit(int c) #define PF_LEFT BIT(0) /* Left-justify */ #define PF_PADZERO BIT(1) /* Pad with 0's not spaces */ #define PF_SIGN BIT(2) /* Add sign (+) for a positive number */ + +/* Deactivate the PF_64BIT flag is 64-bit support is disabled. */ +#ifdef NO_UINT64_SUPPORT +#define PF_64BIT 0 +#else #define PF_64BIT BIT(3) /* Number is 64-bit */ +#endif + +/* + * Print the buffer as a string of bytes in hex. + * Returns 0 on success or an error on failure. + */ +static int print_hex_buffer(int (*addchar)(void *context, int c), + void *context, const char *vstr, int precision, + int pad_width, int flags) + +{ + + /* + * Divide pad_width instead of multiplying precision to avoid overflow + * error in the condition. The "/2" and "2*" can be optimized by + * the compiler. + */ + + if ((pad_width / 2) >= precision) + pad_width -= 2 * precision; + else + pad_width = 0; + + while (pad_width > 0 && !(flags & PF_LEFT)) { + if (addchar(context, flags & PF_PADZERO ? '0' : ' ')) + return EC_ERROR_OVERFLOW; + pad_width--; + } + + for (; precision; precision--, vstr++) { + if (addchar(context, hexdigit(*vstr >> 4)) || + addchar(context, hexdigit(*vstr))) + return EC_ERROR_OVERFLOW; + } + + while (pad_width > 0 && (flags & PF_LEFT)) { + if (addchar(context, ' ')) + return EC_ERROR_OVERFLOW; + pad_width--; + } + + return EC_SUCCESS; +} int vfnprintf(int (*addchar)(void *context, int c), void *context, const char *format, va_list args) @@ -162,54 +212,14 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, vstr = va_arg(args, char *); if (vstr == NULL) vstr = "(NULL)"; - } else if (c == 'h') { - /* Hex dump output */ - vstr = va_arg(args, char *); - - if (precision < 0) { - /* Hex dump requires precision */ - format = error_str; - continue; - } - - /* - * Divide pad_width instead of multiplying - * precision to avoid overflow error - * in the condition. - * The "/2" and "2*" can be optimized by - * the compiler. - */ - if ((pad_width/2) >= precision) - pad_width -= 2*precision; - else - pad_width = 0; - - while (pad_width > 0 && !(flags & PF_LEFT)) { - if (addchar(context, - flags & PF_PADZERO ? '0' : ' ')) - return EC_ERROR_OVERFLOW; - pad_width--; - } - for (; precision; precision--, vstr++) { - if (addchar(context, hexdigit(*vstr >> 4)) || - addchar(context, hexdigit(*vstr))) - return EC_ERROR_OVERFLOW; - } - while (pad_width > 0 && (flags & PF_LEFT)) { - if (addchar(context, ' ')) - return EC_ERROR_OVERFLOW; - pad_width--; - } - continue; } else { int base = 10; #ifdef NO_UINT64_SUPPORT uint32_t v; - - v = va_arg(args, uint32_t); -#else /* NO_UINT64_SUPPORT */ +#else uint64_t v; +#endif int ptrspec; void *ptrval; @@ -223,7 +233,8 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, ptrspec = *format++; ptrval = va_arg(args, void *); /* %pT - print a timestamp. */ - if (ptrspec == 'T') { + if (ptrspec == 'T' && + !IS_ENABLED(NO_UINT64_SUPPORT)) { flags |= PF_64BIT; /* NULL uses the current time. */ if (ptrval == NULL) @@ -239,8 +250,26 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, v /= 1000; } + } else if (ptrspec == 'h') { + /* %ph - Print a hex byte buffer. */ + struct hex_buffer_params *hexbuf = + ptrval; + int rc; + + rc = print_hex_buffer(addchar, + context, + hexbuf->buffer, + hexbuf->size, + 0, + 0); + + if (rc != EC_SUCCESS) + return rc; + + continue; + } else if (ptrspec == 'P') { - /* Print a raw pointer. */ + /* %pP - Print a raw pointer. */ v = (unsigned long)ptrval; if (sizeof(unsigned long) == sizeof(uint64_t)) @@ -255,7 +284,6 @@ int vfnprintf(int (*addchar)(void *context, int c), void *context, } else { v = va_arg(args, uint32_t); } -#endif switch (c) { #ifdef CONFIG_PRINTF_LEGACY_LI_FORMAT |