diff options
Diffstat (limited to 'lib/vsprintf.c')
| -rw-r--r-- | lib/vsprintf.c | 120 | 
1 files changed, 83 insertions, 37 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index e78017a3e1bd..dee8fc467fcf 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/errname.h>  #include <linux/module.h>	/* for KSYM_SYMBOL_LEN */  #include <linux/types.h>  #include <linux/string.h> @@ -38,6 +39,7 @@  #include <net/addrconf.h>  #include <linux/siphash.h>  #include <linux/compiler.h> +#include <linux/property.h>  #ifdef CONFIG_BLOCK  #include <linux/blkdev.h>  #endif @@ -613,6 +615,25 @@ static char *string_nocheck(char *buf, char *end, const char *s,  	return widen_string(buf, len, end, spec);  } +static char *err_ptr(char *buf, char *end, void *ptr, +		     struct printf_spec spec) +{ +	int err = PTR_ERR(ptr); +	const char *sym = errname(err); + +	if (sym) +		return string_nocheck(buf, end, sym, spec); + +	/* +	 * Somebody passed ERR_PTR(-1234) or some other non-existing +	 * Efoo - or perhaps CONFIG_SYMBOLIC_ERRNAME=n. Fall back to +	 * printing it as its decimal representation. +	 */ +	spec.flags |= SIGN; +	spec.base = 10; +	return number(buf, end, err, spec); +} +  /* Be careful: error messages must fit into the given buffer. */  static char *error_string(char *buf, char *end, const char *s,  			  struct printf_spec spec) @@ -918,7 +939,7 @@ char *symbol_string(char *buf, char *end, void *ptr,  #ifdef CONFIG_KALLSYMS  	if (*fmt == 'B')  		sprint_backtrace(sym, value); -	else if (*fmt != 'f' && *fmt != 's') +	else if (*fmt != 's')  		sprint_symbol(sym, value);  	else  		sprint_symbol_no_offset(sym, value); @@ -1872,32 +1893,25 @@ char *flags_string(char *buf, char *end, void *flags_ptr,  	return format_flags(buf, end, flags, names);  } -static const char *device_node_name_for_depth(const struct device_node *np, int depth) -{ -	for ( ; np && depth; depth--) -		np = np->parent; - -	return kbasename(np->full_name); -} -  static noinline_for_stack -char *device_node_gen_full_name(const struct device_node *np, char *buf, char *end) +char *fwnode_full_name_string(struct fwnode_handle *fwnode, char *buf, +			      char *end)  {  	int depth; -	const struct device_node *parent = np->parent; -	/* special case for root node */ -	if (!parent) -		return string_nocheck(buf, end, "/", default_str_spec); +	/* Loop starting from the root node to the current node. */ +	for (depth = fwnode_count_parents(fwnode); depth >= 0; depth--) { +		struct fwnode_handle *__fwnode = +			fwnode_get_nth_parent(fwnode, depth); -	for (depth = 0; parent->parent; depth++) -		parent = parent->parent; - -	for ( ; depth >= 0; depth--) { -		buf = string_nocheck(buf, end, "/", default_str_spec); -		buf = string(buf, end, device_node_name_for_depth(np, depth), +		buf = string(buf, end, fwnode_get_name_prefix(__fwnode), +			     default_str_spec); +		buf = string(buf, end, fwnode_get_name(__fwnode),  			     default_str_spec); + +		fwnode_handle_put(__fwnode);  	} +  	return buf;  } @@ -1921,6 +1935,9 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,  	struct printf_spec str_spec = spec;  	str_spec.field_width = -1; +	if (fmt[0] != 'F') +		return error_string(buf, end, "(%pO?)", spec); +  	if (!IS_ENABLED(CONFIG_OF))  		return error_string(buf, end, "(%pOF?)", spec); @@ -1942,10 +1959,11 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,  		switch (*fmt) {  		case 'f':	/* full_name */ -			buf = device_node_gen_full_name(dn, buf, end); +			buf = fwnode_full_name_string(of_fwnode_handle(dn), buf, +						      end);  			break;  		case 'n':	/* name */ -			p = kbasename(of_node_full_name(dn)); +			p = fwnode_get_name(of_fwnode_handle(dn));  			precision = str_spec.precision;  			str_spec.precision = strchrnul(p, '@') - p;  			buf = string(buf, end, p, str_spec); @@ -1955,7 +1973,7 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,  			buf = number(buf, end, (unsigned int)dn->phandle, num_spec);  			break;  		case 'P':	/* path-spec */ -			p = kbasename(of_node_full_name(dn)); +			p = fwnode_get_name(of_fwnode_handle(dn));  			if (!p[1])  				p = "/";  			buf = string(buf, end, p, str_spec); @@ -1993,15 +2011,34 @@ char *device_node_string(char *buf, char *end, struct device_node *dn,  	return widen_string(buf, buf - buf_start, end, spec);  } -static char *kobject_string(char *buf, char *end, void *ptr, -			    struct printf_spec spec, const char *fmt) +static noinline_for_stack +char *fwnode_string(char *buf, char *end, struct fwnode_handle *fwnode, +		    struct printf_spec spec, const char *fmt)  { -	switch (fmt[1]) { -	case 'F': -		return device_node_string(buf, end, ptr, spec, fmt + 1); +	struct printf_spec str_spec = spec; +	char *buf_start = buf; + +	str_spec.field_width = -1; + +	if (*fmt != 'w') +		return error_string(buf, end, "(%pf?)", spec); + +	if (check_pointer(&buf, end, fwnode, spec)) +		return buf; + +	fmt++; + +	switch (*fmt) { +	case 'P':	/* name */ +		buf = string(buf, end, fwnode_get_name(fwnode), str_spec); +		break; +	case 'f':	/* full_name */ +	default: +		buf = fwnode_full_name_string(fwnode, buf, end); +		break;  	} -	return error_string(buf, end, "(%pO?)", spec); +	return widen_string(buf, buf - buf_start, end, spec);  }  /* @@ -2016,9 +2053,9 @@ static char *kobject_string(char *buf, char *end, void *ptr,   *   * - 'S' For symbolic direct pointers (or function descriptors) with offset   * - 's' For symbolic direct pointers (or function descriptors) without offset - * - 'F' Same as 'S' - * - 'f' Same as 's' - * - '[FfSs]R' as above with __builtin_extract_return_addr() translation + * - '[Ss]R' as above with __builtin_extract_return_addr() translation + * - '[Ff]' %pf and %pF were obsoleted and later removed in favor of + *	    %ps and %pS. Be careful when re-using these specifiers.   * - 'B' For backtraced symbolic direct pointers with offset   * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]   * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] @@ -2108,6 +2145,10 @@ static char *kobject_string(char *buf, char *end, void *ptr,   *                  F device node flags   *                  c major compatible string   *                  C full compatible string + * - 'fw[fP]'	For a firmware node (struct fwnode_handle) pointer + *		Without an option prints the full name of the node + *		f full name + *		P node name, including a possible unit address   * - 'x' For printing the address. Equivalent to "%lx".   *   * ** When making changes please also update: @@ -2121,8 +2162,6 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,  	      struct printf_spec spec)  {  	switch (*fmt) { -	case 'F': -	case 'f':  	case 'S':  	case 's':  		ptr = dereference_symbol_descriptor(ptr); @@ -2184,9 +2223,16 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr,  	case 'G':  		return flags_string(buf, end, ptr, spec, fmt);  	case 'O': -		return kobject_string(buf, end, ptr, spec, fmt); +		return device_node_string(buf, end, ptr, spec, fmt + 1); +	case 'f': +		return fwnode_string(buf, end, ptr, spec, fmt + 1);  	case 'x':  		return pointer_string(buf, end, ptr, spec); +	case 'e': +		/* %pe with a non-ERR_PTR gets treated as plain %p */ +		if (!IS_ERR(ptr)) +			break; +		return err_ptr(buf, end, ptr, spec);  	}  	/* default is to _not_ leak addresses, hash before printing */ @@ -2819,10 +2865,9 @@ int vbin_printf(u32 *bin_buf, size_t size, const char *fmt, va_list args)  			/* Dereference of functions is still OK */  			case 'S':  			case 's': -			case 'F': -			case 'f':  			case 'x':  			case 'K': +			case 'e':  				save_arg(void *);  				break;  			default: @@ -2999,6 +3044,7 @@ int bstr_printf(char *buf, size_t size, const char *fmt, const u32 *bin_buf)  			case 'f':  			case 'x':  			case 'K': +			case 'e':  				process = true;  				break;  			default:  | 
