cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vsprintf.c (12109B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* -*- linux-c -*- ------------------------------------------------------- *
      3 *
      4 *   Copyright (C) 1991, 1992 Linus Torvalds
      5 *   Copyright 2007 rPath, Inc. - All Rights Reserved
      6 *
      7 * ----------------------------------------------------------------------- */
      8
      9/*
     10 * Oh, it's a waste of space, but oh-so-yummy for debugging.
     11 */
     12
     13#include <linux/stdarg.h>
     14
     15#include <linux/compiler.h>
     16#include <linux/ctype.h>
     17#include <linux/kernel.h>
     18#include <linux/limits.h>
     19#include <linux/string.h>
     20#include <linux/types.h>
     21
     22static
     23int skip_atoi(const char **s)
     24{
     25	int i = 0;
     26
     27	while (isdigit(**s))
     28		i = i * 10 + *((*s)++) - '0';
     29	return i;
     30}
     31
     32/*
     33 * put_dec_full4 handles numbers in the range 0 <= r < 10000.
     34 * The multiplier 0xccd is round(2^15/10), and the approximation
     35 * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
     36 */
     37static
     38void put_dec_full4(char *end, unsigned int r)
     39{
     40	int i;
     41
     42	for (i = 0; i < 3; i++) {
     43		unsigned int q = (r * 0xccd) >> 15;
     44		*--end = '0' + (r - q * 10);
     45		r = q;
     46	}
     47	*--end = '0' + r;
     48}
     49
     50/* put_dec is copied from lib/vsprintf.c with small modifications */
     51
     52/*
     53 * Call put_dec_full4 on x % 10000, return x / 10000.
     54 * The approximation x/10000 == (x * 0x346DC5D7) >> 43
     55 * holds for all x < 1,128,869,999.  The largest value this
     56 * helper will ever be asked to convert is 1,125,520,955.
     57 * (second call in the put_dec code, assuming n is all-ones).
     58 */
     59static
     60unsigned int put_dec_helper4(char *end, unsigned int x)
     61{
     62	unsigned int q = (x * 0x346DC5D7ULL) >> 43;
     63
     64	put_dec_full4(end, x - q * 10000);
     65	return q;
     66}
     67
     68/* Based on code by Douglas W. Jones found at
     69 * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
     70 * (with permission from the author).
     71 * Performs no 64-bit division and hence should be fast on 32-bit machines.
     72 */
     73static
     74char *put_dec(char *end, unsigned long long n)
     75{
     76	unsigned int d3, d2, d1, q, h;
     77	char *p = end;
     78
     79	d1  = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
     80	h   = (n >> 32);
     81	d2  = (h      ) & 0xffff;
     82	d3  = (h >> 16); /* implicit "& 0xffff" */
     83
     84	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
     85	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
     86	q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
     87	q = put_dec_helper4(p, q);
     88	p -= 4;
     89
     90	q += 7671 * d3 + 9496 * d2 + 6 * d1;
     91	q = put_dec_helper4(p, q);
     92	p -= 4;
     93
     94	q += 4749 * d3 + 42 * d2;
     95	q = put_dec_helper4(p, q);
     96	p -= 4;
     97
     98	q += 281 * d3;
     99	q = put_dec_helper4(p, q);
    100	p -= 4;
    101
    102	put_dec_full4(p, q);
    103	p -= 4;
    104
    105	/* strip off the extra 0's we printed */
    106	while (p < end && *p == '0')
    107		++p;
    108
    109	return p;
    110}
    111
    112static
    113char *number(char *end, unsigned long long num, int base, char locase)
    114{
    115	/*
    116	 * locase = 0 or 0x20. ORing digits or letters with 'locase'
    117	 * produces same digits or (maybe lowercased) letters
    118	 */
    119
    120	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
    121	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
    122
    123	switch (base) {
    124	case 10:
    125		if (num != 0)
    126			end = put_dec(end, num);
    127		break;
    128	case 8:
    129		for (; num != 0; num >>= 3)
    130			*--end = '0' + (num & 07);
    131		break;
    132	case 16:
    133		for (; num != 0; num >>= 4)
    134			*--end = digits[num & 0xf] | locase;
    135		break;
    136	default:
    137		unreachable();
    138	}
    139
    140	return end;
    141}
    142
    143#define ZEROPAD	1		/* pad with zero */
    144#define SIGN	2		/* unsigned/signed long */
    145#define PLUS	4		/* show plus */
    146#define SPACE	8		/* space if plus */
    147#define LEFT	16		/* left justified */
    148#define SMALL	32		/* Must be 32 == 0x20 */
    149#define SPECIAL	64		/* 0x */
    150#define WIDE	128		/* UTF-16 string */
    151
    152static
    153int get_flags(const char **fmt)
    154{
    155	int flags = 0;
    156
    157	do {
    158		switch (**fmt) {
    159		case '-':
    160			flags |= LEFT;
    161			break;
    162		case '+':
    163			flags |= PLUS;
    164			break;
    165		case ' ':
    166			flags |= SPACE;
    167			break;
    168		case '#':
    169			flags |= SPECIAL;
    170			break;
    171		case '0':
    172			flags |= ZEROPAD;
    173			break;
    174		default:
    175			return flags;
    176		}
    177		++(*fmt);
    178	} while (1);
    179}
    180
    181static
    182int get_int(const char **fmt, va_list *ap)
    183{
    184	if (isdigit(**fmt))
    185		return skip_atoi(fmt);
    186	if (**fmt == '*') {
    187		++(*fmt);
    188		/* it's the next argument */
    189		return va_arg(*ap, int);
    190	}
    191	return 0;
    192}
    193
    194static
    195unsigned long long get_number(int sign, int qualifier, va_list *ap)
    196{
    197	if (sign) {
    198		switch (qualifier) {
    199		case 'L':
    200			return va_arg(*ap, long long);
    201		case 'l':
    202			return va_arg(*ap, long);
    203		case 'h':
    204			return (short)va_arg(*ap, int);
    205		case 'H':
    206			return (signed char)va_arg(*ap, int);
    207		default:
    208			return va_arg(*ap, int);
    209		};
    210	} else {
    211		switch (qualifier) {
    212		case 'L':
    213			return va_arg(*ap, unsigned long long);
    214		case 'l':
    215			return va_arg(*ap, unsigned long);
    216		case 'h':
    217			return (unsigned short)va_arg(*ap, int);
    218		case 'H':
    219			return (unsigned char)va_arg(*ap, int);
    220		default:
    221			return va_arg(*ap, unsigned int);
    222		}
    223	}
    224}
    225
    226static
    227char get_sign(long long *num, int flags)
    228{
    229	if (!(flags & SIGN))
    230		return 0;
    231	if (*num < 0) {
    232		*num = -(*num);
    233		return '-';
    234	}
    235	if (flags & PLUS)
    236		return '+';
    237	if (flags & SPACE)
    238		return ' ';
    239	return 0;
    240}
    241
    242static
    243size_t utf16s_utf8nlen(const u16 *s16, size_t maxlen)
    244{
    245	size_t len, clen;
    246
    247	for (len = 0; len < maxlen && *s16; len += clen) {
    248		u16 c0 = *s16++;
    249
    250		/* First, get the length for a BMP character */
    251		clen = 1 + (c0 >= 0x80) + (c0 >= 0x800);
    252		if (len + clen > maxlen)
    253			break;
    254		/*
    255		 * If this is a high surrogate, and we're already at maxlen, we
    256		 * can't include the character if it's a valid surrogate pair.
    257		 * Avoid accessing one extra word just to check if it's valid
    258		 * or not.
    259		 */
    260		if ((c0 & 0xfc00) == 0xd800) {
    261			if (len + clen == maxlen)
    262				break;
    263			if ((*s16 & 0xfc00) == 0xdc00) {
    264				++s16;
    265				++clen;
    266			}
    267		}
    268	}
    269
    270	return len;
    271}
    272
    273static
    274u32 utf16_to_utf32(const u16 **s16)
    275{
    276	u16 c0, c1;
    277
    278	c0 = *(*s16)++;
    279	/* not a surrogate */
    280	if ((c0 & 0xf800) != 0xd800)
    281		return c0;
    282	/* invalid: low surrogate instead of high */
    283	if (c0 & 0x0400)
    284		return 0xfffd;
    285	c1 = **s16;
    286	/* invalid: missing low surrogate */
    287	if ((c1 & 0xfc00) != 0xdc00)
    288		return 0xfffd;
    289	/* valid surrogate pair */
    290	++(*s16);
    291	return (0x10000 - (0xd800 << 10) - 0xdc00) + (c0 << 10) + c1;
    292}
    293
    294#define PUTC(c) \
    295do {				\
    296	if (pos < size)		\
    297		buf[pos] = (c);	\
    298	++pos;			\
    299} while (0);
    300
    301int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
    302{
    303	/* The maximum space required is to print a 64-bit number in octal */
    304	char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
    305	char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
    306	long long num;
    307	int base;
    308	const char *s;
    309	size_t len, pos;
    310	char sign;
    311
    312	int flags;		/* flags to number() */
    313
    314	int field_width;	/* width of output field */
    315	int precision;		/* min. # of digits for integers; max
    316				   number of chars for from string */
    317	int qualifier;		/* 'h', 'hh', 'l' or 'll' for integer fields */
    318
    319	va_list args;
    320
    321	/*
    322	 * We want to pass our input va_list to helper functions by reference,
    323	 * but there's an annoying edge case. If va_list was originally passed
    324	 * to us by value, we could just pass &ap down to the helpers. This is
    325	 * the case on, for example, X86_32.
    326	 * However, on X86_64 (and possibly others), va_list is actually a
    327	 * size-1 array containing a structure. Our function parameter ap has
    328	 * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
    329	 * which is what will be expected by a function taking a va_list *
    330	 * parameter.
    331	 * One standard way to solve this mess is by creating a copy in a local
    332	 * variable of type va_list and then passing a pointer to that local
    333	 * copy instead, which is what we do here.
    334	 */
    335	va_copy(args, ap);
    336
    337	for (pos = 0; *fmt; ++fmt) {
    338		if (*fmt != '%' || *++fmt == '%') {
    339			PUTC(*fmt);
    340			continue;
    341		}
    342
    343		/* process flags */
    344		flags = get_flags(&fmt);
    345
    346		/* get field width */
    347		field_width = get_int(&fmt, &args);
    348		if (field_width < 0) {
    349			field_width = -field_width;
    350			flags |= LEFT;
    351		}
    352
    353		if (flags & LEFT)
    354			flags &= ~ZEROPAD;
    355
    356		/* get the precision */
    357		precision = -1;
    358		if (*fmt == '.') {
    359			++fmt;
    360			precision = get_int(&fmt, &args);
    361			if (precision >= 0)
    362				flags &= ~ZEROPAD;
    363		}
    364
    365		/* get the conversion qualifier */
    366		qualifier = -1;
    367		if (*fmt == 'h' || *fmt == 'l') {
    368			qualifier = *fmt;
    369			++fmt;
    370			if (qualifier == *fmt) {
    371				qualifier -= 'a'-'A';
    372				++fmt;
    373			}
    374		}
    375
    376		sign = 0;
    377
    378		switch (*fmt) {
    379		case 'c':
    380			flags &= LEFT;
    381			s = tmp;
    382			if (qualifier == 'l') {
    383				((u16 *)tmp)[0] = (u16)va_arg(args, unsigned int);
    384				((u16 *)tmp)[1] = L'\0';
    385				precision = INT_MAX;
    386				goto wstring;
    387			} else {
    388				tmp[0] = (unsigned char)va_arg(args, int);
    389				precision = len = 1;
    390			}
    391			goto output;
    392
    393		case 's':
    394			flags &= LEFT;
    395			if (precision < 0)
    396				precision = INT_MAX;
    397			s = va_arg(args, void *);
    398			if (!s)
    399				s = precision < 6 ? "" : "(null)";
    400			else if (qualifier == 'l') {
    401		wstring:
    402				flags |= WIDE;
    403				precision = len = utf16s_utf8nlen((const u16 *)s, precision);
    404				goto output;
    405			}
    406			precision = len = strnlen(s, precision);
    407			goto output;
    408
    409			/* integer number formats - set up the flags and "break" */
    410		case 'o':
    411			base = 8;
    412			break;
    413
    414		case 'p':
    415			if (precision < 0)
    416				precision = 2 * sizeof(void *);
    417			fallthrough;
    418		case 'x':
    419			flags |= SMALL;
    420			fallthrough;
    421		case 'X':
    422			base = 16;
    423			break;
    424
    425		case 'd':
    426		case 'i':
    427			flags |= SIGN;
    428			fallthrough;
    429		case 'u':
    430			flags &= ~SPECIAL;
    431			base = 10;
    432			break;
    433
    434		default:
    435			/*
    436			 * Bail out if the conversion specifier is invalid.
    437			 * There's probably a typo in the format string and the
    438			 * remaining specifiers are unlikely to match up with
    439			 * the arguments.
    440			 */
    441			goto fail;
    442		}
    443		if (*fmt == 'p') {
    444			num = (unsigned long)va_arg(args, void *);
    445		} else {
    446			num = get_number(flags & SIGN, qualifier, &args);
    447		}
    448
    449		sign = get_sign(&num, flags);
    450		if (sign)
    451			--field_width;
    452
    453		s = number(tmp_end, num, base, flags & SMALL);
    454		len = tmp_end - s;
    455		/* default precision is 1 */
    456		if (precision < 0)
    457			precision = 1;
    458		/* precision is minimum number of digits to print */
    459		if (precision < len)
    460			precision = len;
    461		if (flags & SPECIAL) {
    462			/*
    463			 * For octal, a leading 0 is printed only if necessary,
    464			 * i.e. if it's not already there because of the
    465			 * precision.
    466			 */
    467			if (base == 8 && precision == len)
    468				++precision;
    469			/*
    470			 * For hexadecimal, the leading 0x is skipped if the
    471			 * output is empty, i.e. both the number and the
    472			 * precision are 0.
    473			 */
    474			if (base == 16 && precision > 0)
    475				field_width -= 2;
    476			else
    477				flags &= ~SPECIAL;
    478		}
    479		/*
    480		 * For zero padding, increase the precision to fill the field
    481		 * width.
    482		 */
    483		if ((flags & ZEROPAD) && field_width > precision)
    484			precision = field_width;
    485
    486output:
    487		/* Calculate the padding necessary */
    488		field_width -= precision;
    489		/* Leading padding with ' ' */
    490		if (!(flags & LEFT))
    491			while (field_width-- > 0)
    492				PUTC(' ');
    493		/* sign */
    494		if (sign)
    495			PUTC(sign);
    496		/* 0x/0X for hexadecimal */
    497		if (flags & SPECIAL) {
    498			PUTC('0');
    499			PUTC( 'X' | (flags & SMALL));
    500		}
    501		/* Zero padding and excess precision */
    502		while (precision-- > len)
    503			PUTC('0');
    504		/* Actual output */
    505		if (flags & WIDE) {
    506			const u16 *ws = (const u16 *)s;
    507
    508			while (len-- > 0) {
    509				u32 c32 = utf16_to_utf32(&ws);
    510				u8 *s8;
    511				size_t clen;
    512
    513				if (c32 < 0x80) {
    514					PUTC(c32);
    515					continue;
    516				}
    517
    518				/* Number of trailing octets */
    519				clen = 1 + (c32 >= 0x800) + (c32 >= 0x10000);
    520
    521				len -= clen;
    522				s8 = (u8 *)&buf[pos];
    523
    524				/* Avoid writing partial character */
    525				PUTC('\0');
    526				pos += clen;
    527				if (pos >= size)
    528					continue;
    529
    530				/* Set high bits of leading octet */
    531				*s8 = (0xf00 >> 1) >> clen;
    532				/* Write trailing octets in reverse order */
    533				for (s8 += clen; clen; --clen, c32 >>= 6)
    534					*s8-- = 0x80 | (c32 & 0x3f);
    535				/* Set low bits of leading octet */
    536				*s8 |= c32;
    537			}
    538		} else {
    539			while (len-- > 0)
    540				PUTC(*s++);
    541		}
    542		/* Trailing padding with ' ' */
    543		while (field_width-- > 0)
    544			PUTC(' ');
    545	}
    546fail:
    547	va_end(args);
    548
    549	if (size)
    550		buf[min(pos, size-1)] = '\0';
    551
    552	return pos;
    553}
    554
    555int snprintf(char *buf, size_t size, const char *fmt, ...)
    556{
    557	va_list args;
    558	int i;
    559
    560	va_start(args, fmt);
    561	i = vsnprintf(buf, size, fmt, args);
    562	va_end(args);
    563	return i;
    564}