xref: /openbsd/libexec/ld.so/dl_printf.c (revision 210cc31e)
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 
63 static int lastfd = -1;
64 #define OUTBUFSIZE 128
65 static char outbuf[OUTBUFSIZE];
66 static char *outptr = outbuf;
67 
68 static void kprintn(int, u_long, int);
69 static void kdoprnt(int, const char *, va_list);
70 static void _dl_flushbuf(void);
71 
72 static void putcharfd(int, int);
73 
74 static void
putcharfd(int c,int fd)75 putcharfd(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 
91 static void
_dl_flushbuf()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 
101 void
_dl_printf(const char * fmt,...)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 
111 void
_dl_dprintf(int fd,const char * fmt,...)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 
121 void
_dl_vprintf(const char * fmt,va_list ap)122 _dl_vprintf(const char *fmt, va_list ap)
123 {
124 	kdoprnt(2, fmt, ap);
125 }
126 
127 static void
kdoprnt(int fd,const char * fmt,va_list ap)128 kdoprnt(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;
143 reswitch:
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 
229 static void
kprintn(int fd,unsigned long ul,int base)230 kprintn(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 
244 static const char ldso[] = "ld.so: ";
245 
246 __dead void
_dl_die(const char * fmt,...)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
_dl_oom(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