|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * File: ddb/tr.c ! 27: * Authors: Alan Langerman, Jeffrey Heller ! 28: * Date: 1992 ! 29: * ! 30: * Internal trace routines. Like old-style XPRs but ! 31: * less formatting. ! 32: */ ! 33: ! 34: #include <ddb/tr.h> ! 35: ! 36: #if TRACE_BUFFER ! 37: #include <string.h> ! 38: #include <ddb/db_command.h> ! 39: #include <mach_kdb.h> ! 40: #include <kern/lock.h> ! 41: #include <kern/spl.h> ! 42: ! 43: extern void fc_get(int *); ! 44: ! 45: /* ! 46: * Primitive event tracing facility for kernel debugging. Yes, ! 47: * this has some resemblance to XPRs. However, it is primarily ! 48: * intended for post-mortem analysis through ddb. ! 49: */ ! 50: ! 51: #define TRACE_MAX (4 * 1024) ! 52: #define TRACE_WINDOW 40 ! 53: ! 54: typedef struct trace_event { ! 55: char *funcname; ! 56: char *file; ! 57: char *fmt; ! 58: #if NCPUS > 1 ! 59: char cpu_number; ! 60: #endif /* NCPUS > 1 */ ! 61: unsigned int lineno; ! 62: unsigned int tag1; ! 63: unsigned int tag2; ! 64: unsigned int tag3; ! 65: unsigned int tag4; ! 66: int indent; ! 67: int timestamp[2]; /* largest needed by any clock */ ! 68: } trace_event; ! 69: ! 70: trace_event trace_buffer[TRACE_MAX]; ! 71: unsigned long trace_index; ! 72: #if NCPUS == 1 ! 73: int tr_indent = 0; ! 74: #else /* NCPUS == 1 */ ! 75: int tr_indent[NCPUS]; ! 76: int tr_limit = -1; ! 77: #endif /* NCPUS == 1 */ ! 78: ! 79: decl_simple_lock_data(,trace_lock) ! 80: ! 81: void ! 82: tr_init(void) ! 83: { ! 84: #if NCPUS > 1 ! 85: int i; ! 86: ! 87: for(i=0;i<NCPUS;i++) ! 88: tr_indent[i]=0; ! 89: #endif /* NCPUS > 1 */ ! 90: ! 91: simple_lock_init(&trace_lock, ETAP_DIPC_TRACE); ! 92: } ! 93: ! 94: void ! 95: tr( ! 96: char *funcname, ! 97: char *file, ! 98: unsigned int lineno, ! 99: char *fmt, ! 100: unsigned int tag1, ! 101: unsigned int tag2, ! 102: unsigned int tag3, ! 103: unsigned int tag4) ! 104: { ! 105: int s; ! 106: register unsigned long ti, tn; ! 107: #if NCPUS > 1 ! 108: char cpu; ! 109: #endif /* NCPUS > 1 */ ! 110: ! 111: #if PARAGON860 ! 112: /* ! 113: * The following loop replaces the spl_and_lock sequence that ! 114: * would normally be here, as they are too heavy weight. The ! 115: * cmpsw (compare-and-swap) call returns -1 if unsuccessful. ! 116: */ ! 117: do { ! 118: ti = trace_index; ! 119: tn = ti + 1; ! 120: if (tn >= TRACE_MAX - 1) ! 121: tn = 0; ! 122: } while (cmpsw(ti, tn, &trace_index) == -1); ! 123: fc_get(trace_buffer[ti].timestamp); ! 124: #else /* PARAGON860 */ ! 125: /* ! 126: * Until someone does a cmpsw for other platforms, do it ! 127: * the slow way ! 128: */ ! 129: s = splimp(); ! 130: simple_lock(&trace_lock); ! 131: ! 132: ti = trace_index++; ! 133: if (trace_index >= TRACE_MAX - 1) ! 134: trace_index = 0; ! 135: ! 136: simple_unlock(&trace_lock); ! 137: splx(s); ! 138: ! 139: fc_get(trace_buffer[ti].timestamp); ! 140: /* get_uniq_timestamp(trace_buffer[ti].timestamp);*/ ! 141: #endif /* PARAGON860 */ ! 142: ! 143: trace_buffer[ti].funcname = funcname; ! 144: trace_buffer[ti].file = file; ! 145: trace_buffer[ti].lineno = lineno; ! 146: trace_buffer[ti].fmt = fmt; ! 147: trace_buffer[ti].tag1 = tag1; ! 148: trace_buffer[ti].tag2 = tag2; ! 149: trace_buffer[ti].tag3 = tag3; ! 150: trace_buffer[ti].tag4 = tag4; ! 151: #if NCPUS == 1 ! 152: trace_buffer[ti].indent = tr_indent; ! 153: #else /* NCPUS == 1 */ ! 154: mp_disable_preemption(); ! 155: cpu = cpu_number(); ! 156: trace_buffer[ti].indent = tr_indent[cpu]; ! 157: trace_buffer[ti].cpu_number = cpu; ! 158: mp_enable_preemption(); ! 159: #endif /* NCPUS == 1 */ ! 160: } ! 161: ! 162: #if MACH_KDB ! 163: #include <ddb/db_output.h> ! 164: ! 165: /* ! 166: * Forward. ! 167: */ ! 168: void show_tr( ! 169: unsigned long index, ! 170: unsigned long range, ! 171: unsigned long show_extra); ! 172: ! 173: int matches( ! 174: char *pattern, ! 175: char *target); ! 176: ! 177: void parse_tr( ! 178: unsigned long index, ! 179: unsigned long range); ! 180: ! 181: /* ! 182: * The blank array must be a bit bigger than ! 183: * MAX_BLANKS to leave room for a terminating NULL. ! 184: */ ! 185: #define MAX_BLANKS 16 ! 186: char blanks[MAX_BLANKS+4]; ! 187: ! 188: void ! 189: show_tr( ! 190: unsigned long index, ! 191: unsigned long range, ! 192: unsigned long show_extra) ! 193: { ! 194: char *filename, *cp; ! 195: #if PARAGON860 ! 196: trace_event *last_trace; ! 197: #endif /* PARAGON860 */ ! 198: unsigned int level; ! 199: int old_history; ! 200: int i; ! 201: ! 202: if (index == -1) { ! 203: index = trace_index - (TRACE_WINDOW-4); ! 204: range = TRACE_WINDOW; ! 205: } else if (index == 0) { ! 206: index = trace_index - (TRACE_WINDOW-4); ! 207: range = TRACE_WINDOW; ! 208: show_extra = 0; ! 209: } ! 210: if (index + range > TRACE_MAX) ! 211: range = TRACE_MAX - index; ! 212: #if PARAGON860 ! 213: last_trace = &trace_buffer[index-1]; ! 214: #endif /* PARAGON860 */ ! 215: level = trace_buffer[index-1].indent; ! 216: /* ! 217: * Set up the indentation buffer ! 218: */ ! 219: memset(blanks, ' ', trace_buffer[index].indent); ! 220: blanks[trace_buffer[index].indent] = '\0'; ! 221: for (i = index; i < index + range; ++i) { ! 222: #if NCPUS > 1 ! 223: if ((tr_limit != -1) && ! 224: (trace_buffer[i].cpu_number != tr_limit)) ! 225: continue; ! 226: #endif /* NCPUS > 1 */ ! 227: if (trace_buffer[i].file == (char *) 0 || ! 228: trace_buffer[i].funcname == (char *) 0 || ! 229: trace_buffer[i].lineno == 0 || ! 230: trace_buffer[i].fmt == 0) { ! 231: db_printf("[%04x%s]\n", i, ! 232: i >= trace_index ? "*" : ""); ! 233: continue; ! 234: } ! 235: ! 236: old_history = (i >= trace_index); ! 237: ! 238: /* ! 239: * Adjust the blank count if necessary ! 240: */ ! 241: if (level != trace_buffer[i].indent) { ! 242: level = trace_buffer[i].indent; ! 243: if (level >= MAX_BLANKS) ! 244: level = MAX_BLANKS; ! 245: memset(blanks, ' ', level); ! 246: blanks[level] = '\0'; ! 247: } ! 248: ! 249: for (cp = trace_buffer[i].file; *cp; ++cp) ! 250: if (*cp == '/') ! 251: filename = cp + 1; ! 252: #if NCPUS > 1 ! 253: db_printf("{%02d}",trace_buffer[i].cpu_number); ! 254: #endif /* NCPUS > 1 */ ! 255: db_printf("[%04x%s] %s%-16s", i, old_history ? "*" : "", ! 256: blanks, trace_buffer[i].funcname); ! 257: ! 258: if (show_extra) { ! 259: if (show_extra > 0) { ! 260: db_printf(" (%x/%8x)", ! 261: trace_buffer[i].timestamp[0], ! 262: trace_buffer[i].timestamp[1]); ! 263: #if PARAGON860 ! 264: /* ! 265: * For Paragon only, we compute and ! 266: * print out deltas on the timestamps ! 267: * accumulated in the tr buffer. One ! 268: * interesting case: it is meaningless ! 269: * to compute this delta for the last ! 270: * current entry in the log. ! 271: */ ! 272: if (old_history && ! 273: ((last_trace - trace_buffer) ! 274: < trace_index)) ! 275: db_printf("(N/A)"); ! 276: else ! 277: db_printf("(%d)", ! 278: timer_subtime( ! 279: trace_buffer[i].timestamp, ! 280: last_trace->timestamp)); ! 281: #endif /*PARAGON860*/ ! 282: db_printf(" "); ! 283: } ! 284: if (show_extra > 1) { ! 285: db_printf("(%s:%05d):\n\t", ! 286: filename, trace_buffer[i].lineno); ! 287: } ! 288: } else ! 289: db_printf(": "); ! 290: db_printf(trace_buffer[i].fmt, trace_buffer[i].tag1, ! 291: trace_buffer[i].tag2, trace_buffer[i].tag3, ! 292: trace_buffer[i].tag4); ! 293: db_printf("\n"); ! 294: #if PARAGON860 ! 295: last_trace = &trace_buffer[i]; ! 296: #endif /* PARAGON860 */ ! 297: } ! 298: } ! 299: ! 300: ! 301: int ! 302: matches( ! 303: char *pattern, ! 304: char *target) ! 305: { ! 306: char *cp, *cp1, *cp2; ! 307: ! 308: for (cp = target; *cp; ++cp) { ! 309: for (cp2 = pattern, cp1 = cp; *cp2 && *cp1; ++cp2, ++cp1) ! 310: if (*cp2 != *cp1) ! 311: break; ! 312: if (!*cp2) ! 313: return 1; ! 314: } ! 315: return 0; ! 316: } ! 317: ! 318: ! 319: char parse_tr_buffer[100] = "KMSG"; ! 320: ! 321: void ! 322: parse_tr( ! 323: unsigned long index, ! 324: unsigned long range) ! 325: { ! 326: int i; ! 327: char *filename, *cp; ! 328: char *string = parse_tr_buffer; ! 329: ! 330: if (index == 0) { ! 331: index = trace_index - (TRACE_WINDOW-4); ! 332: range = TRACE_WINDOW; ! 333: } ! 334: if (index + range > TRACE_MAX) ! 335: range = TRACE_MAX - index; ! 336: for (i = index; i < index + range; ++i) { ! 337: #if NCPUS > 1 ! 338: if ((tr_limit != -1) && ! 339: (trace_buffer[i].cpu_number != tr_limit)) ! 340: continue; ! 341: #endif /* NCPUS > 1 */ ! 342: if (trace_buffer[i].file == (char *) 0 || ! 343: trace_buffer[i].funcname == (char *) 0 || ! 344: trace_buffer[i].lineno == 0 || ! 345: trace_buffer[i].fmt == 0) { ! 346: db_printf("[%04x%s]\n", i, ! 347: i >= trace_index ? "*" : ""); ! 348: continue; ! 349: } ! 350: if (!matches(string, trace_buffer[i].fmt)) ! 351: continue; ! 352: for (cp = trace_buffer[i].file; *cp; ++cp) ! 353: if (*cp == '/') ! 354: filename = cp + 1; ! 355: #if NCPUS > 1 ! 356: db_printf("{%02d}",trace_buffer[i].cpu_number); ! 357: #endif /* NCPUS > 1 */ ! 358: db_printf("[%04x%s] %s", i, i >= trace_index ? "*" : "", ! 359: trace_buffer[i].funcname); ! 360: db_printf(": "); ! 361: db_printf(trace_buffer[i].fmt, trace_buffer[i].tag1, ! 362: trace_buffer[i].tag2, trace_buffer[i].tag3, ! 363: trace_buffer[i].tag4); ! 364: db_printf("\n"); ! 365: } ! 366: } ! 367: ! 368: ! 369: void ! 370: db_show_tr( ! 371: db_expr_t addr, ! 372: boolean_t have_addr, ! 373: db_expr_t count, ! 374: char * modif) ! 375: { ! 376: int flag, level; ! 377: ! 378: flag = 0, level = 0; ! 379: if (db_option(modif, 'l')) { ! 380: flag = 1; ! 381: level = -1; ! 382: } ! 383: if (db_option(modif, 'a')) { ! 384: flag = 2; ! 385: level = -1; ! 386: } ! 387: ! 388: TR_SHOW(level, 0, flag); ! 389: } ! 390: ! 391: #endif /* MACH_KDB */ ! 392: ! 393: #endif /* TRACE_BUFFER */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.