From: Kent Overstreet <kent.overstreet@gmail.com>
To: linux-kernel@vger.kernel.org, linux-mm@kvack.org, pmladek@suse.com
Cc: Kent Overstreet <kent.overstreet@gmail.com>,
rostedt@goodmis.org, enozhatsky@chromium.org,
linux@rasmusvillemoes.dk, willy@infradead.org
Subject: [PATCH v4 05/34] vsprintf: %pf(%p)
Date: Sun, 19 Jun 2022 20:42:04 -0400 [thread overview]
Message-ID: <20220620004233.3805-6-kent.overstreet@gmail.com> (raw)
In-Reply-To: <20220620004233.3805-1-kent.overstreet@gmail.com>
This implements two new format strings: both do the same thing, one more
compatible with current gcc format string checking, the other that we'd
like to standardize:
%pf(%p) - more compatible
%(%p) - more prettier
Both can take variable numbers of arguments, i.e. %(%p,%p,%p).
They're used to indicate that snprintf or pr_buf should interpret the
next argument as a pretty-printer function to call, and subsequent
arguments within the parentheses should be passed to the pretty-printer.
A pretty printer takes as its first argument a printbuf, and then zero
or more pointer arguments - integer arguments are not (currently) supported.
Example usage:
static void foo_to_text(struct printbuf *out, struct foo *foo)
{
pr_buf(out, "bar=%u baz=%u", foo->bar, foo->baz);
}
printf("%(%p)", foo_to_text, foo);
The goal is to replace most of our %p format extensions with this
interface, and to move pretty-printers out of the core vsprintf.c code -
this will get us better organization and better discoverability (you'll
be able to cscope to pretty printer calls!), as well as eliminate a lot
of dispatch code in vsprintf.c.
Currently, we can only call pretty printers with pointer arguments. This
could be changed to also allow at least integer arguments in the future
by using libffi.
Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org>
---
Documentation/core-api/printk-formats.rst | 22 ++++++
lib/test_printf.c | 27 ++++++++
lib/vsprintf.c | 83 ++++++++++++++++++++++-
3 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst
index 5e89497ba3..8fc0b62af1 100644
--- a/Documentation/core-api/printk-formats.rst
+++ b/Documentation/core-api/printk-formats.rst
@@ -625,6 +625,28 @@ Examples::
%p4cc Y10 little-endian (0x20303159)
%p4cc NV12 big-endian (0xb231564e)
+Calling a pretty printer function
+---------------------------------
+
+::
+
+ %pf(%p) pretty printer function taking one argument
+ %pf(%p,%p) pretty printer function taking two arguments
+
+For calling generic pretty printers. A pretty printer is a function that takes
+as its first argument a pointer to a printbuf, and then zero or more additional
+pointer arguments. For example:
+
+ void foo_to_text(struct printbuf *out, struct foo *foo)
+ {
+ pr_buf(out, "bar=%u baz=%u", foo->bar, foo->baz);
+ }
+
+ printf("%pf(%p)", foo_to_text, foo);
+
+Note that a pretty-printer may not sleep, if called from printk(). If called
+from pr_buf() or sprintf() there are no such restrictions.
+
Thanks
======
diff --git a/lib/test_printf.c b/lib/test_printf.c
index 07309c45f3..e3de52da91 100644
--- a/lib/test_printf.c
+++ b/lib/test_printf.c
@@ -9,6 +9,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/printk.h>
+#include <linux/printbuf.h>
#include <linux/random.h>
#include <linux/rtc.h>
#include <linux/slab.h>
@@ -783,6 +784,31 @@ test_pointer(void)
fourcc_pointer();
}
+static void printf_test_fn_0(struct printbuf *out)
+{
+ prt_str(out, "0");
+}
+
+static void printf_test_fn_1(struct printbuf *out, void *p)
+{
+ int *i = p;
+
+ prt_printf(out, "%i", *i);
+}
+
+static void __init
+test_fn(void)
+{
+ int i = 1;
+
+ test("0", "%pf()", printf_test_fn_0);
+ test("1", "%pf(%p)", printf_test_fn_1, &i);
+ /*
+ * Not tested, so we don't fail the build with -Werror:
+ */
+ //test("1", "%(%p)", printf_test_fn, &i);
+}
+
static void __init selftest(void)
{
alloced_buffer = kmalloc(BUF_SIZE + 2*PAD_SIZE, GFP_KERNEL);
@@ -794,6 +820,7 @@ static void __init selftest(void)
test_number();
test_string();
test_pointer();
+ test_fn();
kfree(alloced_buffer);
}
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 7b24714674..5afa74dda5 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -436,7 +436,8 @@ enum format_type {
FORMAT_TYPE_UINT,
FORMAT_TYPE_INT,
FORMAT_TYPE_SIZE_T,
- FORMAT_TYPE_PTRDIFF
+ FORMAT_TYPE_PTRDIFF,
+ FORMAT_TYPE_FN,
};
struct printf_spec {
@@ -2520,7 +2521,16 @@ int format_decode(const char *fmt, struct printf_spec *spec)
return ++fmt - start;
case 'p':
- spec->type = FORMAT_TYPE_PTR;
+ fmt++;
+ if (fmt[0] == 'f' &&
+ fmt[1] == '(') {
+ fmt += 2;
+ spec->type = FORMAT_TYPE_FN;
+ } else
+ spec->type = FORMAT_TYPE_PTR;
+ return fmt - start;
+ case '(':
+ spec->type = FORMAT_TYPE_FN;
return ++fmt - start;
case '%':
@@ -2602,6 +2612,49 @@ set_precision(struct printf_spec *spec, int prec)
}
}
+static void call_prt_fn(struct printbuf *out, void *fn, void **fn_args, unsigned nr_args)
+{
+ typedef void (*printf_fn_0)(struct printbuf *);
+ typedef void (*printf_fn_1)(struct printbuf *, void *);
+ typedef void (*printf_fn_2)(struct printbuf *, void *, void *);
+ typedef void (*printf_fn_3)(struct printbuf *, void *, void *, void *);
+ typedef void (*printf_fn_4)(struct printbuf *, void *, void *, void *, void *);
+ typedef void (*printf_fn_5)(struct printbuf *, void *, void *, void *, void *, void *);
+ typedef void (*printf_fn_6)(struct printbuf *, void *, void *, void *, void *, void *, void *);
+ typedef void (*printf_fn_7)(struct printbuf *, void *, void *, void *, void *, void *, void *, void *);
+ typedef void (*printf_fn_8)(struct printbuf *, void *, void *, void *, void *, void *, void *, void *, void *);
+
+ switch (nr_args) {
+ case 0:
+ ((printf_fn_0)fn)(out);
+ break;
+ case 1:
+ ((printf_fn_1)fn)(out, fn_args[0]);
+ break;
+ case 2:
+ ((printf_fn_2)fn)(out, fn_args[0], fn_args[1]);
+ break;
+ case 3:
+ ((printf_fn_3)fn)(out, fn_args[0], fn_args[1], fn_args[2]);
+ break;
+ case 4:
+ ((printf_fn_4)fn)(out, fn_args[0], fn_args[1], fn_args[2], fn_args[3]);
+ break;
+ case 5:
+ ((printf_fn_5)fn)(out, fn_args[0], fn_args[1], fn_args[2], fn_args[3], fn_args[4]);
+ break;
+ case 6:
+ ((printf_fn_6)fn)(out, fn_args[0], fn_args[1], fn_args[2], fn_args[3], fn_args[4], fn_args[5]);
+ break;
+ case 7:
+ ((printf_fn_7)fn)(out, fn_args[0], fn_args[1], fn_args[2], fn_args[3], fn_args[4], fn_args[5], fn_args[6]);
+ break;
+ case 8:
+ ((printf_fn_8)fn)(out, fn_args[0], fn_args[1], fn_args[2], fn_args[3], fn_args[4], fn_args[5], fn_args[6], fn_args[7]);
+ break;
+ }
+}
+
/**
* prt_vprintf - Format a string, outputting to a printbuf
* @out: The printbuf to output to
@@ -2665,6 +2718,32 @@ void prt_vprintf(struct printbuf *out, const char *fmt, va_list args)
fmt++;
break;
+ case FORMAT_TYPE_FN: {
+ unsigned nr_args = 0;
+ void *fn_args[8];
+ void *fn = va_arg(args, void *);
+
+ while (*fmt != ')') {
+ if (nr_args) {
+ if (fmt[0] != ',')
+ goto out;
+ fmt++;
+ }
+
+ if (fmt[0] != '%' || fmt[1] != 'p')
+ goto out;
+ fmt += 2;
+
+ if (WARN_ON_ONCE(nr_args == ARRAY_SIZE(fn_args)))
+ goto out;
+ fn_args[nr_args++] = va_arg(args, void *);
+ }
+
+ call_prt_fn(out, fn, fn_args, nr_args);
+ fmt++; /* past trailing ) */
+ break;
+ }
+
case FORMAT_TYPE_PERCENT_CHAR:
__prt_char(out, '%');
break;
--
2.36.1
next prev parent reply other threads:[~2022-06-20 0:42 UTC|newest]
Thread overview: 85+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-20 0:41 [PATCH v4 00/34] Printbufs - new data structure for building strings Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 01/34] lib/printbuf: New data structure for printing strings Kent Overstreet
2022-06-20 4:44 ` David Laight
2022-06-20 15:30 ` Kent Overstreet
2022-06-20 15:53 ` David Laight
2022-06-20 16:14 ` Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 02/34] lib/string_helpers: Convert string_escape_mem() to printbuf Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 03/34] vsprintf: Convert " Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 04/34] lib/hexdump: " Kent Overstreet
2022-06-20 0:42 ` Kent Overstreet [this message]
2022-06-21 7:04 ` [PATCH v4 05/34] vsprintf: %pf(%p) Rasmus Villemoes
2022-06-21 7:51 ` Kent Overstreet
2022-06-21 8:47 ` Rasmus Villemoes
2022-06-21 11:11 ` David Laight
2022-06-20 0:42 ` [PATCH v4 06/34] lib/string_helpers: string_get_size() now returns characters wrote Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 07/34] lib/printbuf: Heap allocation Kent Overstreet
2022-06-21 7:58 ` Rasmus Villemoes
2022-06-20 0:42 ` [PATCH v4 08/34] lib/printbuf: Tabstops, indenting Kent Overstreet
2022-06-21 8:14 ` Rasmus Villemoes
2022-06-20 0:42 ` [PATCH v4 09/34] lib/printbuf: Unit specifiers Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 10/34] lib/pretty-printers: prt_string_option(), prt_bitflags() Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 11/34] vsprintf: Improve number() Kent Overstreet
2022-06-21 8:33 ` Rasmus Villemoes
2022-06-20 0:42 ` [PATCH v4 12/34] vsprintf: prt_u64_minwidth(), prt_u64() Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 13/34] test_printf: Drop requirement that sprintf not write past nul Kent Overstreet
2022-06-21 7:19 ` Rasmus Villemoes
2022-06-21 7:52 ` Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 14/34] vsprintf: Start consolidating printf_spec handling Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 15/34] vsprintf: Refactor resource_string() Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 16/34] vsprintf: Refactor fourcc_string() Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 17/34] vsprintf: Refactor ip_addr_string() Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 18/34] vsprintf: Refactor mac_address_string() Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 19/34] vsprintf: time_and_date() no longer takes printf_spec Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 20/34] vsprintf: flags_string() " Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 21/34] vsprintf: Refactor device_node_string, fwnode_string Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 22/34] vsprintf: Refactor hex_string, bitmap_string_list, bitmap_string Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 23/34] Input/joystick/analog: Convert from seq_buf -> printbuf Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 24/34] mm/memcontrol.c: Convert to printbuf Kent Overstreet
2022-06-20 11:37 ` Michal Hocko
2022-06-20 15:13 ` Kent Overstreet
2022-06-20 15:52 ` Michal Hocko
2022-06-20 0:42 ` [PATCH v4 25/34] clk: tegra: bpmp: " Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 26/34] tools/testing/nvdimm: " Kent Overstreet
2022-06-24 19:32 ` Dan Williams
2022-06-24 23:42 ` Santosh Sivaraj
2022-07-01 6:32 ` Shivaprasad G Bhat
2022-06-20 0:42 ` [PATCH v4 27/34] powerpc: " Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 28/34] x86/resctrl: " Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 29/34] PCI/P2PDMA: " Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 30/34] tracing: trace_events_synth: " Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 31/34] d_path: prt_path() Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 32/34] ACPI/APEI: Add missing include Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 33/34] tracing: Convert to printbuf Kent Overstreet
2022-06-20 0:42 ` [PATCH v4 34/34] Delete seq_buf Kent Overstreet
2022-06-20 4:19 ` [PATCH v4 00/34] Printbufs - new data structure for building strings David Laight
2022-06-20 4:54 ` Matthew Wilcox
2022-06-20 8:00 ` David Laight
2022-06-20 15:07 ` Kent Overstreet
2022-06-20 15:21 ` David Laight
2022-06-21 0:38 ` Joe Perches
2022-06-21 0:57 ` Kent Overstreet
2022-06-21 1:26 ` Joe Perches
2022-06-21 2:10 ` Joe Perches
2022-06-26 19:53 ` [RFC[ Alloc in vsprintf Joe Perches
2022-06-26 20:06 ` Kent Overstreet
2022-06-26 20:13 ` Joe Perches
2022-06-26 20:19 ` Linus Torvalds
2022-06-26 20:39 ` Joe Perches
2022-06-26 20:51 ` Kent Overstreet
2022-06-26 21:02 ` Joe Perches
2022-06-26 21:10 ` Kent Overstreet
2022-06-26 20:54 ` Linus Torvalds
2022-06-27 8:25 ` David Laight
2022-06-28 2:56 ` Kent Overstreet
2022-06-21 2:31 ` [PATCH v4 00/34] Printbufs - new data structure for building strings Kent Overstreet
2022-06-21 3:11 ` Kent Overstreet
2022-06-21 6:11 ` Rasmus Villemoes
2022-06-21 8:01 ` Kent Overstreet
2022-07-19 23:15 ` Steven Rostedt
2022-07-19 23:43 ` Kent Overstreet
2022-07-20 0:05 ` Steven Rostedt
2022-07-20 0:17 ` Kent Overstreet
2022-07-20 1:11 ` Steven Rostedt
2022-07-20 1:31 ` Kent Overstreet
2022-07-20 1:37 ` Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220620004233.3805-6-kent.overstreet@gmail.com \
--to=kent.overstreet@gmail.com \
--cc=enozhatsky@chromium.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux@rasmusvillemoes.dk \
--cc=pmladek@suse.com \
--cc=rostedt@goodmis.org \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox