3746 lines · 90.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* *  linux/lib/vsprintf.c * *  Copyright (C) 1991, 1992  Linus Torvalds */ /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. *//* * Wirzenius wrote this portably, Torvalds fucked it up :-) */ /* * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> * - changed to provide snprintf and vsnprintf functions * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de> * - scnprintf and vscnprintf */ #include <linux/stdarg.h>#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>#include <linux/ctype.h>#include <linux/hex.h>#include <linux/kernel.h>#include <linux/kallsyms.h>#include <linux/math64.h>#include <linux/uaccess.h>#include <linux/ioport.h>#include <linux/dcache.h>#include <linux/cred.h>#include <linux/rtc.h>#include <linux/sprintf.h>#include <linux/time.h>#include <linux/uuid.h>#include <linux/of.h>#include <net/addrconf.h>#include <linux/siphash.h>#include <linux/compiler.h>#include <linux/property.h>#include <linux/notifier.h>#ifdef CONFIG_BLOCK#include <linux/blkdev.h>#endif #include "../mm/internal.h"	/* For the trace_print_flags arrays */ #include <asm/page.h>		/* for PAGE_SIZE */#include <asm/byteorder.h>	/* cpu_to_le16 */#include <linux/unaligned.h> #include <linux/string_helpers.h>#include "kstrtox.h" /* Disable pointer hashing if requested */bool no_hash_pointers __ro_after_init;EXPORT_SYMBOL_FOR_MODULES(no_hash_pointers, "printf_kunit"); /* * Hashed pointers policy selected by "hash_pointers=..." boot param * * `auto`   - Hashed pointers enabled unless disabled by slub_debug_enabled=true * `always` - Hashed pointers enabled unconditionally * `never`  - Hashed pointers disabled unconditionally */enum hash_pointers_policy {	HASH_PTR_AUTO = 0,	HASH_PTR_ALWAYS,	HASH_PTR_NEVER};static enum hash_pointers_policy hash_pointers_mode __initdata; noinlinestatic unsigned long long simple_strntoull(const char *startp, char **endp, unsigned int base, size_t max_chars){	const char *cp;	unsigned long long result = 0ULL;	size_t prefix_chars;	unsigned int rv; 	cp = _parse_integer_fixup_radix(startp, &base);	prefix_chars = cp - startp;	if (prefix_chars < max_chars) {		rv = _parse_integer_limit(cp, base, &result, max_chars - prefix_chars);		/* FIXME */		cp += (rv & ~KSTRTOX_OVERFLOW);	} else {		/* Field too short for prefix + digit, skip over without converting */		cp = startp + max_chars;	} 	if (endp)		*endp = (char *)cp; 	return result;} /** * simple_strtoull - convert a string to an unsigned long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function has caveats. Please use kstrtoull instead. */noinlineunsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base){	return simple_strntoull(cp, endp, base, INT_MAX);}EXPORT_SYMBOL(simple_strtoull); /** * simple_strtoul - convert a string to an unsigned long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function has caveats. Please use kstrtoul instead. */unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base){	return simple_strtoull(cp, endp, base);}EXPORT_SYMBOL(simple_strtoul); /** * simple_strtol - convert a string to a signed long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function has caveats. Please use kstrtol instead. */long simple_strtol(const char *cp, char **endp, unsigned int base){	if (*cp == '-')		return -simple_strtoul(cp + 1, endp, base); 	return simple_strtoul(cp, endp, base);}EXPORT_SYMBOL(simple_strtol); noinlinestatic long long simple_strntoll(const char *cp, char **endp, unsigned int base, size_t max_chars){	/*	 * simple_strntoull() safely handles receiving max_chars==0 in the	 * case cp[0] == '-' && max_chars == 1.	 * If max_chars == 0 we can drop through and pass it to simple_strntoull()	 * and the content of *cp is irrelevant.	 */	if (*cp == '-' && max_chars > 0)		return -simple_strntoull(cp + 1, endp, base, max_chars - 1); 	return simple_strntoull(cp, endp, base, max_chars);} /** * simple_strtoll - convert a string to a signed long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function has caveats. Please use kstrtoll instead. */long long simple_strtoll(const char *cp, char **endp, unsigned int base){	return simple_strntoll(cp, endp, base, INT_MAX);}EXPORT_SYMBOL(simple_strtoll); static inline int skip_atoi(const char **s){	int i = 0; 	do {		i = i*10 + *((*s)++) - '0';	} while (isdigit(**s)); 	return i;} /* * Decimal conversion is by far the most typical, and is used for * /proc and /sys data. This directly impacts e.g. top performance * with many processes running. We optimize it for speed by emitting * two characters at a time, using a 200 byte lookup table. This * roughly halves the number of multiplications compared to computing * the digits one at a time. Implementation strongly inspired by the * previous version, which in turn used ideas described at * <http://www.cs.uiowa.edu/~jones/bcd/divide.html> (with permission * from the author, Douglas W. Jones). * * It turns out there is precisely one 26 bit fixed-point * approximation a of 64/100 for which x/100 == (x * (u64)a) >> 32 * holds for all x in [0, 10^8-1], namely a = 0x28f5c29. The actual * range happens to be somewhat larger (x <= 1073741898), but that's * irrelevant for our purpose. * * For dividing a number in the range [10^4, 10^6-1] by 100, we still * need a 32x32->64 bit multiply, so we simply use the same constant. * * For dividing a number in the range [100, 10^4-1] by 100, there are * several options. The simplest is (x * 0x147b) >> 19, which is valid * for all x <= 43698. */ static const u16 decpair[100] = {#define _(x) (__force u16) cpu_to_le16(((x % 10) | ((x / 10) << 8)) + 0x3030)	_( 0), _( 1), _( 2), _( 3), _( 4), _( 5), _( 6), _( 7), _( 8), _( 9),	_(10), _(11), _(12), _(13), _(14), _(15), _(16), _(17), _(18), _(19),	_(20), _(21), _(22), _(23), _(24), _(25), _(26), _(27), _(28), _(29),	_(30), _(31), _(32), _(33), _(34), _(35), _(36), _(37), _(38), _(39),	_(40), _(41), _(42), _(43), _(44), _(45), _(46), _(47), _(48), _(49),	_(50), _(51), _(52), _(53), _(54), _(55), _(56), _(57), _(58), _(59),	_(60), _(61), _(62), _(63), _(64), _(65), _(66), _(67), _(68), _(69),	_(70), _(71), _(72), _(73), _(74), _(75), _(76), _(77), _(78), _(79),	_(80), _(81), _(82), _(83), _(84), _(85), _(86), _(87), _(88), _(89),	_(90), _(91), _(92), _(93), _(94), _(95), _(96), _(97), _(98), _(99),#undef _}; /* * This will print a single '0' even if r == 0, since we would * immediately jump to out_r where two 0s would be written but only * one of them accounted for in buf. This is needed by ip4_string * below. All other callers pass a non-zero value of r.*/static noinline_for_stackchar *put_dec_trunc8(char *buf, unsigned r){	unsigned q; 	/* 1 <= r < 10^8 */	if (r < 100)		goto out_r; 	/* 100 <= r < 10^8 */	q = (r * (u64)0x28f5c29) >> 32;	*((u16 *)buf) = decpair[r - 100*q];	buf += 2; 	/* 1 <= q < 10^6 */	if (q < 100)		goto out_q; 	/*  100 <= q < 10^6 */	r = (q * (u64)0x28f5c29) >> 32;	*((u16 *)buf) = decpair[q - 100*r];	buf += 2; 	/* 1 <= r < 10^4 */	if (r < 100)		goto out_r; 	/* 100 <= r < 10^4 */	q = (r * 0x147b) >> 19;	*((u16 *)buf) = decpair[r - 100*q];	buf += 2;out_q:	/* 1 <= q < 100 */	r = q;out_r:	/* 1 <= r < 100 */	*((u16 *)buf) = decpair[r];	buf += r < 10 ? 1 : 2;	return buf;} #if BITS_PER_LONG == 64 && BITS_PER_LONG_LONG == 64static noinline_for_stackchar *put_dec_full8(char *buf, unsigned r){	unsigned q; 	/* 0 <= r < 10^8 */	q = (r * (u64)0x28f5c29) >> 32;	*((u16 *)buf) = decpair[r - 100*q];	buf += 2; 	/* 0 <= q < 10^6 */	r = (q * (u64)0x28f5c29) >> 32;	*((u16 *)buf) = decpair[q - 100*r];	buf += 2; 	/* 0 <= r < 10^4 */	q = (r * 0x147b) >> 19;	*((u16 *)buf) = decpair[r - 100*q];	buf += 2; 	/* 0 <= q < 100 */	*((u16 *)buf) = decpair[q];	buf += 2;	return buf;} static noinline_for_stackchar *put_dec(char *buf, unsigned long long n){	if (n >= 100*1000*1000)		buf = put_dec_full8(buf, do_div(n, 100*1000*1000));	/* 1 <= n <= 1.6e11 */	if (n >= 100*1000*1000)		buf = put_dec_full8(buf, do_div(n, 100*1000*1000));	/* 1 <= n < 1e8 */	return put_dec_trunc8(buf, n);} #elif BITS_PER_LONG == 32 && BITS_PER_LONG_LONG == 64 static voidput_dec_full4(char *buf, unsigned r){	unsigned q; 	/* 0 <= r < 10^4 */	q = (r * 0x147b) >> 19;	*((u16 *)buf) = decpair[r - 100*q];	buf += 2;	/* 0 <= q < 100 */	*((u16 *)buf) = decpair[q];} /* * Call put_dec_full4 on x % 10000, return x / 10000. * The approximation x/10000 == (x * 0x346DC5D7) >> 43 * holds for all x < 1,128,869,999.  The largest value this * helper will ever be asked to convert is 1,125,520,955. * (second call in the put_dec code, assuming n is all-ones). */static noinline_for_stackunsigned put_dec_helper4(char *buf, unsigned x){        uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43;         put_dec_full4(buf, x - q * 10000);        return q;} /* Based on code by Douglas W. Jones found at * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> * (with permission from the author). * Performs no 64-bit division and hence should be fast on 32-bit machines. */staticchar *put_dec(char *buf, unsigned long long n){	uint32_t d3, d2, d1, q, h; 	if (n < 100*1000*1000)		return put_dec_trunc8(buf, n); 	d1  = ((uint32_t)n >> 16); /* implicit "& 0xffff" */	h   = (n >> 32);	d2  = (h      ) & 0xffff;	d3  = (h >> 16); /* implicit "& 0xffff" */ 	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */	q   = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff);	q = put_dec_helper4(buf, q); 	q += 7671 * d3 + 9496 * d2 + 6 * d1;	q = put_dec_helper4(buf+4, q); 	q += 4749 * d3 + 42 * d2;	q = put_dec_helper4(buf+8, q); 	q += 281 * d3;	buf += 12;	if (q)		buf = put_dec_trunc8(buf, q);	else while (buf[-1] == '0')		--buf; 	return buf;} #endif /* * Convert passed number to decimal string. * Returns the length of string.  On buffer overflow, returns 0. * * If speed is not important, use snprintf(). It's easy to read the code. */int num_to_str(char *buf, int size, unsigned long long num, unsigned int width){	/* put_dec requires 2-byte alignment of the buffer. */	char tmp[sizeof(num) * 3] __aligned(2);	int idx, len; 	/* put_dec() may work incorrectly for num = 0 (generate "", not "0") */	if (num <= 9) {		tmp[0] = '0' + num;		len = 1;	} else {		len = put_dec(tmp, num) - tmp;	} 	if (len > size || width > size)		return 0; 	if (width > len) {		width = width - len;		for (idx = 0; idx < width; idx++)			buf[idx] = ' ';	} else {		width = 0;	} 	for (idx = 0; idx < len; ++idx)		buf[idx + width] = tmp[len - idx - 1]; 	return len + width;} #define SIGN	1		/* unsigned/signed */#define LEFT	2		/* left justified */#define PLUS	4		/* show plus */#define SPACE	8		/* space if plus */#define ZEROPAD	16		/* pad with zero, must be 16 == '0' - ' ' */#define SMALL	32		/* use lowercase in hex (must be 32 == 0x20) */#define SPECIAL	64		/* prefix hex with "0x", octal with "0" */ static_assert(ZEROPAD == ('0' - ' '));static_assert(SMALL == ('a' ^ 'A')); enum format_state {	FORMAT_STATE_NONE, /* Just a string part */	FORMAT_STATE_NUM,	FORMAT_STATE_WIDTH,	FORMAT_STATE_PRECISION,	FORMAT_STATE_CHAR,	FORMAT_STATE_STR,	FORMAT_STATE_PTR,	FORMAT_STATE_PERCENT_CHAR,	FORMAT_STATE_INVALID,}; struct printf_spec {	unsigned char	flags;		/* flags to number() */	unsigned char	base;		/* number base, 8, 10 or 16 only */	short		precision;	/* # of digits/chars */	int		field_width;	/* width of output field */} __packed;static_assert(sizeof(struct printf_spec) == 8); #define FIELD_WIDTH_MAX ((1 << 23) - 1)#define PRECISION_MAX ((1 << 15) - 1) static noinline_for_stackchar *number(char *buf, char *end, unsigned long long num,	     struct printf_spec spec){	/* put_dec requires 2-byte alignment of the buffer. */	char tmp[3 * sizeof(num)] __aligned(2);	char sign;	char locase;	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);	int i;	bool is_zero = num == 0LL;	int field_width = spec.field_width;	int precision = spec.precision; 	/* locase = 0 or 0x20. ORing digits or letters with 'locase'	 * produces same digits or (maybe lowercased) letters */	locase = (spec.flags & SMALL);	if (spec.flags & LEFT)		spec.flags &= ~ZEROPAD;	sign = 0;	if (spec.flags & SIGN) {		if ((signed long long)num < 0) {			sign = '-';			num = -(signed long long)num;			field_width--;		} else if (spec.flags & PLUS) {			sign = '+';			field_width--;		} else if (spec.flags & SPACE) {			sign = ' ';			field_width--;		}	}	if (need_pfx) {		if (spec.base == 16)			field_width -= 2;		else if (!is_zero)			field_width--;	} 	/* generate full string in tmp[], in reverse order */	i = 0;	if (num < spec.base)

Lines 1–500 of 3746.