X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/5d5c5d0d5b79ade9a973d55186ffda2638ba2b6e..15129b1c8dbb3650c63b70adb1cad9af601c6c17:/bsd/kern/subr_prof.c?ds=inline diff --git a/bsd/kern/subr_prof.c b/bsd/kern/subr_prof.c index 49f50b536..80b6edc27 100644 --- a/bsd/kern/subr_prof.c +++ b/bsd/kern/subr_prof.c @@ -1,31 +1,29 @@ /* - * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2008 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * @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 - * compliance with the License. The rights granted to you under the - * License may not be used to create, or enable the creation or - * redistribution of, 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. - * Please see the License for the specific language governing rights and + * 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 + * compliance with the License. The rights granted to you under the License + * may not be used to create, or enable the creation or redistribution of, + * 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ /*- @@ -63,6 +61,10 @@ * @(#)subr_prof.c 8.3 (Berkeley) 9/23/93 */ +#ifdef GPROF +#include +#endif + #include #include #include @@ -79,13 +81,14 @@ #include #include -extern boolean_t ml_set_interrupts_enabled(boolean_t enable); - #ifdef GPROF #include #include -#include -#include + +extern int sysctl_doprof(int *, u_int, user_addr_t, size_t *, + user_addr_t, size_t newlen); +extern int sysctl_struct(user_addr_t, size_t *, + user_addr_t, size_t, void *, int); lck_spin_t * mcount_lock; lck_grp_t * mcount_lock_grp; @@ -94,7 +97,7 @@ lck_attr_t * mcount_lock_attr; /* * Froms is actually a bunch of unsigned shorts indexing tos */ -struct gmonparam _gmonparam = { GMON_PROF_OFF }; +struct gmonparam _gmonparam = { .state = GMON_PROF_OFF }; /* * This code uses 32 bit mach object segment information from the currently @@ -103,14 +106,13 @@ struct gmonparam _gmonparam = { GMON_PROF_OFF }; void kmstartup(void) { - char *cp; - u_long fromssize, tossize; - struct segment_command *sgp; /* 32 bit mach object file segment */ + tostruct_t *cp; + kernel_segment_command_t *sgp; /* 32 bit mach object file segment */ struct gmonparam *p = &_gmonparam; sgp = getsegbyname("__TEXT"); - p->lowpc = (u_long)sgp->vmaddr; - p->highpc = (u_long)(sgp->vmaddr + sgp->vmsize); + p->lowpc = (u_int32_t)sgp->vmaddr; + p->highpc = (u_int32_t)(sgp->vmaddr + sgp->vmsize); /* * Round lowpc and highpc to multiples of the density we're using @@ -119,7 +121,7 @@ kmstartup(void) p->lowpc = ROUNDDOWN(p->lowpc, HISTFRACTION * sizeof(HISTCOUNTER)); p->highpc = ROUNDUP(p->highpc, HISTFRACTION * sizeof(HISTCOUNTER)); p->textsize = p->highpc - p->lowpc; - printf("Profiling kernel, textsize=%d [0x%08x..0x%08x]\n", + printf("Profiling kernel, textsize=%lu [0x%016lx..0x%016lx]\n", p->textsize, p->lowpc, p->highpc); p->kcountsize = p->textsize / HISTFRACTION; p->hashfraction = HASHFRACTION; @@ -129,18 +131,18 @@ kmstartup(void) p->tolimit = MINARCS; else if (p->tolimit > MAXARCS) p->tolimit = MAXARCS; - p->tossize = p->tolimit * sizeof(struct tostruct); + p->tossize = p->tolimit * sizeof(tostruct_t); /* Why not use MALLOC with M_GPROF ? */ - cp = (char *)kalloc(p->kcountsize + p->fromssize + p->tossize); + cp = (tostruct_t *)kalloc(p->kcountsize + p->fromssize + p->tossize); if (cp == 0) { printf("No memory for profiling.\n"); return; } bzero(cp, p->kcountsize + p->tossize + p->fromssize); - p->tos = (struct tostruct *)cp; - cp += p->tossize; + p->tos = cp; + cp = (tostruct_t *)((vm_offset_t)cp + p->tossize); p->kcount = (u_short *)cp; - cp += p->kcountsize; + cp = (tostruct_t *)((vm_offset_t)cp + p->kcountsize); p->froms = (u_short *)cp; mcount_lock_grp = lck_grp_alloc_init("MCOUNT", LCK_GRP_ATTR_NULL); @@ -150,14 +152,28 @@ kmstartup(void) } /* - * Return kernel profiling information. + * XXX These should be broken out into per-argument OID values, + * XXX since there are no sub-OID parameter values, but unfortunately + * XXX there is barely enough time for an initial conversion. + * + * Note: These items appear to be read/write. */ -int +STATIC int +sysctl_doprofhandle SYSCTL_HANDLER_ARGS +{ sysctl_doprof(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, user_addr_t newp, size_t newlen) { + __unused int cmd = oidp->oid_arg2; /* subcommand*/ + int *name = arg1; /* oid element argument vector */ + int namelen = arg2; /* number of oid element arguments */ + user_addr_t oldp = req->oldptr; /* user buffer copy out address */ + size_t *oldlenp = req->oldlen; /* user buffer copy out size */ + user_addr_t newp = req->newptr; /* user buffer copy in address */ + size_t newlen = req->newlen; /* user buffer copy in size */ + struct gmonparam *gp = &_gmonparam; - int error; + int error = 0; /* all sysctl names at this level are terminal */ if (namelen != 1) @@ -167,28 +183,44 @@ sysctl_doprof(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, case GPROF_STATE: error = sysctl_int(oldp, oldlenp, newp, newlen, &gp->state); if (error) - return (error); + break; if (gp->state == GMON_PROF_OFF) stopprofclock(kernproc); else startprofclock(kernproc); - return (0); + break; case GPROF_COUNT: - return (sysctl_struct(oldp, oldlenp, newp, newlen, - gp->kcount, gp->kcountsize)); + error = sysctl_struct(oldp, oldlenp, newp, newlen, + gp->kcount, gp->kcountsize); + break; case GPROF_FROMS: - return (sysctl_struct(oldp, oldlenp, newp, newlen, - gp->froms, gp->fromssize)); + error = sysctl_struct(oldp, oldlenp, newp, newlen, + gp->froms, gp->fromssize); + break; case GPROF_TOS: - return (sysctl_struct(oldp, oldlenp, newp, newlen, - gp->tos, gp->tossize)); + error = sysctl_struct(oldp, oldlenp, newp, newlen, + gp->tos, gp->tossize); + break; case GPROF_GMONPARAM: - return (sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp)); + error = sysctl_rdstruct(oldp, oldlenp, newp, gp, sizeof *gp); + break; default: - return (ENOTSUP); + error = ENOTSUP; + break; } - /* NOTREACHED */ + + /* adjust index so we return the right required/consumed amount */ + if (!error) + req->oldidx += req->oldlen; + + return(error); } +SYSCTL_PROC(_kern, KERN_PROF, prof, STLFLAG_NODE|CTLFLAG_RW | CTLFLAG_LOCKED, + 0, /* Pointer argument (arg1) */ + 0, /* Integer argument (arg2) */ + sysctl_doprofhandle, /* Handler function */ + NULL, /* No explicit data */ + ""); /* @@ -196,14 +228,14 @@ sysctl_doprof(int *name, u_int namelen, user_addr_t oldp, size_t *oldlenp, */ void mcount( - register u_long frompc, - register u_long selfpc + uintptr_t frompc, + uintptr_t selfpc ) { unsigned short *frompcindex; - register struct tostruct *top, *prevtop; + tostruct_t *top, *prevtop; struct gmonparam *p = &_gmonparam; - register long toindex; + long toindex; /* * check that we are profiling @@ -310,120 +342,15 @@ overflow: #define PROFILE_LOCK(x) #define PROFILE_UNLOCK(x) -int -profil(struct proc *p, register struct profil_args *uap, __unused register_t *retval) -{ - struct uprof *upp = &p->p_stats->p_prof; - int s; - - if (uap->pcscale > (1 << 16)) - return (EINVAL); - if (uap->pcscale == 0) { - stopprofclock(p); - return (0); - } - - /* Block profile interrupts while changing state. */ - s = ml_set_interrupts_enabled(FALSE); - - if (proc_is64bit(p)) { - struct user_uprof *user_upp = &p->p_stats->user_p_prof; - struct user_uprof *upc, *nupc; - - PROFILE_LOCK(&user_upp->pr_lock); - user_upp->pr_base = uap->bufbase; - user_upp->pr_size = uap->bufsize; - user_upp->pr_off = uap->pcoffset; - user_upp->pr_scale = uap->pcscale; - upp->pr_base = NULL; - upp->pr_size = 0; - upp->pr_scale = 0; - - /* remove buffers previously allocated with add_profil() */ - for (upc = user_upp->pr_next; upc; upc = nupc) { - nupc = upc->pr_next; - kfree(upc, sizeof (*upc)); - } - user_upp->pr_next = 0; - PROFILE_UNLOCK(&user_upp->pr_lock); - } - else { - struct uprof *upc, *nupc; - - PROFILE_LOCK(&upp->pr_lock); - upp->pr_base = CAST_DOWN(caddr_t, uap->bufbase); - upp->pr_size = uap->bufsize; - upp->pr_off = uap->pcoffset; - upp->pr_scale = uap->pcscale; - - /* remove buffers previously allocated with add_profil() */ - for (upc = upp->pr_next; upc; upc = nupc) { - nupc = upc->pr_next; - kfree(upc, sizeof (struct uprof)); - } - upp->pr_next = 0; - PROFILE_UNLOCK(&upp->pr_lock); - } - - startprofclock(p); - ml_set_interrupts_enabled(s); - return(0); -} - -int -add_profil(struct proc *p, register struct add_profil_args *uap, __unused register_t *retval) -{ - struct uprof *upp = &p->p_stats->p_prof, *upc; - struct user_uprof *user_upp = NULL, *user_upc; - int s; - boolean_t is64bit = proc_is64bit(p); - - if (is64bit) { - user_upp = &p->p_stats->user_p_prof; - if (user_upp->pr_scale == 0) - return (0); - } - else { - if (upp->pr_scale == 0) - return (0); - } - - s = ml_set_interrupts_enabled(FALSE); - - if (is64bit) { - user_upc = (struct user_uprof *) kalloc(sizeof (struct user_uprof)); - user_upc->pr_base = uap->bufbase; - user_upc->pr_size = uap->bufsize; - user_upc->pr_off = uap->pcoffset; - user_upc->pr_scale = uap->pcscale; - PROFILE_LOCK(&user_upp->pr_lock); - user_upc->pr_next = user_upp->pr_next; - user_upp->pr_next = user_upc; - PROFILE_UNLOCK(&user_upp->pr_lock); - } - else { - upc = (struct uprof *) kalloc(sizeof (struct uprof)); - upc->pr_base = CAST_DOWN(caddr_t, uap->bufbase); - upc->pr_size = uap->bufsize; - upc->pr_off = uap->pcoffset; - upc->pr_scale = uap->pcscale; - PROFILE_LOCK(&upp->pr_lock); - upc->pr_next = upp->pr_next; - upp->pr_next = upc; - PROFILE_UNLOCK(&upp->pr_lock); - } - - ml_set_interrupts_enabled(s); - return(0); -} /* * Scale is a fixed-point number with the binary point 16 bits * into the value, and is <= 1.0. pc is at most 32 bits, so the * intermediate result is at most 48 bits. */ +//K64todo - this doesn't fit into 64 bit any more, it needs 64+16 #define PC_TO_INDEX(pc, prof) \ - ((int)(((u_quad_t)((pc) - (prof)->pr_off) * \ + ((user_addr_t)(((u_quad_t)((pc) - (prof)->pr_off) * \ (u_quad_t)((prof)->pr_scale)) >> 16) & ~1) /* @@ -441,12 +368,9 @@ add_profil(struct proc *p, register struct add_profil_args *uap, __unused regist * update fails, we simply turn off profiling. */ void -addupc_task(p, pc, ticks) - register struct proc *p; - user_addr_t pc; - u_int ticks; +addupc_task(struct proc *p, user_addr_t pc, u_int ticks) { - register u_int off; + user_addr_t off; u_short count; /* Testing P_PROFIL may be unnecessary, but is certainly safe. */ @@ -478,10 +402,10 @@ addupc_task(p, pc, ticks) short *cell; for (prof = &p->p_stats->p_prof; prof; prof = prof->pr_next) { - off = PC_TO_INDEX(CAST_DOWN(uint, pc),prof); + off = PC_TO_INDEX(pc,prof); cell = (short *)(prof->pr_base + off); if (cell >= (short *)prof->pr_base && - cell < (short*)(prof->pr_size + (int) prof->pr_base)) { + cell < (short*)(prof->pr_size + prof->pr_base)) { if (copyin(CAST_USER_ADDR_T(cell), (caddr_t) &count, sizeof(count)) == 0) { count += ticks; if(copyout((caddr_t) &count, CAST_USER_ADDR_T(cell), sizeof(count)) == 0)