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