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