1e5119382SAaron Lewis // SPDX-License-Identifier: GPL-2.0-only
2e5119382SAaron Lewis #include "test_util.h"
3e5119382SAaron Lewis #include "kvm_util.h"
4e5119382SAaron Lewis #include "ucall_common.h"
5e5119382SAaron Lewis
6e5119382SAaron Lewis #define APPEND_BUFFER_SAFE(str, end, v) \
7e5119382SAaron Lewis do { \
8e5119382SAaron Lewis GUEST_ASSERT(str < end); \
9e5119382SAaron Lewis *str++ = (v); \
10e5119382SAaron Lewis } while (0)
11e5119382SAaron Lewis
isdigit(int ch)12e5119382SAaron Lewis static int isdigit(int ch)
13e5119382SAaron Lewis {
14e5119382SAaron Lewis return (ch >= '0') && (ch <= '9');
15e5119382SAaron Lewis }
16e5119382SAaron Lewis
skip_atoi(const char ** s)17e5119382SAaron Lewis static int skip_atoi(const char **s)
18e5119382SAaron Lewis {
19e5119382SAaron Lewis int i = 0;
20e5119382SAaron Lewis
21e5119382SAaron Lewis while (isdigit(**s))
22e5119382SAaron Lewis i = i * 10 + *((*s)++) - '0';
23e5119382SAaron Lewis return i;
24e5119382SAaron Lewis }
25e5119382SAaron Lewis
26e5119382SAaron Lewis #define ZEROPAD 1 /* pad with zero */
27e5119382SAaron Lewis #define SIGN 2 /* unsigned/signed long */
28e5119382SAaron Lewis #define PLUS 4 /* show plus */
29e5119382SAaron Lewis #define SPACE 8 /* space if plus */
30e5119382SAaron Lewis #define LEFT 16 /* left justified */
31e5119382SAaron Lewis #define SMALL 32 /* Must be 32 == 0x20 */
32e5119382SAaron Lewis #define SPECIAL 64 /* 0x */
33e5119382SAaron Lewis
34e5119382SAaron Lewis #define __do_div(n, base) \
35e5119382SAaron Lewis ({ \
36e5119382SAaron Lewis int __res; \
37e5119382SAaron Lewis \
38e5119382SAaron Lewis __res = ((uint64_t) n) % (uint32_t) base; \
39e5119382SAaron Lewis n = ((uint64_t) n) / (uint32_t) base; \
40e5119382SAaron Lewis __res; \
41e5119382SAaron Lewis })
42e5119382SAaron Lewis
number(char * str,const char * end,long num,int base,int size,int precision,int type)43e5119382SAaron Lewis static char *number(char *str, const char *end, long num, int base, int size,
44e5119382SAaron Lewis int precision, int type)
45e5119382SAaron Lewis {
46e5119382SAaron Lewis /* we are called with base 8, 10 or 16, only, thus don't need "G..." */
47e5119382SAaron Lewis static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
48e5119382SAaron Lewis
49e5119382SAaron Lewis char tmp[66];
50e5119382SAaron Lewis char c, sign, locase;
51e5119382SAaron Lewis int i;
52e5119382SAaron Lewis
53e5119382SAaron Lewis /*
54e5119382SAaron Lewis * locase = 0 or 0x20. ORing digits or letters with 'locase'
55e5119382SAaron Lewis * produces same digits or (maybe lowercased) letters
56e5119382SAaron Lewis */
57e5119382SAaron Lewis locase = (type & SMALL);
58e5119382SAaron Lewis if (type & LEFT)
59e5119382SAaron Lewis type &= ~ZEROPAD;
60e5119382SAaron Lewis if (base < 2 || base > 16)
61e5119382SAaron Lewis return NULL;
62e5119382SAaron Lewis c = (type & ZEROPAD) ? '0' : ' ';
63e5119382SAaron Lewis sign = 0;
64e5119382SAaron Lewis if (type & SIGN) {
65e5119382SAaron Lewis if (num < 0) {
66e5119382SAaron Lewis sign = '-';
67e5119382SAaron Lewis num = -num;
68e5119382SAaron Lewis size--;
69e5119382SAaron Lewis } else if (type & PLUS) {
70e5119382SAaron Lewis sign = '+';
71e5119382SAaron Lewis size--;
72e5119382SAaron Lewis } else if (type & SPACE) {
73e5119382SAaron Lewis sign = ' ';
74e5119382SAaron Lewis size--;
75e5119382SAaron Lewis }
76e5119382SAaron Lewis }
77e5119382SAaron Lewis if (type & SPECIAL) {
78e5119382SAaron Lewis if (base == 16)
79e5119382SAaron Lewis size -= 2;
80e5119382SAaron Lewis else if (base == 8)
81e5119382SAaron Lewis size--;
82e5119382SAaron Lewis }
83e5119382SAaron Lewis i = 0;
84e5119382SAaron Lewis if (num == 0)
85e5119382SAaron Lewis tmp[i++] = '0';
86e5119382SAaron Lewis else
87e5119382SAaron Lewis while (num != 0)
88e5119382SAaron Lewis tmp[i++] = (digits[__do_div(num, base)] | locase);
89e5119382SAaron Lewis if (i > precision)
90e5119382SAaron Lewis precision = i;
91e5119382SAaron Lewis size -= precision;
92e5119382SAaron Lewis if (!(type & (ZEROPAD + LEFT)))
93e5119382SAaron Lewis while (size-- > 0)
94e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, ' ');
95e5119382SAaron Lewis if (sign)
96e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, sign);
97e5119382SAaron Lewis if (type & SPECIAL) {
98e5119382SAaron Lewis if (base == 8)
99e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, '0');
100e5119382SAaron Lewis else if (base == 16) {
101e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, '0');
102e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, 'x');
103e5119382SAaron Lewis }
104e5119382SAaron Lewis }
105e5119382SAaron Lewis if (!(type & LEFT))
106e5119382SAaron Lewis while (size-- > 0)
107e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, c);
108e5119382SAaron Lewis while (i < precision--)
109e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, '0');
110e5119382SAaron Lewis while (i-- > 0)
111e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, tmp[i]);
112e5119382SAaron Lewis while (size-- > 0)
113e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, ' ');
114e5119382SAaron Lewis
115e5119382SAaron Lewis return str;
116e5119382SAaron Lewis }
117e5119382SAaron Lewis
guest_vsnprintf(char * buf,int n,const char * fmt,va_list args)118e5119382SAaron Lewis int guest_vsnprintf(char *buf, int n, const char *fmt, va_list args)
119e5119382SAaron Lewis {
120e5119382SAaron Lewis char *str, *end;
121e5119382SAaron Lewis const char *s;
122e5119382SAaron Lewis uint64_t num;
123e5119382SAaron Lewis int i, base;
124e5119382SAaron Lewis int len;
125e5119382SAaron Lewis
126e5119382SAaron Lewis int flags; /* flags to number() */
127e5119382SAaron Lewis
128e5119382SAaron Lewis int field_width; /* width of output field */
129e5119382SAaron Lewis int precision; /*
130e5119382SAaron Lewis * min. # of digits for integers; max
131e5119382SAaron Lewis * number of chars for from string
132e5119382SAaron Lewis */
133e5119382SAaron Lewis int qualifier; /* 'h', 'l', or 'L' for integer fields */
134e5119382SAaron Lewis
135e5119382SAaron Lewis end = buf + n;
136e5119382SAaron Lewis GUEST_ASSERT(buf < end);
137e5119382SAaron Lewis GUEST_ASSERT(n > 0);
138e5119382SAaron Lewis
139e5119382SAaron Lewis for (str = buf; *fmt; ++fmt) {
140e5119382SAaron Lewis if (*fmt != '%') {
141e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, *fmt);
142e5119382SAaron Lewis continue;
143e5119382SAaron Lewis }
144e5119382SAaron Lewis
145e5119382SAaron Lewis /* process flags */
146e5119382SAaron Lewis flags = 0;
147e5119382SAaron Lewis repeat:
148e5119382SAaron Lewis ++fmt; /* this also skips first '%' */
149e5119382SAaron Lewis switch (*fmt) {
150e5119382SAaron Lewis case '-':
151e5119382SAaron Lewis flags |= LEFT;
152e5119382SAaron Lewis goto repeat;
153e5119382SAaron Lewis case '+':
154e5119382SAaron Lewis flags |= PLUS;
155e5119382SAaron Lewis goto repeat;
156e5119382SAaron Lewis case ' ':
157e5119382SAaron Lewis flags |= SPACE;
158e5119382SAaron Lewis goto repeat;
159e5119382SAaron Lewis case '#':
160e5119382SAaron Lewis flags |= SPECIAL;
161e5119382SAaron Lewis goto repeat;
162e5119382SAaron Lewis case '0':
163e5119382SAaron Lewis flags |= ZEROPAD;
164e5119382SAaron Lewis goto repeat;
165e5119382SAaron Lewis }
166e5119382SAaron Lewis
167e5119382SAaron Lewis /* get field width */
168e5119382SAaron Lewis field_width = -1;
169e5119382SAaron Lewis if (isdigit(*fmt))
170e5119382SAaron Lewis field_width = skip_atoi(&fmt);
171e5119382SAaron Lewis else if (*fmt == '*') {
172e5119382SAaron Lewis ++fmt;
173e5119382SAaron Lewis /* it's the next argument */
174e5119382SAaron Lewis field_width = va_arg(args, int);
175e5119382SAaron Lewis if (field_width < 0) {
176e5119382SAaron Lewis field_width = -field_width;
177e5119382SAaron Lewis flags |= LEFT;
178e5119382SAaron Lewis }
179e5119382SAaron Lewis }
180e5119382SAaron Lewis
181e5119382SAaron Lewis /* get the precision */
182e5119382SAaron Lewis precision = -1;
183e5119382SAaron Lewis if (*fmt == '.') {
184e5119382SAaron Lewis ++fmt;
185e5119382SAaron Lewis if (isdigit(*fmt))
186e5119382SAaron Lewis precision = skip_atoi(&fmt);
187e5119382SAaron Lewis else if (*fmt == '*') {
188e5119382SAaron Lewis ++fmt;
189e5119382SAaron Lewis /* it's the next argument */
190e5119382SAaron Lewis precision = va_arg(args, int);
191e5119382SAaron Lewis }
192e5119382SAaron Lewis if (precision < 0)
193e5119382SAaron Lewis precision = 0;
194e5119382SAaron Lewis }
195e5119382SAaron Lewis
196e5119382SAaron Lewis /* get the conversion qualifier */
197e5119382SAaron Lewis qualifier = -1;
198e5119382SAaron Lewis if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
199e5119382SAaron Lewis qualifier = *fmt;
200e5119382SAaron Lewis ++fmt;
201e5119382SAaron Lewis }
202e5119382SAaron Lewis
203*b15e7490SSean Christopherson /*
204*b15e7490SSean Christopherson * Play nice with %llu, %llx, etc. KVM selftests only support
205*b15e7490SSean Christopherson * 64-bit builds, so just treat %ll* the same as %l*.
206*b15e7490SSean Christopherson */
207*b15e7490SSean Christopherson if (qualifier == 'l' && *fmt == 'l')
208*b15e7490SSean Christopherson ++fmt;
209*b15e7490SSean Christopherson
210e5119382SAaron Lewis /* default base */
211e5119382SAaron Lewis base = 10;
212e5119382SAaron Lewis
213e5119382SAaron Lewis switch (*fmt) {
214e5119382SAaron Lewis case 'c':
215e5119382SAaron Lewis if (!(flags & LEFT))
216e5119382SAaron Lewis while (--field_width > 0)
217e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, ' ');
218e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end,
219e5119382SAaron Lewis (uint8_t)va_arg(args, int));
220e5119382SAaron Lewis while (--field_width > 0)
221e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, ' ');
222e5119382SAaron Lewis continue;
223e5119382SAaron Lewis
224e5119382SAaron Lewis case 's':
225e5119382SAaron Lewis s = va_arg(args, char *);
226e5119382SAaron Lewis len = strnlen(s, precision);
227e5119382SAaron Lewis
228e5119382SAaron Lewis if (!(flags & LEFT))
229e5119382SAaron Lewis while (len < field_width--)
230e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, ' ');
231e5119382SAaron Lewis for (i = 0; i < len; ++i)
232e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, *s++);
233e5119382SAaron Lewis while (len < field_width--)
234e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, ' ');
235e5119382SAaron Lewis continue;
236e5119382SAaron Lewis
237e5119382SAaron Lewis case 'p':
238e5119382SAaron Lewis if (field_width == -1) {
239e5119382SAaron Lewis field_width = 2 * sizeof(void *);
240e5119382SAaron Lewis flags |= SPECIAL | SMALL | ZEROPAD;
241e5119382SAaron Lewis }
242e5119382SAaron Lewis str = number(str, end,
243e5119382SAaron Lewis (uint64_t)va_arg(args, void *), 16,
244e5119382SAaron Lewis field_width, precision, flags);
245e5119382SAaron Lewis continue;
246e5119382SAaron Lewis
247e5119382SAaron Lewis case 'n':
248e5119382SAaron Lewis if (qualifier == 'l') {
249e5119382SAaron Lewis long *ip = va_arg(args, long *);
250e5119382SAaron Lewis *ip = (str - buf);
251e5119382SAaron Lewis } else {
252e5119382SAaron Lewis int *ip = va_arg(args, int *);
253e5119382SAaron Lewis *ip = (str - buf);
254e5119382SAaron Lewis }
255e5119382SAaron Lewis continue;
256e5119382SAaron Lewis
257e5119382SAaron Lewis case '%':
258e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, '%');
259e5119382SAaron Lewis continue;
260e5119382SAaron Lewis
261e5119382SAaron Lewis /* integer number formats - set up the flags and "break" */
262e5119382SAaron Lewis case 'o':
263e5119382SAaron Lewis base = 8;
264e5119382SAaron Lewis break;
265e5119382SAaron Lewis
266e5119382SAaron Lewis case 'x':
267e5119382SAaron Lewis flags |= SMALL;
268e5119382SAaron Lewis case 'X':
269e5119382SAaron Lewis base = 16;
270e5119382SAaron Lewis break;
271e5119382SAaron Lewis
272e5119382SAaron Lewis case 'd':
273e5119382SAaron Lewis case 'i':
274e5119382SAaron Lewis flags |= SIGN;
275e5119382SAaron Lewis case 'u':
276e5119382SAaron Lewis break;
277e5119382SAaron Lewis
278e5119382SAaron Lewis default:
279e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, '%');
280e5119382SAaron Lewis if (*fmt)
281e5119382SAaron Lewis APPEND_BUFFER_SAFE(str, end, *fmt);
282e5119382SAaron Lewis else
283e5119382SAaron Lewis --fmt;
284e5119382SAaron Lewis continue;
285e5119382SAaron Lewis }
286e5119382SAaron Lewis if (qualifier == 'l')
287e5119382SAaron Lewis num = va_arg(args, uint64_t);
288e5119382SAaron Lewis else if (qualifier == 'h') {
289e5119382SAaron Lewis num = (uint16_t)va_arg(args, int);
290e5119382SAaron Lewis if (flags & SIGN)
291e5119382SAaron Lewis num = (int16_t)num;
292e5119382SAaron Lewis } else if (flags & SIGN)
293e5119382SAaron Lewis num = va_arg(args, int);
294e5119382SAaron Lewis else
295e5119382SAaron Lewis num = va_arg(args, uint32_t);
296e5119382SAaron Lewis str = number(str, end, num, base, field_width, precision, flags);
297e5119382SAaron Lewis }
298e5119382SAaron Lewis
299e5119382SAaron Lewis GUEST_ASSERT(str < end);
300e5119382SAaron Lewis *str = '\0';
301e5119382SAaron Lewis return str - buf;
302e5119382SAaron Lewis }
303e5119382SAaron Lewis
guest_snprintf(char * buf,int n,const char * fmt,...)304e5119382SAaron Lewis int guest_snprintf(char *buf, int n, const char *fmt, ...)
305e5119382SAaron Lewis {
306e5119382SAaron Lewis va_list va;
307e5119382SAaron Lewis int len;
308e5119382SAaron Lewis
309e5119382SAaron Lewis va_start(va, fmt);
310e5119382SAaron Lewis len = guest_vsnprintf(buf, n, fmt, va);
311e5119382SAaron Lewis va_end(va);
312e5119382SAaron Lewis
313e5119382SAaron Lewis return len;
314e5119382SAaron Lewis }
315