]>
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 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
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
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.
23 * @APPLE_LICENSE_HEADER_END@
30 * Authors: Alan Langerman, Jeffrey Heller
33 * Internal trace routines. Like old-style XPRs but
41 #include <ddb/db_command.h>
43 #include <kern/lock.h>
46 extern void fc_get(int *);
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.
54 #define TRACE_MAX (4 * 1024)
55 #define TRACE_WINDOW 40
57 typedef struct trace_event
{
63 #endif /* NCPUS > 1 */
70 int timestamp
[2]; /* largest needed by any clock */
73 trace_event trace_buffer
[TRACE_MAX
];
74 unsigned long trace_index
;
77 #else /* NCPUS == 1 */
80 #endif /* NCPUS == 1 */
82 decl_simple_lock_data(,trace_lock
)
92 #endif /* NCPUS > 1 */
94 simple_lock_init(&trace_lock
, ETAP_DIPC_TRACE
);
109 register unsigned long ti
, tn
;
112 #endif /* NCPUS > 1 */
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.
123 if (tn
>= TRACE_MAX
- 1)
125 } while (cmpsw(ti
, tn
, &trace_index
) == -1);
126 fc_get(trace_buffer
[ti
].timestamp
);
127 #else /* PARAGON860 */
129 * Until someone does a cmpsw for other platforms, do it
133 simple_lock(&trace_lock
);
136 if (trace_index
>= TRACE_MAX
- 1)
139 simple_unlock(&trace_lock
);
142 fc_get(trace_buffer
[ti
].timestamp
);
143 /* get_uniq_timestamp(trace_buffer[ti].timestamp);*/
144 #endif /* PARAGON860 */
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
;
155 trace_buffer
[ti
].indent
= tr_indent
;
156 #else /* NCPUS == 1 */
157 mp_disable_preemption();
159 trace_buffer
[ti
].indent
= tr_indent
[cpu
];
160 trace_buffer
[ti
].cpu_number
= cpu
;
161 mp_enable_preemption();
162 #endif /* NCPUS == 1 */
166 #include <ddb/db_output.h>
174 unsigned long show_extra
);
182 unsigned long range
);
185 * The blank array must be a bit bigger than
186 * MAX_BLANKS to leave room for a terminating NULL.
188 #define MAX_BLANKS 16
189 char blanks
[MAX_BLANKS
+4];
195 unsigned long show_extra
)
199 trace_event
*last_trace
;
200 #endif /* PARAGON860 */
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
;
213 if (index
+ range
> TRACE_MAX
)
214 range
= TRACE_MAX
- index
;
216 last_trace
= &trace_buffer
[index
-1];
217 #endif /* PARAGON860 */
218 level
= trace_buffer
[index
-1].indent
;
220 * Set up the indentation buffer
222 memset(blanks
, ' ', trace_buffer
[index
].indent
);
223 blanks
[trace_buffer
[index
].indent
] = '\0';
224 for (i
= index
; i
< index
+ range
; ++i
) {
226 if ((tr_limit
!= -1) &&
227 (trace_buffer
[i
].cpu_number
!= tr_limit
))
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
? "*" : "");
239 old_history
= (i
>= trace_index
);
242 * Adjust the blank count if necessary
244 if (level
!= trace_buffer
[i
].indent
) {
245 level
= trace_buffer
[i
].indent
;
246 if (level
>= MAX_BLANKS
)
248 memset(blanks
, ' ', level
);
249 blanks
[level
] = '\0';
252 for (cp
= trace_buffer
[i
].file
; *cp
; ++cp
)
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
);
262 if (show_extra
> 0) {
263 db_printf(" (%x/%8x)",
264 trace_buffer
[i
].timestamp
[0],
265 trace_buffer
[i
].timestamp
[1]);
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.
276 ((last_trace
- trace_buffer
)
282 trace_buffer
[i
].timestamp
,
283 last_trace
->timestamp
));
284 #endif /*PARAGON860*/
287 if (show_extra
> 1) {
288 db_printf("(%s:%05d):\n\t",
289 filename
, trace_buffer
[i
].lineno
);
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
);
298 last_trace
= &trace_buffer
[i
];
299 #endif /* PARAGON860 */
309 char *cp
, *cp1
, *cp2
;
311 for (cp
= target
; *cp
; ++cp
) {
312 for (cp2
= pattern
, cp1
= cp
; *cp2
&& *cp1
; ++cp2
, ++cp1
)
322 char parse_tr_buffer
[100] = "KMSG";
331 char *string
= parse_tr_buffer
;
334 index
= trace_index
- (TRACE_WINDOW
-4);
335 range
= TRACE_WINDOW
;
337 if (index
+ range
> TRACE_MAX
)
338 range
= TRACE_MAX
- index
;
339 for (i
= index
; i
< index
+ range
; ++i
) {
341 if ((tr_limit
!= -1) &&
342 (trace_buffer
[i
].cpu_number
!= tr_limit
))
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
? "*" : "");
353 if (!matches(string
, trace_buffer
[i
].fmt
))
355 for (cp
= trace_buffer
[i
].file
; *cp
; ++cp
)
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
);
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
);
382 if (db_option(modif
, 'l')) {
386 if (db_option(modif
, 'a')) {
391 TR_SHOW(level
, 0, flag
);
394 #endif /* MACH_KDB */
396 #endif /* TRACE_BUFFER */