Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

printf: add support for printing symbolic error names

It has been suggested several times to extend vsnprintf() to be able
to convert the numeric value of ENOSPC to print "ENOSPC". This
implements that as a %p extension: With %pe, one can do

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

instead of what is seen in quite a few places in the kernel:

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

If the value passed to %pe is an ERR_PTR, but the library function
errname() added here doesn't know about the value, the value is simply
printed in decimal. If the value passed to %pe is not an ERR_PTR, we
treat it as an ordinary %p and thus print the hashed value (passing
non-ERR_PTR values to %pe indicates a bug in the caller, but we can't
do much about that).

With my embedded hat on, and because it's not very invasive to do,
I've made it possible to remove this. The errname() function and
associated lookup tables take up about 3K. For most, that's probably
quite acceptable and a price worth paying for more readable
dmesg (once this starts getting used), while for those that disable
printk() it's of very little use - I don't see a
procfs/sysfs/seq_printf() file reasonably making use of this - and
they clearly want to squeeze vmlinux as much as possible. Hence the
default y if PRINTK.

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/20191015190706.15989-1-linux@rasmusvillemoes.dk
To: "Jonathan Corbet" <corbet@lwn.net>
To: linux-kernel@vger.kernel.org
Cc: "Andy Shevchenko" <andy.shevchenko@gmail.com>
Cc: "Andrew Morton" <akpm@linux-foundation.org>
Cc: "Joe Perches" <joe@perches.com>
Cc: linux-doc@vger.kernel.org
Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk>
Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org>
Reviewed-by: Petr Mladek <pmladek@suse.com>
[andy.shevchenko@gmail.com: use abs()]
Acked-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>

authored by

Rasmus Villemoes and committed by
Petr Mladek
57f5677e ae88de56

+309
+12
Documentation/core-api/printk-formats.rst
··· 79 79 the first 32 bits are zeroed. The kernel will print ``(ptrval)`` until it 80 80 gathers enough entropy. If you *really* want the address see %px below. 81 81 82 + Error Pointers 83 + -------------- 84 + 85 + :: 86 + 87 + %pe -ENOSPC 88 + 89 + For printing error pointers (i.e. a pointer for which IS_ERR() is true) 90 + as a symbolic error name. Error values for which no symbolic name is 91 + known are printed in decimal, while a non-ERR_PTR passed as the 92 + argument to %pe gets treated as ordinary %p. 93 + 82 94 Symbols/Function Pointers 83 95 ------------------------- 84 96
+16
include/linux/errname.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _LINUX_ERRNAME_H 3 + #define _LINUX_ERRNAME_H 4 + 5 + #include <linux/stddef.h> 6 + 7 + #ifdef CONFIG_SYMBOLIC_ERRNAME 8 + const char *errname(int err); 9 + #else 10 + static inline const char *errname(int err) 11 + { 12 + return NULL; 13 + } 14 + #endif 15 + 16 + #endif /* _LINUX_ERRNAME_H */
+9
lib/Kconfig.debug
··· 164 164 See Documentation/admin-guide/dynamic-debug-howto.rst for additional 165 165 information. 166 166 167 + config SYMBOLIC_ERRNAME 168 + bool "Support symbolic error names in printf" 169 + default y if PRINTK 170 + help 171 + If you say Y here, the kernel's printf implementation will 172 + be able to print symbolic error names such as ENOSPC instead 173 + of the number 28. It makes the kernel image slightly larger 174 + (about 3KB), but can make the kernel logs easier to read. 175 + 167 176 endmenu # "printk and dmesg options" 168 177 169 178 menu "Compile-time checks and compiler options"
+1
lib/Makefile
··· 183 183 obj-$(CONFIG_HAVE_ARCH_TRACEHOOK) += syscall.o 184 184 185 185 obj-$(CONFIG_DYNAMIC_DEBUG) += dynamic_debug.o 186 + obj-$(CONFIG_SYMBOLIC_ERRNAME) += errname.o 186 187 187 188 obj-$(CONFIG_NLATTR) += nlattr.o 188 189
+223
lib/errname.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <linux/build_bug.h> 3 + #include <linux/errno.h> 4 + #include <linux/errname.h> 5 + #include <linux/kernel.h> 6 + 7 + /* 8 + * Ensure these tables do not accidentally become gigantic if some 9 + * huge errno makes it in. On most architectures, the first table will 10 + * only have about 140 entries, but mips and parisc have more sparsely 11 + * allocated errnos (with EHWPOISON = 257 on parisc, and EDQUOT = 1133 12 + * on mips), so this wastes a bit of space on those - though we 13 + * special case the EDQUOT case. 14 + */ 15 + #define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = "-" #err 16 + static const char *names_0[] = { 17 + E(E2BIG), 18 + E(EACCES), 19 + E(EADDRINUSE), 20 + E(EADDRNOTAVAIL), 21 + E(EADV), 22 + E(EAFNOSUPPORT), 23 + E(EALREADY), 24 + E(EBADE), 25 + E(EBADF), 26 + E(EBADFD), 27 + E(EBADMSG), 28 + E(EBADR), 29 + E(EBADRQC), 30 + E(EBADSLT), 31 + E(EBFONT), 32 + E(EBUSY), 33 + #ifdef ECANCELLED 34 + E(ECANCELLED), 35 + #endif 36 + E(ECHILD), 37 + E(ECHRNG), 38 + E(ECOMM), 39 + E(ECONNABORTED), 40 + E(ECONNRESET), 41 + E(EDEADLOCK), 42 + E(EDESTADDRREQ), 43 + E(EDOM), 44 + E(EDOTDOT), 45 + #ifndef CONFIG_MIPS 46 + E(EDQUOT), 47 + #endif 48 + E(EEXIST), 49 + E(EFAULT), 50 + E(EFBIG), 51 + E(EHOSTDOWN), 52 + E(EHOSTUNREACH), 53 + E(EHWPOISON), 54 + E(EIDRM), 55 + E(EILSEQ), 56 + #ifdef EINIT 57 + E(EINIT), 58 + #endif 59 + E(EINPROGRESS), 60 + E(EINTR), 61 + E(EINVAL), 62 + E(EIO), 63 + E(EISCONN), 64 + E(EISDIR), 65 + E(EISNAM), 66 + E(EKEYEXPIRED), 67 + E(EKEYREJECTED), 68 + E(EKEYREVOKED), 69 + E(EL2HLT), 70 + E(EL2NSYNC), 71 + E(EL3HLT), 72 + E(EL3RST), 73 + E(ELIBACC), 74 + E(ELIBBAD), 75 + E(ELIBEXEC), 76 + E(ELIBMAX), 77 + E(ELIBSCN), 78 + E(ELNRNG), 79 + E(ELOOP), 80 + E(EMEDIUMTYPE), 81 + E(EMFILE), 82 + E(EMLINK), 83 + E(EMSGSIZE), 84 + E(EMULTIHOP), 85 + E(ENAMETOOLONG), 86 + E(ENAVAIL), 87 + E(ENETDOWN), 88 + E(ENETRESET), 89 + E(ENETUNREACH), 90 + E(ENFILE), 91 + E(ENOANO), 92 + E(ENOBUFS), 93 + E(ENOCSI), 94 + E(ENODATA), 95 + E(ENODEV), 96 + E(ENOENT), 97 + E(ENOEXEC), 98 + E(ENOKEY), 99 + E(ENOLCK), 100 + E(ENOLINK), 101 + E(ENOMEDIUM), 102 + E(ENOMEM), 103 + E(ENOMSG), 104 + E(ENONET), 105 + E(ENOPKG), 106 + E(ENOPROTOOPT), 107 + E(ENOSPC), 108 + E(ENOSR), 109 + E(ENOSTR), 110 + #ifdef ENOSYM 111 + E(ENOSYM), 112 + #endif 113 + E(ENOSYS), 114 + E(ENOTBLK), 115 + E(ENOTCONN), 116 + E(ENOTDIR), 117 + E(ENOTEMPTY), 118 + E(ENOTNAM), 119 + E(ENOTRECOVERABLE), 120 + E(ENOTSOCK), 121 + E(ENOTTY), 122 + E(ENOTUNIQ), 123 + E(ENXIO), 124 + E(EOPNOTSUPP), 125 + E(EOVERFLOW), 126 + E(EOWNERDEAD), 127 + E(EPERM), 128 + E(EPFNOSUPPORT), 129 + E(EPIPE), 130 + #ifdef EPROCLIM 131 + E(EPROCLIM), 132 + #endif 133 + E(EPROTO), 134 + E(EPROTONOSUPPORT), 135 + E(EPROTOTYPE), 136 + E(ERANGE), 137 + E(EREMCHG), 138 + #ifdef EREMDEV 139 + E(EREMDEV), 140 + #endif 141 + E(EREMOTE), 142 + E(EREMOTEIO), 143 + #ifdef EREMOTERELEASE 144 + E(EREMOTERELEASE), 145 + #endif 146 + E(ERESTART), 147 + E(ERFKILL), 148 + E(EROFS), 149 + #ifdef ERREMOTE 150 + E(ERREMOTE), 151 + #endif 152 + E(ESHUTDOWN), 153 + E(ESOCKTNOSUPPORT), 154 + E(ESPIPE), 155 + E(ESRCH), 156 + E(ESRMNT), 157 + E(ESTALE), 158 + E(ESTRPIPE), 159 + E(ETIME), 160 + E(ETIMEDOUT), 161 + E(ETOOMANYREFS), 162 + E(ETXTBSY), 163 + E(EUCLEAN), 164 + E(EUNATCH), 165 + E(EUSERS), 166 + E(EXDEV), 167 + E(EXFULL), 168 + 169 + E(ECANCELED), /* ECANCELLED */ 170 + E(EAGAIN), /* EWOULDBLOCK */ 171 + E(ECONNREFUSED), /* EREFUSED */ 172 + E(EDEADLK), /* EDEADLOCK */ 173 + }; 174 + #undef E 175 + 176 + #define E(err) [err - 512 + BUILD_BUG_ON_ZERO(err < 512 || err > 550)] = "-" #err 177 + static const char *names_512[] = { 178 + E(ERESTARTSYS), 179 + E(ERESTARTNOINTR), 180 + E(ERESTARTNOHAND), 181 + E(ENOIOCTLCMD), 182 + E(ERESTART_RESTARTBLOCK), 183 + E(EPROBE_DEFER), 184 + E(EOPENSTALE), 185 + E(ENOPARAM), 186 + 187 + E(EBADHANDLE), 188 + E(ENOTSYNC), 189 + E(EBADCOOKIE), 190 + E(ENOTSUPP), 191 + E(ETOOSMALL), 192 + E(ESERVERFAULT), 193 + E(EBADTYPE), 194 + E(EJUKEBOX), 195 + E(EIOCBQUEUED), 196 + E(ERECALLCONFLICT), 197 + }; 198 + #undef E 199 + 200 + static const char *__errname(unsigned err) 201 + { 202 + if (err < ARRAY_SIZE(names_0)) 203 + return names_0[err]; 204 + if (err >= 512 && err - 512 < ARRAY_SIZE(names_512)) 205 + return names_512[err - 512]; 206 + /* But why? */ 207 + if (IS_ENABLED(CONFIG_MIPS) && err == EDQUOT) /* 1133 */ 208 + return "-EDQUOT"; 209 + return NULL; 210 + } 211 + 212 + /* 213 + * errname(EIO) -> "EIO" 214 + * errname(-EIO) -> "-EIO" 215 + */ 216 + const char *errname(int err) 217 + { 218 + const char *name = __errname(abs(err)); 219 + if (!name) 220 + return NULL; 221 + 222 + return err > 0 ? name + 1 : name; 223 + }
+21
lib/test_printf.c
··· 594 594 } 595 595 596 596 static void __init 597 + errptr(void) 598 + { 599 + test("-1234", "%pe", ERR_PTR(-1234)); 600 + 601 + /* Check that %pe with a non-ERR_PTR gets treated as ordinary %p. */ 602 + BUILD_BUG_ON(IS_ERR(PTR)); 603 + test_hashed("%pe", PTR); 604 + 605 + #ifdef CONFIG_SYMBOLIC_ERRNAME 606 + test("(-ENOTSOCK)", "(%pe)", ERR_PTR(-ENOTSOCK)); 607 + test("(-EAGAIN)", "(%pe)", ERR_PTR(-EAGAIN)); 608 + BUILD_BUG_ON(EAGAIN != EWOULDBLOCK); 609 + test("(-EAGAIN)", "(%pe)", ERR_PTR(-EWOULDBLOCK)); 610 + test("[-EIO ]", "[%-8pe]", ERR_PTR(-EIO)); 611 + test("[ -EIO]", "[%8pe]", ERR_PTR(-EIO)); 612 + test("-EPROBE_DEFER", "%pe", ERR_PTR(-EPROBE_DEFER)); 613 + #endif 614 + } 615 + 616 + static void __init 597 617 test_pointer(void) 598 618 { 599 619 plain(); ··· 635 615 bitmap(); 636 616 netdev_features(); 637 617 flags(); 618 + errptr(); 638 619 } 639 620 640 621 static void __init selftest(void)
+27
lib/vsprintf.c
··· 21 21 #include <linux/build_bug.h> 22 22 #include <linux/clk.h> 23 23 #include <linux/clk-provider.h> 24 + #include <linux/errname.h> 24 25 #include <linux/module.h> /* for KSYM_SYMBOL_LEN */ 25 26 #include <linux/types.h> 26 27 #include <linux/string.h> ··· 612 611 ++len; 613 612 } 614 613 return widen_string(buf, len, end, spec); 614 + } 615 + 616 + static char *err_ptr(char *buf, char *end, void *ptr, 617 + struct printf_spec spec) 618 + { 619 + int err = PTR_ERR(ptr); 620 + const char *sym = errname(err); 621 + 622 + if (sym) 623 + return string_nocheck(buf, end, sym, spec); 624 + 625 + /* 626 + * Somebody passed ERR_PTR(-1234) or some other non-existing 627 + * Efoo - or perhaps CONFIG_SYMBOLIC_ERRNAME=n. Fall back to 628 + * printing it as its decimal representation. 629 + */ 630 + spec.flags |= SIGN; 631 + spec.base = 10; 632 + return number(buf, end, err, spec); 615 633 } 616 634 617 635 /* Be careful: error messages must fit into the given buffer. */ ··· 2207 2187 return kobject_string(buf, end, ptr, spec, fmt); 2208 2188 case 'x': 2209 2189 return pointer_string(buf, end, ptr, spec); 2190 + case 'e': 2191 + /* %pe with a non-ERR_PTR gets treated as plain %p */ 2192 + if (!IS_ERR(ptr)) 2193 + break; 2194 + return err_ptr(buf, end, ptr, spec); 2210 2195 } 2211 2196 2212 2197 /* default is to _not_ leak addresses, hash before printing */ ··· 2848 2823 case 'f': 2849 2824 case 'x': 2850 2825 case 'K': 2826 + case 'e': 2851 2827 save_arg(void *); 2852 2828 break; 2853 2829 default: ··· 3025 2999 case 'f': 3026 3000 case 'x': 3027 3001 case 'K': 3002 + case 'e': 3028 3003 process = true; 3029 3004 break; 3030 3005 default: