]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ddb/tr.c
xnu-792.6.76.tar.gz
[apple/xnu.git] / osfmk / ddb / tr.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
A
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.
1c79356b 11 *
37839358
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
37839358
A
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.
1c79356b
A
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
43extern 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
54typedef 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
70trace_event trace_buffer[TRACE_MAX];
71unsigned long trace_index;
72#if NCPUS == 1
73int tr_indent = 0;
74#else /* NCPUS == 1 */
75int tr_indent[NCPUS];
76int tr_limit = -1;
77#endif /* NCPUS == 1 */
78
79decl_simple_lock_data(,trace_lock)
80
81void
82tr_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
91447636 91 simple_lock_init(&trace_lock, 0);
1c79356b
A
92}
93
94void
95tr(
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 */
168void show_tr(
169 unsigned long index,
170 unsigned long range,
171 unsigned long show_extra);
172
173int matches(
174 char *pattern,
175 char *target);
176
177void 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
186char blanks[MAX_BLANKS+4];
187
188void
189show_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
301int
302matches(
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
319char parse_tr_buffer[100] = "KMSG";
320
321void
322parse_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
369void
370db_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 */