X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/2d21ac55c334faf3a56e5634905ed6987fc787d4..0a7de7458d150b5d4dffc935ba399be265ef0a1a:/bsd/kern/kern_pcsamples.c diff --git a/bsd/kern/kern_pcsamples.c b/bsd/kern/kern_pcsamples.c index 36757c2af..69694bc5b 100644 --- a/bsd/kern/kern_pcsamples.c +++ b/bsd/kern/kern_pcsamples.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2012 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,7 +22,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ @@ -37,9 +37,9 @@ #include vm_offset_t pc_buftomem = 0; -unsigned int * pc_buffer = 0; /* buffer that holds each pc */ -unsigned int * pc_bufptr = 0; -unsigned int * pc_buflast = 0; +unsigned int * pc_buffer = 0; /* buffer that holds each pc */ +unsigned int * pc_bufptr = 0; +unsigned int * pc_buflast = 0; unsigned int npcbufs = 8192; /* number of pc entries in buffer */ unsigned int pc_bufsize = 0; unsigned int pcsample_flags = 0; @@ -72,46 +72,40 @@ int pcsamples_reinit(void); int enable_branch_tracing(void) { -#ifndef i386 - struct proc *p; - if (-1 != pc_sample_pid) { - p = proc_find(pc_sample_pid); - if (p) { - p->p_btrace = 1; - proc_rele(p); - } - } - else { - pc_trace_frameworks = TRUE; - } - - return 1; - -#else - return 0; -#endif + struct proc *p; + if (-1 != pc_sample_pid) { + p = proc_find(pc_sample_pid); + if (p) { + p->p_btrace = 1; + proc_rele(p); + } + } else { + pc_trace_frameworks = TRUE; + } + + return 1; } int disable_branch_tracing(void) { - struct proc *p; - switch (pc_sample_pid) { - case -1: - pc_trace_frameworks = FALSE; - break; - case 0: - break; - default: - p = proc_find(pc_sample_pid); - if (p) { - p->p_btrace = 0; + struct proc *p; + switch (pc_sample_pid) { + case -1: + pc_trace_frameworks = FALSE; + break; + case 0: + break; + default: + p = proc_find(pc_sample_pid); + if (p) { + p->p_btrace = 0; proc_rele(p); - } - break; - } - clr_be_bit(); - return 1; + } + break; + } + clr_be_bit(); + return 1; } /* @@ -121,12 +115,14 @@ disable_branch_tracing(void) int branch_tracing_enabled(void) { - struct proc *p = current_proc(); - if (TRUE == pc_trace_frameworks) return TRUE; - if (p) { - return (p->p_btrace); - } - return 0; + struct proc *p = current_proc(); + if (TRUE == pc_trace_frameworks) { + return TRUE; + } + if (p) { + return p->p_btrace; + } + return 0; } @@ -134,92 +130,93 @@ void add_pcbuffer(void) { int i; - unsigned int pc; - - if (!pcsample_enable) - return; - - for (i=0; i < pc_trace_cnt; i++) - { - pc = pc_trace_buf[i]; - - if ((pcsample_beg <= pc) && (pc < pcsample_end)) - { - if (pc_bufptr > pc_buffer) - { - if ( (*(pc_bufptr-1)) == pc ) - continue; /* Ignore, probably spinning */ - } - - /* Then the sample is in our range */ - *pc_bufptr = pc; - pc_bufptr++; - } - } + unsigned int pc; + + if (!pcsample_enable) { + return; + } + + for (i = 0; i < pc_trace_cnt; i++) { + pc = pc_trace_buf[i]; + + if ((pcsample_beg <= pc) && (pc < pcsample_end)) { + if (pc_bufptr > pc_buffer) { + if ((*(pc_bufptr - 1)) == pc) { + continue; /* Ignore, probably spinning */ + } + } + + /* Then the sample is in our range */ + *pc_bufptr = pc; + pc_bufptr++; + } + } /* We never wrap the buffer */ - if ((pc_bufptr + pc_trace_cnt) >= pc_buflast) - { - pcsample_enable = 0; - (void)disable_branch_tracing(); - wakeup(&pcsample_enable); - } + if ((pc_bufptr + pc_trace_cnt) >= pc_buflast) { + pcsample_enable = 0; + (void)disable_branch_tracing(); + wakeup(&pcsample_enable); + } return; } int pcsamples_bootstrap(void) { - if (!disable_branch_tracing()) - return(ENOTSUP); + if (!disable_branch_tracing()) { + return ENOTSUP; + } - pc_bufsize = npcbufs * sizeof(* pc_buffer); + pc_bufsize = npcbufs * sizeof(*pc_buffer); if (kmem_alloc(kernel_map, &pc_buftomem, - (vm_size_t)pc_bufsize) == KERN_SUCCESS) - pc_buffer = (unsigned int *) pc_buftomem; - else - pc_buffer = NULL; + (vm_size_t)pc_bufsize) == KERN_SUCCESS) { + pc_buffer = (unsigned int *) pc_buftomem; + } else { + pc_buffer = NULL; + } if (pc_buffer) { pc_bufptr = pc_buffer; pc_buflast = &pc_bufptr[npcbufs]; pcsample_enable = 0; - return(0); + return 0; } else { - pc_bufsize=0; - return(EINVAL); + pc_bufsize = 0; + return EINVAL; } - } int pcsamples_reinit(void) { - int ret=0; + int ret = 0; - pcsample_enable = 0; + pcsample_enable = 0; - if (pc_bufsize && pc_buffer) + if (pc_bufsize && pc_buffer) { kmem_free(kernel_map, (vm_offset_t)pc_buffer, pc_bufsize); + } - ret= pcsamples_bootstrap(); - return(ret); + ret = pcsamples_bootstrap(); + return ret; } void pcsamples_clear(void) { - /* Clean up the sample buffer, set defaults */ - global_state_pid = -1; + /* Clean up the sample buffer, set defaults */ + global_state_pid = -1; pcsample_enable = 0; - if(pc_bufsize && pc_buffer) - kmem_free(kernel_map, (vm_offset_t)pc_buffer, pc_bufsize); + if (pc_bufsize && pc_buffer) { + kmem_free(kernel_map, (vm_offset_t)pc_buffer, pc_bufsize); + } pc_buffer = NULL; pc_bufptr = NULL; pc_buflast = NULL; pc_bufsize = 0; - pcsample_beg= 0; - pcsample_end= 0; + pcsample_beg = 0; + pcsample_end = 0; bzero((void *)pcsample_comm, sizeof(pcsample_comm)); (void)disable_branch_tracing(); pc_sample_pid = 0; @@ -229,226 +226,199 @@ pcsamples_clear(void) int pcsamples_control(int *name, __unused u_int namelen, user_addr_t where, size_t *sizep) { - int ret=0; - size_t size=*sizep; - int value = name[1]; - pcinfo_t pc_bufinfo; - pid_t *pidcheck; - - pid_t curpid; - struct proc *p, *curproc; - - if (name[0] != PCSAMPLE_GETNUMBUF) - { - curproc = current_proc(); - if (curproc) - curpid = curproc->p_pid; - else - return (ESRCH); - - if (global_state_pid == -1) - global_state_pid = curpid; - else if (global_state_pid != curpid) - { - if((p = proc_find(global_state_pid)) == NULL) - { - /* The global pid no longer exists */ - global_state_pid = curpid; - } - else - { - proc_rele(p); - /* The global pid exists, deny this request */ - return(EBUSY); - } - } - } - - - switch(name[0]) { - case PCSAMPLE_DISABLE: /* used to disable */ - pcsample_enable=0; - break; - case PCSAMPLE_SETNUMBUF: - /* The buffer size is bounded by a min and max number of samples */ - if (value < pc_trace_cnt) { - ret=EINVAL; - break; + int ret = 0; + size_t size = *sizep; + int value = name[1]; + pcinfo_t pc_bufinfo = {}; + pid_t *pidcheck; + + pid_t curpid; + struct proc *p, *curproc; + + if (name[0] != PCSAMPLE_GETNUMBUF) { + curproc = current_proc(); + if (curproc) { + curpid = curproc->p_pid; + } else { + return ESRCH; + } + + if (global_state_pid == -1) { + global_state_pid = curpid; + } else if (global_state_pid != curpid) { + if ((p = proc_find(global_state_pid)) == NULL) { + /* The global pid no longer exists */ + global_state_pid = curpid; + } else { + proc_rele(p); + /* The global pid exists, deny this request */ + return EBUSY; } - if (value <= MAX_PCSAMPLES) - /* npcbufs = value & ~(PC_TRACE_CNT-1); */ - npcbufs = value; - else - npcbufs = MAX_PCSAMPLES; + } + } + + + switch (name[0]) { + case PCSAMPLE_DISABLE: /* used to disable */ + pcsample_enable = 0; + break; + case PCSAMPLE_SETNUMBUF: + /* The buffer size is bounded by a min and max number of samples */ + if (value < pc_trace_cnt) { + ret = EINVAL; break; - case PCSAMPLE_GETNUMBUF: - if (size < sizeof(pc_bufinfo)) { - ret=EINVAL; - break; - } - pc_bufinfo.npcbufs = npcbufs; - pc_bufinfo.bufsize = pc_bufsize; - pc_bufinfo.enable = pcsample_enable; - pc_bufinfo.pcsample_beg = pcsample_beg; - pc_bufinfo.pcsample_end = pcsample_end; - if(copyout (&pc_bufinfo, where, sizeof(pc_bufinfo))) - { - ret=EINVAL; - } + } + if (value <= MAX_PCSAMPLES) { + /* npcbufs = value & ~(PC_TRACE_CNT-1); */ + npcbufs = value; + } else { + npcbufs = MAX_PCSAMPLES; + } + break; + case PCSAMPLE_GETNUMBUF: + if (size < sizeof(pc_bufinfo)) { + ret = EINVAL; break; - case PCSAMPLE_SETUP: - ret=pcsamples_reinit(); + } + pc_bufinfo.npcbufs = npcbufs; + pc_bufinfo.bufsize = pc_bufsize; + pc_bufinfo.enable = pcsample_enable; + pc_bufinfo.pcsample_beg = pcsample_beg; + pc_bufinfo.pcsample_end = pcsample_end; + if (copyout(&pc_bufinfo, where, sizeof(pc_bufinfo))) { + ret = EINVAL; + } + break; + case PCSAMPLE_SETUP: + ret = pcsamples_reinit(); + break; + case PCSAMPLE_REMOVE: + pcsamples_clear(); + break; + case PCSAMPLE_READBUF: + /* A nonzero value says enable and wait on the buffer */ + /* A zero value says read up the buffer immediately */ + if (value == 0) { + /* Do not wait on the buffer */ + pcsample_enable = 0; + (void)disable_branch_tracing(); + ret = pcsamples_read(where, sizep); break; - case PCSAMPLE_REMOVE: - pcsamples_clear(); + } else if ((pc_bufsize <= 0) || (!pc_buffer)) { + /* enable only if buffer is initialized */ + ret = EINVAL; break; - case PCSAMPLE_READBUF: - /* A nonzero value says enable and wait on the buffer */ - /* A zero value says read up the buffer immediately */ - if (value == 0) - { - /* Do not wait on the buffer */ - pcsample_enable = 0; - (void)disable_branch_tracing(); - ret = pcsamples_read(where, sizep); - break; - } - else if ((pc_bufsize <= 0) || (!pc_buffer)) - { - /* enable only if buffer is initialized */ - ret=EINVAL; - break; - } + } - /* Turn on branch tracing */ - if (!enable_branch_tracing()) - { - ret = ENOTSUP; - break; - } + /* Turn on branch tracing */ + if (!enable_branch_tracing()) { + ret = ENOTSUP; + break; + } - /* Enable sampling */ - pcsample_enable = 1; + /* Enable sampling */ + pcsample_enable = 1; - ret = tsleep(&pcsample_enable, PRIBIO | PCATCH, "pcsample", 0); - pcsample_enable = 0; - (void)disable_branch_tracing(); + ret = tsleep(&pcsample_enable, PRIBIO | PCATCH, "pcsample", 0); + pcsample_enable = 0; + (void)disable_branch_tracing(); - if (ret) - { - /* Eventually fix this... if (ret != EINTR) */ - if (ret) - { + if (ret) { + /* Eventually fix this... if (ret != EINTR) */ + if (ret) { /* On errors, except EINTR, we want to cleanup buffer ptrs */ /* pc_bufptr = pc_buffer; */ *sizep = 0; - } - } - else - { - /* The only way to get here is if the buffer is full */ - ret = pcsamples_read(where, sizep); - } + } + } else { + /* The only way to get here is if the buffer is full */ + ret = pcsamples_read(where, sizep); + } + + break; + case PCSAMPLE_SETREG: + if (size < sizeof(pc_bufinfo)) { + ret = EINVAL; + break; + } + if (copyin(where, &pc_bufinfo, sizeof(pc_bufinfo))) { + ret = EINVAL; + break; + } + pcsample_beg = pc_bufinfo.pcsample_beg; + pcsample_end = pc_bufinfo.pcsample_end; + break; + case PCSAMPLE_COMM: + if (!(sizeof(pcsample_comm) > size)) { + ret = EINVAL; break; - case PCSAMPLE_SETREG: - if (size < sizeof(pc_bufinfo)) - { - ret = EINVAL; - break; - } - if (copyin(where, &pc_bufinfo, sizeof(pc_bufinfo))) - { - ret = EINVAL; - break; - } - - pcsample_beg = pc_bufinfo.pcsample_beg; - pcsample_end = pc_bufinfo.pcsample_end; + } + bzero((void *)pcsample_comm, sizeof(pcsample_comm)); + if (copyin(where, pcsample_comm, size)) { + ret = EINVAL; + break; + } + + /* Check for command name or pid */ + if (pcsample_comm[0] != '\0') { + ret = ENOTSUP; break; - case PCSAMPLE_COMM: - if (!(sizeof(pcsample_comm) > size)) - { - ret = EINVAL; - break; - } - bzero((void *)pcsample_comm, sizeof(pcsample_comm)); - if (copyin(where, pcsample_comm, size)) - { - ret = EINVAL; - break; - } - - /* Check for command name or pid */ - if (pcsample_comm[0] != '\0') - { - ret= ENOTSUP; - break; - } - else - { - if (size != (2 * sizeof(pid_t))) - { - ret = EINVAL; - break; - } - else - { + } else { + if (size != (2 * sizeof(pid_t))) { + ret = EINVAL; + break; + } else { pidcheck = (pid_t *)pcsample_comm; pc_sample_pid = pidcheck[1]; - } - } - break; - default: - ret= ENOTSUP; - break; + } + } + break; + default: + ret = ENOTSUP; + break; } - return(ret); + return ret; } -/* - This buffer must be read up in one call. - If the buffer isn't big enough to hold - all the samples, it will copy up enough - to fill the buffer and throw the rest away. - This buffer never wraps. -*/ +/* + * This buffer must be read up in one call. + * If the buffer isn't big enough to hold + * all the samples, it will copy up enough + * to fill the buffer and throw the rest away. + * This buffer never wraps. + */ int pcsamples_read(user_addr_t buffer, size_t *number) { - size_t count=0; - size_t copycount; - - count = (*number)/sizeof(* pc_buffer); - - if (count && pc_bufsize && pc_buffer) - { - copycount = pc_bufptr - pc_buffer; - - if (copycount <= 0) - { - *number = 0; - return(0); + size_t count = 0; + size_t copycount; + + count = (*number) / sizeof(*pc_buffer); + + if (count && pc_bufsize && pc_buffer) { + copycount = pc_bufptr - pc_buffer; + + if (copycount <= 0) { + *number = 0; + return 0; } - if (copycount > count) - copycount = count; + if (copycount > count) { + copycount = count; + } - /* We actually have data to send up */ - if(copyout(pc_buffer, buffer, copycount * sizeof(* pc_buffer))) - { - *number = 0; - return(EINVAL); + /* We actually have data to send up */ + if (copyout(pc_buffer, buffer, copycount * sizeof(*pc_buffer))) { + *number = 0; + return EINVAL; } - *number = copycount; - pc_bufptr = pc_buffer; - return(0); - } - else - { - *number = 0; - return(0); - } + *number = copycount; + pc_bufptr = pc_buffer; + return 0; + } else { + *number = 0; + return 0; + } } -