xref: /openbsd-src/libexec/ld.so/dl_printf.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: dl_printf.c,v 1.17 2012/12/05 23:20:06 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 "syscall.h"
60 #include "util.h"
61 
62 int lastfd = -1;
63 #define OUTBUFSIZE 128
64 static char outbuf[OUTBUFSIZE];
65 static char *outptr = outbuf;
66 
67 static void kprintn(int, u_long, int);
68 static void kdoprnt(int, const char *, va_list);
69 static void _dl_flushbuf(void);
70 
71 static void putcharfd(int, int );
72 
73 static void
74 putcharfd(int c, int fd)
75 {
76 	char b = c;
77 	int len;
78 
79 	if (fd != lastfd) {
80 		_dl_flushbuf();
81 		lastfd = fd;
82 	}
83 	*outptr++ = b;
84 	len = outptr - outbuf;
85 	if ((len >= OUTBUFSIZE) || (b == '\n') || (b == '\r')) {
86 		_dl_flushbuf();
87 	}
88 }
89 
90 static void
91 _dl_flushbuf()
92 {
93 	int len = outptr - outbuf;
94 	if (len != 0) {
95 		_dl_write(lastfd, outbuf, len);
96 		outptr = outbuf;
97 	}
98 }
99 
100 void
101 _dl_printf(const char *fmt, ...)
102 {
103 	va_list ap;
104 
105 	va_start(ap, fmt);
106 	kdoprnt(2, fmt, ap);
107 	va_end(ap);
108 }
109 
110 void
111 _dl_fdprintf(int fd, const char *fmt, ...)
112 {
113 	va_list ap;
114 
115 	va_start(ap, fmt);
116 	kdoprnt(fd, fmt, ap);
117 	va_end(ap);
118 }
119 
120 void
121 _dl_vprintf(const char *fmt, va_list ap)
122 {
123 	kdoprnt(2, fmt, ap);
124 }
125 
126 static void
127 kdoprnt(int fd, const char *fmt, va_list ap)
128 {
129 	unsigned long ul;
130 	int lflag, ch;
131 	char *p;
132 
133 	for (;;) {
134 		while ((ch = *fmt++) != '%') {
135 			if (ch == '\0')
136 				return;
137 			putcharfd(ch, fd);
138 		}
139 		lflag = 0;
140 reswitch:
141 		switch (ch = *fmt++) {
142 		case 'l':
143 			lflag = 1;
144 			goto reswitch;
145 		case 'b':
146 		{
147 			int set, n;
148 
149 			ul = va_arg(ap, int);
150 			p = va_arg(ap, char *);
151 			kprintn(fd, ul, *p++);
152 
153 			if (!ul)
154 				break;
155 
156 			for (set = 0; (n = *p++);) {
157 				if (ul & (1 << (n - 1))) {
158 					putcharfd(set ? ',' : '<', fd);
159 					for (; (n = *p) > ' '; ++p)
160 						putcharfd(n, fd);
161 					set = 1;
162 				} else
163 					for (; *p > ' '; ++p);
164 			}
165 			if (set)
166 				putcharfd('>', fd);
167 		}
168 			break;
169 		case 'c':
170 			ch = va_arg(ap, int);
171 			putcharfd(ch & 0x7f, fd);
172 			break;
173 		case 's':
174 			p = va_arg(ap, char *);
175 			while ((ch = *p++))
176 				putcharfd(ch, fd);
177 			break;
178 		case 'd':
179 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
180 			if ((long)ul < 0) {
181 				putcharfd('-', fd);
182 				ul = -(long)ul;
183 			}
184 			kprintn(fd, ul, 10);
185 			break;
186 		case 'o':
187 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
188 			kprintn(fd, ul, 8);
189 			break;
190 		case 'u':
191 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
192 			kprintn(fd, ul, 10);
193 			break;
194 		case 'p':
195 			putcharfd('0', fd);
196 			putcharfd('x', fd);
197 			lflag += sizeof(void *)==sizeof(u_long)? 1 : 0;
198 		case 'x':
199 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
200 			kprintn(fd, ul, 16);
201 			break;
202 		case 'X':
203 		{
204 			int l;
205 
206 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
207 			if (lflag)
208 				l = (sizeof(ulong) * 8) - 4;
209 			else
210 				l = (sizeof(u_int) * 8) - 4;
211 			while (l >= 0) {
212 				putcharfd("0123456789abcdef"[(ul >> l) & 0xf], fd);
213 				l -= 4;
214 			}
215 			break;
216 		}
217 		default:
218 			putcharfd('%', fd);
219 			if (lflag)
220 				putcharfd('l', fd);
221 			putcharfd(ch, fd);
222 		}
223 	}
224 	_dl_flushbuf();
225 }
226 
227 static void
228 kprintn(int fd, unsigned long ul, int base)
229 {
230 	/* hold a long in base 8 */
231 	char *p, buf[(sizeof(long) * NBBY / 3) + 1];
232 
233 	p = buf;
234 	do {
235 		*p++ = "0123456789abcdef"[ul % base];
236 	} while (ul /= base);
237 	do {
238 		putcharfd(*--p, fd);
239 	} while (p > buf);
240 }
241