%pS is a kernel extension for printing the name and offset of a symbol.
This is useful for function pointers/callbacks especially. When symbol
lookup is enabled this can make for much easier debugging of driver ops
and other places.

Signed-off-by: Casey Connolly <casey.conno...@linaro.org>
---
 lib/vsprintf.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 
c7340a047b2e9385b9366d90e1363c99882db398..11cc3e6c0e9abd0440b76219b0d56056345ddd7f
 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -24,8 +24,9 @@
 #include <linux/ctype.h>
 #include <linux/err.h>
 #include <linux/types.h>
 #include <linux/string.h>
+#include <symbols.h>
 
 /* we use this so that we can do without the ctype library */
 #define is_digit(c)    ((c) >= '0' && (c) <= '9')
 
@@ -437,8 +438,25 @@ static char *uuid_string(char *buf, char *end, u8 *addr, 
int field_width,
        return string(buf, end, uuid, field_width, precision, flags);
 }
 #endif
 
+/*
+ * Given an address, print the symbol name and offset to the address.
+ */
+static char *ptr_symbol(phys_addr_t addr, char *buf, char *end,
+                       int field_width, int precision, int flags)
+{
+       unsigned long offset;
+       char namebuf[KSYM_NAME_LEN + 1] = { 0 };
+
+       symbol_lookup(addr, NULL, &offset, namebuf);
+
+       strlcat(namebuf, "+0x", KSYM_NAME_LEN + 1);
+
+       buf = string(buf, end, namebuf, field_width, precision, flags);
+       return number(buf, end, offset, 16, field_width, precision, flags);
+}
+
 /*
  * Show a '%p' thing.  A kernel extension is that the '%p' is followed
  * by an extra set of alphanumeric characters that are extended format
  * specifiers.
@@ -450,8 +468,9 @@ static char *uuid_string(char *buf, char *end, u8 *addr, 
int field_width,
  * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated
  *       decimal for v4 and colon separated network-order 16 bit hex for v6)
  * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
  *       currently the same
+ * - 'S' for a symbol address, it prints the symbol name and offset
  */
 static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
                int field_width, int precision, int flags)
 {
@@ -502,8 +521,14 @@ static char *pointer(const char *fmt, char *buf, char 
*end, void *ptr,
                        return ip4_addr_string(buf, end, ptr, field_width,
                                               precision, flags);
                flags &= ~SPECIAL;
                break;
+       case 'S':
+               if (IS_ENABLED(CONFIG_SYMBOL_LOOKUP))
+                       return ptr_symbol((phys_addr_t)ptr, buf, end,
+                                         field_width, precision, flags);
+               flags |= SPECIAL;
+               break;
 #ifdef CONFIG_LIB_UUID
        case 'U':
                return uuid_string(buf, end, ptr, field_width, precision,
                                   flags, fmt);

-- 
2.50.0

Reply via email to