]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_pcsamples.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@
23 #include <sys/kdebug.h>
24 #include <sys/errno.h>
25 #include <sys/param.h>
28 #include <sys/sysctl.h>
29 #include <vm/vm_kern.h>
31 unsigned int pc_buftomem
= 0;
32 u_long
* pc_buffer
= 0; /* buffer that holds each pc */
33 u_long
* pc_bufptr
= 0;
34 u_long
* pc_buflast
= 0;
35 unsigned int npcbufs
= 8192; /* number of pc entries in buffer */
36 unsigned int pc_bufsize
= 0;
37 unsigned int pcsample_flags
= 0;
38 unsigned int pcsample_enable
= 0;
40 char pcsample_comm
[MAXCOMLEN
+ 1];
42 /* Set the default framework boundaries */
43 u_long pcsample_beg
= 0;
44 u_long pcsample_end
= 0;
46 static pid_t global_state_pid
= -1; /* Used to control exclusive use of pc_buffer */
48 extern int pc_trace_buf
[];
49 extern int pc_trace_cnt
;
57 extern unsigned int kdebug_flags
;
62 if (pcsample_comm
[0] != '\0')
64 /* If command string does not match, then return */
65 curproc
= current_proc();
67 (strncmp(curproc
->p_comm
, pcsample_comm
, sizeof(pcsample_comm
))))
71 for (i
=0; i
< pc_trace_cnt
; i
++)
75 if ((pcsample_beg
<= pc
) && (pc
< pcsample_end
))
77 if (pc_bufptr
> pc_buffer
)
79 if ( (*(pc_bufptr
-1)) == pc
)
80 continue; /* Ignore, probably spinning */
83 /* Then the sample is in our range */
84 *pc_bufptr
= (u_long
)pc
;
89 /* We never wrap the buffer */
90 if ((pc_bufptr
+ pc_trace_cnt
) >= pc_buflast
)
94 wakeup(&pcsample_enable
);
104 pc_bufsize
= npcbufs
* sizeof(* pc_buffer
);
105 if (kmem_alloc(kernel_map
, &pc_buftomem
,
106 (vm_size_t
)pc_bufsize
) == KERN_SUCCESS
)
107 pc_buffer
= (u_long
*) pc_buftomem
;
109 pc_buffer
= (u_long
*) 0;
112 pc_bufptr
= pc_buffer
;
113 pc_buflast
= &pc_bufptr
[npcbufs
];
130 if (pc_bufsize
&& pc_buffer
)
131 kmem_free(kernel_map
,pc_buffer
,pc_bufsize
);
133 ret
= pcsamples_bootstrap();
139 /* Clean up the sample buffer, set defaults */
140 global_state_pid
= -1;
142 if(pc_bufsize
&& pc_buffer
)
143 kmem_free(kernel_map
,pc_buffer
,pc_bufsize
);
144 pc_buffer
= (u_long
*)0;
145 pc_bufptr
= (u_long
*)0;
146 pc_buflast
= (u_long
*)0;
150 bzero((void *)pcsample_comm
, sizeof(pcsample_comm
));
154 pcsamples_control(name
, namelen
, where
, sizep
)
162 unsigned int value
= name
[1];
166 struct proc
*p
, *curproc
;
168 if (name
[0] != PCSAMPLE_GETNUMBUF
)
170 if(curproc
= current_proc())
171 curpid
= curproc
->p_pid
;
175 if (global_state_pid
== -1)
176 global_state_pid
= curpid
;
177 else if (global_state_pid
!= curpid
)
179 if((p
= pfind(global_state_pid
)) == NULL
)
181 /* The global pid no longer exists */
182 global_state_pid
= curpid
;
186 /* The global pid exists, deny this request */
194 case PCSAMPLE_DISABLE
: /* used to disable */
197 case PCSAMPLE_SETNUMBUF
:
198 /* The buffer size is bounded by a min and max number of samples */
199 if (value
< pc_trace_cnt
) {
203 if (value
<= MAX_PCSAMPLES
)
204 /* npcbufs = value & ~(PC_TRACE_CNT-1); */
207 npcbufs
= MAX_PCSAMPLES
;
209 case PCSAMPLE_GETNUMBUF
:
210 if(size
< sizeof(pcinfo_t
)) {
214 pc_bufinfo
.npcbufs
= npcbufs
;
215 pc_bufinfo
.bufsize
= pc_bufsize
;
216 pc_bufinfo
.enable
= pcsample_enable
;
217 pc_bufinfo
.pcsample_beg
= pcsample_beg
;
218 pc_bufinfo
.pcsample_end
= pcsample_end
;
219 if(copyout (&pc_bufinfo
, where
, sizeof(pc_bufinfo
)))
225 ret
=pcsamples_reinit();
227 case PCSAMPLE_REMOVE
:
230 case PCSAMPLE_READBUF
:
231 /* A nonzero value says enable and wait on the buffer */
232 /* A zero value says read up the buffer immediately */
235 /* Do not wait on the buffer */
238 ret
= pcsamples_read(where
, sizep
);
241 else if ((pc_bufsize
<= 0) || (!pc_buffer
))
243 /* enable only if buffer is initialized */
248 /* Turn on branch tracing */
255 /* Enable sampling */
258 ret
= tsleep(&pcsample_enable
, PRIBIO
| PCATCH
, "pcsample", 0);
264 /* Eventually fix this... if (ret != EINTR) */
267 /* On errors, except EINTR, we want to cleanup buffer ptrs */
268 /* pc_bufptr = pc_buffer; */
274 /* The only way to get here is if the buffer is full */
275 ret
= pcsamples_read(where
, sizep
);
279 case PCSAMPLE_SETREG
:
280 if (size
< sizeof(pcinfo_t
))
285 if (copyin(where
, &pc_bufinfo
, sizeof(pcinfo_t
)))
291 pcsample_beg
= pc_bufinfo
.pcsample_beg
;
292 pcsample_end
= pc_bufinfo
.pcsample_end
;
295 if (!(sizeof(pcsample_comm
) > size
))
300 bzero((void *)pcsample_comm
, sizeof(pcsample_comm
));
301 if (copyin(where
, pcsample_comm
, size
))
315 This buffer must be read up in one call.
316 If the buffer isn't big enough to hold
317 all the samples, it will copy up enough
318 to fill the buffer and throw the rest away.
319 This buffer never wraps.
321 pcsamples_read(u_long
*buffer
, size_t *number
)
327 count
= (*number
)/sizeof(u_long
);
329 if (count
&& pc_bufsize
&& pc_buffer
)
331 copycount
= pc_bufptr
- pc_buffer
;
339 if (copycount
> count
)
342 /* We actually have data to send up */
343 if(copyout(pc_buffer
, buffer
, copycount
* sizeof(u_long
)))
349 pc_bufptr
= pc_buffer
;