1/*	$OpenBSD: dl_printf.c,v 1.23 2024/01/22 02:08:31 deraadt Exp $	*/
2
3/*-
4 * Copyright (c) 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *	@(#)printf.c	8.1 (Berkeley) 6/11/93
32 */
33
34/*
35 * Scaled down version of printf(3).
36 *
37 * One additional format:
38 *
39 * The format %b is supported to decode error registers.
40 * Its usage is:
41 *
42 *	printf("reg=%b\n", regval, "<base><arg>*");
43 *
44 * where <base> is the output base expressed as a control character, e.g.
45 * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
46 * the first of which gives the bit number to be inspected (origin 1), and
47 * the next characters (up to a control character, i.e. a character <= 32),
48 * give the name of the register.  Thus:
49 *
50 *	printf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
51 *
52 * would produce output:
53 *
54 *	reg=3<BITTWO,BITONE>
55 */
56
57#include <sys/types.h>
58#include <stdarg.h>
59#include "resolve.h"		/* for __progname */
60#include "syscall.h"
61#include "util.h"
62
63static int lastfd = -1;
64#define OUTBUFSIZE 128
65static char outbuf[OUTBUFSIZE];
66static char *outptr = outbuf;
67
68static void kprintn(int, u_long, int);
69static void kdoprnt(int, const char *, va_list);
70static void _dl_flushbuf(void);
71
72static void putcharfd(int, int);
73
74static void
75putcharfd(int c, int fd)
76{
77	char b = c;
78	int len;
79
80	if (fd != lastfd) {
81		_dl_flushbuf();
82		lastfd = fd;
83	}
84	*outptr++ = b;
85	len = outptr - outbuf;
86	if ((len >= OUTBUFSIZE) || (b == '\n') || (b == '\r')) {
87		_dl_flushbuf();
88	}
89}
90
91static void
92_dl_flushbuf()
93{
94	int len = outptr - outbuf;
95	if (len != 0) {
96		_dl_write(lastfd, outbuf, len);
97		outptr = outbuf;
98	}
99}
100
101void
102_dl_printf(const char *fmt, ...)
103{
104	va_list ap;
105
106	va_start(ap, fmt);
107	kdoprnt(2, fmt, ap);
108	va_end(ap);
109}
110
111void
112_dl_dprintf(int fd, const char *fmt, ...)
113{
114	va_list ap;
115
116	va_start(ap, fmt);
117	kdoprnt(fd, fmt, ap);
118	va_end(ap);
119}
120
121void
122_dl_vprintf(const char *fmt, va_list ap)
123{
124	kdoprnt(2, fmt, ap);
125}
126
127static void
128kdoprnt(int fd, const char *fmt, va_list ap)
129{
130	unsigned long ul;
131	int lflag, ch;
132	char *p;
133
134	for (;;) {
135		while ((ch = *fmt++) != '%') {
136			if (ch == '\0') {
137				_dl_flushbuf();
138				return;
139			}
140			putcharfd(ch, fd);
141		}
142		lflag = 0;
143reswitch:
144		switch (ch = *fmt++) {
145		case 'l':
146			lflag = 1;
147			goto reswitch;
148		case 'b':
149		{
150			int set, n;
151
152			ul = va_arg(ap, int);
153			p = va_arg(ap, char *);
154			kprintn(fd, ul, *p++);
155
156			if (!ul)
157				break;
158
159			for (set = 0; (n = *p++);) {
160				if (ul & (1 << (n - 1))) {
161					putcharfd(set ? ',' : '<', fd);
162					for (; (n = *p) > ' '; ++p)
163						putcharfd(n, fd);
164					set = 1;
165				} else
166					for (; *p > ' '; ++p);
167			}
168			if (set)
169				putcharfd('>', fd);
170		}
171			break;
172		case 'c':
173			ch = va_arg(ap, int);
174			putcharfd(ch & 0x7f, fd);
175			break;
176		case 's':
177			p = va_arg(ap, char *);
178			while ((ch = *p++))
179				putcharfd(ch, fd);
180			break;
181		case 'd':
182			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
183			if ((long)ul < 0) {
184				putcharfd('-', fd);
185				ul = -(long)ul;
186			}
187			kprintn(fd, ul, 10);
188			break;
189		case 'o':
190			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
191			kprintn(fd, ul, 8);
192			break;
193		case 'u':
194			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
195			kprintn(fd, ul, 10);
196			break;
197		case 'p':
198			putcharfd('0', fd);
199			putcharfd('x', fd);
200			lflag += sizeof(void *)==sizeof(u_long)? 1 : 0;
201		case 'x':
202			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
203			kprintn(fd, ul, 16);
204			break;
205		case 'X':
206		{
207			int l;
208
209			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
210			if (lflag)
211				l = (sizeof(ulong) * 8) - 4;
212			else
213				l = (sizeof(u_int) * 8) - 4;
214			while (l >= 0) {
215				putcharfd("0123456789abcdef"[(ul >> l) & 0xf], fd);
216				l -= 4;
217			}
218			break;
219		}
220		default:
221			putcharfd('%', fd);
222			if (lflag)
223				putcharfd('l', fd);
224			putcharfd(ch, fd);
225		}
226	}
227}
228
229static void
230kprintn(int fd, unsigned long ul, int base)
231{
232	/* hold a long in base 8 */
233	char *p, buf[(sizeof(long) * 8 / 3) + 1];
234
235	p = buf;
236	do {
237		*p++ = "0123456789abcdef"[ul % base];
238	} while (ul /= base);
239	do {
240		putcharfd(*--p, fd);
241	} while (p > buf);
242}
243
244static const char ldso[] = "ld.so: ";
245
246__dead void
247_dl_die(const char *fmt, ...)
248{
249	va_list ap;
250
251	_dl_printf("%s%s: ", ldso, __progname);
252	va_start(ap, fmt);
253	kdoprnt(2, fmt, ap);
254	_dl_write(2, "\n", 1);
255	va_end(ap);
256
257	_dl_diedie();
258}
259
260__dead void
261_dl_oom(void)
262{
263	static const char oom[] = ": out of memory\n";
264
265	_dl_write(2, ldso, sizeof(ldso) - 1);
266	_dl_write(2, __progname, _dl_strlen(__progname));
267	_dl_write(2, oom, sizeof(oom) - 1);
268	_dl_diedie();
269}
270