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