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