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