]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/tr.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
33 * Authors: Alan Langerman, Jeffrey Heller
36 * Internal trace routines. Like old-style XPRs but
44 #include <ddb/db_command.h>
46 #include <kern/lock.h>
49 extern void fc_get(int *);
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.
57 #define TRACE_MAX (4 * 1024)
58 #define TRACE_WINDOW 40
60 typedef struct trace_event
{
66 #endif /* NCPUS > 1 */
73 int timestamp
[2]; /* largest needed by any clock */
76 trace_event trace_buffer
[TRACE_MAX
];
77 unsigned long trace_index
;
80 #else /* NCPUS == 1 */
83 #endif /* NCPUS == 1 */
85 decl_simple_lock_data(,trace_lock
)
95 #endif /* NCPUS > 1 */
97 simple_lock_init(&trace_lock
, 0);
112 register unsigned long ti
, tn
;
115 #endif /* NCPUS > 1 */
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.
126 if (tn
>= TRACE_MAX
- 1)
128 } while (cmpsw(ti
, tn
, &trace_index
) == -1);
129 fc_get(trace_buffer
[ti
].timestamp
);
130 #else /* PARAGON860 */
132 * Until someone does a cmpsw for other platforms, do it
136 simple_lock(&trace_lock
);
139 if (trace_index
>= TRACE_MAX
- 1)
142 simple_unlock(&trace_lock
);
145 fc_get(trace_buffer
[ti
].timestamp
);
146 /* get_uniq_timestamp(trace_buffer[ti].timestamp);*/
147 #endif /* PARAGON860 */
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
;
158 trace_buffer
[ti
].indent
= tr_indent
;
159 #else /* NCPUS == 1 */
160 mp_disable_preemption();
162 trace_buffer
[ti
].indent
= tr_indent
[cpu
];
163 trace_buffer
[ti
].cpu_number
= cpu
;
164 mp_enable_preemption();
165 #endif /* NCPUS == 1 */
169 #include <ddb/db_output.h>
177 unsigned long show_extra
);
185 unsigned long range
);
188 * The blank array must be a bit bigger than
189 * MAX_BLANKS to leave room for a terminating NULL.
191 #define MAX_BLANKS 16
192 char blanks
[MAX_BLANKS
+4];
198 unsigned long show_extra
)
202 trace_event
*last_trace
;
203 #endif /* PARAGON860 */
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
;
216 if (index
+ range
> TRACE_MAX
)
217 range
= TRACE_MAX
- index
;
219 last_trace
= &trace_buffer
[index
-1];
220 #endif /* PARAGON860 */
221 level
= trace_buffer
[index
-1].indent
;
223 * Set up the indentation buffer
225 memset(blanks
, ' ', trace_buffer
[index
].indent
);
226 blanks
[trace_buffer
[index
].indent
] = '\0';
227 for (i
= index
; i
< index
+ range
; ++i
) {
229 if ((tr_limit
!= -1) &&
230 (trace_buffer
[i
].cpu_number
!= tr_limit
))
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
? "*" : "");
242 old_history
= (i
>= trace_index
);
245 * Adjust the blank count if necessary
247 if (level
!= trace_buffer
[i
].indent
) {
248 level
= trace_buffer
[i
].indent
;
249 if (level
>= MAX_BLANKS
)
251 memset(blanks
, ' ', level
);
252 blanks
[level
] = '\0';
255 for (cp
= trace_buffer
[i
].file
; *cp
; ++cp
)
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
);
265 if (show_extra
> 0) {
266 db_printf(" (%x/%8x)",
267 trace_buffer
[i
].timestamp
[0],
268 trace_buffer
[i
].timestamp
[1]);
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.
279 ((last_trace
- trace_buffer
)
285 trace_buffer
[i
].timestamp
,
286 last_trace
->timestamp
));
287 #endif /*PARAGON860*/
290 if (show_extra
> 1) {
291 db_printf("(%s:%05d):\n\t",
292 filename
, trace_buffer
[i
].lineno
);
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
);
301 last_trace
= &trace_buffer
[i
];
302 #endif /* PARAGON860 */
312 char *cp
, *cp1
, *cp2
;
314 for (cp
= target
; *cp
; ++cp
) {
315 for (cp2
= pattern
, cp1
= cp
; *cp2
&& *cp1
; ++cp2
, ++cp1
)
325 char parse_tr_buffer
[100] = "KMSG";
334 char *string
= parse_tr_buffer
;
337 index
= trace_index
- (TRACE_WINDOW
-4);
338 range
= TRACE_WINDOW
;
340 if (index
+ range
> TRACE_MAX
)
341 range
= TRACE_MAX
- index
;
342 for (i
= index
; i
< index
+ range
; ++i
) {
344 if ((tr_limit
!= -1) &&
345 (trace_buffer
[i
].cpu_number
!= tr_limit
))
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
? "*" : "");
356 if (!matches(string
, trace_buffer
[i
].fmt
))
358 for (cp
= trace_buffer
[i
].file
; *cp
; ++cp
)
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
);
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
);
385 if (db_option(modif
, 'l')) {
389 if (db_option(modif
, 'a')) {
394 TR_SHOW(level
, 0, flag
);
397 #endif /* MACH_KDB */
399 #endif /* TRACE_BUFFER */