rtld_printf.c revision 330897
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 * 4. 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: stable/11/libexec/rtld-elf/rtld_printf.c 330897 2018-03-14 03:19:51Z eadler $
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
53struct 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
62static void
63printf_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
73static void
74snprintf_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
94static char const hex2ascii_lower[] = "0123456789abcdefghijklmnopqrstuvwxyz";
95static char const hex2ascii_upper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
96#define	hex2ascii(hex)	(hex2ascii_lower[hex])
97#define	hex2ascii_upper(hex)	(hex2ascii_upper[hex])
98
99static __inline int
100imax(int a, int b)
101{
102
103	return (a > b ? a : b);
104}
105
106static char *
107ksprintn(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
123static int
124kvprintf(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;
158reswitch:	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;
337handle_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;
356handle_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);
373number:
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
433int
434rtld_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
445int
446rtld_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
461int
462rtld_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
477int
478rtld_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
489void
490rtld_fdputstr(int fd, const char *str)
491{
492
493	write(fd, str, strlen(str));
494}
495
496void
497rtld_fdputchar(int fd, int c)
498{
499	char c1;
500
501	c1 = c;
502	write(fd, &c1, 1);
503}
504