2 * Copyright (C) 2008 John Birrell <jb@freebsd.org>.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice(s), this list of conditions and the following disclaimer as
10 * the first lines of this file unmodified other than the possible
11 * addition of one or more copyright notices.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice(s), this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34 #if defined(__amd64__)
36 dtrace_cmpset_long(volatile u_long *dst, u_long exp, u_long src)
45 "# dtrace_cmpset_long"
55 #elif defined(__i386__)
57 dtrace_cmpset_long(volatile u_long *dst, u_long exp, u_long src)
66 "# dtrace_cmpset_long"
78 #define DTRACE_DEBUG_BUFR_SIZE (32 * 1024)
80 struct dtrace_debug_data {
81 char bufr[DTRACE_DEBUG_BUFR_SIZE];
85 } dtrace_debug_data[MAXCPU];
87 static char dtrace_debug_bufr[DTRACE_DEBUG_BUFR_SIZE];
89 static volatile u_long dtrace_debug_flag[MAXCPU];
92 dtrace_debug_lock(int cpu)
94 while (dtrace_cmpset_long(&dtrace_debug_flag[cpu], 0, 1) == 0)
95 /* Loop until the lock is obtained. */
100 dtrace_debug_unlock(int cpu)
102 dtrace_debug_flag[cpu] = 0;
106 dtrace_debug_init(void *dummy)
109 struct dtrace_debug_data *d;
111 for (i = 0; i <= mp_maxid; i++) {
112 if (pcpu_find(i) == NULL)
115 d = &dtrace_debug_data[i];
117 if (d->first == NULL) {
120 d->last = d->bufr + DTRACE_DEBUG_BUFR_SIZE - 1;
126 SYSINIT(dtrace_debug_init, SI_SUB_KDTRACE, SI_ORDER_ANY, dtrace_debug_init, NULL);
127 SYSINIT(dtrace_debug_smpinit, SI_SUB_SMP, SI_ORDER_ANY, dtrace_debug_init, NULL);
130 dtrace_debug_output(void)
134 struct dtrace_debug_data *d;
137 for (i = 0; i <= mp_maxid; i++) {
138 if (pcpu_find(i) == NULL)
141 dtrace_debug_lock(i);
143 d = &dtrace_debug_data[i];
147 if (d->first < d->next) {
148 char *p1 = dtrace_debug_bufr;
150 count = (uintptr_t) d->next - (uintptr_t) d->first;
152 for (p = d->first; p < d->next; p++)
154 } else if (d->next > d->first) {
155 char *p1 = dtrace_debug_bufr;
157 count = (uintptr_t) d->last - (uintptr_t) d->first;
159 for (p = d->first; p < d->last; p++)
162 count += (uintptr_t) d->next - (uintptr_t) d->bufr;
164 for (p = d->bufr; p < d->next; p++)
171 dtrace_debug_unlock(i);
174 char *last = dtrace_debug_bufr + count;
176 p = dtrace_debug_bufr;
193 * Functions below here are called from the probe context, so they can't call
194 * _any_ functions outside the dtrace module without running foul of the function
195 * boundary trace provider (fbt). The purpose of these functions is limited to
196 * buffering debug strings for output when the probe completes on the current CPU.
200 dtrace_debug__putc(char c)
202 struct dtrace_debug_data *d = &dtrace_debug_data[curcpu];
206 if (d->next == d->last)
211 if (d->next == d->first)
214 if (d->first == d->last)
219 dtrace_debug_putc(char c)
221 dtrace_debug_lock(curcpu);
223 dtrace_debug__putc(c);
225 dtrace_debug_unlock(curcpu);
229 dtrace_debug_puts(const char *s)
231 dtrace_debug_lock(curcpu);
234 dtrace_debug__putc(*s++);
236 dtrace_debug__putc('\0');
238 dtrace_debug_unlock(curcpu);
242 * Snaffled from sys/kern/subr_prf.c
244 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
245 * order; return an optional length and a pointer to the last character
246 * written in the buffer (i.e., the first character of the string).
247 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
250 dtrace_debug_ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
257 c = hex2ascii(num % base);
258 *++p = upper ? toupper(c) : c;
259 } while (num /= base);
265 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
268 dtrace_debug_vprintf(const char *fmt, va_list ap)
271 const char *p, *percent, *q;
275 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
276 int cflag, hflag, jflag, tflag, zflag;
280 int stop = 0, retval = 0;
285 fmt = "(fmt null)\n";
290 while ((ch = (u_char)*fmt++) != '%' || stop) {
292 dtrace_debug__putc('\0');
295 dtrace_debug__putc(ch);
298 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
299 sign = 0; dot = 0; dwidth = 0; upper = 0;
300 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
301 reswitch: switch (ch = (u_char)*fmt++) {
315 dtrace_debug__putc(ch);
319 width = va_arg(ap, int);
325 dwidth = va_arg(ap, int);
333 case '1': case '2': case '3': case '4':
334 case '5': case '6': case '7': case '8': case '9':
335 for (n = 0;; ++fmt) {
336 n = n * 10 + ch - '0';
338 if (ch < '0' || ch > '9')
347 num = (u_int)va_arg(ap, int);
348 p = va_arg(ap, char *);
349 for (q = dtrace_debug_ksprintn(nbuf, num, *p++, NULL, 0); *q;)
350 dtrace_debug__putc(*q--);
357 if (num & (1 << (n - 1))) {
358 dtrace_debug__putc(tmp ? ',' : '<');
359 for (; (n = *p) > ' '; ++p)
360 dtrace_debug__putc(n);
363 for (; *p > ' '; ++p)
367 dtrace_debug__putc('>');
370 dtrace_debug__putc(va_arg(ap, int));
373 up = va_arg(ap, u_char *);
374 p = va_arg(ap, char *);
378 dtrace_debug__putc(hex2ascii(*up >> 4));
379 dtrace_debug__putc(hex2ascii(*up & 0x0f));
383 dtrace_debug__putc(*q);
410 *(va_arg(ap, intmax_t *)) = retval;
412 *(va_arg(ap, quad_t *)) = retval;
414 *(va_arg(ap, long *)) = retval;
416 *(va_arg(ap, size_t *)) = retval;
418 *(va_arg(ap, short *)) = retval;
420 *(va_arg(ap, char *)) = retval;
422 *(va_arg(ap, int *)) = retval;
429 sharpflag = (width == 0);
431 num = (uintptr_t)va_arg(ap, void *);
442 p = va_arg(ap, char *);
448 for (n = 0; n < dwidth && p[n]; n++)
453 if (!ladjust && width > 0)
455 dtrace_debug__putc(padc);
457 dtrace_debug__putc(*p++);
458 if (ladjust && width > 0)
460 dtrace_debug__putc(padc);
483 num = va_arg(ap, uintmax_t);
485 num = va_arg(ap, u_quad_t);
487 num = va_arg(ap, ptrdiff_t);
489 num = va_arg(ap, u_long);
491 num = va_arg(ap, size_t);
493 num = (u_short)va_arg(ap, int);
495 num = (u_char)va_arg(ap, int);
497 num = va_arg(ap, u_int);
501 num = va_arg(ap, intmax_t);
503 num = va_arg(ap, quad_t);
505 num = va_arg(ap, ptrdiff_t);
507 num = va_arg(ap, long);
509 num = va_arg(ap, size_t);
511 num = (short)va_arg(ap, int);
513 num = (char)va_arg(ap, int);
515 num = va_arg(ap, int);
517 if (sign && (intmax_t)num < 0) {
519 num = -(intmax_t)num;
521 p = dtrace_debug_ksprintn(nbuf, num, base, &tmp, upper);
522 if (sharpflag && num != 0) {
531 if (!ladjust && padc != '0' && width
532 && (width -= tmp) > 0)
534 dtrace_debug__putc(padc);
536 dtrace_debug__putc('-');
537 if (sharpflag && num != 0) {
539 dtrace_debug__putc('0');
540 } else if (base == 16) {
541 dtrace_debug__putc('0');
542 dtrace_debug__putc('x');
545 if (!ladjust && width && (width -= tmp) > 0)
547 dtrace_debug__putc(padc);
550 dtrace_debug__putc(*p--);
552 if (ladjust && width && (width -= tmp) > 0)
554 dtrace_debug__putc(padc);
558 while (percent < fmt)
559 dtrace_debug__putc(*percent++);
561 * Since we ignore an formatting argument it is no
562 * longer safe to obey the remaining formatting
563 * arguments as the arguments will no longer match
571 dtrace_debug__putc('\0');
575 dtrace_debug_printf(const char *fmt, ...)
579 dtrace_debug_lock(curcpu);
583 dtrace_debug_vprintf(fmt, ap);
587 dtrace_debug_unlock(curcpu);
592 #define dtrace_debug_output()
593 #define dtrace_debug_puts(_s)
594 #define dtrace_debug_printf(fmt, ...)