]>
git.saurik.com Git - apple/xnu.git/blob - osfmk/ddb/tr.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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.
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
20 * @APPLE_LICENSE_HEADER_END@
27 * Authors: Alan Langerman, Jeffrey Heller
30 * Internal trace routines. Like old-style XPRs but
38 #include <ddb/db_command.h>
40 #include <kern/lock.h>
43 extern void fc_get(int *);
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.
51 #define TRACE_MAX (4 * 1024)
52 #define TRACE_WINDOW 40
54 typedef struct trace_event
{
60 #endif /* NCPUS > 1 */
67 int timestamp
[2]; /* largest needed by any clock */
70 trace_event trace_buffer
[TRACE_MAX
];
71 unsigned long trace_index
;
74 #else /* NCPUS == 1 */
77 #endif /* NCPUS == 1 */
79 decl_simple_lock_data(,trace_lock
)
89 #endif /* NCPUS > 1 */
91 simple_lock_init(&trace_lock
, ETAP_DIPC_TRACE
);
106 register unsigned long ti
, tn
;
109 #endif /* NCPUS > 1 */
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.
120 if (tn
>= TRACE_MAX
- 1)
122 } while (cmpsw(ti
, tn
, &trace_index
) == -1);
123 fc_get(trace_buffer
[ti
].timestamp
);
124 #else /* PARAGON860 */
126 * Until someone does a cmpsw for other platforms, do it
130 simple_lock(&trace_lock
);
133 if (trace_index
>= TRACE_MAX
- 1)
136 simple_unlock(&trace_lock
);
139 fc_get(trace_buffer
[ti
].timestamp
);
140 /* get_uniq_timestamp(trace_buffer[ti].timestamp);*/
141 #endif /* PARAGON860 */
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
;
152 trace_buffer
[ti
].indent
= tr_indent
;
153 #else /* NCPUS == 1 */
154 mp_disable_preemption();
156 trace_buffer
[ti
].indent
= tr_indent
[cpu
];
157 trace_buffer
[ti
].cpu_number
= cpu
;
158 mp_enable_preemption();
159 #endif /* NCPUS == 1 */
163 #include <ddb/db_output.h>
171 unsigned long show_extra
);
179 unsigned long range
);
182 * The blank array must be a bit bigger than
183 * MAX_BLANKS to leave room for a terminating NULL.
185 #define MAX_BLANKS 16
186 char blanks
[MAX_BLANKS
+4];
192 unsigned long show_extra
)
196 trace_event
*last_trace
;
197 #endif /* PARAGON860 */
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
;
210 if (index
+ range
> TRACE_MAX
)
211 range
= TRACE_MAX
- index
;
213 last_trace
= &trace_buffer
[index
-1];
214 #endif /* PARAGON860 */
215 level
= trace_buffer
[index
-1].indent
;
217 * Set up the indentation buffer
219 memset(blanks
, ' ', trace_buffer
[index
].indent
);
220 blanks
[trace_buffer
[index
].indent
] = '\0';
221 for (i
= index
; i
< index
+ range
; ++i
) {
223 if ((tr_limit
!= -1) &&
224 (trace_buffer
[i
].cpu_number
!= tr_limit
))
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
? "*" : "");
236 old_history
= (i
>= trace_index
);
239 * Adjust the blank count if necessary
241 if (level
!= trace_buffer
[i
].indent
) {
242 level
= trace_buffer
[i
].indent
;
243 if (level
>= MAX_BLANKS
)
245 memset(blanks
, ' ', level
);
246 blanks
[level
] = '\0';
249 for (cp
= trace_buffer
[i
].file
; *cp
; ++cp
)
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
);
259 if (show_extra
> 0) {
260 db_printf(" (%x/%8x)",
261 trace_buffer
[i
].timestamp
[0],
262 trace_buffer
[i
].timestamp
[1]);
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.
273 ((last_trace
- trace_buffer
)
279 trace_buffer
[i
].timestamp
,
280 last_trace
->timestamp
));
281 #endif /*PARAGON860*/
284 if (show_extra
> 1) {
285 db_printf("(%s:%05d):\n\t",
286 filename
, trace_buffer
[i
].lineno
);
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
);
295 last_trace
= &trace_buffer
[i
];
296 #endif /* PARAGON860 */
306 char *cp
, *cp1
, *cp2
;
308 for (cp
= target
; *cp
; ++cp
) {
309 for (cp2
= pattern
, cp1
= cp
; *cp2
&& *cp1
; ++cp2
, ++cp1
)
319 char parse_tr_buffer
[100] = "KMSG";
328 char *string
= parse_tr_buffer
;
331 index
= trace_index
- (TRACE_WINDOW
-4);
332 range
= TRACE_WINDOW
;
334 if (index
+ range
> TRACE_MAX
)
335 range
= TRACE_MAX
- index
;
336 for (i
= index
; i
< index
+ range
; ++i
) {
338 if ((tr_limit
!= -1) &&
339 (trace_buffer
[i
].cpu_number
!= tr_limit
))
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
? "*" : "");
350 if (!matches(string
, trace_buffer
[i
].fmt
))
352 for (cp
= trace_buffer
[i
].file
; *cp
; ++cp
)
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
);
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
);
379 if (db_option(modif
, 'l')) {
383 if (db_option(modif
, 'a')) {
388 TR_SHOW(level
, 0, flag
);
391 #endif /* MACH_KDB */
393 #endif /* TRACE_BUFFER */