1 /* $NetBSD: dtrace_debug.c,v 1.6 2013/04/14 16:39:59 christos 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 #if defined(__amd64__) 40 static __inline int 41 dtrace_cmpset_long(volatile u_long *dst, u_long exp, u_long src) 42 { 43 u_char res; 44 45 __asm __volatile( 46 " lock ; " 47 " cmpxchgq %2,%1 ; " 48 " sete %0 ; " 49 "1: " 50 "# dtrace_cmpset_long" 51 : "=a" (res), /* 0 */ 52 "=m" (*dst) /* 1 */ 53 : "r" (src), /* 2 */ 54 "a" (exp), /* 3 */ 55 "m" (*dst) /* 4 */ 56 : "memory"); 57 58 return (res); 59 } 60 #elif defined(__i386__) 61 static __inline int 62 dtrace_cmpset_long(volatile u_long *dst, u_long exp, u_long src) 63 { 64 u_char res; 65 66 __asm __volatile( 67 " lock ; " 68 " cmpxchgl %2,%1 ; " 69 " sete %0 ; " 70 "1: " 71 "# dtrace_cmpset_long" 72 : "=a" (res), /* 0 */ 73 "=m" (*dst) /* 1 */ 74 : "r" (src), /* 2 */ 75 "a" (exp), /* 3 */ 76 "m" (*dst) /* 4 */ 77 : "memory"); 78 79 return (res); 80 } 81 #elif defined(__arm__) 82 static __inline int 83 dtrace_cmpset_long(volatile u_long *dst, u_long exp, u_long src) 84 { 85 u_char res; 86 if (*dst == src) { 87 res = *dst; 88 *dst = src; 89 return res; 90 } 91 return exp; 92 } 93 #endif 94 95 #define DTRACE_DEBUG_BUFR_SIZE (32 * 1024) 96 97 struct dtrace_debug_data { 98 char bufr[DTRACE_DEBUG_BUFR_SIZE]; 99 char *first; 100 char *last; 101 char *next; 102 } dtrace_debug_data[MAXCPUS]; 103 104 static char dtrace_debug_bufr[DTRACE_DEBUG_BUFR_SIZE]; 105 106 static volatile u_long dtrace_debug_flag[MAXCPUS]; 107 108 static void 109 dtrace_debug_lock(int cpu) 110 { 111 while (dtrace_cmpset_long(&dtrace_debug_flag[cpu], 0, 1) == 0) 112 /* Loop until the lock is obtained. */ 113 ; 114 } 115 116 static void 117 dtrace_debug_unlock(int cpu) 118 { 119 dtrace_debug_flag[cpu] = 0; 120 } 121 122 static void 123 dtrace_debug_init(void *dummy) 124 { 125 struct dtrace_debug_data *d; 126 CPU_INFO_ITERATOR cpuind; 127 struct cpu_info *cinfo; 128 129 for (CPU_INFO_FOREACH(cpuind, cinfo)) { 130 d = &dtrace_debug_data[cpu_index(cinfo)]; 131 132 if (d->first == NULL) { 133 d->first = d->bufr; 134 d->next = d->bufr; 135 d->last = d->bufr + DTRACE_DEBUG_BUFR_SIZE - 1; 136 *(d->last) = '\0'; 137 } 138 } 139 } 140 141 //SYSINIT(dtrace_debug_init, SI_SUB_KDTRACE, SI_ORDER_ANY, dtrace_debug_init, NULL); 142 //SYSINIT(dtrace_debug_smpinit, SI_SUB_SMP, SI_ORDER_ANY, dtrace_debug_init, NULL); 143 144 static void 145 dtrace_debug_output(void) 146 { 147 char *p; 148 struct dtrace_debug_data *d; 149 uintptr_t count; 150 CPU_INFO_ITERATOR cpuind; 151 struct cpu_info *cinfo; 152 cpuid_t cpuid; 153 154 for (CPU_INFO_FOREACH(cpuind, cinfo)) { 155 cpuid = cpu_index(cinfo); 156 157 dtrace_debug_lock(cpuid); 158 159 d = &dtrace_debug_data[cpuid]; 160 161 count = 0; 162 163 if (d->first < d->next) { 164 char *p1 = dtrace_debug_bufr; 165 166 count = (uintptr_t) d->next - (uintptr_t) d->first; 167 168 for (p = d->first; p < d->next; p++) 169 *p1++ = *p; 170 } else if (d->next > d->first) { 171 char *p1 = dtrace_debug_bufr; 172 173 count = (uintptr_t) d->last - (uintptr_t) d->first; 174 175 for (p = d->first; p < d->last; p++) 176 *p1++ = *p; 177 178 count += (uintptr_t) d->next - (uintptr_t) d->bufr; 179 180 for (p = d->bufr; p < d->next; p++) 181 *p1++ = *p; 182 } 183 184 d->first = d->bufr; 185 d->next = d->bufr; 186 187 dtrace_debug_unlock(cpuid); 188 189 if (count > 0) { 190 char *last = dtrace_debug_bufr + count; 191 192 p = dtrace_debug_bufr; 193 194 while (p < last) { 195 if (*p == '\0') { 196 p++; 197 continue; 198 } 199 200 printf("%s", p); 201 202 p += strlen(p); 203 } 204 } 205 } 206 } 207 208 /* 209 * Functions below here are called from the probe context, so they can't call 210 * _any_ functions outside the dtrace module without running foul of the function 211 * boundary trace provider (fbt). The purpose of these functions is limited to 212 * buffering debug strings for output when the probe completes on the current CPU. 213 */ 214 215 static __inline void 216 dtrace_debug__putc(char c) 217 { 218 struct dtrace_debug_data *d = &dtrace_debug_data[cpu_number()]; 219 220 *d->next++ = c; 221 222 if (d->next == d->last) 223 d->next = d->bufr; 224 225 *(d->next) = '\0'; 226 227 if (d->next == d->first) 228 d->first++; 229 230 if (d->first == d->last) 231 d->first = d->bufr; 232 } 233 234 static void __used 235 dtrace_debug_putc(char c) 236 { 237 dtrace_debug_lock(cpu_number()); 238 239 dtrace_debug__putc(c); 240 241 dtrace_debug_unlock(cpu_number()); 242 } 243 244 static void __used 245 dtrace_debug_puts(const char *s) 246 { 247 dtrace_debug_lock(cpu_number()); 248 249 while (*s != '\0') 250 dtrace_debug__putc(*s++); 251 252 dtrace_debug__putc('\0'); 253 254 dtrace_debug_unlock(cpu_number()); 255 } 256 257 /* 258 * Snaffled from sys/kern/subr_prf.c 259 * 260 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse 261 * order; return an optional length and a pointer to the last character 262 * written in the buffer (i.e., the first character of the string). 263 * The buffer pointed to by `xbuf' must have length >= MAXNBUF. 264 */ 265 static char * 266 dtrace_debug_ksprintn(char *xbuf, uintmax_t num, int base, int *lenp, int upper) 267 { 268 char *p, c; 269 270 p = xbuf; 271 *p = '\0'; 272 do { 273 c = hex2ascii(num % base); 274 *++p = upper ? toupper(c) : c; 275 } while (num /= base); 276 if (lenp) 277 *lenp = p - xbuf; 278 return (p); 279 } 280 281 #define MAXNBUF (sizeof(intmax_t) * NBBY + 1) 282 283 static void 284 dtrace_debug_vprintf(const char *fmt, va_list ap) 285 { 286 char xbuf[MAXNBUF]; 287 const char *p, *percent, *q; 288 u_char *up; 289 int ch, n; 290 uintmax_t num; 291 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot; 292 int cflag, hflag, jflag, tflag, zflag; 293 int dwidth, upper; 294 int radix = 10; 295 char padc; 296 int stop = 0, retval = 0; 297 298 num = 0; 299 300 if (fmt == NULL) 301 fmt = "(fmt null)\n"; 302 303 for (;;) { 304 padc = ' '; 305 width = 0; 306 while ((ch = (u_char)*fmt++) != '%' || stop) { 307 if (ch == '\0') { 308 dtrace_debug__putc('\0'); 309 return; 310 } 311 dtrace_debug__putc(ch); 312 } 313 percent = fmt - 1; 314 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0; 315 sign = 0; dot = 0; dwidth = 0; upper = 0; 316 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0; 317 reswitch: switch (ch = (u_char)*fmt++) { 318 case '.': 319 dot = 1; 320 goto reswitch; 321 case '#': 322 sharpflag = 1; 323 goto reswitch; 324 case '+': 325 sign = 1; 326 goto reswitch; 327 case '-': 328 ladjust = 1; 329 goto reswitch; 330 case '%': 331 dtrace_debug__putc(ch); 332 break; 333 case '*': 334 if (!dot) { 335 width = va_arg(ap, int); 336 if (width < 0) { 337 ladjust = !ladjust; 338 width = -width; 339 } 340 } else { 341 dwidth = va_arg(ap, int); 342 } 343 goto reswitch; 344 case '0': 345 if (!dot) { 346 padc = '0'; 347 goto reswitch; 348 } 349 case '1': case '2': case '3': case '4': 350 case '5': case '6': case '7': case '8': case '9': 351 for (n = 0;; ++fmt) { 352 n = n * 10 + ch - '0'; 353 ch = *fmt; 354 if (ch < '0' || ch > '9') 355 break; 356 } 357 if (dot) 358 dwidth = n; 359 else 360 width = n; 361 goto reswitch; 362 case 'b': 363 num = (u_int)va_arg(ap, int); 364 p = va_arg(ap, char *); 365 for (q = dtrace_debug_ksprintn(xbuf, num, *p++, NULL, 0); *q;) 366 dtrace_debug__putc(*q--); 367 368 if (num == 0) 369 break; 370 371 for (tmp = 0; *p;) { 372 n = *p++; 373 if (num & (1 << (n - 1))) { 374 dtrace_debug__putc(tmp ? ',' : '<'); 375 for (; (n = *p) > ' '; ++p) 376 dtrace_debug__putc(n); 377 tmp = 1; 378 } else 379 for (; *p > ' '; ++p) 380 continue; 381 } 382 if (tmp) 383 dtrace_debug__putc('>'); 384 break; 385 case 'c': 386 dtrace_debug__putc(va_arg(ap, int)); 387 break; 388 case 'D': 389 up = va_arg(ap, u_char *); 390 p = va_arg(ap, char *); 391 if (!width) 392 width = 16; 393 while(width--) { 394 dtrace_debug__putc(hex2ascii(*up >> 4)); 395 dtrace_debug__putc(hex2ascii(*up & 0x0f)); 396 up++; 397 if (width) 398 for (q=p;*q;q++) 399 dtrace_debug__putc(*q); 400 } 401 break; 402 case 'd': 403 case 'i': 404 base = 10; 405 sign = 1; 406 goto handle_sign; 407 case 'h': 408 if (hflag) { 409 hflag = 0; 410 cflag = 1; 411 } else 412 hflag = 1; 413 goto reswitch; 414 case 'j': 415 jflag = 1; 416 goto reswitch; 417 case 'l': 418 if (lflag) { 419 lflag = 0; 420 qflag = 1; 421 } else 422 lflag = 1; 423 goto reswitch; 424 case 'n': 425 if (jflag) 426 *(va_arg(ap, intmax_t *)) = retval; 427 else if (qflag) 428 *(va_arg(ap, quad_t *)) = retval; 429 else if (lflag) 430 *(va_arg(ap, long *)) = retval; 431 else if (zflag) 432 *(va_arg(ap, size_t *)) = retval; 433 else if (hflag) 434 *(va_arg(ap, short *)) = retval; 435 else if (cflag) 436 *(va_arg(ap, char *)) = retval; 437 else 438 *(va_arg(ap, int *)) = retval; 439 break; 440 case 'o': 441 base = 8; 442 goto handle_nosign; 443 case 'p': 444 base = 16; 445 sharpflag = (width == 0); 446 sign = 0; 447 num = (uintptr_t)va_arg(ap, void *); 448 goto number; 449 case 'q': 450 qflag = 1; 451 goto reswitch; 452 case 'r': 453 base = radix; 454 if (sign) 455 goto handle_sign; 456 goto handle_nosign; 457 case 's': 458 p = va_arg(ap, char *); 459 if (p == NULL) 460 p = "(null)"; 461 if (!dot) 462 n = strlen (p); 463 else 464 for (n = 0; n < dwidth && p[n]; n++) 465 continue; 466 467 width -= n; 468 469 if (!ladjust && width > 0) 470 while (width--) 471 dtrace_debug__putc(padc); 472 while (n--) 473 dtrace_debug__putc(*p++); 474 if (ladjust && width > 0) 475 while (width--) 476 dtrace_debug__putc(padc); 477 break; 478 case 't': 479 tflag = 1; 480 goto reswitch; 481 case 'u': 482 base = 10; 483 goto handle_nosign; 484 case 'X': 485 upper = 1; 486 case 'x': 487 base = 16; 488 goto handle_nosign; 489 case 'y': 490 base = 16; 491 sign = 1; 492 goto handle_sign; 493 case 'z': 494 zflag = 1; 495 goto reswitch; 496 handle_nosign: 497 sign = 0; 498 if (jflag) 499 num = va_arg(ap, uintmax_t); 500 else if (qflag) 501 num = va_arg(ap, u_quad_t); 502 else if (tflag) 503 num = va_arg(ap, ptrdiff_t); 504 else if (lflag) 505 num = va_arg(ap, u_long); 506 else if (zflag) 507 num = va_arg(ap, size_t); 508 else if (hflag) 509 num = (u_short)va_arg(ap, int); 510 else if (cflag) 511 num = (u_char)va_arg(ap, int); 512 else 513 num = va_arg(ap, u_int); 514 goto number; 515 handle_sign: 516 if (jflag) 517 num = va_arg(ap, intmax_t); 518 else if (qflag) 519 num = va_arg(ap, quad_t); 520 else if (tflag) 521 num = va_arg(ap, ptrdiff_t); 522 else if (lflag) 523 num = va_arg(ap, long); 524 else if (zflag) 525 num = va_arg(ap, size_t); 526 else if (hflag) 527 num = (short)va_arg(ap, int); 528 else if (cflag) 529 num = (char)va_arg(ap, int); 530 else 531 num = va_arg(ap, int); 532 number: 533 if (sign && (intmax_t)num < 0) { 534 neg = 1; 535 num = -(intmax_t)num; 536 } 537 p = dtrace_debug_ksprintn(xbuf, num, base, &tmp, upper); 538 if (sharpflag && num != 0) { 539 if (base == 8) 540 tmp++; 541 else if (base == 16) 542 tmp += 2; 543 } 544 if (neg) 545 tmp++; 546 547 if (!ladjust && padc != '0' && width 548 && (width -= tmp) > 0) 549 while (width--) 550 dtrace_debug__putc(padc); 551 if (neg) 552 dtrace_debug__putc('-'); 553 if (sharpflag && num != 0) { 554 if (base == 8) { 555 dtrace_debug__putc('0'); 556 } else if (base == 16) { 557 dtrace_debug__putc('0'); 558 dtrace_debug__putc('x'); 559 } 560 } 561 if (!ladjust && width && (width -= tmp) > 0) 562 while (width--) 563 dtrace_debug__putc(padc); 564 565 while (*p) 566 dtrace_debug__putc(*p--); 567 568 if (ladjust && width && (width -= tmp) > 0) 569 while (width--) 570 dtrace_debug__putc(padc); 571 572 break; 573 default: 574 while (percent < fmt) 575 dtrace_debug__putc(*percent++); 576 /* 577 * Since we ignore an formatting argument it is no 578 * longer safe to obey the remaining formatting 579 * arguments as the arguments will no longer match 580 * the format specs. 581 */ 582 stop = 1; 583 break; 584 } 585 } 586 587 dtrace_debug__putc('\0'); 588 } 589 590 void 591 dtrace_debug_printf(const char *fmt, ...) 592 { 593 va_list ap; 594 595 dtrace_debug_lock(cpu_number()); 596 597 va_start(ap, fmt); 598 599 dtrace_debug_vprintf(fmt, ap); 600 601 va_end(ap); 602 603 dtrace_debug_unlock(cpu_number()); 604 } 605 606 #else 607 608 #define dtrace_debug_output() 609 #define dtrace_debug_puts(_s) 610 #define dtrace_debug_printf(fmt, ...) 611 612 #endif 613