+ printf-add-support-for-printing-symbolic-error-codes.patch added to -mm tree

From: akpm
Date: Sat Oct 05 2019 - 17:52:11 EST



The patch titled
Subject: vsprintf: add support for printing symbolic error codes
has been added to the -mm tree. Its filename is
printf-add-support-for-printing-symbolic-error-codes.patch

This patch should soon appear at
http://ozlabs.org/~akpm/mmots/broken-out/printf-add-support-for-printing-symbolic-error-codes.patch
and later at
http://ozlabs.org/~akpm/mmotm/broken-out/printf-add-support-for-printing-symbolic-error-codes.patch

Before you just go and hit "reply", please:
a) Consider who else should be cc'ed
b) Prefer to cc a suitable mailing list as well
c) Ideally: find the original patch on the mailing list and do a
reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/process/submit-checklist.rst when testing your code ***

The -mm tree is included into linux-next and is updated
there every 3-4 working days

------------------------------------------------------
From: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx>
Subject: vsprintf: add support for printing symbolic error codes

It has been suggested several times to extend vsnprintf() to be able to
convert the numeric value of ENOSPC to print "ENOSPC". This is yet
another attempt. Rather than adding another %p extension, simply teach
plain %p to convert ERR_PTRs. While the primary use case is

if (IS_ERR(foo)) {
pr_err("Sorry, can't do that: %p
", foo);
return PTR_ERR(foo);
}

It is also more helpful to get a symbolic error code (or, worst case, a
decimal number) in case an ERR_PTR is accidentally passed to some
%p<something>, rather than the (efault) that check_pointer() would result
in.

With my embedded hat on, I've made it possible to remove this.

I've tested that the #ifdeffery in errcode.c is sufficient to make this
compile on arm, arm64, mips, powerpc, s390, x86 - I'm sure the 0day bot
will tell me which ones I've missed.

The symbols to include have been found by massaging the output of

find arch include -iname 'errno*.h' | xargs grep -E 'define\s*E'

In the cases where some common aliasing exists (e.g. EAGAIN=EWOULDBLOCK
on all platforms, EDEADLOCK=EDEADLK on most), I've moved the more popular
one (in terms of 'git grep -w Efoo | wc) to the bottom so that one takes
precedence.

Link: http://lkml.kernel.org/r/20190917065959.5560-1-linux@xxxxxxxxxxxxxxxxxx
Signed-off-by: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx>
Acked-by: Uwe Kleine-KÃnig <uwe@xxxxxxxxxxxxxxxxx>
Cc: Jonathan Corbet <corbet@xxxxxxx>
Cc: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx>
Cc: Andy Shevchenko <andy.shevchenko@xxxxxxxxx>
Cc: Joe Perches <joe@xxxxxxxxxxx>
Cc: Petr Mladek <pmladek@xxxxxxxx>
Cc: Sergey Senozhatsky <sergey.senozhatsky.work@xxxxxxxxx>
Cc: Jani Nikula <jani.nikula@xxxxxxxxxxxxxxx>
Cc: Linux Kernel Mailing List <linux-kernel@xxxxxxxxxxxxxxx>
Cc: Pavel Machek <pavel@xxxxxx>
Cc: Mike Kravetz <mike.kravetz@xxxxxxxxxx>
Cc: Hugh Dickins <hughd@xxxxxxxxxx>
Cc: Andrea Arcangeli <aarcange@xxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
---

Documentation/core-api/printk-formats.rst | 8
include/linux/errcode.h | 16 +
lib/Kconfig.debug | 8
lib/Makefile | 1
lib/errcode.c | 212 ++++++++++++++++++++
lib/test_printf.c | 14 +
lib/vsprintf.c | 26 ++
7 files changed, 285 insertions(+)

--- a/Documentation/core-api/printk-formats.rst~printf-add-support-for-printing-symbolic-error-codes
+++ a/Documentation/core-api/printk-formats.rst
@@ -66,6 +66,14 @@ might be printed instead of the unreacha
(efault) data on invalid address
(einval) invalid data on a valid address

+Error pointers, i.e. pointers for which IS_ERR() is true, are handled
+as follows: If CONFIG_SYMBOLIC_ERRCODE is set, an appropriate symbolic
+constant is printed. For example, '"%p", PTR_ERR(-ENOSPC)' results in
+"ENOSPC", while '"%p", PTR_ERR(-EWOULDBLOCK)' results in "EAGAIN"
+(since EAGAIN == EWOULDBLOCK, and the former is the most common). If
+CONFIG_SYMBOLIC_ERRCODE is not set, ERR_PTRs are printed as their
+decimal representation ("-28" and "-11" for the two examples).
+
Plain Pointers
--------------

--- /dev/null
+++ a/include/linux/errcode.h
@@ -0,0 +1,16 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_ERRCODE_H
+#define _LINUX_ERRCODE_H
+
+#include <linux/stddef.h>
+
+#ifdef CONFIG_SYMBOLIC_ERRCODE
+const char *errcode(int err);
+#else
+static inline const char *errcode(int err)
+{
+ return NULL;
+}
+#endif
+
+#endif /* _LINUX_ERRCODE_H */
--- /dev/null
+++ a/lib/errcode.c
@@ -0,0 +1,212 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <linux/build_bug.h>
+#include <linux/errno.h>
+#include <linux/errcode.h>
+#include <linux/kernel.h>
+
+/*
+ * Ensure these tables to not accidentally become gigantic if some
+ * huge errno makes it in. On most architectures, the first table will
+ * only have about 140 entries, but mips and parisc have more sparsely
+ * allocated errnos (with EHWPOISON = 257 on parisc, and EDQUOT = 1133
+ * on mips), so this wastes a bit of space on those - though we
+ * special case the EDQUOT case.
+ */
+#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = #err
+static const char *codes_0[] = {
+ E(E2BIG),
+ E(EACCES),
+ E(EADDRINUSE),
+ E(EADDRNOTAVAIL),
+ E(EADV),
+ E(EAFNOSUPPORT),
+ E(EALREADY),
+ E(EBADE),
+ E(EBADF),
+ E(EBADFD),
+ E(EBADMSG),
+ E(EBADR),
+ E(EBADRQC),
+ E(EBADSLT),
+ E(EBFONT),
+ E(EBUSY),
+#ifdef ECANCELLED
+ E(ECANCELLED),
+#endif
+ E(ECHILD),
+ E(ECHRNG),
+ E(ECOMM),
+ E(ECONNABORTED),
+ E(ECONNRESET),
+ E(EDEADLOCK),
+ E(EDESTADDRREQ),
+ E(EDOM),
+ E(EDOTDOT),
+#ifndef CONFIG_MIPS
+ E(EDQUOT),
+#endif
+ E(EEXIST),
+ E(EFAULT),
+ E(EFBIG),
+ E(EHOSTDOWN),
+ E(EHOSTUNREACH),
+ E(EHWPOISON),
+ E(EIDRM),
+ E(EILSEQ),
+#ifdef EINIT
+ E(EINIT),
+#endif
+ E(EINPROGRESS),
+ E(EINTR),
+ E(EINVAL),
+ E(EIO),
+ E(EISCONN),
+ E(EISDIR),
+ E(EISNAM),
+ E(EKEYEXPIRED),
+ E(EKEYREJECTED),
+ E(EKEYREVOKED),
+ E(EL2HLT),
+ E(EL2NSYNC),
+ E(EL3HLT),
+ E(EL3RST),
+ E(ELIBACC),
+ E(ELIBBAD),
+ E(ELIBEXEC),
+ E(ELIBMAX),
+ E(ELIBSCN),
+ E(ELNRNG),
+ E(ELOOP),
+ E(EMEDIUMTYPE),
+ E(EMFILE),
+ E(EMLINK),
+ E(EMSGSIZE),
+ E(EMULTIHOP),
+ E(ENAMETOOLONG),
+ E(ENAVAIL),
+ E(ENETDOWN),
+ E(ENETRESET),
+ E(ENETUNREACH),
+ E(ENFILE),
+ E(ENOANO),
+ E(ENOBUFS),
+ E(ENOCSI),
+ E(ENODATA),
+ E(ENODEV),
+ E(ENOENT),
+ E(ENOEXEC),
+ E(ENOKEY),
+ E(ENOLCK),
+ E(ENOLINK),
+ E(ENOMEDIUM),
+ E(ENOMEM),
+ E(ENOMSG),
+ E(ENONET),
+ E(ENOPKG),
+ E(ENOPROTOOPT),
+ E(ENOSPC),
+ E(ENOSR),
+ E(ENOSTR),
+#ifdef ENOSYM
+ E(ENOSYM),
+#endif
+ E(ENOSYS),
+ E(ENOTBLK),
+ E(ENOTCONN),
+ E(ENOTDIR),
+ E(ENOTEMPTY),
+ E(ENOTNAM),
+ E(ENOTRECOVERABLE),
+ E(ENOTSOCK),
+ E(ENOTTY),
+ E(ENOTUNIQ),
+ E(ENXIO),
+ E(EOPNOTSUPP),
+ E(EOVERFLOW),
+ E(EOWNERDEAD),
+ E(EPERM),
+ E(EPFNOSUPPORT),
+ E(EPIPE),
+#ifdef EPROCLIM
+ E(EPROCLIM),
+#endif
+ E(EPROTO),
+ E(EPROTONOSUPPORT),
+ E(EPROTOTYPE),
+ E(ERANGE),
+ E(EREMCHG),
+#ifdef EREMDEV
+ E(EREMDEV),
+#endif
+ E(EREMOTE),
+ E(EREMOTEIO),
+#ifdef EREMOTERELEASE
+ E(EREMOTERELEASE),
+#endif
+ E(ERESTART),
+ E(ERFKILL),
+ E(EROFS),
+#ifdef ERREMOTE
+ E(ERREMOTE),
+#endif
+ E(ESHUTDOWN),
+ E(ESOCKTNOSUPPORT),
+ E(ESPIPE),
+ E(ESRCH),
+ E(ESRMNT),
+ E(ESTALE),
+ E(ESTRPIPE),
+ E(ETIME),
+ E(ETIMEDOUT),
+ E(ETOOMANYREFS),
+ E(ETXTBSY),
+ E(EUCLEAN),
+ E(EUNATCH),
+ E(EUSERS),
+ E(EXDEV),
+ E(EXFULL),
+
+ E(ECANCELED),
+ E(EAGAIN), /* EWOULDBLOCK */
+ E(ECONNREFUSED), /* EREFUSED */
+ E(EDEADLK), /* EDEADLK */
+};
+#undef E
+
+#define E(err) [err - 512 + BUILD_BUG_ON_ZERO(err < 512 || err > 550)] = #err
+static const char *codes_512[] = {
+ E(ERESTARTSYS),
+ E(ERESTARTNOINTR),
+ E(ERESTARTNOHAND),
+ E(ENOIOCTLCMD),
+ E(ERESTART_RESTARTBLOCK),
+ E(EPROBE_DEFER),
+ E(EOPENSTALE),
+ E(ENOPARAM),
+
+ E(EBADHANDLE),
+ E(ENOTSYNC),
+ E(EBADCOOKIE),
+ E(ENOTSUPP),
+ E(ETOOSMALL),
+ E(ESERVERFAULT),
+ E(EBADTYPE),
+ E(EJUKEBOX),
+ E(EIOCBQUEUED),
+ E(ERECALLCONFLICT),
+};
+#undef E
+
+const char *errcode(int err)
+{
+ if (err <= 0)
+ return NULL;
+ if (err < ARRAY_SIZE(codes_0))
+ return codes_0[err];
+ if (err >= 512 && err - 512 < ARRAY_SIZE(codes_512))
+ return codes_512[err - 512];
+ /* But why? */
+ if (IS_ENABLED(CONFIG_MIPS) && err == EDQUOT) /* 1133 */
+ return "EDQUOT";
+ return NULL;
+}
--- a/lib/Kconfig.debug~printf-add-support-for-printing-symbolic-error-codes
+++ a/lib/Kconfig.debug
@@ -164,6 +164,14 @@ config DYNAMIC_DEBUG
See Documentation/admin-guide/dynamic-debug-howto.rst for additional
information.

+config SYMBOLIC_ERRCODE
+ bool "Support symbolic error codes in printf"
+ help
+ If you say Y here, the kernel's printf implementation will
+ be able to print symbolic errors such as ENOSPC instead of
+ the number 28. It makes the kernel image slightly larger
+ (about 3KB), but can make the kernel logs easier to read.
+
endmenu # "printk and dmesg options"

menu "Compile-time checks and compiler options"
--- a/lib/Makefile~printf-add-support-for-printing-symbolic-error-codes
+++ a/lib/Makefile
@@ -181,6 +181,7 @@ lib-$(CONFIG_GENERIC_BUG) += bug.o
obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o

obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o
+obj-$(CONFIG_SYMBOLIC_ERRCODE) += errcode.o

obj-$(CONFIG_NLATTR) += nlattr.o

--- a/lib/test_printf.c~printf-add-support-for-printing-symbolic-error-codes
+++ a/lib/test_printf.c
@@ -212,6 +212,7 @@ test_string(void)
#define PTR_STR "ffff0123456789ab"
#define PTR_VAL_NO_CRNG "(____ptrval____)"
#define ZEROS "00000000" /* hex 32 zero bits */
+#define FFFFS "ffffffff"

static int __init
plain_format(void)
@@ -243,6 +244,7 @@ plain_format(void)
#define PTR_STR "456789ab"
#define PTR_VAL_NO_CRNG "(ptrval)"
#define ZEROS ""
+#define FFFFS ""

static int __init
plain_format(void)
@@ -594,6 +596,17 @@ flags(void)
}

static void __init
+errptr(void)
+{
+ test("-1234", "%p", ERR_PTR(-1234));
+ test(FFFFS "ffffffff " FFFFS "ffffff00", "%px %px", ERR_PTR(-1), ERR_PTR(-256));
+#ifdef CONFIG_SYMBOLIC_ERRCODE
+ test("EIO EINVAL ENOSPC", "%p %p %p", ERR_PTR(-EIO), ERR_PTR(-EINVAL), ERR_PTR(-ENOSPC));
+ test("EAGAIN EAGAIN", "%p %p", ERR_PTR(-EAGAIN), ERR_PTR(-EWOULDBLOCK));
+#endif
+}
+
+static void __init
test_pointer(void)
{
plain();
@@ -615,6 +628,7 @@ test_pointer(void)
bitmap();
netdev_features();
flags();
+ errptr();
}

static void __init selftest(void)
--- a/lib/vsprintf.c~printf-add-support-for-printing-symbolic-error-codes
+++ a/lib/vsprintf.c
@@ -21,6 +21,7 @@
#include <linux/build_bug.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
+#include <linux/errcode.h>
#include <linux/module.h> /* for KSYM_SYMBOL_LEN */
#include <linux/types.h>
#include <linux/string.h>
@@ -2120,6 +2121,31 @@ static noinline_for_stack
char *pointer(const char *fmt, char *buf, char *end, void *ptr,
struct printf_spec spec)
{
+ /*
+ * If it's an ERR_PTR, try to print its symbolic
+ * representation, except for %px, where the user explicitly
+ * wanted the pointer formatted as a hex value.
+ */
+ if (IS_ERR(ptr) && *fmt != 'x') {
+ int err = PTR_ERR(ptr);
+ const char *sym = errcode(-err);
+ if (sym)
+ return string_nocheck(buf, end, sym, spec);
+ /*
+ * Funky, somebody passed ERR_PTR(-1234) or some other
+ * non-existing Efoo - or more likely
+ * CONFIG_SYMBOLIC_ERRCODE=n. None of the
+ * %p<something> extensions can make any sense of an
+ * ERR_PTR(), and if this was just a plain %p, the
+ * user is still better off getting the decimal
+ * representation rather than the hash value that
+ * ptr_to_id() would generate.
+ */
+ spec.flags |= SIGN;
+ spec.base = 10;
+ return number(buf, end, err, spec);
+ }
+
switch (*fmt) {
case 'F':
case 'f':
_

Patches currently in -mm which might be from linux@xxxxxxxxxxxxxxxxxx are

printf-add-support-for-printing-symbolic-error-codes.patch