]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/rtld-elf/rtld_printf.c
Merge ^/head r338731 through r338987.
[FreeBSD/FreeBSD.git] / libexec / rtld-elf / rtld_printf.c
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 <kib@FreeBSD.org>
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  * $FreeBSD$
38  */
39
40 #include <sys/param.h>
41 #include <inttypes.h>
42 #include <stdarg.h>
43 #include <stddef.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include "rtld_printf.h"
47
48 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
49
50 #define PRINT_METHOD_SNPRINTF   1
51 #define PRINT_METHOD_WRITE      2
52
53 struct snprintf_arg {
54         int     method;
55         char    *str;
56         char    *buf;
57         size_t  remain;
58         size_t  buf_total;
59         int     fd;
60 };
61
62 static void
63 printf_out(struct snprintf_arg *info)
64 {
65
66         if (info->remain == info->buf_total)
67                 return;
68         write(info->fd, info->buf, info->buf_total - info->remain);
69         info->str = info->buf;
70         info->remain = info->buf_total;
71 }
72
73 static void
74 snprintf_func(int ch, struct snprintf_arg *const info)
75 {
76
77         switch (info->method) {
78         case PRINT_METHOD_SNPRINTF:
79                 if (info->remain >= 2) {
80                         *info->str++ = ch;
81                         info->remain--;
82                 }
83                 break;
84         case PRINT_METHOD_WRITE:
85                 if (info->remain > 0) {
86                         *info->str++ = ch;
87                         info->remain--;
88                 } else
89                         printf_out(info);
90                 break;
91         }
92 }
93
94 static char const hex2ascii_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
95 static char const hex2ascii_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
96 #define hex2ascii(hex)  (hex2ascii_lower[hex])
97 #define hex2ascii_upper(hex)    (hex2ascii_upper[hex])
98
99 static __inline int
100 imax(int a, int b)
101 {
102
103         return (a > b ? a : b);
104 }
105
106 static char *
107 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
108 {
109         char *p, c;
110
111         p = nbuf;
112         *p = '\0';
113         do {
114                 c = upper ? hex2ascii_upper(num % base) :
115                     hex2ascii(num % base);
116                 *++p = c;
117         } while (num /= base);
118         if (lenp)
119                 *lenp = p - nbuf;
120         return (p);
121 }
122
123 static int
124 kvprintf(char const *fmt, struct snprintf_arg *arg, int radix, va_list ap)
125 {
126 #define PCHAR(c) snprintf_func((c), arg)
127         char nbuf[MAXNBUF];
128         const char *p, *percent, *q;
129         u_char *up;
130         int ch, n;
131         uintmax_t num;
132         int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
133         int cflag, hflag, jflag, tflag, zflag;
134         int dwidth, upper;
135         char padc;
136         int stop = 0, retval = 0;
137
138         num = 0;
139
140         if (fmt == NULL)
141                 fmt = "(fmt null)\n";
142
143         if (radix < 2 || radix > 36)
144                 radix = 10;
145
146         for (;;) {
147                 padc = ' ';
148                 width = 0;
149                 while ((ch = (u_char)*fmt++) != '%' || stop) {
150                         if (ch == '\0')
151                                 return (retval);
152                         PCHAR(ch);
153                 }
154                 percent = fmt - 1;
155                 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
156                 sign = 0; dot = 0; dwidth = 0; upper = 0;
157                 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
158 reswitch:       switch (ch = (u_char)*fmt++) {
159                 case '.':
160                         dot = 1;
161                         goto reswitch;
162                 case '#':
163                         sharpflag = 1;
164                         goto reswitch;
165                 case '+':
166                         sign = 1;
167                         goto reswitch;
168                 case '-':
169                         ladjust = 1;
170                         goto reswitch;
171                 case '%':
172                         PCHAR(ch);
173                         break;
174                 case '*':
175                         if (!dot) {
176                                 width = va_arg(ap, int);
177                                 if (width < 0) {
178                                         ladjust = !ladjust;
179                                         width = -width;
180                                 }
181                         } else {
182                                 dwidth = va_arg(ap, int);
183                         }
184                         goto reswitch;
185                 case '0':
186                         if (!dot) {
187                                 padc = '0';
188                                 goto reswitch;
189                         }
190                 case '1': case '2': case '3': case '4':
191                 case '5': case '6': case '7': case '8': case '9':
192                                 for (n = 0;; ++fmt) {
193                                         n = n * 10 + ch - '0';
194                                         ch = *fmt;
195                                         if (ch < '0' || ch > '9')
196                                                 break;
197                                 }
198                         if (dot)
199                                 dwidth = n;
200                         else
201                                 width = n;
202                         goto reswitch;
203                 case 'b':
204                         num = (u_int)va_arg(ap, int);
205                         p = va_arg(ap, char *);
206                         for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
207                                 PCHAR(*q--);
208
209                         if (num == 0)
210                                 break;
211
212                         for (tmp = 0; *p;) {
213                                 n = *p++;
214                                 if (num & (1 << (n - 1))) {
215                                         PCHAR(tmp ? ',' : '<');
216                                         for (; (n = *p) > ' '; ++p)
217                                                 PCHAR(n);
218                                         tmp = 1;
219                                 } else
220                                         for (; *p > ' '; ++p)
221                                                 continue;
222                         }
223                         if (tmp)
224                                 PCHAR('>');
225                         break;
226                 case 'c':
227                         PCHAR(va_arg(ap, int));
228                         break;
229                 case 'D':
230                         up = va_arg(ap, u_char *);
231                         p = va_arg(ap, char *);
232                         if (!width)
233                                 width = 16;
234                         while(width--) {
235                                 PCHAR(hex2ascii(*up >> 4));
236                                 PCHAR(hex2ascii(*up & 0x0f));
237                                 up++;
238                                 if (width)
239                                         for (q=p;*q;q++)
240                                                 PCHAR(*q);
241                         }
242                         break;
243                 case 'd':
244                 case 'i':
245                         base = 10;
246                         sign = 1;
247                         goto handle_sign;
248                 case 'h':
249                         if (hflag) {
250                                 hflag = 0;
251                                 cflag = 1;
252                         } else
253                                 hflag = 1;
254                         goto reswitch;
255                 case 'j':
256                         jflag = 1;
257                         goto reswitch;
258                 case 'l':
259                         if (lflag) {
260                                 lflag = 0;
261                                 qflag = 1;
262                         } else
263                                 lflag = 1;
264                         goto reswitch;
265                 case 'n':
266                         if (jflag)
267                                 *(va_arg(ap, intmax_t *)) = retval;
268                         else if (qflag)
269                                 *(va_arg(ap, quad_t *)) = retval;
270                         else if (lflag)
271                                 *(va_arg(ap, long *)) = retval;
272                         else if (zflag)
273                                 *(va_arg(ap, size_t *)) = retval;
274                         else if (hflag)
275                                 *(va_arg(ap, short *)) = retval;
276                         else if (cflag)
277                                 *(va_arg(ap, char *)) = retval;
278                         else
279                                 *(va_arg(ap, int *)) = retval;
280                         break;
281                 case 'o':
282                         base = 8;
283                         goto handle_nosign;
284                 case 'p':
285                         base = 16;
286                         sharpflag = (width == 0);
287                         sign = 0;
288                         num = (uintptr_t)va_arg(ap, void *);
289                         goto number;
290                 case 'q':
291                         qflag = 1;
292                         goto reswitch;
293                 case 'r':
294                         base = radix;
295                         if (sign)
296                                 goto handle_sign;
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                 case 'x':
328                         base = 16;
329                         goto handle_nosign;
330                 case 'y':
331                         base = 16;
332                         sign = 1;
333                         goto handle_sign;
334                 case 'z':
335                         zflag = 1;
336                         goto reswitch;
337 handle_nosign:
338                         sign = 0;
339                         if (jflag)
340                                 num = va_arg(ap, uintmax_t);
341                         else if (qflag)
342                                 num = va_arg(ap, u_quad_t);
343                         else if (tflag)
344                                 num = va_arg(ap, ptrdiff_t);
345                         else if (lflag)
346                                 num = va_arg(ap, u_long);
347                         else if (zflag)
348                                 num = va_arg(ap, size_t);
349                         else if (hflag)
350                                 num = (u_short)va_arg(ap, int);
351                         else if (cflag)
352                                 num = (u_char)va_arg(ap, int);
353                         else
354                                 num = va_arg(ap, u_int);
355                         goto number;
356 handle_sign:
357                         if (jflag)
358                                 num = va_arg(ap, intmax_t);
359                         else if (qflag)
360                                 num = va_arg(ap, quad_t);
361                         else if (tflag)
362                                 num = va_arg(ap, ptrdiff_t);
363                         else if (lflag)
364                                 num = va_arg(ap, long);
365                         else if (zflag)
366                                 num = va_arg(ap, ssize_t);
367                         else if (hflag)
368                                 num = (short)va_arg(ap, int);
369                         else if (cflag)
370                                 num = (char)va_arg(ap, int);
371                         else
372                                 num = va_arg(ap, int);
373 number:
374                         if (sign && (intmax_t)num < 0) {
375                                 neg = 1;
376                                 num = -(intmax_t)num;
377                         }
378                         p = ksprintn(nbuf, num, base, &n, upper);
379                         tmp = 0;
380                         if (sharpflag && num != 0) {
381                                 if (base == 8)
382                                         tmp++;
383                                 else if (base == 16)
384                                         tmp += 2;
385                         }
386                         if (neg)
387                                 tmp++;
388
389                         if (!ladjust && padc == '0')
390                                 dwidth = width - tmp;
391                         width -= tmp + imax(dwidth, n);
392                         dwidth -= n;
393                         if (!ladjust)
394                                 while (width-- > 0)
395                                         PCHAR(' ');
396                         if (neg)
397                                 PCHAR('-');
398                         if (sharpflag && num != 0) {
399                                 if (base == 8) {
400                                         PCHAR('0');
401                                 } else if (base == 16) {
402                                         PCHAR('0');
403                                         PCHAR('x');
404                                 }
405                         }
406                         while (dwidth-- > 0)
407                                 PCHAR('0');
408
409                         while (*p)
410                                 PCHAR(*p--);
411
412                         if (ladjust)
413                                 while (width-- > 0)
414                                         PCHAR(' ');
415
416                         break;
417                 default:
418                         while (percent < fmt)
419                                 PCHAR(*percent++);
420                         /*
421                          * Since we ignore an formatting argument it is no
422                          * longer safe to obey the remaining formatting
423                          * arguments as the arguments will no longer match
424                          * the format specs.
425                          */
426                         stop = 1;
427                         break;
428                 }
429         }
430 #undef PCHAR
431 }
432
433 int
434 rtld_snprintf(char *buf, size_t bufsize, const char *fmt, ...)
435 {
436         va_list ap;
437         int retval;
438
439         va_start(ap, fmt);
440         retval = rtld_vsnprintf(buf, bufsize, fmt, ap);
441         va_end(ap);
442         return (retval);
443 }
444
445 int
446 rtld_vsnprintf(char *buf, size_t bufsize, const char *fmt, va_list ap)
447 {
448         struct snprintf_arg info;
449         int retval;
450
451         info.method = PRINT_METHOD_SNPRINTF;
452         info.buf = info.str = buf;
453         info.buf_total = info.remain = bufsize;
454         info.fd = -1;
455         retval = kvprintf(fmt, &info, 10, ap);
456         if (info.remain >= 1)
457                 *info.str++ = '\0';
458         return (retval);
459 }
460
461 int
462 rtld_vfdprintf(int fd, const char *fmt, va_list ap)
463 {
464         char buf[512];
465         struct snprintf_arg info;
466         int retval;
467
468         info.method = PRINT_METHOD_WRITE;
469         info.buf = info.str = buf;
470         info.buf_total = info.remain = sizeof(buf);
471         info.fd = fd;
472         retval = kvprintf(fmt, &info, 10, ap);
473         printf_out(&info);
474         return (retval);
475 }
476
477 int
478 rtld_fdprintf(int fd, const char *fmt, ...)
479 {
480         va_list ap;
481         int retval;
482
483         va_start(ap, fmt);
484         retval = rtld_vfdprintf(fd, fmt, ap);
485         va_end(ap);
486         return (retval);
487 }
488
489 void
490 rtld_fdputstr(int fd, const char *str)
491 {
492
493         write(fd, str, strlen(str));
494 }
495
496 void
497 rtld_fdputchar(int fd, int c)
498 {
499         char c1;
500
501         c1 = c;
502         write(fd, &c1, 1);
503 }