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