xref: /openbsd-src/libexec/ld.so/dl_printf.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: dl_printf.c,v 1.16 2010/01/02 00:59:01 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/cdefs.h>
58 #include <sys/types.h>
59 #include <stdarg.h>
60 #include "syscall.h"
61 #include "util.h"
62 
63 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
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
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
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
112 _dl_fdprintf(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
122 _dl_vprintf(const char *fmt, va_list ap)
123 {
124 	kdoprnt(2, fmt, ap);
125 }
126 
127 static void
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 				return;
138 			putcharfd(ch, fd);
139 		}
140 		lflag = 0;
141 reswitch:
142 		switch (ch = *fmt++) {
143 		case 'l':
144 			lflag = 1;
145 			goto reswitch;
146 		case 'b':
147 		{
148 			int set, n;
149 
150 			ul = va_arg(ap, int);
151 			p = va_arg(ap, char *);
152 			kprintn(fd, ul, *p++);
153 
154 			if (!ul)
155 				break;
156 
157 			for (set = 0; (n = *p++);) {
158 				if (ul & (1 << (n - 1))) {
159 					putcharfd(set ? ',' : '<', fd);
160 					for (; (n = *p) > ' '; ++p)
161 						putcharfd(n, fd);
162 					set = 1;
163 				} else
164 					for (; *p > ' '; ++p);
165 			}
166 			if (set)
167 				putcharfd('>', fd);
168 		}
169 			break;
170 		case 'c':
171 			ch = va_arg(ap, int);
172 			putcharfd(ch & 0x7f, fd);
173 			break;
174 		case 's':
175 			p = va_arg(ap, char *);
176 			while ((ch = *p++))
177 				putcharfd(ch, fd);
178 			break;
179 		case 'd':
180 			ul = lflag ? va_arg(ap, long) : va_arg(ap, int);
181 			if ((long)ul < 0) {
182 				putcharfd('-', fd);
183 				ul = -(long)ul;
184 			}
185 			kprintn(fd, ul, 10);
186 			break;
187 		case 'o':
188 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
189 			kprintn(fd, ul, 8);
190 			break;
191 		case 'u':
192 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
193 			kprintn(fd, ul, 10);
194 			break;
195 		case 'p':
196 			putcharfd('0', fd);
197 			putcharfd('x', fd);
198 			lflag += sizeof(void *)==sizeof(u_long)? 1 : 0;
199 		case 'x':
200 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
201 			kprintn(fd, ul, 16);
202 			break;
203 		case 'X':
204 		{
205 			int l;
206 
207 			ul = lflag ? va_arg(ap, u_long) : va_arg(ap, u_int);
208 			if (lflag)
209 				l = (sizeof(ulong) * 8) - 4;
210 			else
211 				l = (sizeof(u_int) * 8) - 4;
212 			while (l >= 0) {
213 				putcharfd("0123456789abcdef"[(ul >> l) & 0xf], fd);
214 				l -= 4;
215 			}
216 			break;
217 		}
218 		default:
219 			putcharfd('%', fd);
220 			if (lflag)
221 				putcharfd('l', fd);
222 			putcharfd(ch, fd);
223 		}
224 	}
225 	_dl_flushbuf();
226 }
227 
228 static void
229 kprintn(int fd, unsigned long ul, int base)
230 {
231 	/* hold a long in base 8 */
232 	char *p, buf[(sizeof(long) * NBBY / 3) + 1];
233 
234 	p = buf;
235 	do {
236 		*p++ = "0123456789abcdef"[ul % base];
237 	} while (ul /= base);
238 	do {
239 		putcharfd(*--p, fd);
240 	} while (p > buf);
241 }
242