OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
UbsanPrintf.c
Go to the documentation of this file.
1/*
2File: tinyprintf.c
3
4Copyright (c) 2004,2012 Kustaa Nyholm / SpareTimeLabs
5All rights reserved.
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of Kustaa Nyholm or SpareTimeLabs nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
17
18THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER BE LIABLE FOR ANY
22DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29*/
30
31#include "Ubsan.h"
32
33#ifdef HAVE_UBSAN_SUPPORT
34
35/*
36 * Configuration
37 */
38
39/* Enable long int support */
40#define PRINTF_LONG_SUPPORT
41
42/* Enable long long int support (implies long int support) */
43#define PRINTF_LONG_LONG_SUPPORT
44
45/* Enable %z (size_t) support */
46#define PRINTF_SIZE_T_SUPPORT
47
48/*
49 * Configuration adjustments
50 */
51#ifdef PRINTF_SIZE_T_SUPPORT
52// #include <sys/types.h>
53#endif
54
55#ifdef PRINTF_LONG_LONG_SUPPORT
56# define PRINTF_LONG_SUPPORT
57#endif
58
59/* __SIZEOF_<type>__ defined at least by gcc */
60#ifdef __SIZEOF_POINTER__
61# define SIZEOF_POINTER __SIZEOF_POINTER__
62#endif
63#ifdef __SIZEOF_LONG_LONG__
64# define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
65#endif
66#ifdef __SIZEOF_LONG__
67# define SIZEOF_LONG __SIZEOF_LONG__
68#endif
69#ifdef __SIZEOF_INT__
70# define SIZEOF_INT __SIZEOF_INT__
71#endif
72
73#if defined(__GNUC__) || defined(__clang__)
74# define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline))
75#else
76# define _TFP_GCC_NO_INLINE_
77#endif
78
79/*
80 * Implementation
81 */
82struct param {
83 char lz:1;
84 char alt:1;
85 char uc:1;
86 char align_left:1;
87 unsigned int width;
88 char sign;
89 unsigned int base;
90 char *bf;
91};
92
93
94#ifdef PRINTF_LONG_LONG_SUPPORT
95static void _TFP_GCC_NO_INLINE_ ulli2a(
96 unsigned long long int num, struct param *p)
97{
98 int n = 0;
99 unsigned long long int d = 1;
100 char *bf = p->bf;
101 while (num / d >= p->base)
102 d *= p->base;
103 while (d != 0) {
104 int dgt = num / d;
105 num %= d;
106 d /= p->base;
107 if (n || dgt > 0 || d == 0) {
108 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
109 ++n;
110 }
111 }
112 *bf = 0;
113}
114
115static void lli2a(long long int num, struct param *p)
116{
117 if (num < 0) {
118 num = -num;
119 p->sign = '-';
120 }
121 ulli2a(num, p);
122}
123#endif
124
125#ifdef PRINTF_LONG_SUPPORT
126static void uli2a(unsigned long int num, struct param *p)
127{
128 int n = 0;
129 unsigned long int d = 1;
130 char *bf = p->bf;
131 while (num / d >= p->base)
132 d *= p->base;
133 while (d != 0) {
134 int dgt = num / d;
135 num %= d;
136 d /= p->base;
137 if (n || dgt > 0 || d == 0) {
138 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
139 ++n;
140 }
141 }
142 *bf = 0;
143}
144
145static void li2a(long num, struct param *p)
146{
147 if (num < 0) {
148 num = -num;
149 p->sign = '-';
150 }
151 uli2a(num, p);
152}
153#endif
154
155static void ui2a(unsigned int num, struct param *p)
156{
157 int n = 0;
158 unsigned int d = 1;
159 char *bf = p->bf;
160 while (num / d >= p->base)
161 d *= p->base;
162 while (d != 0) {
163 int dgt = num / d;
164 num %= d;
165 d /= p->base;
166 if (n || dgt > 0 || d == 0) {
167 *bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
168 ++n;
169 }
170 }
171 *bf = 0;
172}
173
174static void i2a(int num, struct param *p)
175{
176 if (num < 0) {
177 num = -num;
178 p->sign = '-';
179 }
180 ui2a(num, p);
181}
182
183static int a2d(char ch)
184{
185 if (ch >= '0' && ch <= '9')
186 return ch - '0';
187 else if (ch >= 'a' && ch <= 'f')
188 return ch - 'a' + 10;
189 else if (ch >= 'A' && ch <= 'F')
190 return ch - 'A' + 10;
191 else
192 return -1;
193}
194
195static char a2u(char ch, const char **src, int base, unsigned int *nump)
196{
197 const char *p = *src;
198 unsigned int num = 0;
199 int digit;
200 while ((digit = a2d(ch)) >= 0) {
201 if (digit > base)
202 break;
203 num = num * base + digit;
204 ch = *p++;
205 }
206 *src = p;
207 *nump = num;
208 return ch;
209}
210
211static void putchw(void *putp, putcf putf, struct param *p)
212{
213 char ch;
214 int n = p->width;
215 char *bf = p->bf;
216
217 /* Number of filling characters */
218 while (*bf++ && n > 0)
219 n--;
220 if (p->sign)
221 n--;
222 if (p->alt && p->base == 16)
223 n -= 2;
224 else if (p->alt && p->base == 8)
225 n--;
226
227 /* Fill with space to align to the right, before alternate or sign */
228 if (!p->lz && !p->align_left) {
229 while (n-- > 0)
230 putf(putp, ' ');
231 }
232
233 /* print sign */
234 if (p->sign)
235 putf(putp, p->sign);
236
237 /* Alternate */
238 if (p->alt && p->base == 16) {
239 putf(putp, '0');
240 putf(putp, (p->uc ? 'X' : 'x'));
241 } else if (p->alt && p->base == 8) {
242 putf(putp, '0');
243 }
244
245 /* Fill with zeros, after alternate or sign */
246 if (p->lz) {
247 while (n-- > 0)
248 putf(putp, '0');
249 }
250
251 /* Put actual buffer */
252 bf = p->bf;
253 while ((ch = *bf++))
254 putf(putp, ch);
255
256 /* Fill with space to align to the left, after string */
257 if (!p->lz && p->align_left) {
258 while (n-- > 0)
259 putf(putp, ' ');
260 }
261}
262
263void EFIAPI tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
264{
265 struct param p;
266#ifdef PRINTF_LONG_SUPPORT
267 char bf[23]; /* long = 64b on some architectures */
268#else
269 char bf[12]; /* int = 32b on some architectures */
270#endif
271 char ch;
272 p.bf = bf;
273
274 while ((ch = *(fmt++))) {
275 if (ch != '%') {
276 putf(putp, ch);
277 } else {
278#ifdef PRINTF_LONG_SUPPORT
279 char lng = 0; /* 1 for long, 2 for long long */
280#endif
281 /* Init parameter struct */
282 p.lz = 0;
283 p.alt = 0;
284 p.width = 0;
285 p.align_left = 0;
286 p.sign = 0;
287
288 /* Flags */
289 while ((ch = *(fmt++))) {
290 switch (ch) {
291 case '-':
292 p.align_left = 1;
293 continue;
294 case '0':
295 p.lz = 1;
296 continue;
297 case '#':
298 p.alt = 1;
299 continue;
300 default:
301 break;
302 }
303 break;
304 }
305
306 /* Width */
307 if (ch >= '0' && ch <= '9') {
308 ch = a2u(ch, &fmt, 10, &(p.width));
309 }
310
311 /* We accept 'x.y' format but don't support it completely:
312 * we ignore the 'y' digit => this ignores 0-fill
313 * size and makes it == width (ie. 'x') */
314 if (ch == '.') {
315 p.lz = 1; /* zero-padding */
316 /* ignore actual 0-fill size: */
317 do {
318 ch = *(fmt++);
319 } while ((ch >= '0') && (ch <= '9'));
320 }
321
322#ifdef PRINTF_SIZE_T_SUPPORT
323# ifdef PRINTF_LONG_SUPPORT
324 if (ch == 'z') {
325 ch = *(fmt++);
326 if (sizeof(size_t) == sizeof(unsigned long int))
327 lng = 1;
328# ifdef PRINTF_LONG_LONG_SUPPORT
329 else if (sizeof(size_t) == sizeof(unsigned long long int))
330 lng = 2;
331# endif
332 } else
333# endif
334#endif
335
336#ifdef PRINTF_LONG_SUPPORT
337 if (ch == 'l') {
338 ch = *(fmt++);
339 lng = 1;
340#ifdef PRINTF_LONG_LONG_SUPPORT
341 if (ch == 'l') {
342 ch = *(fmt++);
343 lng = 2;
344 }
345#endif
346 }
347#endif
348 switch (ch) {
349 case 0:
350 goto abort;
351 case 'u':
352 p.base = 10;
353 p.uc = 0;
354#ifdef PRINTF_LONG_SUPPORT
355#ifdef PRINTF_LONG_LONG_SUPPORT
356 if (2 == lng)
357 ulli2a(va_arg(va, unsigned long long int), &p);
358 else
359#endif
360 if (1 == lng)
361 uli2a(va_arg(va, unsigned long int), &p);
362 else
363#endif
364 ui2a(va_arg(va, unsigned int), &p);
365 putchw(putp, putf, &p);
366 break;
367 case 'd':
368 case 'i':
369 p.base = 10;
370#ifdef PRINTF_LONG_SUPPORT
371#ifdef PRINTF_LONG_LONG_SUPPORT
372 if (2 == lng)
373 lli2a(va_arg(va, long long int), &p);
374 else
375#endif
376 if (1 == lng)
377 li2a(va_arg(va, long int), &p);
378 else
379#endif
380 i2a(va_arg(va, int), &p);
381 putchw(putp, putf, &p);
382 break;
383#ifdef SIZEOF_POINTER
384 case 'p':
385 p.alt = 1;
386# if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT
387 lng = 0;
388# elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG
389 lng = 1;
390# elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG
391 lng = 2;
392# endif
393 // Fallthrough
394#endif
395 case 'x':
396 case 'X':
397 p.base = 16;
398 p.uc = (ch == 'X')?1:0;
399#ifdef PRINTF_LONG_SUPPORT
400#ifdef PRINTF_LONG_LONG_SUPPORT
401 if (2 == lng)
402 ulli2a(va_arg(va, unsigned long long int), &p);
403 else
404#endif
405 if (1 == lng)
406 uli2a(va_arg(va, unsigned long int), &p);
407 else
408#endif
409 ui2a(va_arg(va, unsigned int), &p);
410 putchw(putp, putf, &p);
411 break;
412 case 'o':
413 p.base = 8;
414 p.uc = 0;
415 ui2a(va_arg(va, unsigned int), &p);
416 putchw(putp, putf, &p);
417 break;
418 case 'c':
419 putf(putp, (char)(va_arg(va, int)));
420 break;
421 case 's':
422 p.bf = va_arg(va, char *);
423 putchw(putp, putf, &p);
424 p.bf = bf;
425 break;
426 case '%':
427 putf(putp, ch);
428 default:
429 break;
430 }
431 }
432 }
433 abort:;
434}
435
436#if TINYPRINTF_DEFINE_TFP_PRINTF
437static putcf stdout_putf;
438static void *stdout_putp;
439
440void init_printf(void *putp, putcf putf)
441{
442 stdout_putf = putf;
443 stdout_putp = putp;
444}
445
446void EFIAPI tfp_printf(char *fmt, ...)
447{
448 va_list va;
449 va_start(va, fmt);
450 tfp_format(stdout_putp, stdout_putf, fmt, va);
451 va_end(va);
452}
453#endif
454
455#if TINYPRINTF_DEFINE_TFP_SPRINTF
456struct _vsnprintf_putcf_data
457{
458 size_t dest_capacity;
459 char *dest;
460 size_t num_chars;
461};
462
463static void _vsnprintf_putcf(void *p, char c)
464{
465 struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p;
466 if (data->num_chars < data->dest_capacity)
467 data->dest[data->num_chars] = c;
468 data->num_chars ++;
469}
470
471int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
472{
473 struct _vsnprintf_putcf_data data;
474
475 if (size < 1)
476 return 0;
477
478 data.dest = str;
479 data.dest_capacity = size-1;
480 data.num_chars = 0;
481 tfp_format(&data, _vsnprintf_putcf, format, ap);
482
483 if (data.num_chars < data.dest_capacity)
484 data.dest[data.num_chars] = '\0';
485 else
486 data.dest[data.dest_capacity] = '\0';
487
488 return data.num_chars;
489}
490
491int EFIAPI tfp_snprintf(char *str, size_t size, const char *format, ...)
492{
493 va_list ap;
494 int retval;
495
496 va_start(ap, format);
497 retval = tfp_vsnprintf(str, size, format, ap);
498 va_end(ap);
499 return retval;
500}
501
502struct _vsprintf_putcf_data
503{
504 char *dest;
505 size_t num_chars;
506};
507
508static void _vsprintf_putcf(void *p, char c)
509{
510 struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p;
511 data->dest[data->num_chars++] = c;
512}
513
514int EFIAPI tfp_vsprintf(char *str, const char *format, va_list ap)
515{
516 struct _vsprintf_putcf_data data;
517 data.dest = str;
518 data.num_chars = 0;
519 tfp_format(&data, _vsprintf_putcf, format, ap);
520 data.dest[data.num_chars] = '\0';
521 return data.num_chars;
522}
523
524int EFIAPI tfp_sprintf(char *str, const char *format, ...)
525{
526 va_list ap;
527 int retval;
528
529 va_start(ap, format);
530 retval = tfp_vsprintf(str, format, ap);
531 va_end(ap);
532 return retval;
533}
534#endif
535
536#endif // HAVE_UBSAN_SUPPORT
537
UINT16 width
Definition BmfFile.h:85
UINT16 base
Definition BmfFile.h:58
UINT32 size
#define va_end
Definition Ubsan.h:99
#define va_arg
Definition Ubsan.h:100
int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap)
#define va_list
Definition Ubsan.h:97
int EFIAPI tfp_sprintf(char *str, const char *fmt,...) __printflike(2
int EFIAPI int EFIAPI tfp_vsprintf(char *str, const char *fmt, va_list ap)
void EFIAPI tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
void(* putcf)(void *, char)
Definition Ubsan.h:197
#define va_start
Definition Ubsan.h:98
int EFIAPI tfp_snprintf(char *str, size_t size, const char *fmt,...) __printflike(3