xref: /netbsd-src/external/cddl/osnet/dev/dtrace/dtrace_debug.c (revision 9d2dfffd738a1c4fec3bcc7affe5bcb9b26633ae)
1 /*	$NetBSD: dtrace_debug.c,v 1.8 2014/03/05 06:06:42 ozaki-r Exp $	*/
2 
3 /*-
4  * Copyright (C) 2008 John Birrell <jb@freebsd.org>.
5  * 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(s), this list of conditions and the following disclaimer as
12  *    the first lines of this file unmodified other than the possible
13  *    addition of one or more copyright notices.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice(s), this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
28  * DAMAGE.
29  *
30  * $FreeBSD: src/sys/cddl/dev/dtrace/dtrace_debug.c,v 1.1.4.1 2009/08/03 08:13:06 kensmith Exp $
31  *
32  */
33 
34 static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
35 #define	hex2ascii(hex)	(hex2ascii_data[hex])
36 
37 #ifdef DEBUG
38 
39 #define DTRACE_DEBUG_BUFR_SIZE	(32 * 1024)
40 
41 struct dtrace_debug_data {
42 	char bufr[DTRACE_DEBUG_BUFR_SIZE];
43 	char *first;
44 	char *last;
45 	char *next;
46 } dtrace_debug_data[MAXCPUS];
47 
48 static char dtrace_debug_bufr[DTRACE_DEBUG_BUFR_SIZE];
49 
50 static volatile u_long	dtrace_debug_flag[MAXCPUS];
51 
52 static void
53 dtrace_debug_lock(int cpu)
54 {
55 	/* FIXME: use atomic_cmpset_ulong once we have it  */
56 	while (atomic_cas_ulong(&dtrace_debug_flag[cpu], 0, 1) == 0)
57 		/* Loop until the lock is obtained. */
58 		;
59 }
60 
61 static void
62 dtrace_debug_unlock(int cpu)
63 {
64 	dtrace_debug_flag[cpu] = 0;
65 }
66 
67 static void
68 dtrace_debug_init(void *dummy)
69 {
70 	struct dtrace_debug_data *d;
71 	CPU_INFO_ITERATOR cpuind;
72 	struct cpu_info *cinfo;
73 
74 	for (CPU_INFO_FOREACH(cpuind, cinfo)) {
75 		d = &dtrace_debug_data[cpu_index(cinfo)];
76 
77 		if (d->first == NULL) {
78 			d->first = d->bufr;
79 			d->next = d->bufr;
80 			d->last = d->bufr + DTRACE_DEBUG_BUFR_SIZE - 1;
81 			*(d->last) = '\0';
82 		}
83 	}
84 }
85 
86 //SYSINIT(dtrace_debug_init, SI_SUB_KDTRACE, SI_ORDER_ANY, dtrace_debug_init, NULL);
87 //SYSINIT(dtrace_debug_smpinit, SI_SUB_SMP, SI_ORDER_ANY, dtrace_debug_init, NULL);
88 
89 static void
90 dtrace_debug_output(void)
91 {
92 	char *p;
93 	struct dtrace_debug_data *d;
94 	uintptr_t count;
95 	CPU_INFO_ITERATOR cpuind;
96 	struct cpu_info *cinfo;
97 	cpuid_t cpuid;
98 
99 	for (CPU_INFO_FOREACH(cpuind, cinfo)) {
100 	    	cpuid = cpu_index(cinfo);
101 
102 		dtrace_debug_lock(cpuid);
103 
104 		d = &dtrace_debug_data[cpuid];
105 
106 		count = 0;
107 
108 		if (d->first < d->next) {
109 			char *p1 = dtrace_debug_bufr;
110 
111 			count = (uintptr_t) d->next - (uintptr_t) d->first;
112 
113 			for (p = d->first; p < d->next; p++)
114 				*p1++ = *p;
115 		} else if (d->first > d->next) {
116 			char *p1 = dtrace_debug_bufr;
117 
118 			count = (uintptr_t) d->last - (uintptr_t) d->first;
119 
120 			for (p = d->first; p < d->last; p++)
121 				*p1++ = *p;
122 
123 			count += (uintptr_t) d->next - (uintptr_t) d->bufr;
124 
125 			for (p = d->bufr; p < d->next; p++)
126 				*p1++ = *p;
127 		}
128 
129 		d->first = d->bufr;
130 		d->next = d->bufr;
131 
132 		dtrace_debug_unlock(cpuid);
133 
134 		if (count > 0) {
135 			char *last = dtrace_debug_bufr + count;
136 
137 			p = dtrace_debug_bufr;
138 
139 			while (p < last) {
140 				if (*p == '\0') {
141 					p++;
142 					continue;
143 				}
144 
145 				printf("%s", p);
146 
147 				p += strlen(p);
148 			}
149 		}
150 	}
151 }
152 
153 /*
154  * Functions below here are called from the probe context, so they can't call
155  * _any_ functions outside the dtrace module without running foul of the function
156  * boundary trace provider (fbt). The purpose of these functions is limited to
157  * buffering debug strings for output when the probe completes on the current CPU.
158  */
159 
160 static __inline void
161 dtrace_debug__putc(char c)
162 {
163 	struct dtrace_debug_data *d = &dtrace_debug_data[cpu_number()];
164 
165 	*d->next++ = c;
166 
167 	if (d->next == d->last)
168 		d->next = d->bufr;
169 
170 	*(d->next) = '\0';
171 
172 	if (d->next == d->first)
173 		d->first++;
174 
175 	if (d->first == d->last)
176 		d->first = d->bufr;
177 }
178 
179 static void __used
180 dtrace_debug_putc(char c)
181 {
182 	dtrace_debug_lock(cpu_number());
183 
184 	dtrace_debug__putc(c);
185 
186 	dtrace_debug_unlock(cpu_number());
187 }
188 
189 static void __used
190 dtrace_debug_puts(const char *s)
191 {
192 	dtrace_debug_lock(cpu_number());
193 
194 	while (*s != '\0')
195 		dtrace_debug__putc(*s++);
196 
197 	dtrace_debug__putc('\0');
198 
199 	dtrace_debug_unlock(cpu_number());
200 }
201 
202 /*
203  * Snaffled from sys/kern/subr_prf.c
204  *
205  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
206  * order; return an optional length and a pointer to the last character
207  * written in the buffer (i.e., the first character of the string).
208  * The buffer pointed to by `xbuf' must have length >= MAXNBUF.
209  */
210 static char *
211 dtrace_debug_ksprintn(char *xbuf, uintmax_t num, int base, int *lenp, int upper)
212 {
213 	char *p, c;
214 
215 	p = xbuf;
216 	*p = '\0';
217 	do {
218 		c = hex2ascii(num % base);
219 		*++p = upper ? toupper(c) : c;
220 	} while (num /= base);
221 	if (lenp)
222 		*lenp = p - xbuf;
223 	return (p);
224 }
225 
226 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
227 
228 static void
229 dtrace_debug_vprintf(const char *fmt, va_list ap)
230 {
231 	char xbuf[MAXNBUF];
232 	const char *p, *percent, *q;
233 	u_char *up;
234 	int ch, n;
235 	uintmax_t num;
236 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
237 	int cflag, hflag, jflag, tflag, zflag;
238 	int dwidth, upper;
239 	int radix = 10;
240 	char padc;
241 	int stop = 0, retval = 0;
242 
243 	num = 0;
244 
245 	if (fmt == NULL)
246 		fmt = "(fmt null)\n";
247 
248 	for (;;) {
249 		padc = ' ';
250 		width = 0;
251 		while ((ch = (u_char)*fmt++) != '%' || stop) {
252 			if (ch == '\0') {
253 				dtrace_debug__putc('\0');
254 				return;
255 			}
256 			dtrace_debug__putc(ch);
257 		}
258 		percent = fmt - 1;
259 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
260 		sign = 0; dot = 0; dwidth = 0; upper = 0;
261 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
262 reswitch:	switch (ch = (u_char)*fmt++) {
263 		case '.':
264 			dot = 1;
265 			goto reswitch;
266 		case '#':
267 			sharpflag = 1;
268 			goto reswitch;
269 		case '+':
270 			sign = 1;
271 			goto reswitch;
272 		case '-':
273 			ladjust = 1;
274 			goto reswitch;
275 		case '%':
276 			dtrace_debug__putc(ch);
277 			break;
278 		case '*':
279 			if (!dot) {
280 				width = va_arg(ap, int);
281 				if (width < 0) {
282 					ladjust = !ladjust;
283 					width = -width;
284 				}
285 			} else {
286 				dwidth = va_arg(ap, int);
287 			}
288 			goto reswitch;
289 		case '0':
290 			if (!dot) {
291 				padc = '0';
292 				goto reswitch;
293 			}
294 		case '1': case '2': case '3': case '4':
295 		case '5': case '6': case '7': case '8': case '9':
296 				for (n = 0;; ++fmt) {
297 					n = n * 10 + ch - '0';
298 					ch = *fmt;
299 					if (ch < '0' || ch > '9')
300 						break;
301 				}
302 			if (dot)
303 				dwidth = n;
304 			else
305 				width = n;
306 			goto reswitch;
307 		case 'b':
308 			num = (u_int)va_arg(ap, int);
309 			p = va_arg(ap, char *);
310 			for (q = dtrace_debug_ksprintn(xbuf, num, *p++, NULL, 0); *q;)
311 				dtrace_debug__putc(*q--);
312 
313 			if (num == 0)
314 				break;
315 
316 			for (tmp = 0; *p;) {
317 				n = *p++;
318 				if (num & (1 << (n - 1))) {
319 					dtrace_debug__putc(tmp ? ',' : '<');
320 					for (; (n = *p) > ' '; ++p)
321 						dtrace_debug__putc(n);
322 					tmp = 1;
323 				} else
324 					for (; *p > ' '; ++p)
325 						continue;
326 			}
327 			if (tmp)
328 				dtrace_debug__putc('>');
329 			break;
330 		case 'c':
331 			dtrace_debug__putc(va_arg(ap, int));
332 			break;
333 		case 'D':
334 			up = va_arg(ap, u_char *);
335 			p = va_arg(ap, char *);
336 			if (!width)
337 				width = 16;
338 			while(width--) {
339 				dtrace_debug__putc(hex2ascii(*up >> 4));
340 				dtrace_debug__putc(hex2ascii(*up & 0x0f));
341 				up++;
342 				if (width)
343 					for (q=p;*q;q++)
344 						dtrace_debug__putc(*q);
345 			}
346 			break;
347 		case 'd':
348 		case 'i':
349 			base = 10;
350 			sign = 1;
351 			goto handle_sign;
352 		case 'h':
353 			if (hflag) {
354 				hflag = 0;
355 				cflag = 1;
356 			} else
357 				hflag = 1;
358 			goto reswitch;
359 		case 'j':
360 			jflag = 1;
361 			goto reswitch;
362 		case 'l':
363 			if (lflag) {
364 				lflag = 0;
365 				qflag = 1;
366 			} else
367 				lflag = 1;
368 			goto reswitch;
369 		case 'n':
370 			if (jflag)
371 				*(va_arg(ap, intmax_t *)) = retval;
372 			else if (qflag)
373 				*(va_arg(ap, quad_t *)) = retval;
374 			else if (lflag)
375 				*(va_arg(ap, long *)) = retval;
376 			else if (zflag)
377 				*(va_arg(ap, size_t *)) = retval;
378 			else if (hflag)
379 				*(va_arg(ap, short *)) = retval;
380 			else if (cflag)
381 				*(va_arg(ap, char *)) = retval;
382 			else
383 				*(va_arg(ap, int *)) = retval;
384 			break;
385 		case 'o':
386 			base = 8;
387 			goto handle_nosign;
388 		case 'p':
389 			base = 16;
390 			sharpflag = (width == 0);
391 			sign = 0;
392 			num = (uintptr_t)va_arg(ap, void *);
393 			goto number;
394 		case 'q':
395 			qflag = 1;
396 			goto reswitch;
397 		case 'r':
398 			base = radix;
399 			if (sign)
400 				goto handle_sign;
401 			goto handle_nosign;
402 		case 's':
403 			p = va_arg(ap, char *);
404 			if (p == NULL)
405 				p = "(null)";
406 			if (!dot)
407 				n = strlen (p);
408 			else
409 				for (n = 0; n < dwidth && p[n]; n++)
410 					continue;
411 
412 			width -= n;
413 
414 			if (!ladjust && width > 0)
415 				while (width--)
416 					dtrace_debug__putc(padc);
417 			while (n--)
418 				dtrace_debug__putc(*p++);
419 			if (ladjust && width > 0)
420 				while (width--)
421 					dtrace_debug__putc(padc);
422 			break;
423 		case 't':
424 			tflag = 1;
425 			goto reswitch;
426 		case 'u':
427 			base = 10;
428 			goto handle_nosign;
429 		case 'X':
430 			upper = 1;
431 		case 'x':
432 			base = 16;
433 			goto handle_nosign;
434 		case 'y':
435 			base = 16;
436 			sign = 1;
437 			goto handle_sign;
438 		case 'z':
439 			zflag = 1;
440 			goto reswitch;
441 handle_nosign:
442 			sign = 0;
443 			if (jflag)
444 				num = va_arg(ap, uintmax_t);
445 			else if (qflag)
446 				num = va_arg(ap, u_quad_t);
447 			else if (tflag)
448 				num = va_arg(ap, ptrdiff_t);
449 			else if (lflag)
450 				num = va_arg(ap, u_long);
451 			else if (zflag)
452 				num = va_arg(ap, size_t);
453 			else if (hflag)
454 				num = (u_short)va_arg(ap, int);
455 			else if (cflag)
456 				num = (u_char)va_arg(ap, int);
457 			else
458 				num = va_arg(ap, u_int);
459 			goto number;
460 handle_sign:
461 			if (jflag)
462 				num = va_arg(ap, intmax_t);
463 			else if (qflag)
464 				num = va_arg(ap, quad_t);
465 			else if (tflag)
466 				num = va_arg(ap, ptrdiff_t);
467 			else if (lflag)
468 				num = va_arg(ap, long);
469 			else if (zflag)
470 				num = va_arg(ap, size_t);
471 			else if (hflag)
472 				num = (short)va_arg(ap, int);
473 			else if (cflag)
474 				num = (char)va_arg(ap, int);
475 			else
476 				num = va_arg(ap, int);
477 number:
478 			if (sign && (intmax_t)num < 0) {
479 				neg = 1;
480 				num = -(intmax_t)num;
481 			}
482 			p = dtrace_debug_ksprintn(xbuf, num, base, &tmp, upper);
483 			if (sharpflag && num != 0) {
484 				if (base == 8)
485 					tmp++;
486 				else if (base == 16)
487 					tmp += 2;
488 			}
489 			if (neg)
490 				tmp++;
491 
492 			if (!ladjust && padc != '0' && width
493 			    && (width -= tmp) > 0)
494 				while (width--)
495 					dtrace_debug__putc(padc);
496 			if (neg)
497 				dtrace_debug__putc('-');
498 			if (sharpflag && num != 0) {
499 				if (base == 8) {
500 					dtrace_debug__putc('0');
501 				} else if (base == 16) {
502 					dtrace_debug__putc('0');
503 					dtrace_debug__putc('x');
504 				}
505 			}
506 			if (!ladjust && width && (width -= tmp) > 0)
507 				while (width--)
508 					dtrace_debug__putc(padc);
509 
510 			while (*p)
511 				dtrace_debug__putc(*p--);
512 
513 			if (ladjust && width && (width -= tmp) > 0)
514 				while (width--)
515 					dtrace_debug__putc(padc);
516 
517 			break;
518 		default:
519 			while (percent < fmt)
520 				dtrace_debug__putc(*percent++);
521 			/*
522 			 * Since we ignore an formatting argument it is no
523 			 * longer safe to obey the remaining formatting
524 			 * arguments as the arguments will no longer match
525 			 * the format specs.
526 			 */
527 			stop = 1;
528 			break;
529 		}
530 	}
531 
532 	dtrace_debug__putc('\0');
533 }
534 
535 void
536 dtrace_debug_printf(const char *fmt, ...)
537 {
538 	va_list ap;
539 
540 	dtrace_debug_lock(cpu_number());
541 
542 	va_start(ap, fmt);
543 
544 	dtrace_debug_vprintf(fmt, ap);
545 
546 	va_end(ap);
547 
548 	dtrace_debug_unlock(cpu_number());
549 }
550 
551 #else
552 
553 #define dtrace_debug_output()
554 #define dtrace_debug_puts(_s)
555 #define dtrace_debug_printf(fmt, ...)
556 
557 #endif
558