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 #include <machine/atomic.h>
36 #define DTRACE_DEBUG_BUFR_SIZE (32 * 1024)
38 struct dtrace_debug_data {
39 uintptr_t lock __aligned(CACHE_LINE_SIZE);
40 char bufr[DTRACE_DEBUG_BUFR_SIZE];
44 } dtrace_debug_data[MAXCPU];
46 static char dtrace_debug_bufr[DTRACE_DEBUG_BUFR_SIZE];
49 dtrace_debug_lock(int cpu)
53 tid = (uintptr_t)curthread;
55 while (atomic_cmpset_acq_ptr(&dtrace_debug_data[cpu].lock, 0, tid) == 0) /* Loop until the lock is obtained. */
60 dtrace_debug_unlock(int cpu)
62 atomic_store_rel_ptr(&dtrace_debug_data[cpu].lock, 0);
67 dtrace_debug_init(void *dummy)
70 struct dtrace_debug_data *d;
73 d = &dtrace_debug_data[i];
75 if (d->first == NULL) {
78 d->last = d->bufr + DTRACE_DEBUG_BUFR_SIZE - 1;
84 SYSINIT(dtrace_debug_init, SI_SUB_KDTRACE, SI_ORDER_ANY, dtrace_debug_init, NULL);
85 SYSINIT(dtrace_debug_smpinit, SI_SUB_SMP, SI_ORDER_ANY, dtrace_debug_init, NULL);
88 dtrace_debug_output(void)
92 struct dtrace_debug_data *d;
98 d = &dtrace_debug_data[i];
102 if (d->first < d->next) {
103 char *p1 = dtrace_debug_bufr;
105 count = (uintptr_t) d->next - (uintptr_t) d->first;
107 for (p = d->first; p < d->next; p++)
109 } else if (d->next > d->first) {
110 char *p1 = dtrace_debug_bufr;
112 count = (uintptr_t) d->last - (uintptr_t) d->first;
114 for (p = d->first; p < d->last; p++)
117 count += (uintptr_t) d->next - (uintptr_t) d->bufr;
119 for (p = d->bufr; p < d->next; p++)
126 dtrace_debug_unlock(i);
129 char *last = dtrace_debug_bufr + count;
131 p = dtrace_debug_bufr;
148 * Functions below here are called from the probe context, so they can't call
149 * _any_ functions outside the dtrace module without running foul of the function
150 * boundary trace provider (fbt). The purpose of these functions is limited to
151 * buffering debug strings for output when the probe completes on the current CPU.
155 dtrace_debug__putc(int cpu, char c)
157 struct dtrace_debug_data *d;
159 d = &dtrace_debug_data[cpu];
162 if (d->next == d->last)
167 if (d->next == d->first)
170 if (d->first == d->last)
175 dtrace_debug_putc(char c)
180 dtrace_debug_lock(cpu);
182 dtrace_debug__putc(cpu, c);
184 dtrace_debug_unlock(cpu);
188 dtrace_debug_puts(const char *s)
193 dtrace_debug_lock(cpu);
196 dtrace_debug__putc(cpu, *s++);
198 dtrace_debug__putc(cpu, '\0');
200 dtrace_debug_unlock(cpu);
204 * Snaffled from sys/kern/subr_prf.c
206 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
207 * order; return an optional length and a pointer to the last character
208 * written in the buffer (i.e., the first character of the string).
209 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
212 dtrace_debug_ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
219 c = hex2ascii(num % base);
220 *++p = upper ? toupper(c) : c;
221 } while (num /= base);
227 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
230 dtrace_debug_vprintf(int cpu, const char *fmt, va_list ap)
233 const char *p, *percent, *q;
237 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
238 int cflag, hflag, jflag, tflag, zflag;
242 int stop = 0, retval = 0;
247 fmt = "(fmt null)\n";
252 while ((ch = (u_char)*fmt++) != '%' || stop) {
254 dtrace_debug__putc(cpu, '\0');
257 dtrace_debug__putc(cpu, ch);
260 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
261 sign = 0; dot = 0; dwidth = 0; upper = 0;
262 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
263 reswitch: switch (ch = (u_char)*fmt++) {
277 dtrace_debug__putc(cpu, ch);
281 width = va_arg(ap, int);
287 dwidth = va_arg(ap, int);
295 case '1': case '2': case '3': case '4':
296 case '5': case '6': case '7': case '8': case '9':
297 for (n = 0;; ++fmt) {
298 n = n * 10 + ch - '0';
300 if (ch < '0' || ch > '9')
309 num = (u_int)va_arg(ap, int);
310 p = va_arg(ap, char *);
311 for (q = dtrace_debug_ksprintn(nbuf, num, *p++, NULL, 0); *q;)
312 dtrace_debug__putc(cpu, *q--);
319 if (num & (1 << (n - 1))) {
320 dtrace_debug__putc(cpu, tmp ? ',' : '<');
321 for (; (n = *p) > ' '; ++p)
322 dtrace_debug__putc(cpu, n);
325 for (; *p > ' '; ++p)
329 dtrace_debug__putc(cpu, '>');
332 dtrace_debug__putc(cpu, va_arg(ap, int));
335 up = va_arg(ap, u_char *);
336 p = va_arg(ap, char *);
340 dtrace_debug__putc(cpu, hex2ascii(*up >> 4));
341 dtrace_debug__putc(cpu, hex2ascii(*up & 0x0f));
345 dtrace_debug__putc(cpu, *q);
372 *(va_arg(ap, intmax_t *)) = retval;
374 *(va_arg(ap, quad_t *)) = retval;
376 *(va_arg(ap, long *)) = retval;
378 *(va_arg(ap, size_t *)) = retval;
380 *(va_arg(ap, short *)) = retval;
382 *(va_arg(ap, char *)) = retval;
384 *(va_arg(ap, int *)) = retval;
391 sharpflag = (width == 0);
393 num = (uintptr_t)va_arg(ap, void *);
404 p = va_arg(ap, char *);
410 for (n = 0; n < dwidth && p[n]; n++)
415 if (!ladjust && width > 0)
417 dtrace_debug__putc(cpu, padc);
419 dtrace_debug__putc(cpu, *p++);
420 if (ladjust && width > 0)
422 dtrace_debug__putc(cpu, padc);
445 num = va_arg(ap, uintmax_t);
447 num = va_arg(ap, u_quad_t);
449 num = va_arg(ap, ptrdiff_t);
451 num = va_arg(ap, u_long);
453 num = va_arg(ap, size_t);
455 num = (u_short)va_arg(ap, int);
457 num = (u_char)va_arg(ap, int);
459 num = va_arg(ap, u_int);
463 num = va_arg(ap, intmax_t);
465 num = va_arg(ap, quad_t);
467 num = va_arg(ap, ptrdiff_t);
469 num = va_arg(ap, long);
471 num = va_arg(ap, size_t);
473 num = (short)va_arg(ap, int);
475 num = (char)va_arg(ap, int);
477 num = va_arg(ap, int);
479 if (sign && (intmax_t)num < 0) {
481 num = -(intmax_t)num;
483 p = dtrace_debug_ksprintn(nbuf, num, base, &tmp, upper);
484 if (sharpflag && num != 0) {
493 if (!ladjust && padc != '0' && width
494 && (width -= tmp) > 0)
496 dtrace_debug__putc(cpu, padc);
498 dtrace_debug__putc(cpu, '-');
499 if (sharpflag && num != 0) {
501 dtrace_debug__putc(cpu, '0');
502 } else if (base == 16) {
503 dtrace_debug__putc(cpu, '0');
504 dtrace_debug__putc(cpu, 'x');
507 if (!ladjust && width && (width -= tmp) > 0)
509 dtrace_debug__putc(cpu, padc);
512 dtrace_debug__putc(cpu, *p--);
514 if (ladjust && width && (width -= tmp) > 0)
516 dtrace_debug__putc(cpu, padc);
520 while (percent < fmt)
521 dtrace_debug__putc(cpu, *percent++);
523 * Since we ignore an formatting argument it is no
524 * longer safe to obey the remaining formatting
525 * arguments as the arguments will no longer match
533 dtrace_debug__putc(cpu, '\0');
537 dtrace_debug_printf(const char *fmt, ...)
543 dtrace_debug_lock(cpu);
547 dtrace_debug_vprintf(cpu, fmt, ap);
551 dtrace_debug_unlock(cpu);
556 #define dtrace_debug_output()
557 #define dtrace_debug_puts(_s)
558 #define dtrace_debug_printf(fmt, ...)