|
|
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.