Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/libexec/rtld-elf/rtld_printf.c
34822 views
1
/*-
2
* SPDX-License-Identifier: BSD-3-Clause
3
*
4
* Copyright (c) 1986, 1988, 1991, 1993
5
* The Regents of the University of California. All rights reserved.
6
* (c) UNIX System Laboratories, Inc.
7
* All or some portions of this file are derived from material licensed
8
* to the University of California by American Telephone and Telegraph
9
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
10
* the permission of UNIX System Laboratories, Inc.
11
* Copyright (c) 2011 Konstantin Belousov <[email protected]>
12
*
13
* Redistribution and use in source and binary forms, with or without
14
* modification, are permitted provided that the following conditions
15
* are met:
16
* 1. Redistributions of source code must retain the above copyright
17
* notice, this list of conditions and the following disclaimer.
18
* 2. Redistributions in binary form must reproduce the above copyright
19
* notice, this list of conditions and the following disclaimer in the
20
* documentation and/or other materials provided with the distribution.
21
* 3. Neither the name of the University nor the names of its contributors
22
* may be used to endorse or promote products derived from this software
23
* without specific prior written permission.
24
*
25
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35
* SUCH DAMAGE.
36
*/
37
38
#include <sys/param.h>
39
#include <inttypes.h>
40
#include <stdarg.h>
41
#include <stddef.h>
42
#include <string.h>
43
#include <unistd.h>
44
#include "rtld_printf.h"
45
#include "rtld_libc.h"
46
47
#define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
48
49
#define PRINT_METHOD_SNPRINTF 1
50
#define PRINT_METHOD_WRITE 2
51
52
struct snprintf_arg {
53
int method;
54
char *str;
55
char *buf;
56
size_t remain;
57
size_t buf_total;
58
int fd;
59
};
60
61
static void
62
printf_out(struct snprintf_arg *info)
63
{
64
65
if (info->remain == info->buf_total)
66
return;
67
write(info->fd, info->buf, info->buf_total - info->remain);
68
info->str = info->buf;
69
info->remain = info->buf_total;
70
}
71
72
static void
73
snprintf_func(int ch, struct snprintf_arg *const info)
74
{
75
76
switch (info->method) {
77
case PRINT_METHOD_SNPRINTF:
78
if (info->remain >= 2) {
79
*info->str++ = ch;
80
info->remain--;
81
}
82
break;
83
case PRINT_METHOD_WRITE:
84
if (info->remain == 0)
85
printf_out(info);
86
*info->str++ = ch;
87
info->remain--;
88
break;
89
}
90
}
91
92
static char const hex2ascii_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
93
static char const hex2ascii_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
94
#define hex2ascii(hex) (hex2ascii_lower[hex])
95
#define hex2ascii_upper(hex) (hex2ascii_upper[hex])
96
97
static __inline int
98
imax(int a, int b)
99
{
100
101
return (a > b ? a : b);
102
}
103
104
static char *
105
ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
106
{
107
char *p, c;
108
109
p = nbuf;
110
*p = '\0';
111
do {
112
c = upper ? hex2ascii_upper(num % base) :
113
hex2ascii(num % base);
114
*++p = c;
115
} while (num /= base);
116
if (lenp)
117
*lenp = p - nbuf;
118
return (p);
119
}
120
121
static int
122
kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap)
123
{
124
#define PCHAR(c) snprintf_func((c), arg)
125
char nbuf[MAXNBUF];
126
const char *p, *percent, *q;
127
u_char *up;
128
int ch, n, sign;
129
uintmax_t num;
130
int base, lflag, qflag, tmp, width, ladjust, sharpflag, dot;
131
int cflag, hflag, jflag, tflag, zflag;
132
int dwidth, upper;
133
char padc;
134
int stop = 0, retval = 0;
135
136
num = 0;
137
138
if (fmt == NULL)
139
fmt = "(fmt null)\n";
140
141
if (radix < 2 || radix > 36)
142
radix = 10;
143
144
for (;;) {
145
padc = ' ';
146
width = 0;
147
while ((ch = (u_char)*fmt++) != '%' || stop) {
148
if (ch == '\0')
149
return (retval);
150
PCHAR(ch);
151
}
152
percent = fmt - 1;
153
qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0;
154
sign = 0; dot = 0; dwidth = 0; upper = 0;
155
cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
156
reswitch: switch (ch = (u_char)*fmt++) {
157
case '.':
158
dot = 1;
159
goto reswitch;
160
case '#':
161
sharpflag = 1;
162
goto reswitch;
163
case '+':
164
sign = '+';
165
goto reswitch;
166
case '-':
167
ladjust = 1;
168
goto reswitch;
169
case '%':
170
PCHAR(ch);
171
break;
172
case '*':
173
if (!dot) {
174
width = va_arg(ap, int);
175
if (width < 0) {
176
ladjust = !ladjust;
177
width = -width;
178
}
179
} else {
180
dwidth = va_arg(ap, int);
181
}
182
goto reswitch;
183
case '0':
184
if (!dot) {
185
padc = '0';
186
goto reswitch;
187
}
188
/* FALLTHROUGH */
189
case '1': case '2': case '3': case '4':
190
case '5': case '6': case '7': case '8': case '9':
191
for (n = 0;; ++fmt) {
192
n = n * 10 + ch - '0';
193
ch = *fmt;
194
if (ch < '0' || ch > '9')
195
break;
196
}
197
if (dot)
198
dwidth = n;
199
else
200
width = n;
201
goto reswitch;
202
case 'b':
203
num = (u_int)va_arg(ap, int);
204
p = va_arg(ap, char *);
205
for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
206
PCHAR(*q--);
207
208
if (num == 0)
209
break;
210
211
for (tmp = 0; *p;) {
212
n = *p++;
213
if (num & (1 << (n - 1))) {
214
PCHAR(tmp ? ',' : '<');
215
for (; (n = *p) > ' '; ++p)
216
PCHAR(n);
217
tmp = 1;
218
} else
219
for (; *p > ' '; ++p)
220
continue;
221
}
222
if (tmp)
223
PCHAR('>');
224
break;
225
case 'c':
226
PCHAR(va_arg(ap, int));
227
break;
228
case 'D':
229
up = va_arg(ap, u_char *);
230
p = va_arg(ap, char *);
231
if (!width)
232
width = 16;
233
while(width--) {
234
PCHAR(hex2ascii(*up >> 4));
235
PCHAR(hex2ascii(*up & 0x0f));
236
up++;
237
if (width)
238
for (q=p;*q;q++)
239
PCHAR(*q);
240
}
241
break;
242
case 'd':
243
case 'i':
244
base = 10;
245
goto handle_sign;
246
case 'h':
247
if (hflag) {
248
hflag = 0;
249
cflag = 1;
250
} else
251
hflag = 1;
252
goto reswitch;
253
case 'j':
254
jflag = 1;
255
goto reswitch;
256
case 'l':
257
if (lflag) {
258
lflag = 0;
259
qflag = 1;
260
} else
261
lflag = 1;
262
goto reswitch;
263
case 'n':
264
if (jflag)
265
*(va_arg(ap, intmax_t *)) = retval;
266
else if (qflag)
267
*(va_arg(ap, quad_t *)) = retval;
268
else if (lflag)
269
*(va_arg(ap, long *)) = retval;
270
else if (zflag)
271
*(va_arg(ap, size_t *)) = retval;
272
else if (hflag)
273
*(va_arg(ap, short *)) = retval;
274
else if (cflag)
275
*(va_arg(ap, char *)) = retval;
276
else
277
*(va_arg(ap, int *)) = retval;
278
break;
279
case 'o':
280
base = 8;
281
goto handle_nosign;
282
case 'p':
283
base = 16;
284
sharpflag = (width == 0);
285
sign = 0;
286
num = (uintptr_t)va_arg(ap, void *);
287
goto number;
288
case 'q':
289
qflag = 1;
290
goto reswitch;
291
case 'r':
292
base = radix;
293
if (sign) {
294
sign = 0;
295
goto handle_sign;
296
}
297
goto handle_nosign;
298
case 's':
299
p = va_arg(ap, char *);
300
if (p == NULL)
301
p = "(null)";
302
if (!dot)
303
n = strlen (p);
304
else
305
for (n = 0; n < dwidth && p[n]; n++)
306
continue;
307
308
width -= n;
309
310
if (!ladjust && width > 0)
311
while (width--)
312
PCHAR(padc);
313
while (n--)
314
PCHAR(*p++);
315
if (ladjust && width > 0)
316
while (width--)
317
PCHAR(padc);
318
break;
319
case 't':
320
tflag = 1;
321
goto reswitch;
322
case 'u':
323
base = 10;
324
goto handle_nosign;
325
case 'X':
326
upper = 1;
327
/* FALLTHROUGH */
328
case 'x':
329
base = 16;
330
goto handle_nosign;
331
case 'y':
332
base = 16;
333
goto handle_sign;
334
case 'z':
335
zflag = 1;
336
goto reswitch;
337
handle_nosign:
338
if (jflag)
339
num = va_arg(ap, uintmax_t);
340
else if (qflag)
341
num = va_arg(ap, u_quad_t);
342
else if (tflag)
343
num = va_arg(ap, ptrdiff_t);
344
else if (lflag)
345
num = va_arg(ap, u_long);
346
else if (zflag)
347
num = va_arg(ap, size_t);
348
else if (hflag)
349
num = (u_short)va_arg(ap, int);
350
else if (cflag)
351
num = (u_char)va_arg(ap, int);
352
else
353
num = va_arg(ap, u_int);
354
goto number;
355
handle_sign:
356
if (jflag)
357
num = va_arg(ap, intmax_t);
358
else if (qflag)
359
num = va_arg(ap, quad_t);
360
else if (tflag)
361
num = va_arg(ap, ptrdiff_t);
362
else if (lflag)
363
num = va_arg(ap, long);
364
else if (zflag)
365
num = va_arg(ap, ssize_t);
366
else if (hflag)
367
num = (short)va_arg(ap, int);
368
else if (cflag)
369
num = (signed char)va_arg(ap, int);
370
else
371
num = va_arg(ap, int);
372
if ((intmax_t)num < 0) {
373
sign = '-';
374
num = -(intmax_t)num;
375
}
376
number:
377
p = ksprintn(nbuf, num, base, &n, upper);
378
tmp = 0;
379
if (sharpflag && num != 0) {
380
if (base == 8)
381
tmp++;
382
else if (base == 16)
383
tmp += 2;
384
}
385
if (sign)
386
tmp++;
387
388
if (!ladjust && padc == '0')
389
dwidth = width - tmp;
390
width -= tmp + imax(dwidth, n);
391
dwidth -= n;
392
if (!ladjust)
393
while (width-- > 0)
394
PCHAR(' ');
395
if (sign)
396
PCHAR(sign);
397
if (sharpflag && num != 0) {
398
if (base == 8) {
399
PCHAR('0');
400
} else if (base == 16) {
401
PCHAR('0');
402
PCHAR('x');
403
}
404
}
405
while (dwidth-- > 0)
406
PCHAR('0');
407
408
while (*p)
409
PCHAR(*p--);
410
411
if (ladjust)
412
while (width-- > 0)
413
PCHAR(' ');
414
415
break;
416
default:
417
while (percent < fmt)
418
PCHAR(*percent++);
419
/*
420
* Since we ignore an formatting argument it is no
421
* longer safe to obey the remaining formatting
422
* arguments as the arguments will no longer match
423
* the format specs.
424
*/
425
stop = 1;
426
break;
427
}
428
}
429
#undef PCHAR
430
}
431
432
int
433
rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...)
434
{
435
va_list ap;
436
int retval;
437
438
va_start(ap, fmt);
439
retval = rtld_vsnprintf(buf, bufsize, fmt, ap);
440
va_end(ap);
441
return (retval);
442
}
443
444
int
445
rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap)
446
{
447
struct snprintf_arg info;
448
int retval;
449
450
info.method = PRINT_METHOD_SNPRINTF;
451
info.buf = info.str = buf;
452
info.buf_total = info.remain = bufsize;
453
info.fd = -1;
454
retval = kvprintf(fmt, &info, 10, ap);
455
if (info.remain >= 1)
456
*info.str++ = '\0';
457
return (retval);
458
}
459
460
int
461
rtld_vfdprintf(int fd, const char *fmt, va_list ap)
462
{
463
char buf[512];
464
struct snprintf_arg info;
465
int retval;
466
467
info.method = PRINT_METHOD_WRITE;
468
info.buf = info.str = buf;
469
info.buf_total = info.remain = sizeof(buf);
470
info.fd = fd;
471
retval = kvprintf(fmt, &info, 10, ap);
472
printf_out(&info);
473
return (retval);
474
}
475
476
int
477
rtld_fdprintf(int fd, const char *fmt, ...)
478
{
479
va_list ap;
480
int retval;
481
482
va_start(ap, fmt);
483
retval = rtld_vfdprintf(fd, fmt, ap);
484
va_end(ap);
485
return (retval);
486
}
487
488
int
489
rtld_fdprintfx(int fd, const char *fmt, ...)
490
{
491
va_list ap;
492
int retval;
493
494
va_start(ap, fmt);
495
retval = rtld_vfdprintf(fd, fmt, ap);
496
va_end(ap);
497
return (retval);
498
}
499
500
void
501
rtld_fdputstr(int fd, const char *str)
502
{
503
504
write(fd, str, strlen(str));
505
}
506
507
void
508
rtld_fdputchar(int fd, int c)
509
{
510
char c1;
511
512
c1 = c;
513
write(fd, &c1, 1);
514
}
515
516