1 /*-
2 * Copyright (C) 2008 John Birrell <jb@freebsd.org>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
15 *
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
26 * DAMAGE.
27 *
28 * $FreeBSD$
29 *
30 */
31
32 #ifdef DEBUG
33
34 #include <machine/atomic.h>
35
36 #define DTRACE_DEBUG_BUFR_SIZE (32 * 1024)
37
38 struct dtrace_debug_data {
39 uintptr_t lock __aligned(CACHE_LINE_SIZE);
40 char bufr[DTRACE_DEBUG_BUFR_SIZE];
41 char *first;
42 char *last;
43 char *next;
44 } dtrace_debug_data[MAXCPU];
45
46 static char dtrace_debug_bufr[DTRACE_DEBUG_BUFR_SIZE];
47
48 static void
49 dtrace_debug_lock(int cpu)
50 {
51 uintptr_t tid;
52
53 tid = (uintptr_t)curthread;
54 spinlock_enter();
55 while (atomic_cmpset_acq_ptr(&dtrace_debug_data[cpu].lock, 0, tid) == 0) /* Loop until the lock is obtained. */
56 ;
57 }
58
59 static void
60 dtrace_debug_unlock(int cpu)
61 {
62 atomic_store_rel_ptr(&dtrace_debug_data[cpu].lock, 0);
63 spinlock_exit();
64 }
65
66 static void
67 dtrace_debug_init(void *dummy)
68 {
69 int i;
70 struct dtrace_debug_data *d;
71
72 CPU_FOREACH(i) {
73 d = &dtrace_debug_data[i];
74
75 if (d->first == NULL) {
76 d->first = d->bufr;
77 d->next = d->bufr;
78 d->last = d->bufr + DTRACE_DEBUG_BUFR_SIZE - 1;
79 *(d->last) = '\0';
80 }
81 }
82 }
83
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);
86
87 static void
88 dtrace_debug_output(void)
89 {
90 char *p;
91 int i;
92 struct dtrace_debug_data *d;
93 uintptr_t count;
94
95 CPU_FOREACH(i) {
96 dtrace_debug_lock(i);
97
98 d = &dtrace_debug_data[i];
99
100 count = 0;
101
102 if (d->first < d->next) {
103 char *p1 = dtrace_debug_bufr;
104
105 count = (uintptr_t) d->next - (uintptr_t) d->first;
106
107 for (p = d->first; p < d->next; p++)
108 *p1++ = *p;
109 } else if (d->first > d->next) {
110 char *p1 = dtrace_debug_bufr;
111
112 count = (uintptr_t) d->last - (uintptr_t) d->first;
113
114 for (p = d->first; p < d->last; p++)
115 *p1++ = *p;
116
117 count += (uintptr_t) d->next - (uintptr_t) d->bufr;
118
119 for (p = d->bufr; p < d->next; p++)
120 *p1++ = *p;
121 }
122
123 d->first = d->bufr;
124 d->next = d->bufr;
125
126 dtrace_debug_unlock(i);
127
128 if (count > 0) {
129 char *last = dtrace_debug_bufr + count;
130
131 p = dtrace_debug_bufr;
132
133 while (p < last) {
134 if (*p == '\0') {
135 p++;
136 continue;
137 }
138
139 printf("%s", p);
140
141 p += strlen(p);
142 }
143 }
144 }
145 }
146
147 /*
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.
152 */
153
154 static __inline void
155 dtrace_debug__putc(int cpu, char c)
156 {
157 struct dtrace_debug_data *d;
158
159 d = &dtrace_debug_data[cpu];
160 *d->next++ = c;
161
162 if (d->next == d->last)
163 d->next = d->bufr;
164
165 *(d->next) = '\0';
166
167 if (d->next == d->first)
168 d->first++;
169
170 if (d->first == d->last)
171 d->first = d->bufr;
172 }
173
174 static void __used
175 dtrace_debug_putc(char c)
176 {
177 int cpu;
178
179 cpu = curcpu;
180 dtrace_debug_lock(cpu);
181
182 dtrace_debug__putc(cpu, c);
183
184 dtrace_debug_unlock(cpu);
185 }
186
187 static void __used
188 dtrace_debug_puts(const char *s)
189 {
190 int cpu;
191
192 cpu = curcpu;
193 dtrace_debug_lock(cpu);
194
195 while (*s != '\0')
196 dtrace_debug__putc(cpu, *s++);
197
198 dtrace_debug__putc(cpu, '\0');
199
200 dtrace_debug_unlock(cpu);
201 }
202
203 /*
204 * Snaffled from sys/kern/subr_prf.c
205 *
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.
210 */
211 static char *
212 dtrace_debug_ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
213 {
214 char *p, c;
215
216 p = nbuf;
217 *p = '\0';
218 do {
219 c = hex2ascii(num % base);
220 *++p = upper ? toupper(c) : c;
221 } while (num /= base);
222 if (lenp)
223 *lenp = p - nbuf;
224 return (p);
225 }
226
227 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1)
228
229 static void
230 dtrace_debug_vprintf(int cpu, const char *fmt, va_list ap)
231 {
232 char nbuf[MAXNBUF];
233 const char *p, *percent, *q;
234 u_char *up;
235 int ch, n;
236 uintmax_t num;
237 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
238 int cflag, hflag, jflag, tflag, zflag;
239 int dwidth, upper;
240 int radix = 10;
241 char padc;
242 int stop = 0, retval = 0;
243
244 num = 0;
245
246 if (fmt == NULL)
247 fmt = "(fmt null)\n";
248
249 for (;;) {
250 padc = ' ';
251 width = 0;
252 while ((ch = (u_char)*fmt++) != '%' || stop) {
253 if (ch == '\0') {
254 dtrace_debug__putc(cpu, '\0');
255 return;
256 }
257 dtrace_debug__putc(cpu, ch);
258 }
259 percent = fmt - 1;
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++) {
264 case '.':
265 dot = 1;
266 goto reswitch;
267 case '#':
268 sharpflag = 1;
269 goto reswitch;
270 case '+':
271 sign = 1;
272 goto reswitch;
273 case '-':
274 ladjust = 1;
275 goto reswitch;
276 case '%':
277 dtrace_debug__putc(cpu, ch);
278 break;
279 case '*':
280 if (!dot) {
281 width = va_arg(ap, int);
282 if (width < 0) {
283 ladjust = !ladjust;
284 width = -width;
285 }
286 } else {
287 dwidth = va_arg(ap, int);
288 }
289 goto reswitch;
290 case '':
291 if (!dot) {
292 padc = '';
293 goto reswitch;
294 }
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 - '';
299 ch = *fmt;
300 if (ch < '' || ch > '9')
301 break;
302 }
303 if (dot)
304 dwidth = n;
305 else
306 width = n;
307 goto reswitch;
308 case 'b':
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--);
313
314 if (num == 0)
315 break;
316
317 for (tmp = 0; *p;) {
318 n = *p++;
319 if (num & (1 << (n - 1))) {
320 dtrace_debug__putc(cpu, tmp ? ',' : '<');
321 for (; (n = *p) > ' '; ++p)
322 dtrace_debug__putc(cpu, n);
323 tmp = 1;
324 } else
325 for (; *p > ' '; ++p)
326 continue;
327 }
328 if (tmp)
329 dtrace_debug__putc(cpu, '>');
330 break;
331 case 'c':
332 dtrace_debug__putc(cpu, va_arg(ap, int));
333 break;
334 case 'D':
335 up = va_arg(ap, u_char *);
336 p = va_arg(ap, char *);
337 if (!width)
338 width = 16;
339 while(width--) {
340 dtrace_debug__putc(cpu, hex2ascii(*up >> 4));
341 dtrace_debug__putc(cpu, hex2ascii(*up & 0x0f));
342 up++;
343 if (width)
344 for (q=p;*q;q++)
345 dtrace_debug__putc(cpu, *q);
346 }
347 break;
348 case 'd':
349 case 'i':
350 base = 10;
351 sign = 1;
352 goto handle_sign;
353 case 'h':
354 if (hflag) {
355 hflag = 0;
356 cflag = 1;
357 } else
358 hflag = 1;
359 goto reswitch;
360 case 'j':
361 jflag = 1;
362 goto reswitch;
363 case 'l':
364 if (lflag) {
365 lflag = 0;
366 qflag = 1;
367 } else
368 lflag = 1;
369 goto reswitch;
370 case 'n':
371 if (jflag)
372 *(va_arg(ap, intmax_t *)) = retval;
373 else if (qflag)
374 *(va_arg(ap, quad_t *)) = retval;
375 else if (lflag)
376 *(va_arg(ap, long *)) = retval;
377 else if (zflag)
378 *(va_arg(ap, size_t *)) = retval;
379 else if (hflag)
380 *(va_arg(ap, short *)) = retval;
381 else if (cflag)
382 *(va_arg(ap, char *)) = retval;
383 else
384 *(va_arg(ap, int *)) = retval;
385 break;
386 case 'o':
387 base = 8;
388 goto handle_nosign;
389 case 'p':
390 base = 16;
391 sharpflag = (width == 0);
392 sign = 0;
393 num = (uintptr_t)va_arg(ap, void *);
394 goto number;
395 case 'q':
396 qflag = 1;
397 goto reswitch;
398 case 'r':
399 base = radix;
400 if (sign)
401 goto handle_sign;
402 goto handle_nosign;
403 case 's':
404 p = va_arg(ap, char *);
405 if (p == NULL)
406 p = "(null)";
407 if (!dot)
408 n = strlen (p);
409 else
410 for (n = 0; n < dwidth && p[n]; n++)
411 continue;
412
413 width -= n;
414
415 if (!ladjust && width > 0)
416 while (width--)
417 dtrace_debug__putc(cpu, padc);
418 while (n--)
419 dtrace_debug__putc(cpu, *p++);
420 if (ladjust && width > 0)
421 while (width--)
422 dtrace_debug__putc(cpu, padc);
423 break;
424 case 't':
425 tflag = 1;
426 goto reswitch;
427 case 'u':
428 base = 10;
429 goto handle_nosign;
430 case 'X':
431 upper = 1;
432 case 'x':
433 base = 16;
434 goto handle_nosign;
435 case 'y':
436 base = 16;
437 sign = 1;
438 goto handle_sign;
439 case 'z':
440 zflag = 1;
441 goto reswitch;
442 handle_nosign:
443 sign = 0;
444 if (jflag)
445 num = va_arg(ap, uintmax_t);
446 else if (qflag)
447 num = va_arg(ap, u_quad_t);
448 else if (tflag)
449 num = va_arg(ap, ptrdiff_t);
450 else if (lflag)
451 num = va_arg(ap, u_long);
452 else if (zflag)
453 num = va_arg(ap, size_t);
454 else if (hflag)
455 num = (u_short)va_arg(ap, int);
456 else if (cflag)
457 num = (u_char)va_arg(ap, int);
458 else
459 num = va_arg(ap, u_int);
460 goto number;
461 handle_sign:
462 if (jflag)
463 num = va_arg(ap, intmax_t);
464 else if (qflag)
465 num = va_arg(ap, quad_t);
466 else if (tflag)
467 num = va_arg(ap, ptrdiff_t);
468 else if (lflag)
469 num = va_arg(ap, long);
470 else if (zflag)
471 num = va_arg(ap, size_t);
472 else if (hflag)
473 num = (short)va_arg(ap, int);
474 else if (cflag)
475 num = (char)va_arg(ap, int);
476 else
477 num = va_arg(ap, int);
478 number:
479 if (sign && (intmax_t)num < 0) {
480 neg = 1;
481 num = -(intmax_t)num;
482 }
483 p = dtrace_debug_ksprintn(nbuf, num, base, &tmp, upper);
484 if (sharpflag && num != 0) {
485 if (base == 8)
486 tmp++;
487 else if (base == 16)
488 tmp += 2;
489 }
490 if (neg)
491 tmp++;
492
493 if (!ladjust && padc != '' && width
494 && (width -= tmp) > 0)
495 while (width--)
496 dtrace_debug__putc(cpu, padc);
497 if (neg)
498 dtrace_debug__putc(cpu, '-');
499 if (sharpflag && num != 0) {
500 if (base == 8) {
501 dtrace_debug__putc(cpu, '');
502 } else if (base == 16) {
503 dtrace_debug__putc(cpu, '');
504 dtrace_debug__putc(cpu, 'x');
505 }
506 }
507 if (!ladjust && width && (width -= tmp) > 0)
508 while (width--)
509 dtrace_debug__putc(cpu, padc);
510
511 while (*p)
512 dtrace_debug__putc(cpu, *p--);
513
514 if (ladjust && width && (width -= tmp) > 0)
515 while (width--)
516 dtrace_debug__putc(cpu, padc);
517
518 break;
519 default:
520 while (percent < fmt)
521 dtrace_debug__putc(cpu, *percent++);
522 /*
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
526 * the format specs.
527 */
528 stop = 1;
529 break;
530 }
531 }
532
533 dtrace_debug__putc(cpu, '\0');
534 }
535
536 void
537 dtrace_debug_printf(const char *fmt, ...)
538 {
539 va_list ap;
540 int cpu;
541
542 cpu = curcpu;
543 dtrace_debug_lock(cpu);
544
545 va_start(ap, fmt);
546
547 dtrace_debug_vprintf(cpu, fmt, ap);
548
549 va_end(ap);
550
551 dtrace_debug_unlock(cpu);
552 }
553
554 #else
555
556 #define dtrace_debug_output()
557 #define dtrace_debug_puts(_s)
558 #define dtrace_debug_printf(fmt, ...)
559
560 #endif
Cache object: 511002d4cef69fb1e4187f60b5a5f292
|