From patchwork Fri Oct 6 05:30:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oliver O'Halloran X-Patchwork-Id: 822230 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3y7dX75lTFz9t3m for ; Fri, 6 Oct 2017 16:30:47 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ER7svI2G"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 3y7dX72m3VzDqlP for ; Fri, 6 Oct 2017 16:30:47 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ER7svI2G"; dkim-atps=neutral X-Original-To: skiboot@lists.ozlabs.org Delivered-To: skiboot@lists.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gmail.com (client-ip=2607:f8b0:400e:c05::244; helo=mail-pg0-x244.google.com; envelope-from=oohall@gmail.com; receiver=) Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="ER7svI2G"; dkim-atps=neutral Received: from mail-pg0-x244.google.com (mail-pg0-x244.google.com [IPv6:2607:f8b0:400e:c05::244]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 3y7dX36VTqzDqhg for ; Fri, 6 Oct 2017 16:30:42 +1100 (AEDT) Received: by mail-pg0-x244.google.com with SMTP id o1so16051872pga.4 for ; Thu, 05 Oct 2017 22:30:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=utbrphHDYO+fPw+s2zlYPiX5Mjhmt6zR0D1CaPNImb0=; b=ER7svI2GcWeB34R5PDIw6MQJmqOh+H76aJms4kgLWOgtVEylnscmqC1lhNT7y2HQdw dtwlj3zmsSMDlKSYBW6zJ8gv6MMcyNgURDqyyN/YHVRzTo700++91vLyGpWUlj7h97p9 VRhXFxuZgvnOaUukenzoLAFgWyyU0pRXwX4s4DZNvpe+1sjG+SInKbadQCO8YlHo+dcR jz5WWoCSFnzJMMsfYjGF78JM4iCEVuuJEp/h6gqkaMGlIDlGAkx5O9RmjYtb6JRfwKd6 RyfqkSLI63qVt3e3rNumfmv2qbtB0JER0e7HlG8YJ63Su0OfzNAdZw49uEOJxo8O2cpQ O3Lw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=utbrphHDYO+fPw+s2zlYPiX5Mjhmt6zR0D1CaPNImb0=; b=W52SDRa6ZccE7YUWvS52FWWapWdifCnFus6vluKHB+oSzD7wM0T/yaQyLzyPZr9z/U Hz9MbzoVocTEkEzGv6TxbZVHI7wYLKuWEM+3TcLwWmRzLw4Dy82lgZ8vFFKBmy3/zFqO 893Y7d5Oxh4vWTtoQPH5stiVfJE41dfR6TbFvtOtiNRbSgKUYlYASFxOOXGNw+3yZr2r gTnrxnxmeQ2z5edDbt26pYcbz+3NCCqr+ETLaxYcstfLnLjrrkkdfViI61WzuMeSMD2Y 8AP3a6JqRhScMUA62eAWnkZ3/KChCzkU+phl6rM8baKP2qJW2idPq/ROvqsP2uT5bazd MF8Q== X-Gm-Message-State: AMCzsaUW55BGo20GBDqAMu0ZdMdNsgtehnJxy4Z90RP/n7v6a8orEsn5 KvKqKm+bOSjExhq/LYfawpPnUw== X-Google-Smtp-Source: AOwi7QBdltiheKU5VO5xGdChzB73lDxxFMLxzxAcKbwtS074rMtRSqvSI6oromp0TfgLsA2SQH5hbw== X-Received: by 10.98.55.3 with SMTP id e3mr1042359pfa.215.1507267840393; Thu, 05 Oct 2017 22:30:40 -0700 (PDT) Received: from flat-canetoad.ozlabs.ibm.com ([122.99.82.10]) by smtp.gmail.com with ESMTPSA id z89sm1067276pff.21.2017.10.05.22.30.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 05 Oct 2017 22:30:39 -0700 (PDT) From: Oliver O'Halloran To: skiboot@lists.ozlabs.org Date: Fri, 6 Oct 2017 16:30:28 +1100 Message-Id: <20171006053029.1118-1-oohall@gmail.com> X-Mailer: git-send-email 2.9.5 Subject: [Skiboot] [RFC PATCH 1/2] libc: Add custom printf specifiers X-BeenThere: skiboot@lists.ozlabs.org X-Mailman-Version: 2.1.24 Precedence: list List-Id: Mailing list for skiboot development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: skiboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Skiboot" Add support for %p printf specifiers to our vsnprintf. This is similar to the custom printf specifier support that exists in Linux for dumping the contents of certain data structures. Hopefully this will make writing better logging a bit easier all around. Cc: matthew.brown.dev@gmail.com Signed-off-by: Oliver O'Halloran --- This is based on something Matt wrote. I've reworked it heavily, but it's still pretty similar overall. --- libc/include/stdio.h | 10 +++++++ libc/stdio/vsnprintf.c | 79 +++++++++++++++++++++++++++++++++++++++++++++----- skiboot.lds.S | 6 ++++ 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/libc/include/stdio.h b/libc/include/stdio.h index 5dc4502b0a5d..9adf9586dfb9 100644 --- a/libc/include/stdio.h +++ b/libc/include/stdio.h @@ -69,4 +69,14 @@ int vsscanf(const char *str, const char *format, va_list); int getc(FILE *stream); int getchar(void); +/* non-std io here */ + +struct custom_format { + const char *specifier; + /* writes a formatted version of *value into the printf buffer */ + int (*func) (char **buffer, size_t bufsize, const void *value); +}; + +#define DECLARE_PRINTFMT(name) \ +static const struct custom_format __used __section(".custom_printf") name ##_fmt #endif diff --git a/libc/stdio/vsnprintf.c b/libc/stdio/vsnprintf.c index 410a806cb388..c45f78c0c495 100644 --- a/libc/stdio/vsnprintf.c +++ b/libc/stdio/vsnprintf.c @@ -124,9 +124,43 @@ print_fill(char **buffer, size_t bufsize, char *sizec, unsigned long size, } +extern struct custom_format __custom_printf_start; +extern struct custom_format __custom_printf_end; + +/* + * Check if input string matches or is a substring of the + * custom specifiers. + * + * Return true is strings match / are substrings. + * If strings match exactly, the res pointer is set to the corresponding + * custom format specifier struct. + */ +static const struct custom_format *find_custom_fmt(const char *format) +{ + struct custom_format *fmt; + + for (fmt = &__custom_printf_start; fmt < &__custom_printf_end; fmt++) { + const char *spec = fmt->specifier; + int i = 0; + + /* + * we don't know how long the specifier is, so do a bytewise + * compare. + */ + while (format[i] == spec[i] && format[i] && spec[i]) + i++; + + if (spec[i] == '\0') + return fmt; + } + + return NULL; +} + static int print_format(char **buffer, size_t bufsize, const char *format, void *var) { + const struct custom_format *custom_format; char *start; unsigned int i = 0, length_mod = sizeof(int); unsigned long value = 0; @@ -134,7 +168,6 @@ print_format(char **buffer, size_t bufsize, const char *format, void *var) char *form, sizec[32]; char sign = ' '; bool upper = false; - form = (char *) format; start = *buffer; @@ -144,6 +177,13 @@ print_format(char **buffer, size_t bufsize, const char *format, void *var) form++; } + /* check for custom printfs */ + custom_format = find_custom_fmt(format); + if (custom_format) { + custom_format->func(buffer, bufsize, var); + return (long int) (*buffer - start); + } + while ((*form != '\0') && ((*buffer - start) < bufsize)) { switch(*form) { case 'u': @@ -239,7 +279,6 @@ print_format(char **buffer, size_t bufsize, const char *format, void *var) return (long int) (*buffer - start); } - /* * The vsnprintf function prints a formatted strings into a buffer. * BUG: buffer size checking does not fully work yet @@ -247,6 +286,7 @@ print_format(char **buffer, size_t bufsize, const char *format, void *var) int vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg) { + const struct custom_format *fmt; char *ptr, *bstart; bstart = buffer; @@ -266,20 +306,43 @@ vsnprintf(char *buffer, size_t bufsize, const char *format, va_list arg) { if(*ptr == '%') { char formstr[20]; - int i=0; - + int i = 0; + do { formstr[i] = *ptr; ptr++; i++; - } while(!(*ptr == 'd' || *ptr == 'i' || *ptr == 'u' || *ptr == 'x' || *ptr == 'X' - || *ptr == 'p' || *ptr == 'c' || *ptr == 's' || *ptr == '%' - || *ptr == 'O' || *ptr == 'o' )); + } while(!(*ptr == 'd' || *ptr == 'i' || + *ptr == 'u' || *ptr == 'x' || + *ptr == 'X' || *ptr == 'p' || + *ptr == 's' || *ptr == '%' || + *ptr == 'O' || *ptr == 'o')); + + /* Add last char to buffer*/ formstr[i++] = *ptr; formstr[i] = '\0'; - if(*ptr == '%') { + + /* + * if we terminated on a p then check if the next + * few characters match one of our custom formats + */ + if (*ptr == 'p') + fmt = find_custom_fmt(ptr + 1); + else + fmt = NULL; + + if (*ptr == '%') { *buffer++ = '%'; + } else if (fmt) { + fmt->func(&buffer, + bufsize - (buffer - bstart), + va_arg(arg, void *)); + ptr += strlen(fmt->specifier); } else { + /* + * This changes the format specifier into the + * actual string. + */ print_format(&buffer, bufsize - (buffer - bstart), formstr, va_arg(arg, void *)); diff --git a/skiboot.lds.S b/skiboot.lds.S index 7f71d5cd1b40..ef287c7870e4 100644 --- a/skiboot.lds.S +++ b/skiboot.lds.S @@ -115,6 +115,12 @@ SECTIONS __platforms_end = .; } + .custom_printf : { + __custom_printf_start = .; + KEEP(*(.custom_printf)) + __custom_printf_end = .; + } + /* Do I need to keep these ? */ .dynsym : { *(.dynsym) } .dynstr : { *(.dynstr) }