xref: /freebsd/sys/cddl/dev/dtrace/dtrace_debug.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
191eaf3e1SJohn Birrell /*-
291eaf3e1SJohn Birrell  * Copyright (C) 2008 John Birrell <jb@freebsd.org>.
391eaf3e1SJohn Birrell  * All rights reserved.
491eaf3e1SJohn Birrell  *
591eaf3e1SJohn Birrell  * Redistribution and use in source and binary forms, with or without
691eaf3e1SJohn Birrell  * modification, are permitted provided that the following conditions
791eaf3e1SJohn Birrell  * are met:
891eaf3e1SJohn Birrell  * 1. Redistributions of source code must retain the above copyright
991eaf3e1SJohn Birrell  *    notice(s), this list of conditions and the following disclaimer as
1091eaf3e1SJohn Birrell  *    the first lines of this file unmodified other than the possible
1191eaf3e1SJohn Birrell  *    addition of one or more copyright notices.
1291eaf3e1SJohn Birrell  * 2. Redistributions in binary form must reproduce the above copyright
1391eaf3e1SJohn Birrell  *    notice(s), this list of conditions and the following disclaimer in the
1491eaf3e1SJohn Birrell  *    documentation and/or other materials provided with the distribution.
1591eaf3e1SJohn Birrell  *
1691eaf3e1SJohn Birrell  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
1791eaf3e1SJohn Birrell  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1891eaf3e1SJohn Birrell  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
1991eaf3e1SJohn Birrell  * DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
2091eaf3e1SJohn Birrell  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
2191eaf3e1SJohn Birrell  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
2291eaf3e1SJohn Birrell  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
2391eaf3e1SJohn Birrell  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2491eaf3e1SJohn Birrell  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2591eaf3e1SJohn Birrell  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
2691eaf3e1SJohn Birrell  * DAMAGE.
2791eaf3e1SJohn Birrell  *
2891eaf3e1SJohn Birrell  */
2991eaf3e1SJohn Birrell 
3091eaf3e1SJohn Birrell #ifdef DEBUG
3191eaf3e1SJohn Birrell 
32ad4e66a6SMarcel Moolenaar #include <machine/atomic.h>
3391eaf3e1SJohn Birrell 
3491eaf3e1SJohn Birrell #define DTRACE_DEBUG_BUFR_SIZE	(32 * 1024)
3591eaf3e1SJohn Birrell 
3691eaf3e1SJohn Birrell struct dtrace_debug_data {
376969ef66SRyan Stone 	uintptr_t lock __aligned(CACHE_LINE_SIZE);
3891eaf3e1SJohn Birrell 	char bufr[DTRACE_DEBUG_BUFR_SIZE];
3991eaf3e1SJohn Birrell 	char *first;
4091eaf3e1SJohn Birrell 	char *last;
4191eaf3e1SJohn Birrell 	char *next;
4291eaf3e1SJohn Birrell } dtrace_debug_data[MAXCPU];
4391eaf3e1SJohn Birrell 
4491eaf3e1SJohn Birrell static char dtrace_debug_bufr[DTRACE_DEBUG_BUFR_SIZE];
4591eaf3e1SJohn Birrell 
4691eaf3e1SJohn Birrell static void
dtrace_debug_lock(int cpu)4791eaf3e1SJohn Birrell dtrace_debug_lock(int cpu)
4891eaf3e1SJohn Birrell {
496969ef66SRyan Stone 	 uintptr_t tid;
506969ef66SRyan Stone 
516969ef66SRyan Stone 	tid = (uintptr_t)curthread;
526969ef66SRyan Stone 	spinlock_enter();
536969ef66SRyan Stone 	while (atomic_cmpset_acq_ptr(&dtrace_debug_data[cpu].lock, 0, tid) == 0)		/* Loop until the lock is obtained. */
5491eaf3e1SJohn Birrell 		;
5591eaf3e1SJohn Birrell }
5691eaf3e1SJohn Birrell 
5791eaf3e1SJohn Birrell static void
dtrace_debug_unlock(int cpu)5891eaf3e1SJohn Birrell dtrace_debug_unlock(int cpu)
5991eaf3e1SJohn Birrell {
606969ef66SRyan Stone 	atomic_store_rel_ptr(&dtrace_debug_data[cpu].lock, 0);
616969ef66SRyan Stone 	spinlock_exit();
6291eaf3e1SJohn Birrell }
6391eaf3e1SJohn Birrell 
6491eaf3e1SJohn Birrell static void
dtrace_debug_init(void * dummy)6591eaf3e1SJohn Birrell dtrace_debug_init(void *dummy)
6691eaf3e1SJohn Birrell {
6791eaf3e1SJohn Birrell 	int i;
6891eaf3e1SJohn Birrell 	struct dtrace_debug_data *d;
6991eaf3e1SJohn Birrell 
703aa6d94eSJohn Baldwin 	CPU_FOREACH(i) {
7191eaf3e1SJohn Birrell 		d = &dtrace_debug_data[i];
7291eaf3e1SJohn Birrell 
7391eaf3e1SJohn Birrell 		if (d->first == NULL) {
7491eaf3e1SJohn Birrell 			d->first = d->bufr;
7591eaf3e1SJohn Birrell 			d->next = d->bufr;
7691eaf3e1SJohn Birrell 			d->last = d->bufr + DTRACE_DEBUG_BUFR_SIZE - 1;
7791eaf3e1SJohn Birrell 			*(d->last) = '\0';
7891eaf3e1SJohn Birrell 		}
7991eaf3e1SJohn Birrell 	}
8091eaf3e1SJohn Birrell }
8191eaf3e1SJohn Birrell 
8291eaf3e1SJohn Birrell SYSINIT(dtrace_debug_init, SI_SUB_KDTRACE, SI_ORDER_ANY, dtrace_debug_init, NULL);
8391eaf3e1SJohn Birrell SYSINIT(dtrace_debug_smpinit, SI_SUB_SMP, SI_ORDER_ANY, dtrace_debug_init, NULL);
8491eaf3e1SJohn Birrell 
8591eaf3e1SJohn Birrell static void
dtrace_debug_output(void)8691eaf3e1SJohn Birrell dtrace_debug_output(void)
8791eaf3e1SJohn Birrell {
8891eaf3e1SJohn Birrell 	char *p;
8991eaf3e1SJohn Birrell 	int i;
9091eaf3e1SJohn Birrell 	struct dtrace_debug_data *d;
9191eaf3e1SJohn Birrell 	uintptr_t count;
9291eaf3e1SJohn Birrell 
933aa6d94eSJohn Baldwin 	CPU_FOREACH(i) {
9491eaf3e1SJohn Birrell 		dtrace_debug_lock(i);
9591eaf3e1SJohn Birrell 
9691eaf3e1SJohn Birrell 		d = &dtrace_debug_data[i];
9791eaf3e1SJohn Birrell 
9891eaf3e1SJohn Birrell 		count = 0;
9991eaf3e1SJohn Birrell 
10091eaf3e1SJohn Birrell 		if (d->first < d->next) {
10191eaf3e1SJohn Birrell 			char *p1 = dtrace_debug_bufr;
10291eaf3e1SJohn Birrell 
10391eaf3e1SJohn Birrell 			count = (uintptr_t) d->next - (uintptr_t) d->first;
10491eaf3e1SJohn Birrell 
10591eaf3e1SJohn Birrell 			for (p = d->first; p < d->next; p++)
10691eaf3e1SJohn Birrell 				*p1++ = *p;
107*9fc47d24SMark Johnston 		} else if (d->first > d->next) {
10891eaf3e1SJohn Birrell 			char *p1 = dtrace_debug_bufr;
10991eaf3e1SJohn Birrell 
11091eaf3e1SJohn Birrell 			count = (uintptr_t) d->last - (uintptr_t) d->first;
11191eaf3e1SJohn Birrell 
11291eaf3e1SJohn Birrell 			for (p = d->first; p < d->last; p++)
11391eaf3e1SJohn Birrell 				*p1++ = *p;
11491eaf3e1SJohn Birrell 
11591eaf3e1SJohn Birrell 			count += (uintptr_t) d->next - (uintptr_t) d->bufr;
11691eaf3e1SJohn Birrell 
11791eaf3e1SJohn Birrell 			for (p = d->bufr; p < d->next; p++)
11891eaf3e1SJohn Birrell 				*p1++ = *p;
11991eaf3e1SJohn Birrell 		}
12091eaf3e1SJohn Birrell 
12191eaf3e1SJohn Birrell 		d->first = d->bufr;
12291eaf3e1SJohn Birrell 		d->next = d->bufr;
12391eaf3e1SJohn Birrell 
12491eaf3e1SJohn Birrell 		dtrace_debug_unlock(i);
12591eaf3e1SJohn Birrell 
12691eaf3e1SJohn Birrell 		if (count > 0) {
12791eaf3e1SJohn Birrell 			char *last = dtrace_debug_bufr + count;
12891eaf3e1SJohn Birrell 
12991eaf3e1SJohn Birrell 			p = dtrace_debug_bufr;
13091eaf3e1SJohn Birrell 
13191eaf3e1SJohn Birrell 			while (p < last) {
13291eaf3e1SJohn Birrell 				if (*p == '\0') {
13391eaf3e1SJohn Birrell 					p++;
13491eaf3e1SJohn Birrell 					continue;
13591eaf3e1SJohn Birrell 				}
13691eaf3e1SJohn Birrell 
13791eaf3e1SJohn Birrell 				printf("%s", p);
13891eaf3e1SJohn Birrell 
13991eaf3e1SJohn Birrell 				p += strlen(p);
14091eaf3e1SJohn Birrell 			}
14191eaf3e1SJohn Birrell 		}
14291eaf3e1SJohn Birrell 	}
14391eaf3e1SJohn Birrell }
14491eaf3e1SJohn Birrell 
14591eaf3e1SJohn Birrell /*
14691eaf3e1SJohn Birrell  * Functions below here are called from the probe context, so they can't call
14791eaf3e1SJohn Birrell  * _any_ functions outside the dtrace module without running foul of the function
14891eaf3e1SJohn Birrell  * boundary trace provider (fbt). The purpose of these functions is limited to
14991eaf3e1SJohn Birrell  * buffering debug strings for output when the probe completes on the current CPU.
15091eaf3e1SJohn Birrell  */
15191eaf3e1SJohn Birrell 
15291eaf3e1SJohn Birrell static __inline void
dtrace_debug__putc(int cpu,char c)1536969ef66SRyan Stone dtrace_debug__putc(int cpu, char c)
15491eaf3e1SJohn Birrell {
1556969ef66SRyan Stone 	struct dtrace_debug_data *d;
15691eaf3e1SJohn Birrell 
1576969ef66SRyan Stone 	d = &dtrace_debug_data[cpu];
15891eaf3e1SJohn Birrell 	*d->next++ = c;
15991eaf3e1SJohn Birrell 
16091eaf3e1SJohn Birrell 	if (d->next == d->last)
16191eaf3e1SJohn Birrell 		d->next = d->bufr;
16291eaf3e1SJohn Birrell 
16391eaf3e1SJohn Birrell 	*(d->next) = '\0';
16491eaf3e1SJohn Birrell 
16591eaf3e1SJohn Birrell 	if (d->next == d->first)
16691eaf3e1SJohn Birrell 		d->first++;
16791eaf3e1SJohn Birrell 
16891eaf3e1SJohn Birrell 	if (d->first == d->last)
16991eaf3e1SJohn Birrell 		d->first = d->bufr;
17091eaf3e1SJohn Birrell }
17191eaf3e1SJohn Birrell 
17291eaf3e1SJohn Birrell static void __used
dtrace_debug_putc(char c)17391eaf3e1SJohn Birrell dtrace_debug_putc(char c)
17491eaf3e1SJohn Birrell {
1756969ef66SRyan Stone 	int cpu;
17691eaf3e1SJohn Birrell 
1776969ef66SRyan Stone 	cpu = curcpu;
1786969ef66SRyan Stone 	dtrace_debug_lock(cpu);
17991eaf3e1SJohn Birrell 
1806969ef66SRyan Stone 	dtrace_debug__putc(cpu, c);
1816969ef66SRyan Stone 
1826969ef66SRyan Stone 	dtrace_debug_unlock(cpu);
18391eaf3e1SJohn Birrell }
18491eaf3e1SJohn Birrell 
18591eaf3e1SJohn Birrell static void __used
dtrace_debug_puts(const char * s)18691eaf3e1SJohn Birrell dtrace_debug_puts(const char *s)
18791eaf3e1SJohn Birrell {
1886969ef66SRyan Stone 	int cpu;
1896969ef66SRyan Stone 
1906969ef66SRyan Stone 	cpu = curcpu;
1916969ef66SRyan Stone 	dtrace_debug_lock(cpu);
19291eaf3e1SJohn Birrell 
19391eaf3e1SJohn Birrell 	while (*s != '\0')
1946969ef66SRyan Stone 		dtrace_debug__putc(cpu, *s++);
19591eaf3e1SJohn Birrell 
1966969ef66SRyan Stone 	dtrace_debug__putc(cpu, '\0');
19791eaf3e1SJohn Birrell 
1986969ef66SRyan Stone 	dtrace_debug_unlock(cpu);
19991eaf3e1SJohn Birrell }
20091eaf3e1SJohn Birrell 
20191eaf3e1SJohn Birrell /*
20291eaf3e1SJohn Birrell  * Snaffled from sys/kern/subr_prf.c
20391eaf3e1SJohn Birrell  *
20491eaf3e1SJohn Birrell  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
20591eaf3e1SJohn Birrell  * order; return an optional length and a pointer to the last character
20691eaf3e1SJohn Birrell  * written in the buffer (i.e., the first character of the string).
20791eaf3e1SJohn Birrell  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
20891eaf3e1SJohn Birrell  */
20991eaf3e1SJohn Birrell static char *
dtrace_debug_ksprintn(char * nbuf,uintmax_t num,int base,int * lenp,int upper)21091eaf3e1SJohn Birrell dtrace_debug_ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
21191eaf3e1SJohn Birrell {
21291eaf3e1SJohn Birrell 	char *p, c;
21391eaf3e1SJohn Birrell 
21491eaf3e1SJohn Birrell 	p = nbuf;
21591eaf3e1SJohn Birrell 	*p = '\0';
21691eaf3e1SJohn Birrell 	do {
21791eaf3e1SJohn Birrell 		c = hex2ascii(num % base);
21891eaf3e1SJohn Birrell 		*++p = upper ? toupper(c) : c;
21991eaf3e1SJohn Birrell 	} while (num /= base);
22091eaf3e1SJohn Birrell 	if (lenp)
22191eaf3e1SJohn Birrell 		*lenp = p - nbuf;
22291eaf3e1SJohn Birrell 	return (p);
22391eaf3e1SJohn Birrell }
22491eaf3e1SJohn Birrell 
22591eaf3e1SJohn Birrell #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
22691eaf3e1SJohn Birrell 
22791eaf3e1SJohn Birrell static void
dtrace_debug_vprintf(int cpu,const char * fmt,va_list ap)2286969ef66SRyan Stone dtrace_debug_vprintf(int cpu, const char *fmt, va_list ap)
22991eaf3e1SJohn Birrell {
23091eaf3e1SJohn Birrell 	char nbuf[MAXNBUF];
23191eaf3e1SJohn Birrell 	const char *p, *percent, *q;
23291eaf3e1SJohn Birrell 	u_char *up;
23391eaf3e1SJohn Birrell 	int ch, n;
23491eaf3e1SJohn Birrell 	uintmax_t num;
23591eaf3e1SJohn Birrell 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
23691eaf3e1SJohn Birrell 	int cflag, hflag, jflag, tflag, zflag;
23791eaf3e1SJohn Birrell 	int dwidth, upper;
23891eaf3e1SJohn Birrell 	int radix = 10;
23991eaf3e1SJohn Birrell 	char padc;
24091eaf3e1SJohn Birrell 	int stop = 0, retval = 0;
24191eaf3e1SJohn Birrell 
24291eaf3e1SJohn Birrell 	num = 0;
24391eaf3e1SJohn Birrell 
24491eaf3e1SJohn Birrell 	if (fmt == NULL)
24591eaf3e1SJohn Birrell 		fmt = "(fmt null)\n";
24691eaf3e1SJohn Birrell 
24791eaf3e1SJohn Birrell 	for (;;) {
24891eaf3e1SJohn Birrell 		padc = ' ';
24991eaf3e1SJohn Birrell 		width = 0;
25091eaf3e1SJohn Birrell 		while ((ch = (u_char)*fmt++) != '%' || stop) {
25191eaf3e1SJohn Birrell 			if (ch == '\0') {
2526969ef66SRyan Stone 				dtrace_debug__putc(cpu, '\0');
25391eaf3e1SJohn Birrell 				return;
25491eaf3e1SJohn Birrell 			}
2556969ef66SRyan Stone 			dtrace_debug__putc(cpu, ch);
25691eaf3e1SJohn Birrell 		}
25791eaf3e1SJohn Birrell 		percent = fmt - 1;
25891eaf3e1SJohn Birrell 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
25991eaf3e1SJohn Birrell 		sign = 0; dot = 0; dwidth = 0; upper = 0;
26091eaf3e1SJohn Birrell 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
26191eaf3e1SJohn Birrell reswitch:	switch (ch = (u_char)*fmt++) {
26291eaf3e1SJohn Birrell 		case '.':
26391eaf3e1SJohn Birrell 			dot = 1;
26491eaf3e1SJohn Birrell 			goto reswitch;
26591eaf3e1SJohn Birrell 		case '#':
26691eaf3e1SJohn Birrell 			sharpflag = 1;
26791eaf3e1SJohn Birrell 			goto reswitch;
26891eaf3e1SJohn Birrell 		case '+':
26991eaf3e1SJohn Birrell 			sign = 1;
27091eaf3e1SJohn Birrell 			goto reswitch;
27191eaf3e1SJohn Birrell 		case '-':
27291eaf3e1SJohn Birrell 			ladjust = 1;
27391eaf3e1SJohn Birrell 			goto reswitch;
27491eaf3e1SJohn Birrell 		case '%':
2756969ef66SRyan Stone 			dtrace_debug__putc(cpu, ch);
27691eaf3e1SJohn Birrell 			break;
27791eaf3e1SJohn Birrell 		case '*':
27891eaf3e1SJohn Birrell 			if (!dot) {
27991eaf3e1SJohn Birrell 				width = va_arg(ap, int);
28091eaf3e1SJohn Birrell 				if (width < 0) {
28191eaf3e1SJohn Birrell 					ladjust = !ladjust;
28291eaf3e1SJohn Birrell 					width = -width;
28391eaf3e1SJohn Birrell 				}
28491eaf3e1SJohn Birrell 			} else {
28591eaf3e1SJohn Birrell 				dwidth = va_arg(ap, int);
28691eaf3e1SJohn Birrell 			}
28791eaf3e1SJohn Birrell 			goto reswitch;
28891eaf3e1SJohn Birrell 		case '0':
28991eaf3e1SJohn Birrell 			if (!dot) {
29091eaf3e1SJohn Birrell 				padc = '0';
29191eaf3e1SJohn Birrell 				goto reswitch;
29291eaf3e1SJohn Birrell 			}
29391eaf3e1SJohn Birrell 		case '1': case '2': case '3': case '4':
29491eaf3e1SJohn Birrell 		case '5': case '6': case '7': case '8': case '9':
29591eaf3e1SJohn Birrell 				for (n = 0;; ++fmt) {
29691eaf3e1SJohn Birrell 					n = n * 10 + ch - '0';
29791eaf3e1SJohn Birrell 					ch = *fmt;
29891eaf3e1SJohn Birrell 					if (ch < '0' || ch > '9')
29991eaf3e1SJohn Birrell 						break;
30091eaf3e1SJohn Birrell 				}
30191eaf3e1SJohn Birrell 			if (dot)
30291eaf3e1SJohn Birrell 				dwidth = n;
30391eaf3e1SJohn Birrell 			else
30491eaf3e1SJohn Birrell 				width = n;
30591eaf3e1SJohn Birrell 			goto reswitch;
30691eaf3e1SJohn Birrell 		case 'b':
30791eaf3e1SJohn Birrell 			num = (u_int)va_arg(ap, int);
30891eaf3e1SJohn Birrell 			p = va_arg(ap, char *);
30991eaf3e1SJohn Birrell 			for (q = dtrace_debug_ksprintn(nbuf, num, *p++, NULL, 0); *q;)
3106969ef66SRyan Stone 				dtrace_debug__putc(cpu, *q--);
31191eaf3e1SJohn Birrell 
31291eaf3e1SJohn Birrell 			if (num == 0)
31391eaf3e1SJohn Birrell 				break;
31491eaf3e1SJohn Birrell 
31591eaf3e1SJohn Birrell 			for (tmp = 0; *p;) {
31691eaf3e1SJohn Birrell 				n = *p++;
31791eaf3e1SJohn Birrell 				if (num & (1 << (n - 1))) {
3186969ef66SRyan Stone 					dtrace_debug__putc(cpu, tmp ? ',' : '<');
31991eaf3e1SJohn Birrell 					for (; (n = *p) > ' '; ++p)
3206969ef66SRyan Stone 						dtrace_debug__putc(cpu, n);
32191eaf3e1SJohn Birrell 					tmp = 1;
32291eaf3e1SJohn Birrell 				} else
32391eaf3e1SJohn Birrell 					for (; *p > ' '; ++p)
32491eaf3e1SJohn Birrell 						continue;
32591eaf3e1SJohn Birrell 			}
32691eaf3e1SJohn Birrell 			if (tmp)
3276969ef66SRyan Stone 				dtrace_debug__putc(cpu, '>');
32891eaf3e1SJohn Birrell 			break;
32991eaf3e1SJohn Birrell 		case 'c':
3306969ef66SRyan Stone 			dtrace_debug__putc(cpu, va_arg(ap, int));
33191eaf3e1SJohn Birrell 			break;
33291eaf3e1SJohn Birrell 		case 'D':
33391eaf3e1SJohn Birrell 			up = va_arg(ap, u_char *);
33491eaf3e1SJohn Birrell 			p = va_arg(ap, char *);
33591eaf3e1SJohn Birrell 			if (!width)
33691eaf3e1SJohn Birrell 				width = 16;
33791eaf3e1SJohn Birrell 			while(width--) {
3386969ef66SRyan Stone 				dtrace_debug__putc(cpu, hex2ascii(*up >> 4));
3396969ef66SRyan Stone 				dtrace_debug__putc(cpu, hex2ascii(*up & 0x0f));
34091eaf3e1SJohn Birrell 				up++;
34191eaf3e1SJohn Birrell 				if (width)
34291eaf3e1SJohn Birrell 					for (q=p;*q;q++)
3436969ef66SRyan Stone 						dtrace_debug__putc(cpu, *q);
34491eaf3e1SJohn Birrell 			}
34591eaf3e1SJohn Birrell 			break;
34691eaf3e1SJohn Birrell 		case 'd':
34791eaf3e1SJohn Birrell 		case 'i':
34891eaf3e1SJohn Birrell 			base = 10;
34991eaf3e1SJohn Birrell 			sign = 1;
35091eaf3e1SJohn Birrell 			goto handle_sign;
35191eaf3e1SJohn Birrell 		case 'h':
35291eaf3e1SJohn Birrell 			if (hflag) {
35391eaf3e1SJohn Birrell 				hflag = 0;
35491eaf3e1SJohn Birrell 				cflag = 1;
35591eaf3e1SJohn Birrell 			} else
35691eaf3e1SJohn Birrell 				hflag = 1;
35791eaf3e1SJohn Birrell 			goto reswitch;
35891eaf3e1SJohn Birrell 		case 'j':
35991eaf3e1SJohn Birrell 			jflag = 1;
36091eaf3e1SJohn Birrell 			goto reswitch;
36191eaf3e1SJohn Birrell 		case 'l':
36291eaf3e1SJohn Birrell 			if (lflag) {
36391eaf3e1SJohn Birrell 				lflag = 0;
36491eaf3e1SJohn Birrell 				qflag = 1;
36591eaf3e1SJohn Birrell 			} else
36691eaf3e1SJohn Birrell 				lflag = 1;
36791eaf3e1SJohn Birrell 			goto reswitch;
36891eaf3e1SJohn Birrell 		case 'n':
36991eaf3e1SJohn Birrell 			if (jflag)
37091eaf3e1SJohn Birrell 				*(va_arg(ap, intmax_t *)) = retval;
37191eaf3e1SJohn Birrell 			else if (qflag)
37291eaf3e1SJohn Birrell 				*(va_arg(ap, quad_t *)) = retval;
37391eaf3e1SJohn Birrell 			else if (lflag)
37491eaf3e1SJohn Birrell 				*(va_arg(ap, long *)) = retval;
37591eaf3e1SJohn Birrell 			else if (zflag)
37691eaf3e1SJohn Birrell 				*(va_arg(ap, size_t *)) = retval;
37791eaf3e1SJohn Birrell 			else if (hflag)
37891eaf3e1SJohn Birrell 				*(va_arg(ap, short *)) = retval;
37991eaf3e1SJohn Birrell 			else if (cflag)
38091eaf3e1SJohn Birrell 				*(va_arg(ap, char *)) = retval;
38191eaf3e1SJohn Birrell 			else
38291eaf3e1SJohn Birrell 				*(va_arg(ap, int *)) = retval;
38391eaf3e1SJohn Birrell 			break;
38491eaf3e1SJohn Birrell 		case 'o':
38591eaf3e1SJohn Birrell 			base = 8;
38691eaf3e1SJohn Birrell 			goto handle_nosign;
38791eaf3e1SJohn Birrell 		case 'p':
38891eaf3e1SJohn Birrell 			base = 16;
38991eaf3e1SJohn Birrell 			sharpflag = (width == 0);
39091eaf3e1SJohn Birrell 			sign = 0;
39191eaf3e1SJohn Birrell 			num = (uintptr_t)va_arg(ap, void *);
39291eaf3e1SJohn Birrell 			goto number;
39391eaf3e1SJohn Birrell 		case 'q':
39491eaf3e1SJohn Birrell 			qflag = 1;
39591eaf3e1SJohn Birrell 			goto reswitch;
39691eaf3e1SJohn Birrell 		case 'r':
39791eaf3e1SJohn Birrell 			base = radix;
39891eaf3e1SJohn Birrell 			if (sign)
39991eaf3e1SJohn Birrell 				goto handle_sign;
40091eaf3e1SJohn Birrell 			goto handle_nosign;
40191eaf3e1SJohn Birrell 		case 's':
40291eaf3e1SJohn Birrell 			p = va_arg(ap, char *);
40391eaf3e1SJohn Birrell 			if (p == NULL)
40491eaf3e1SJohn Birrell 				p = "(null)";
40591eaf3e1SJohn Birrell 			if (!dot)
40691eaf3e1SJohn Birrell 				n = strlen (p);
40791eaf3e1SJohn Birrell 			else
40891eaf3e1SJohn Birrell 				for (n = 0; n < dwidth && p[n]; n++)
40991eaf3e1SJohn Birrell 					continue;
41091eaf3e1SJohn Birrell 
41191eaf3e1SJohn Birrell 			width -= n;
41291eaf3e1SJohn Birrell 
41391eaf3e1SJohn Birrell 			if (!ladjust && width > 0)
41491eaf3e1SJohn Birrell 				while (width--)
4156969ef66SRyan Stone 					dtrace_debug__putc(cpu, padc);
41691eaf3e1SJohn Birrell 			while (n--)
4176969ef66SRyan Stone 				dtrace_debug__putc(cpu, *p++);
41891eaf3e1SJohn Birrell 			if (ladjust && width > 0)
41991eaf3e1SJohn Birrell 				while (width--)
4206969ef66SRyan Stone 					dtrace_debug__putc(cpu, padc);
42191eaf3e1SJohn Birrell 			break;
42291eaf3e1SJohn Birrell 		case 't':
42391eaf3e1SJohn Birrell 			tflag = 1;
42491eaf3e1SJohn Birrell 			goto reswitch;
42591eaf3e1SJohn Birrell 		case 'u':
42691eaf3e1SJohn Birrell 			base = 10;
42791eaf3e1SJohn Birrell 			goto handle_nosign;
42891eaf3e1SJohn Birrell 		case 'X':
42991eaf3e1SJohn Birrell 			upper = 1;
43091eaf3e1SJohn Birrell 		case 'x':
43191eaf3e1SJohn Birrell 			base = 16;
43291eaf3e1SJohn Birrell 			goto handle_nosign;
43391eaf3e1SJohn Birrell 		case 'y':
43491eaf3e1SJohn Birrell 			base = 16;
43591eaf3e1SJohn Birrell 			sign = 1;
43691eaf3e1SJohn Birrell 			goto handle_sign;
43791eaf3e1SJohn Birrell 		case 'z':
43891eaf3e1SJohn Birrell 			zflag = 1;
43991eaf3e1SJohn Birrell 			goto reswitch;
44091eaf3e1SJohn Birrell handle_nosign:
44191eaf3e1SJohn Birrell 			sign = 0;
44291eaf3e1SJohn Birrell 			if (jflag)
44391eaf3e1SJohn Birrell 				num = va_arg(ap, uintmax_t);
44491eaf3e1SJohn Birrell 			else if (qflag)
44591eaf3e1SJohn Birrell 				num = va_arg(ap, u_quad_t);
44691eaf3e1SJohn Birrell 			else if (tflag)
44791eaf3e1SJohn Birrell 				num = va_arg(ap, ptrdiff_t);
44891eaf3e1SJohn Birrell 			else if (lflag)
44991eaf3e1SJohn Birrell 				num = va_arg(ap, u_long);
45091eaf3e1SJohn Birrell 			else if (zflag)
45191eaf3e1SJohn Birrell 				num = va_arg(ap, size_t);
45291eaf3e1SJohn Birrell 			else if (hflag)
45391eaf3e1SJohn Birrell 				num = (u_short)va_arg(ap, int);
45491eaf3e1SJohn Birrell 			else if (cflag)
45591eaf3e1SJohn Birrell 				num = (u_char)va_arg(ap, int);
45691eaf3e1SJohn Birrell 			else
45791eaf3e1SJohn Birrell 				num = va_arg(ap, u_int);
45891eaf3e1SJohn Birrell 			goto number;
45991eaf3e1SJohn Birrell handle_sign:
46091eaf3e1SJohn Birrell 			if (jflag)
46191eaf3e1SJohn Birrell 				num = va_arg(ap, intmax_t);
46291eaf3e1SJohn Birrell 			else if (qflag)
46391eaf3e1SJohn Birrell 				num = va_arg(ap, quad_t);
46491eaf3e1SJohn Birrell 			else if (tflag)
46591eaf3e1SJohn Birrell 				num = va_arg(ap, ptrdiff_t);
46691eaf3e1SJohn Birrell 			else if (lflag)
46791eaf3e1SJohn Birrell 				num = va_arg(ap, long);
46891eaf3e1SJohn Birrell 			else if (zflag)
46991eaf3e1SJohn Birrell 				num = va_arg(ap, size_t);
47091eaf3e1SJohn Birrell 			else if (hflag)
47191eaf3e1SJohn Birrell 				num = (short)va_arg(ap, int);
47291eaf3e1SJohn Birrell 			else if (cflag)
47391eaf3e1SJohn Birrell 				num = (char)va_arg(ap, int);
47491eaf3e1SJohn Birrell 			else
47591eaf3e1SJohn Birrell 				num = va_arg(ap, int);
47691eaf3e1SJohn Birrell number:
47791eaf3e1SJohn Birrell 			if (sign && (intmax_t)num < 0) {
47891eaf3e1SJohn Birrell 				neg = 1;
47991eaf3e1SJohn Birrell 				num = -(intmax_t)num;
48091eaf3e1SJohn Birrell 			}
48191eaf3e1SJohn Birrell 			p = dtrace_debug_ksprintn(nbuf, num, base, &tmp, upper);
48291eaf3e1SJohn Birrell 			if (sharpflag && num != 0) {
48391eaf3e1SJohn Birrell 				if (base == 8)
48491eaf3e1SJohn Birrell 					tmp++;
48591eaf3e1SJohn Birrell 				else if (base == 16)
48691eaf3e1SJohn Birrell 					tmp += 2;
48791eaf3e1SJohn Birrell 			}
48891eaf3e1SJohn Birrell 			if (neg)
48991eaf3e1SJohn Birrell 				tmp++;
49091eaf3e1SJohn Birrell 
49191eaf3e1SJohn Birrell 			if (!ladjust && padc != '0' && width
49291eaf3e1SJohn Birrell 			    && (width -= tmp) > 0)
49391eaf3e1SJohn Birrell 				while (width--)
4946969ef66SRyan Stone 					dtrace_debug__putc(cpu, padc);
49591eaf3e1SJohn Birrell 			if (neg)
4966969ef66SRyan Stone 				dtrace_debug__putc(cpu, '-');
49791eaf3e1SJohn Birrell 			if (sharpflag && num != 0) {
49891eaf3e1SJohn Birrell 				if (base == 8) {
4996969ef66SRyan Stone 					dtrace_debug__putc(cpu, '0');
50091eaf3e1SJohn Birrell 				} else if (base == 16) {
5016969ef66SRyan Stone 					dtrace_debug__putc(cpu, '0');
5026969ef66SRyan Stone 					dtrace_debug__putc(cpu, 'x');
50391eaf3e1SJohn Birrell 				}
50491eaf3e1SJohn Birrell 			}
50591eaf3e1SJohn Birrell 			if (!ladjust && width && (width -= tmp) > 0)
50691eaf3e1SJohn Birrell 				while (width--)
5076969ef66SRyan Stone 					dtrace_debug__putc(cpu, padc);
50891eaf3e1SJohn Birrell 
50991eaf3e1SJohn Birrell 			while (*p)
5106969ef66SRyan Stone 				dtrace_debug__putc(cpu, *p--);
51191eaf3e1SJohn Birrell 
51291eaf3e1SJohn Birrell 			if (ladjust && width && (width -= tmp) > 0)
51391eaf3e1SJohn Birrell 				while (width--)
5146969ef66SRyan Stone 					dtrace_debug__putc(cpu, padc);
51591eaf3e1SJohn Birrell 
51691eaf3e1SJohn Birrell 			break;
51791eaf3e1SJohn Birrell 		default:
51891eaf3e1SJohn Birrell 			while (percent < fmt)
5196969ef66SRyan Stone 				dtrace_debug__putc(cpu, *percent++);
52091eaf3e1SJohn Birrell 			/*
52191eaf3e1SJohn Birrell 			 * Since we ignore an formatting argument it is no
52291eaf3e1SJohn Birrell 			 * longer safe to obey the remaining formatting
52391eaf3e1SJohn Birrell 			 * arguments as the arguments will no longer match
52491eaf3e1SJohn Birrell 			 * the format specs.
52591eaf3e1SJohn Birrell 			 */
52691eaf3e1SJohn Birrell 			stop = 1;
52791eaf3e1SJohn Birrell 			break;
52891eaf3e1SJohn Birrell 		}
52991eaf3e1SJohn Birrell 	}
53091eaf3e1SJohn Birrell 
5316969ef66SRyan Stone 	dtrace_debug__putc(cpu, '\0');
53291eaf3e1SJohn Birrell }
53391eaf3e1SJohn Birrell 
53491eaf3e1SJohn Birrell void
dtrace_debug_printf(const char * fmt,...)53591eaf3e1SJohn Birrell dtrace_debug_printf(const char *fmt, ...)
53691eaf3e1SJohn Birrell {
53791eaf3e1SJohn Birrell 	va_list ap;
5386969ef66SRyan Stone 	int cpu;
53991eaf3e1SJohn Birrell 
5406969ef66SRyan Stone 	cpu = curcpu;
5416969ef66SRyan Stone 	dtrace_debug_lock(cpu);
54291eaf3e1SJohn Birrell 
54391eaf3e1SJohn Birrell 	va_start(ap, fmt);
54491eaf3e1SJohn Birrell 
5456969ef66SRyan Stone 	dtrace_debug_vprintf(cpu, fmt, ap);
54691eaf3e1SJohn Birrell 
54791eaf3e1SJohn Birrell 	va_end(ap);
54891eaf3e1SJohn Birrell 
5496969ef66SRyan Stone 	dtrace_debug_unlock(cpu);
55091eaf3e1SJohn Birrell }
55191eaf3e1SJohn Birrell 
55291eaf3e1SJohn Birrell #else
55391eaf3e1SJohn Birrell 
55491eaf3e1SJohn Birrell #define dtrace_debug_output()
55591eaf3e1SJohn Birrell #define dtrace_debug_puts(_s)
55691eaf3e1SJohn Birrell #define dtrace_debug_printf(fmt, ...)
55791eaf3e1SJohn Birrell 
55891eaf3e1SJohn Birrell #endif
559