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@
26 #include <sys/kdebug.h>
27 #include <sys/errno.h>
28 #include <sys/param.h>
31 #include <sys/sysctl.h>
32 #include <vm/vm_kern.h>
34 unsigned int pc_buftomem
= 0;
35 u_long
* pc_buffer
= 0; /* buffer that holds each pc */
36 u_long
* pc_bufptr
= 0;
37 u_long
* pc_buflast
= 0;
38 unsigned int npcbufs
= 8192; /* number of pc entries in buffer */
39 unsigned int pc_bufsize
= 0;
40 unsigned int pcsample_flags
= 0;
41 unsigned int pcsample_enable
= 0;
43 pid_t pc_sample_pid
= 0;
44 boolean_t pc_trace_frameworks
= FALSE
;
46 char pcsample_comm
[MAXCOMLEN
+ 1];
48 /* Set the default framework boundaries */
49 u_long pcsample_beg
= 0;
50 u_long pcsample_end
= 0;
52 static pid_t global_state_pid
= -1; /* Used to control exclusive use of pc_buffer */
54 extern int pc_trace_buf
[];
55 extern int pc_trace_cnt
;
58 enable_branch_tracing()
62 if (-1 != pc_sample_pid
) {
63 p
= pfind(pc_sample_pid
);
65 p
->p_flag
|= P_BTRACE
;
69 pc_trace_frameworks
= TRUE
;
80 disable_branch_tracing()
83 switch (pc_sample_pid
) {
85 pc_trace_frameworks
= FALSE
;
90 p
= pfind(pc_sample_pid
);
92 p
->p_flag
&= ~P_BTRACE
;
101 * this only works for the current proc as it
102 * is called from context_switch in the scheduler
105 branch_tracing_enabled()
107 struct proc
*p
= current_proc();
108 if (TRUE
== pc_trace_frameworks
) return TRUE
;
110 return (P_BTRACE
== (p
->p_flag
& P_BTRACE
));
121 struct proc
*curproc
;
122 extern unsigned int kdebug_flags
;
124 if (!pcsample_enable
)
127 for (i
=0; i
< pc_trace_cnt
; i
++)
129 pc
= pc_trace_buf
[i
];
131 if ((pcsample_beg
<= pc
) && (pc
< pcsample_end
))
133 if (pc_bufptr
> pc_buffer
)
135 if ( (*(pc_bufptr
-1)) == pc
)
136 continue; /* Ignore, probably spinning */
139 /* Then the sample is in our range */
140 *pc_bufptr
= (u_long
)pc
;
145 /* We never wrap the buffer */
146 if ((pc_bufptr
+ pc_trace_cnt
) >= pc_buflast
)
149 (void)disable_branch_tracing();
150 wakeup(&pcsample_enable
);
155 pcsamples_bootstrap()
157 if (!disable_branch_tracing())
160 pc_bufsize
= npcbufs
* sizeof(* pc_buffer
);
161 if (kmem_alloc(kernel_map
, &pc_buftomem
,
162 (vm_size_t
)pc_bufsize
) == KERN_SUCCESS
)
163 pc_buffer
= (u_long
*) pc_buftomem
;
165 pc_buffer
= (u_long
*) 0;
168 pc_bufptr
= pc_buffer
;
169 pc_buflast
= &pc_bufptr
[npcbufs
];
186 if (pc_bufsize
&& pc_buffer
)
187 kmem_free(kernel_map
, (vm_offset_t
)pc_buffer
, pc_bufsize
);
189 ret
= pcsamples_bootstrap();
195 /* Clean up the sample buffer, set defaults */
196 global_state_pid
= -1;
198 if(pc_bufsize
&& pc_buffer
)
199 kmem_free(kernel_map
, (vm_offset_t
)pc_buffer
, pc_bufsize
);
200 pc_buffer
= (u_long
*)0;
201 pc_bufptr
= (u_long
*)0;
202 pc_buflast
= (u_long
*)0;
206 bzero((void *)pcsample_comm
, sizeof(pcsample_comm
));
207 (void)disable_branch_tracing();
209 pc_trace_frameworks
= FALSE
;
213 pcsamples_control(name
, namelen
, where
, sizep
)
221 unsigned int value
= name
[1];
226 struct proc
*p
, *curproc
;
228 if (name
[0] != PCSAMPLE_GETNUMBUF
)
230 if(curproc
= current_proc())
231 curpid
= curproc
->p_pid
;
235 if (global_state_pid
== -1)
236 global_state_pid
= curpid
;
237 else if (global_state_pid
!= curpid
)
239 if((p
= pfind(global_state_pid
)) == NULL
)
241 /* The global pid no longer exists */
242 global_state_pid
= curpid
;
246 /* The global pid exists, deny this request */
254 case PCSAMPLE_DISABLE
: /* used to disable */
257 case PCSAMPLE_SETNUMBUF
:
258 /* The buffer size is bounded by a min and max number of samples */
259 if (value
< pc_trace_cnt
) {
263 if (value
<= MAX_PCSAMPLES
)
264 /* npcbufs = value & ~(PC_TRACE_CNT-1); */
267 npcbufs
= MAX_PCSAMPLES
;
269 case PCSAMPLE_GETNUMBUF
:
270 if(size
< sizeof(pcinfo_t
)) {
274 pc_bufinfo
.npcbufs
= npcbufs
;
275 pc_bufinfo
.bufsize
= pc_bufsize
;
276 pc_bufinfo
.enable
= pcsample_enable
;
277 pc_bufinfo
.pcsample_beg
= pcsample_beg
;
278 pc_bufinfo
.pcsample_end
= pcsample_end
;
279 if(copyout (&pc_bufinfo
, where
, sizeof(pc_bufinfo
)))
285 ret
=pcsamples_reinit();
287 case PCSAMPLE_REMOVE
:
290 case PCSAMPLE_READBUF
:
291 /* A nonzero value says enable and wait on the buffer */
292 /* A zero value says read up the buffer immediately */
295 /* Do not wait on the buffer */
297 (void)disable_branch_tracing();
298 ret
= pcsamples_read(where
, sizep
);
301 else if ((pc_bufsize
<= 0) || (!pc_buffer
))
303 /* enable only if buffer is initialized */
308 /* Turn on branch tracing */
309 if (!enable_branch_tracing())
315 /* Enable sampling */
318 ret
= tsleep(&pcsample_enable
, PRIBIO
| PCATCH
, "pcsample", 0);
320 (void)disable_branch_tracing();
324 /* Eventually fix this... if (ret != EINTR) */
327 /* On errors, except EINTR, we want to cleanup buffer ptrs */
328 /* pc_bufptr = pc_buffer; */
334 /* The only way to get here is if the buffer is full */
335 ret
= pcsamples_read(where
, sizep
);
339 case PCSAMPLE_SETREG
:
340 if (size
< sizeof(pcinfo_t
))
345 if (copyin(where
, &pc_bufinfo
, sizeof(pcinfo_t
)))
351 pcsample_beg
= pc_bufinfo
.pcsample_beg
;
352 pcsample_end
= pc_bufinfo
.pcsample_end
;
355 if (!(sizeof(pcsample_comm
) > size
))
360 bzero((void *)pcsample_comm
, sizeof(pcsample_comm
));
361 if (copyin(where
, pcsample_comm
, size
))
367 /* Check for command name or pid */
368 if (pcsample_comm
[0] != '\0')
375 if (size
!= (2 * sizeof(pid_t
)))
382 pidcheck
= (pid_t
*)pcsample_comm
;
383 pc_sample_pid
= pidcheck
[1];
396 This buffer must be read up in one call.
397 If the buffer isn't big enough to hold
398 all the samples, it will copy up enough
399 to fill the buffer and throw the rest away.
400 This buffer never wraps.
402 pcsamples_read(u_long
*buffer
, size_t *number
)
408 count
= (*number
)/sizeof(u_long
);
410 if (count
&& pc_bufsize
&& pc_buffer
)
412 copycount
= pc_bufptr
- pc_buffer
;
420 if (copycount
> count
)
423 /* We actually have data to send up */
424 if(copyout(pc_buffer
, buffer
, copycount
* sizeof(u_long
)))
430 pc_bufptr
= pc_buffer
;