* [PATCH v2] printf: add support for printing symbolic error codes [not found] <20190830214655.6625-1-linux@rasmusvillemoes.dk> @ 2019-09-09 20:38 ` Rasmus Villemoes 2019-09-10 15:26 ` Andy Shevchenko ` (3 more replies) 0 siblings, 4 replies; 15+ messages in thread From: Rasmus Villemoes @ 2019-09-09 20:38 UTC (permalink / raw) To: Andrew Morton, Jonathan Corbet Cc: Rasmus Villemoes, Andy Shevchenko, Joe Perches, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Uwe Kleine-König, linux-doc 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\n", 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. Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org> Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> --- v2: - add #include <linux/stddef.h> to errcode.h (0day) - keep 'x' handling in switch() (Andy) - add paragraph to Documentation/core-api/printk-formats.rst - add ack from Uwe Documentation/core-api/printk-formats.rst | 8 + include/linux/errcode.h | 16 ++ lib/Kconfig.debug | 8 + lib/Makefile | 1 + lib/errcode.c | 215 ++++++++++++++++++++++ lib/test_printf.c | 14 ++ lib/vsprintf.c | 26 +++ 7 files changed, 288 insertions(+) create mode 100644 include/linux/errcode.h create mode 100644 lib/errcode.c diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index c6224d039bcb..7d3bf3cb207b 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -66,6 +66,14 @@ might be printed instead of the unreachable information:: (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 -------------- diff --git a/include/linux/errcode.h b/include/linux/errcode.h new file mode 100644 index 000000000000..c6a4c1b04f9c --- /dev/null +++ b/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 */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5960e2980a8a..dc1b20872774 100644 --- a/lib/Kconfig.debug +++ b/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" diff --git a/lib/Makefile b/lib/Makefile index 29c02a924973..664ecf10ee2a 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -185,6 +185,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 diff --git a/lib/errcode.c b/lib/errcode.c new file mode 100644 index 000000000000..7dcf97d5307f --- /dev/null +++ b/lib/errcode.c @@ -0,0 +1,215 @@ +// 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) +{ + /* Might as well accept both -EIO and EIO. */ + if (err < 0) + err = -err; + if (err <= 0) /* INT_MIN or 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; +} diff --git a/lib/test_printf.c b/lib/test_printf.c index 944eb50f3862..0401a2341245 100644 --- a/lib/test_printf.c +++ b/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) @@ -588,6 +590,17 @@ flags(void) kfree(cmp_buffer); } +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) { @@ -610,6 +623,7 @@ test_pointer(void) bitmap(); netdev_features(); flags(); + errptr(); } static void __init selftest(void) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index b0967cf17137..bfa5c3025965 100644 --- a/lib/vsprintf.c +++ b/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> @@ -2111,6 +2112,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') { + long 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': -- 2.20.1 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-09 20:38 ` [PATCH v2] printf: add support for printing symbolic error codes Rasmus Villemoes @ 2019-09-10 15:26 ` Andy Shevchenko 2019-09-11 0:15 ` Joe Perches 2019-09-15 9:43 ` Pavel Machek ` (2 subsequent siblings) 3 siblings, 1 reply; 15+ messages in thread From: Andy Shevchenko @ 2019-09-10 15:26 UTC (permalink / raw) To: Rasmus Villemoes Cc: Andrew Morton, Jonathan Corbet, Joe Perches, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Uwe Kleine-König, Linux Documentation List On Mon, Sep 9, 2019 at 11:39 PM Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote: > > 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\n", 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. > +#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = #err > +#define E(err) [err - 512 + BUILD_BUG_ON_ZERO(err < 512 || err > 550)] = #err From long term prospective 300 and 550 hard coded here may be forgotten. > +const char *errcode(int err) We got long, why not to use long type for it? > +{ > + /* Might as well accept both -EIO and EIO. */ > + if (err < 0) > + err = -err; > + if (err <= 0) /* INT_MIN or 0 */ > + return NULL; > + if (err < ARRAY_SIZE(codes_0)) > + return codes_0[err]; It won't work if one of the #ifdef:s in the array fails. Would it? > + 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; > +} > + long err = PTR_ERR(ptr); > + const char *sym = errcode(-err); Do we need additional sign change if we already have such check inside errcode()? -- With Best Regards, Andy Shevchenko ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-10 15:26 ` Andy Shevchenko @ 2019-09-11 0:15 ` Joe Perches 2019-09-11 6:43 ` Rasmus Villemoes 0 siblings, 1 reply; 15+ messages in thread From: Joe Perches @ 2019-09-11 0:15 UTC (permalink / raw) To: Andy Shevchenko, Rasmus Villemoes Cc: Andrew Morton, Jonathan Corbet, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Uwe Kleine-König, Linux Documentation List On Tue, 2019-09-10 at 18:26 +0300, Andy Shevchenko wrote: > On Mon, Sep 9, 2019 at 11:39 PM Rasmus Villemoes > <linux@rasmusvillemoes.dk> wrote: > > 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\n", 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. > > +#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = #err > > +#define E(err) [err - 512 + BUILD_BUG_ON_ZERO(err < 512 || err > 550)] = #err > > From long term prospective 300 and 550 hard coded here may be forgotten. > > > +const char *errcode(int err) > We got long, why not to use long type for it? > > > +{ > > + /* Might as well accept both -EIO and EIO. */ > > + if (err < 0) > > + err = -err; > > + if (err <= 0) /* INT_MIN or 0 */ > > + return NULL; > > + if (err < ARRAY_SIZE(codes_0)) > > + return codes_0[err]; > > It won't work if one of the #ifdef:s in the array fails. > Would it? > > > + 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; > > +} > > + long err = PTR_ERR(ptr); > > + const char *sym = errcode(-err); > > Do we need additional sign change if we already have such check inside > errcode()? How is EBUSY differentiated from ZERO_SIZE_PTR ? ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-11 0:15 ` Joe Perches @ 2019-09-11 6:43 ` Rasmus Villemoes 2019-09-11 9:37 ` Uwe Kleine-König 0 siblings, 1 reply; 15+ messages in thread From: Rasmus Villemoes @ 2019-09-11 6:43 UTC (permalink / raw) To: Joe Perches, Andy Shevchenko Cc: Andrew Morton, Jonathan Corbet, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Uwe Kleine-König, Linux Documentation List On 11/09/2019 02.15, Joe Perches wrote: > On Tue, 2019-09-10 at 18:26 +0300, Andy Shevchenko wrote: >> On Mon, Sep 9, 2019 at 11:39 PM Rasmus Villemoes >> <linux@rasmusvillemoes.dk> wrote: >>> +#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = #err >>> +#define E(err) [err - 512 + BUILD_BUG_ON_ZERO(err < 512 || err > 550)] = #err >> >> From long term prospective 300 and 550 hard coded here may be forgotten. No? The point of the BUILD_BUG_ON_ZEROs is that if you add a new Esomething, you'll get an instant build error if Esomething doesn't fit nicely in the array you put it in. Then one can go back and figure out whether the limit should be raised, a new codes_foo should be created, or if it's early enough so it's not ABI yet, simply change Esomething to a saner value. A much bigger problem is that it's possible to add something to some errno.h without updating this table, but there's no good solution for that, I'm afraid. However, new Esomething are very rarely added, and printf() will still handle it gracefully until somebody notices. >>> +const char *errcode(int err) >> We got long, why not to use long type for it? Because errno values by definition have type int - and the linux syscall ABI very clearly limits values to [1,4095]. I can change the type used in vsnprintf.c if you prefer. >>> +{ >>> + /* Might as well accept both -EIO and EIO. */ >>> + if (err < 0) >>> + err = -err; >>> + if (err <= 0) /* INT_MIN or 0 */ >>> + return NULL; >>> + if (err < ARRAY_SIZE(codes_0)) >>> + return codes_0[err]; >> >> It won't work if one of the #ifdef:s in the array fails. >> Would it? I don't understand what you mean. How can an ifdef fail(?), and what exactly won't work? >>> +} >>> + long err = PTR_ERR(ptr); >>> + const char *sym = errcode(-err); >> >> Do we need additional sign change if we already have such check inside >> errcode()? Nah, but I went back and forth on this and ended up falling between two stools. I think I'll drop the handling of negative arguments to errcode(), the INT_MIN case makes that slightly ugly anyway. > How is EBUSY differentiated from ZERO_SIZE_PTR ? Huh? ZERO_SIZE_PTR aka (void*)(16L) is not IS_ERR(), so we won't get here in that case. Rasmus ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-11 6:43 ` Rasmus Villemoes @ 2019-09-11 9:37 ` Uwe Kleine-König 2019-09-11 10:14 ` Rasmus Villemoes 0 siblings, 1 reply; 15+ messages in thread From: Uwe Kleine-König @ 2019-09-11 9:37 UTC (permalink / raw) To: Rasmus Villemoes, Joe Perches, Andy Shevchenko Cc: Andrew Morton, Jonathan Corbet, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Linux Documentation List [-- Attachment #1.1: Type: text/plain, Size: 2060 bytes --] On 9/11/19 8:43 AM, Rasmus Villemoes wrote: > On 11/09/2019 02.15, Joe Perches wrote: >> On Tue, 2019-09-10 at 18:26 +0300, Andy Shevchenko wrote: >>> On Mon, Sep 9, 2019 at 11:39 PM Rasmus Villemoes >>> <linux@rasmusvillemoes.dk> wrote: > >>>> +#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = #err >>>> +#define E(err) [err - 512 + BUILD_BUG_ON_ZERO(err < 512 || err > 550)] = #err >>> >>> From long term prospective 300 and 550 hard coded here may be forgotten. > > No? The point of the BUILD_BUG_ON_ZEROs is that if you add a new > Esomething, you'll get an instant build error if Esomething doesn't fit > nicely in the array you put it in. Then one can go back and figure out > whether the limit should be raised, a new codes_foo should be created, > or if it's early enough so it's not ABI yet, simply change Esomething to > a saner value. > > A much bigger problem is that it's possible to add something to some > errno.h without updating this table, but there's no good solution for > that, I'm afraid. However, new Esomething are very rarely added, and > printf() will still handle it gracefully until somebody notices. > >>>> +const char *errcode(int err) >>> We got long, why not to use long type for it? > > Because errno values by definition have type int - and the linux syscall > ABI very clearly limits values to [1,4095]. I can change the type used > in vsnprintf.c if you prefer. > >>>> +{ >>>> + /* Might as well accept both -EIO and EIO. */ >>>> + if (err < 0) >>>> + err = -err; >>>> + if (err <= 0) /* INT_MIN or 0 */ >>>> + return NULL; >>>> + if (err < ARRAY_SIZE(codes_0)) >>>> + return codes_0[err]; >>> >>> It won't work if one of the #ifdef:s in the array fails. >>> Would it? > > I don't understand what you mean. How can an ifdef fail(?), and what > exactly won't work? I think Joe means: What happens if codes_0[57] is "" because there is no ESOMETHING with value 57. Best regards Uwe [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-11 9:37 ` Uwe Kleine-König @ 2019-09-11 10:14 ` Rasmus Villemoes 0 siblings, 0 replies; 15+ messages in thread From: Rasmus Villemoes @ 2019-09-11 10:14 UTC (permalink / raw) To: Uwe Kleine-König, Joe Perches, Andy Shevchenko Cc: Andrew Morton, Jonathan Corbet, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Linux Documentation List On 11/09/2019 11.37, Uwe Kleine-König wrote: > On 9/11/19 8:43 AM, Rasmus Villemoes wrote: >> On 11/09/2019 02.15, Joe Perches wrote: >>> On Tue, 2019-09-10 at 18:26 +0300, Andy Shevchenko wrote: >>>> On Mon, Sep 9, 2019 at 11:39 PM Rasmus Villemoes >>>> <linux@rasmusvillemoes.dk> wrote: >>>>> +{ >>>>> + /* Might as well accept both -EIO and EIO. */ >>>>> + if (err < 0) >>>>> + err = -err; >>>>> + if (err <= 0) /* INT_MIN or 0 */ >>>>> + return NULL; >>>>> + if (err < ARRAY_SIZE(codes_0)) >>>>> + return codes_0[err]; >>>> >>>> It won't work if one of the #ifdef:s in the array fails. >>>> Would it? >> >> I don't understand what you mean. How can an ifdef fail(?), and what >> exactly won't work? > > I think Joe means: What happens if codes_0[57] is "" because there is no > ESOMETHING with value 57. [That was Andy, not Joe, I was lazy and replied to both in one email since Joe quoted all of Andy's questions]. So first, for good measure, codes_0[57] may be NULL but not "". Second, if we're passed 57 but no Exxx on this architecture has the value 57, then yes, we return NULL, just as if we're passed -18 or 0 or 1234. But 57 (or -57, or ERR_PTR(-57)) would realistically never find its way into an err variable (be it pointer or integer) in the first place when no ESOMETHING has the value 57. Except for the case where somebody in the future adds #define ESOMETHING 57 to their asm/errno.h and starts using ESOMETHING, without updating the table in errcode.c. But if that's the case, letting the caller handle the "sorry, I can't translate 57 to some string" is still the right thing to do. Rasmus ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-09 20:38 ` [PATCH v2] printf: add support for printing symbolic error codes Rasmus Villemoes 2019-09-10 15:26 ` Andy Shevchenko @ 2019-09-15 9:43 ` Pavel Machek 2019-09-16 12:23 ` Uwe Kleine-König 2019-09-17 6:59 ` [PATCH v3] " Rasmus Villemoes 3 siblings, 0 replies; 15+ messages in thread From: Pavel Machek @ 2019-09-15 9:43 UTC (permalink / raw) To: Rasmus Villemoes Cc: Andrew Morton, Jonathan Corbet, Andy Shevchenko, Joe Perches, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Uwe Kleine-K??nig, linux-doc On Mon 2019-09-09 22:38:25, Rasmus Villemoes wrote: > 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 For the record, I hate manually decoding errors, so I like this patch. Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-09 20:38 ` [PATCH v2] printf: add support for printing symbolic error codes Rasmus Villemoes 2019-09-10 15:26 ` Andy Shevchenko 2019-09-15 9:43 ` Pavel Machek @ 2019-09-16 12:23 ` Uwe Kleine-König 2019-09-16 13:23 ` Rasmus Villemoes 2019-09-17 6:59 ` [PATCH v3] " Rasmus Villemoes 3 siblings, 1 reply; 15+ messages in thread From: Uwe Kleine-König @ 2019-09-16 12:23 UTC (permalink / raw) To: Rasmus Villemoes, Andrew Morton, Jonathan Corbet Cc: Andy Shevchenko, Joe Perches, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, linux-doc [-- Attachment #1.1: Type: text/plain, Size: 2000 bytes --] Hello Rasmus, On 9/9/19 10:38 PM, Rasmus Villemoes wrote: > 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\n", 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. > > Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org> > Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> Even with my ack already given I still think having %pE (or %pe) for ints holding an error code is sensible. So I wonder if it would be a good idea to split this patch into one that introduces errcode() and then the patch that teaches vsprintf about emitting its return value for error valued pointers. Then I could rebase my initial patch for %pe on top of your first one. Other than that I wonder how we can go forward from here. So I think it is time for v3 which picks up the few suggestions. Best regards Uwe [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-16 12:23 ` Uwe Kleine-König @ 2019-09-16 13:23 ` Rasmus Villemoes 2019-09-16 13:36 ` Uwe Kleine-König 0 siblings, 1 reply; 15+ messages in thread From: Rasmus Villemoes @ 2019-09-16 13:23 UTC (permalink / raw) To: Uwe Kleine-König, Rasmus Villemoes, Andrew Morton, Jonathan Corbet Cc: Andy Shevchenko, Joe Perches, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, linux-doc On 16/09/2019 14.23, Uwe Kleine-König wrote: > Hello Rasmus, > > On 9/9/19 10:38 PM, Rasmus Villemoes wrote: >> 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\n", 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. >> >> Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org> >> Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> > > Even with my ack already given I still think having %pE (or %pe) for > ints holding an error code is sensible. I don't understand why you'd want an explicit %p<something> to do what %p does by itself - in fact, with the current vsnprintf implementation, "%pe", ERR_PTR(-EFOO) would already do what you want (since after %p is processed, all alphanumeric are skipped whether they were interpreted or not). So we could "reserve" %pe perhaps in order to make the call sites a little more readable, but no code change in vsnprintf.c would be necessary. Or did you mean %pe with the argument being an (int*), so one would do if (err < 0) pr_err("bad: %pe\n", &err); Maybe I'd buy that one, though I don't think it's much worse to do if (err < 0) pr_err("bad: %p\n", ERR_PTR(err)); Also, the former has less type safety/type genericity than the latter; if err happens to be a long (or s8 or s16) the former won't work while the latter will. Or perhaps you meant introduce a %d<something> extension? I still think that's a bad idea, and I've in the meantime found another reason (covering %d in particular): Netdevices can be given a name containing exactly one occurrence of %d (or no % at all), and then the actual name will be determined based on that pattern. These patterns are settable from userspace. And everything of course breaks horribly if somebody set a name to "bla%deth" and that got turned into "blaEPERMth". > So I wonder if it would be a > good idea to split this patch into one that introduces errcode() and > then the patch that teaches vsprintf about emitting its return value for > error valued pointers. Then I could rebase my initial patch for %pe on > top of your first one. Well, I think my patch as-is is simple enough, there's not much point separating the few lines in vsnprintf() from the introduction of errcode() (which, realistically, will never have other callers). > Other than that I wonder how we can go forward from here. So I think it > is time for v3 which picks up the few suggestions. Yes, I have actually prepared a v3, was just waiting for additional comments on my responses to the v2 review comments. Rasmus ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v2] printf: add support for printing symbolic error codes 2019-09-16 13:23 ` Rasmus Villemoes @ 2019-09-16 13:36 ` Uwe Kleine-König 0 siblings, 0 replies; 15+ messages in thread From: Uwe Kleine-König @ 2019-09-16 13:36 UTC (permalink / raw) To: Rasmus Villemoes, Andrew Morton, Jonathan Corbet Cc: Andy Shevchenko, Joe Perches, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, linux-doc [-- Attachment #1.1: Type: text/plain, Size: 3786 bytes --] On 9/16/19 3:23 PM, Rasmus Villemoes wrote: > On 16/09/2019 14.23, Uwe Kleine-König wrote: >> Hello Rasmus, >> >> On 9/9/19 10:38 PM, Rasmus Villemoes wrote: >>> 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\n", 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. >>> >>> Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org> >>> Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> >> >> Even with my ack already given I still think having %pE (or %pe) for >> ints holding an error code is sensible. > > I don't understand why you'd want an explicit %p<something> to do what > %p does by itself - in fact, with the current vsnprintf implementation, > "%pe", ERR_PTR(-EFOO) would already do what you want (since after %p is > processed, all alphanumeric are skipped whether they were interpreted or > not). So we could "reserve" %pe perhaps in order to make the call sites > a little more readable, but no code change in vsnprintf.c would be > necessary. Sorry, I meant I still consider %de (or %dE) sensible which I suggested at the start of this thread. > Or perhaps you meant introduce a %d<something> extension? I still think > that's a bad idea, and I've in the meantime found another reason > (covering %d in particular): Netdevices can be given a name containing > exactly one occurrence of %d (or no % at all), and then the actual name > will be determined based on that pattern. These patterns are settable > from userspace. And everything of course breaks horribly if somebody set > a name to "bla%deth" and that got turned into "blaEPERMth". Sure, this should not happen. I don't see imminent danger though. (ethernet IDs are usually positive, right?) I think having a possibility to print error codes in an int is beneficial, as otherwise I'd have to convert to a pointer first when printing the code which is IMHO unnecessary burden. >> So I wonder if it would be a >> good idea to split this patch into one that introduces errcode() and >> then the patch that teaches vsprintf about emitting its return value for >> error valued pointers. Then I could rebase my initial patch for %pe on >> top of your first one. > > Well, I think my patch as-is is simple enough, there's not much point > separating the few lines in vsnprintf() from the introduction of > errcode() (which, realistically, will never have other callers). Fine if your series goes in soon. If not I'd like to use errcode() without having to discuss the changes to how pointers are printed. Best regards Uwe [-- Attachment #2: OpenPGP digital signature --] [-- Type: application/pgp-signature, Size: 488 bytes --] ^ permalink raw reply [flat|nested] 15+ messages in thread
* [PATCH v3] printf: add support for printing symbolic error codes 2019-09-09 20:38 ` [PATCH v2] printf: add support for printing symbolic error codes Rasmus Villemoes ` (2 preceding siblings ...) 2019-09-16 12:23 ` Uwe Kleine-König @ 2019-09-17 6:59 ` Rasmus Villemoes 2019-09-25 14:36 ` Petr Mladek 2019-10-05 21:48 ` Andrew Morton 3 siblings, 2 replies; 15+ messages in thread From: Rasmus Villemoes @ 2019-09-17 6:59 UTC (permalink / raw) To: Andrew Morton, Jonathan Corbet Cc: Rasmus Villemoes, Andy Shevchenko, Joe Perches, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Uwe Kleine-König, linux-doc, Pavel Machek 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\n", 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. Acked-by: Uwe Kleine-König <uwe@kleine-koenig.org> Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> --- Andrew: please consider picking this up, even if we're already in the merge window. Quite a few people have said they'd like to see something like this, it's a debug improvement in its own right (the "ERR_PTR accidentally passed to printf" case), the printf tests pass, and it's much easier to start adding (and testing) users around the tree once this is in master. v3: - only accept positive errno values in errcode() - change type of err variable in pointer() from long to int v2: - add #include <linux/stddef.h> to errcode.h (0day) - keep 'x' handling in switch() (Andy) - add paragraph to Documentation/core-api/printk-formats.rst - add ack from Uwe 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(+) create mode 100644 include/linux/errcode.h create mode 100644 lib/errcode.c diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst index c6224d039bcb..7d3bf3cb207b 100644 --- a/Documentation/core-api/printk-formats.rst +++ b/Documentation/core-api/printk-formats.rst @@ -66,6 +66,14 @@ might be printed instead of the unreachable information:: (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 -------------- diff --git a/include/linux/errcode.h b/include/linux/errcode.h new file mode 100644 index 000000000000..c6a4c1b04f9c --- /dev/null +++ b/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 */ diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index 5960e2980a8a..dc1b20872774 100644 --- a/lib/Kconfig.debug +++ b/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" diff --git a/lib/Makefile b/lib/Makefile index c5892807e06f..9f14edc7ef63 100644 --- a/lib/Makefile +++ b/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 diff --git a/lib/errcode.c b/lib/errcode.c new file mode 100644 index 000000000000..3e519b13245e --- /dev/null +++ b/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; +} diff --git a/lib/test_printf.c b/lib/test_printf.c index 944eb50f3862..0401a2341245 100644 --- a/lib/test_printf.c +++ b/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) @@ -588,6 +590,17 @@ flags(void) kfree(cmp_buffer); } +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) { @@ -610,6 +623,7 @@ test_pointer(void) bitmap(); netdev_features(); flags(); + errptr(); } static void __init selftest(void) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index b0967cf17137..299fce317eb3 100644 --- a/lib/vsprintf.c +++ b/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> @@ -2111,6 +2112,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': -- 2.20.1 ^ permalink raw reply related [flat|nested] 15+ messages in thread
* Re: [PATCH v3] printf: add support for printing symbolic error codes 2019-09-17 6:59 ` [PATCH v3] " Rasmus Villemoes @ 2019-09-25 14:36 ` Petr Mladek 2019-09-29 20:09 ` Rasmus Villemoes 2019-10-05 21:48 ` Andrew Morton 1 sibling, 1 reply; 15+ messages in thread From: Petr Mladek @ 2019-09-25 14:36 UTC (permalink / raw) To: Rasmus Villemoes Cc: Andrew Morton, Jonathan Corbet, Andy Shevchenko, Sergey Senozhatsky, Uwe Kleine-König, Jani Nikula, Joe Perches, Pavel Machek, linux-doc, Linux Kernel Mailing List First, I am sorry that I replay so late. I was traveling the previous two weeks and was not able to follow the discussion about this patch. I am fine with adding this feature. But I would like to do it a cleaner way, see below. On Tue 2019-09-17 08:59:59, Rasmus Villemoes wrote: > 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. Please, remove the above two paragraphs in the final patch. They make sense for review but not for git history. > Andrew: please consider picking this up, even if we're already in the > merge window. Quite a few people have said they'd like to see > something like this, it's a debug improvement in its own right (the > "ERR_PTR accidentally passed to printf" case), the printf tests pass, > and it's much easier to start adding (and testing) users around the > tree once this is in master. This change would deserve to spend some time in linux-next. Anyway, it is already too late for 5.4. > diff --git a/include/linux/errcode.h b/include/linux/errcode.h > new file mode 100644 > index 000000000000..c6a4c1b04f9c > --- /dev/null > +++ b/include/linux/errcode.h The word "code" is quite ambiguous. I am not sure if it is the name or the number. I think that it is actually both (the relation between the two. Both "man 3 errno" and https://www.gnu.org/software/libc/manual/html_node/Checking-for-Errors.html#Checking-for-Errors talks about numbers and symbolic names. Please use errname or so instead of errcode everywhere. > diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug > index 5960e2980a8a..dc1b20872774 100644 > --- a/lib/Kconfig.debug > +++ b/lib/Kconfig.debug > @@ -164,6 +164,14 @@ config DYNAMIC_DEBUG > See Documentation/admin-guide/dynamic-debug-howto.rst for additional > information. > > +config SYMBOLIC_ERRCODE What is the exact reason to make this configurable, please? Nobody was really against this feature. The only question was if it was worth the code complexity and maintenance. If we are going to have the code then we should use it. Then there was a concerns that it might be too big for embedded people. But did it come from people working on embedded kernel or was it just theoretical? I would personally enable it when CONFIG_PRINTK is enabled. We could always introduce a new config option later when anyone really wants to disable it. > --- /dev/null > +++ b/lib/errcode.c > @@ -0,0 +1,212 @@ > +#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = #err > +static const char *codes_0[] = { > + E(E2BIG), I really like the way how the array is initialized. > diff --git a/lib/test_printf.c b/lib/test_printf.c > index 944eb50f3862..0401a2341245 100644 > --- a/lib/test_printf.c > +++ b/lib/test_printf.c > +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)); I like that you check more values. But please split it to check only one value per line to make it better readable. > diff --git a/lib/vsprintf.c b/lib/vsprintf.c > index b0967cf17137..299fce317eb3 100644 > --- a/lib/vsprintf.c > +++ b/lib/vsprintf.c > @@ -2111,6 +2112,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') { We had similar code before the commit 3e5903eb9cff70730171 ("vsprintf: Prevent crash when dereferencing invalid pointers"). Note that the original code kept the original value also for *fmt == 'K'. Anyway, the above commit tried to unify the handling of special values: + use the same strings for special values + check for special values only when pointer is dereferenced This patch makes it inconsistent again. I mean that the code will: + check for (null) and (efault) only when the pointer is dereferenced + check for err codes in more situations but not in all and not in %s + use another style to print the error (uppercase without brackets) I would like to keep it consistent. My proposal is: 1. Print the plain error code name only when a new %pe modifier is used. This will be useful in the error messages, e.g. void *p = ERR_PTR(-ENOMEM); if (IS_ERR(foo)) { pr_err("Sorry, can't do that: %pe\n", foo); return PTR_ERR(foo); would produce Sorry, can't do that: -ENOMEM 2. Use error code names also in check_pointer_msg() instead of (efault). But put it into brackets to distinguish it from the expected value, for example: /* valid pointer */ phys_addr_t addr = 0xab; printk("value: %pa\n", &addr); /* known error code */ printk("value: %pa\n", ERR_PTR(-ENOMEM)); /* unknown error code */ printk("value: %pa\n", ERR_PTR(-1234)); would produce: value: 0xab value: (-ENOMEM) value: (-1234) 3. Unify the style for the null pointer: + use (NULL) instead of (null) 4. Do not use error code names for internal vsprintf error to avoid confusion. For example: + replace the one (einval) with (%piS-err) or so How does that sound, please? Best Regards, Petr ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3] printf: add support for printing symbolic error codes 2019-09-25 14:36 ` Petr Mladek @ 2019-09-29 20:09 ` Rasmus Villemoes 2019-10-02 8:34 ` Petr Mladek 0 siblings, 1 reply; 15+ messages in thread From: Rasmus Villemoes @ 2019-09-29 20:09 UTC (permalink / raw) To: Petr Mladek Cc: Andrew Morton, Jonathan Corbet, Andy Shevchenko, Sergey Senozhatsky, Uwe Kleine-König, Jani Nikula, Joe Perches, Pavel Machek, linux-doc, Linux Kernel Mailing List On 25/09/2019 16.36, Petr Mladek wrote: > First, I am sorry that I replay so late. I was traveling the previous > two weeks and was not able to follow the discussion about this patch. > > I am fine with adding this feature. But I would like to do it > a cleaner way, see below. > > > On Tue 2019-09-17 08:59:59, Rasmus Villemoes wrote: >> 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. > > Please, remove the above two paragraphs in the final patch. They make > sense for review but not for git history. Agree for the latter, but not the former - I do want to explain why it's possible to configure out; see also below. > This change would deserve to spend some time in linux-next. Anyway, > it is already too late for 5.4. Yes, it's of course way too late now. Perhaps I should ask you to take it via the printk tree? Anyway, let's see what we can agree to. > The word "code" is quite ambiguous. I am not sure if it is the name or > the number. I think that it is actually both (the relation between > the two. > > Both "man 3 errno" and > https://www.gnu.org/software/libc/manual/html_node/Checking-for-Errors.html#Checking-for-Errors > talks about numbers and symbolic names. > > Please use errname or so instead of errcode everywhere. OK. I wasn't too happy about errcode anyway - but I wanted to avoid "str" being in there to avoid anyone thinking it was a strerror(). So "CONFIG_SYMBOLIC_ERRNAME" and errname() seems fine with the above justification. >> +config SYMBOLIC_ERRCODE > > What is the exact reason to make this configurable, please? > > Nobody was really against this feature. The only question > was if it was worth the code complexity and maintenance. > If we are going to have the code then we should use it. > > Then there was a concerns that it might be too big for embedded > people. But did it come from people working on embedded kernel > or was it just theoretical? I am one such person, and while 3K may not be a lot, death by a thousand paper cuts... > I would personally enable it when CONFIG_PRINTK is enabled. Agree. So let's make it 'default y if PRINTK'? These are only/mostly useful when destined for dmesg, I can't imagine any of the sysfs/procfs uses of vsprintf() to want this. So if somebody has gone to the rather extremely length of disabling printk (which even I rarely do), they really want the absolute minimal kernel, and would not benefit from this anyway. While for the common case, it gets enabled for anyone that just updates their defconfig and accepts new default values. > We could always introduce a new config option later when > anyone really wants to disable it. No, because by the time the kernel has grown too large for some target, it's almost impossible to start figuring out which small pieces can be chopped away with suitable config options, and even harder to get upstream to accept such configurability ("why, that would only gain you 3K..."). >> --- /dev/null >> +++ b/lib/errcode.c >> @@ -0,0 +1,212 @@ >> +#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = #err >> +static const char *codes_0[] = { >> + E(E2BIG), > > I really like the way how the array is initialized. Thanks. > >> diff --git a/lib/test_printf.c b/lib/test_printf.c >> index 944eb50f3862..0401a2341245 100644 >> --- a/lib/test_printf.c >> +++ b/lib/test_printf.c >> +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)); > > I like that you check more values. But please split it to check > only one value per line to make it better readable. Hm, ok, but I actually do it this way on purpose - I want to ensure that the test where one passes a random not-zero-but-too-small buffer size sometimes hits in the middle of the %p output, sometimes just before and sometimes just after. The very reason I added test_printf was because there were some %p extensions that violated the basic rule of snprintf()'s return value and/or wrote beyond the provided buffer. Not a big deal, so if you insist I'll break it up. > >> diff --git a/lib/vsprintf.c b/lib/vsprintf.c >> index b0967cf17137..299fce317eb3 100644 >> --- a/lib/vsprintf.c >> +++ b/lib/vsprintf.c >> @@ -2111,6 +2112,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') { > > We had similar code before the commit 3e5903eb9cff70730171 ("vsprintf: > Prevent crash when dereferencing invalid pointers"). Note that the > original code kept the original value also for *fmt == 'K'. > > Anyway, the above commit tried to unify the handling of special > values: > > + use the same strings for special values > + check for special values only when pointer is dereferenced > > This patch makes it inconsistent again. I mean that the code will: > > + check for (null) and (efault) only when the pointer is > dereferenced > > + check for err codes in more situations but not in all > and not in %s > > + use another style to print the error (uppercase without > brackets) > > > I would like to keep it consistent. My proposal is: > > 1. Print the plain error code name only when > a new %pe modifier is used. This will be useful > in the error messages, e.g. > > void *p = ERR_PTR(-ENOMEM); > if (IS_ERR(foo)) { > pr_err("Sorry, can't do that: %pe\n", foo); > return PTR_ERR(foo); > > would produce > > Sorry, can't do that: -ENOMEM Well, we can certainly do that. However, I didn't want that for two reasons: (1) I want plain %p to be more useful when passed an ERR_PTR. Printing the value, possibly symbolically, doesn't leak anything about kernel addresses, so the hashing is pointless and just makes the printk() less useful - and non-repeatable across reboots, making debugging needlessly harder. (2) With a dedicated extension, we have to define what happens if a non-ERR_PTR gets passed as %pe argument. [and (3), we're running out of %p<foo> namespace]. So, if you have some good answer to (2) I can do that - but if the answer is "fall through to handling it as just a normal %p", well, then we haven't really won much. And I don't see what else we could do - print "(!ERR_PTR)"? > 2. Use error code names also in check_pointer_msg() instead > of (efault). But put it into brackets to distinguish it > from the expected value, for example: > > /* valid pointer */ > phys_addr_t addr = 0xab; > printk("value: %pa\n", &addr); > /* known error code */ > printk("value: %pa\n", ERR_PTR(-ENOMEM)); > /* unknown error code */ > printk("value: %pa\n", ERR_PTR(-1234)); > > would produce: > > value: 0xab > value: (-ENOMEM) > value: (-1234) Yes, I think this is a good idea. But only for ERR_PTRs, for other obviously-not-a-kernel-address pointer values (i.e. the < PAGE_SIZE case) we still need some other string. So how about I try to add something like this so that would-be-dereferenced ERR_PTRs get printed symbolically in brackets, while I move the check for IS_ERR() to after the switch() (i.e. before handing over to do the hashing)? Then all ERR_PTRs get printed symbolically - except for %px and possibly %pK which are explicitly "print this value". > 3. Unify the style for the null pointer: > > + use (NULL) instead of (null) Yes, that's better. But somewhat out of scope for this patch. > 4. Do not use error code names for internal vsprintf error > to avoid confusion. For example: > > + replace the one (einval) with (%piS-err) or so > > How does that sound, please? Oh, yes, I never was a fan of the (einval) (efault) strings. Rasmus ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3] printf: add support for printing symbolic error codes 2019-09-29 20:09 ` Rasmus Villemoes @ 2019-10-02 8:34 ` Petr Mladek 0 siblings, 0 replies; 15+ messages in thread From: Petr Mladek @ 2019-10-02 8:34 UTC (permalink / raw) To: Rasmus Villemoes Cc: Andy Shevchenko, Sergey Senozhatsky, Uwe Kleine-König, Andrew Morton, Jani Nikula, Jonathan Corbet, Joe Perches, Pavel Machek, linux-doc, Linux Kernel Mailing List On Sun 2019-09-29 22:09:28, Rasmus Villemoes wrote: > > On Tue 2019-09-17 08:59:59, Rasmus Villemoes wrote: > >> 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. > > > > Please, remove the above two paragraphs in the final patch. They make > > sense for review but not for git history. > > Agree for the latter, but not the former - I do want to explain why it's > possible to configure out; see also below. I see. It was too cryptic for me. I did not get the proper meaning and context ;-) > > This change would deserve to spend some time in linux-next. Anyway, > > it is already too late for 5.4. > > Yes, it's of course way too late now. Perhaps I should ask you to take > it via the printk tree? Anyway, let's see what we can agree to. Yup, I could take it via printk.git. > >> +config SYMBOLIC_ERRCODE > > > > What is the exact reason to make this configurable, please? > > I am one such person, and while 3K may not be a lot, death by a thousand > paper cuts... > > > I would personally enable it when CONFIG_PRINTK is enabled. > > Agree. So let's make it 'default y if PRINTK'? Yeah, it makes perfect sense to me. > > We could always introduce a new config option later when > > anyone really wants to disable it. > > No, because by the time the kernel has grown too large for some target, > it's almost impossible to start figuring out which small pieces can be > chopped away with suitable config options OK, if you are the embedded guy and you would appreciate the config then let's have it. Just please add it by a separate patch, ideally with some numbers. > and even harder to get > upstream to accept such configurability ("why, that would only gain you > 3K..."). I remeber LWN articles about shrinking the kernel for embeded systems and that every kB was important. > >> --- /dev/null > >> +++ b/lib/errcode.c > >> @@ -0,0 +1,212 @@ > >> +#define E(err) [err + BUILD_BUG_ON_ZERO(err <= 0 || err > 300)] = #err > >> +static const char *codes_0[] = { > >> + E(E2BIG), > > > > I really like the way how the array is initialized. > > Thanks. > > > > >> diff --git a/lib/test_printf.c b/lib/test_printf.c > >> index 944eb50f3862..0401a2341245 100644 > >> --- a/lib/test_printf.c > >> +++ b/lib/test_printf.c > >> +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)); > > > > I like that you check more values. But please split it to check > > only one value per line to make it better readable. > > Hm, ok, but I actually do it this way on purpose - I want to ensure that > the test where one passes a random not-zero-but-too-small buffer size > sometimes hits in the middle of the %p output, sometimes just before and > sometimes just after. Is this really tested? do_test() function uses buffer for 256 characters. There are some consistency checks. But any of your test string is not truncated by the size of the buffer. Do I miss anything, please? > The very reason I added test_printf was because > there were some %p extensions that violated the basic rule of > snprintf()'s return value and/or wrote beyond the provided buffer. This sounds like a serious bug. Are your aware of any still existing %p extension that causes this? > Not a big deal, so if you insist I'll break it up. Yes, it is not a big deal. But I would still prefer to understand what is tested. And it is better to have more tests focused on different aspects than a single magic one. > > > >> diff --git a/lib/vsprintf.c b/lib/vsprintf.c > >> index b0967cf17137..299fce317eb3 100644 > >> --- a/lib/vsprintf.c > >> +++ b/lib/vsprintf.c > >> @@ -2111,6 +2112,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') { > > > > We had similar code before the commit 3e5903eb9cff70730171 ("vsprintf: > > Prevent crash when dereferencing invalid pointers"). Note that the > > original code kept the original value also for *fmt == 'K'. > > > > Anyway, the above commit tried to unify the handling of special > > values: > > > > + use the same strings for special values > > + check for special values only when pointer is dereferenced > > > > This patch makes it inconsistent again. I mean that the code will: > > > > + check for (null) and (efault) only when the pointer is > > dereferenced > > > > + check for err codes in more situations but not in all > > and not in %s > > > > + use another style to print the error (uppercase without > > brackets) > > > > > > I would like to keep it consistent. My proposal is: > > > > 1. Print the plain error code name only when > > a new %pe modifier is used. This will be useful > > in the error messages, e.g. > > > > void *p = ERR_PTR(-ENOMEM); > > if (IS_ERR(foo)) { > > pr_err("Sorry, can't do that: %pe\n", foo); > > return PTR_ERR(foo); > > > > would produce > > > > Sorry, can't do that: -ENOMEM > > Well, we can certainly do that. However, I didn't want that for two > reasons: (1) I want plain %p to be more useful when passed an ERR_PTR. > Printing the value, possibly symbolically, doesn't leak anything about > kernel addresses, so the hashing is pointless and just makes the > printk() less useful - and non-repeatable across reboots, making > debugging needlessly harder. (2) With a dedicated extension, we have to > define what happens if a non-ERR_PTR gets passed as %pe argument. [and > (3), we're running out of %p<foo> namespace]. > > So, if you have some good answer to (2) I can do that - but if the > answer is "fall through to handling it as just a normal %p", well, then > we haven't really won much. And I don't see what else we could do - > print "(!ERR_PTR)"? This made me to remember the long discussion about filtering kernel pointers, see https://lkml.kernel.org/r/1506816410-10230-1-git-send-email-me@tobin.cc It was basically about that %p might leak information. %pK failed because it did not force people to remove the dangerous %p calls. It ended with hashing %p to actually force people to convert %p into something more useful and safe. IMHO, the most extreme was a wish to get rid of %p and %pa completely, see https://lkml.kernel.org/r/CA+55aFwac2BzgZs-X1_VhekkuGfuLqNui2+2DbvLiDyptS-rXQ@mail.gmail.com I do not think that exposing ERR_PTR values might be dangerous. Well, it would be great to confirm this by some security guys. Anyway, I do not think that it is a good idea to make %p more useful again. I would print the hashed pointer value when the value passed to %pe is out of range. Best Regards, Petr ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [PATCH v3] printf: add support for printing symbolic error codes 2019-09-17 6:59 ` [PATCH v3] " Rasmus Villemoes 2019-09-25 14:36 ` Petr Mladek @ 2019-10-05 21:48 ` Andrew Morton 1 sibling, 0 replies; 15+ messages in thread From: Andrew Morton @ 2019-10-05 21:48 UTC (permalink / raw) To: Rasmus Villemoes Cc: Jonathan Corbet, Andy Shevchenko, Joe Perches, Petr Mladek, Sergey Senozhatsky, Jani Nikula, Linux Kernel Mailing List, Uwe Kleine-König, linux-doc, Pavel Machek On Tue, 17 Sep 2019 08:59:59 +0200 Rasmus Villemoes <linux@rasmusvillemoes.dk> wrote: > 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\n", 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. Looks reasonable to me. Is there any existing kernel code which presently uses this? Can we get some conversions done to demonstrate and hopefully test the feature? ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2019-10-05 21:48 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <20190830214655.6625-1-linux@rasmusvillemoes.dk>
2019-09-09 20:38 ` [PATCH v2] printf: add support for printing symbolic error codes Rasmus Villemoes
2019-09-10 15:26 ` Andy Shevchenko
2019-09-11 0:15 ` Joe Perches
2019-09-11 6:43 ` Rasmus Villemoes
2019-09-11 9:37 ` Uwe Kleine-König
2019-09-11 10:14 ` Rasmus Villemoes
2019-09-15 9:43 ` Pavel Machek
2019-09-16 12:23 ` Uwe Kleine-König
2019-09-16 13:23 ` Rasmus Villemoes
2019-09-16 13:36 ` Uwe Kleine-König
2019-09-17 6:59 ` [PATCH v3] " Rasmus Villemoes
2019-09-25 14:36 ` Petr Mladek
2019-09-29 20:09 ` Rasmus Villemoes
2019-10-02 8:34 ` Petr Mladek
2019-10-05 21:48 ` Andrew Morton
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).