X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..743b15655a24ee3fe9f458f383003e011db0558f:/bsd/kern/kern_pcsamples.c?ds=sidebyside diff --git a/bsd/kern/kern_pcsamples.c b/bsd/kern/kern_pcsamples.c index 68ba7cc97..f231dd6cb 100644 --- a/bsd/kern/kern_pcsamples.c +++ b/bsd/kern/kern_pcsamples.c @@ -23,51 +23,114 @@ #include #include #include -#include +#include #include #include +#include #include +#include -unsigned int pc_buftomem = 0; -u_long * pc_buffer = 0; /* buffer that holds each pc */ -u_long * pc_bufptr = 0; -u_long * pc_buflast = 0; +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 npcbufs = 8192; /* number of pc entries in buffer */ unsigned int pc_bufsize = 0; unsigned int pcsample_flags = 0; unsigned int pcsample_enable = 0; +pid_t pc_sample_pid = 0; +boolean_t pc_trace_frameworks = FALSE; + char pcsample_comm[MAXCOMLEN + 1]; /* Set the default framework boundaries */ -u_long pcsample_beg = 0; -u_long pcsample_end = 0; +unsigned int pcsample_beg = 0; +unsigned int pcsample_end = 0; static pid_t global_state_pid = -1; /* Used to control exclusive use of pc_buffer */ extern int pc_trace_buf[]; extern int pc_trace_cnt; +void add_pcbuffer(void); +int branch_tracing_enabled(void); +int disable_branch_tracing(void); +int enable_branch_tracing(void); +int pcsamples_bootstrap(void); +void pcsamples_clear(void); +int pcsamples_control(int *name, u_int namelen, user_addr_t where, size_t *sizep); +int pcsamples_read(user_addr_t buffer, size_t *number); +int pcsamples_reinit(void); + +int +enable_branch_tracing(void) +{ +#ifndef i386 + struct proc *p; + if (-1 != pc_sample_pid) { + p = pfind(pc_sample_pid); + if (p) { + p->p_flag |= P_BTRACE; + } + } + else { + pc_trace_frameworks = TRUE; + } + + return 1; + +#else + return 0; +#endif +} + +int +disable_branch_tracing(void) +{ + struct proc *p; + switch (pc_sample_pid) { + case -1: + pc_trace_frameworks = FALSE; + break; + case 0: + break; + default: + p = pfind(pc_sample_pid); + if (p) { + p->p_flag &= ~P_BTRACE; + } + break; + } + clr_be_bit(); + return 1; +} + +/* + * this only works for the current proc as it + * is called from context_switch in the scheduler + */ +int +branch_tracing_enabled(void) +{ + struct proc *p = current_proc(); + if (TRUE == pc_trace_frameworks) return TRUE; + if (p) { + return (P_BTRACE == (p->p_flag & P_BTRACE)); + } + return 0; +} + + void -add_pcbuffer() +add_pcbuffer(void) { int i; - u_long pc; - struct proc *curproc; - extern unsigned int kdebug_flags; + unsigned int pc; if (!pcsample_enable) return; - if (pcsample_comm[0] != '\0') - { - /* If command string does not match, then return */ - curproc = current_proc(); - if (curproc && - (strncmp(curproc->p_comm, pcsample_comm, sizeof(pcsample_comm)))) - return; - } - for (i=0; i < pc_trace_cnt; i++) { pc = pc_trace_buf[i]; @@ -81,7 +144,7 @@ add_pcbuffer() } /* Then the sample is in our range */ - *pc_bufptr = (u_long)pc; + *pc_bufptr = pc; pc_bufptr++; } } @@ -90,23 +153,24 @@ add_pcbuffer() if ((pc_bufptr + pc_trace_cnt) >= pc_buflast) { pcsample_enable = 0; - (void)clr_be_bit(); + (void)disable_branch_tracing(); wakeup(&pcsample_enable); } return; } -pcsamples_bootstrap() +int +pcsamples_bootstrap(void) { - if (!clr_be_bit()) + if (!disable_branch_tracing()) return(ENOTSUP); pc_bufsize = npcbufs * sizeof(* pc_buffer); if (kmem_alloc(kernel_map, &pc_buftomem, (vm_size_t)pc_bufsize) == KERN_SUCCESS) - pc_buffer = (u_long *) pc_buftomem; + pc_buffer = (unsigned int *) pc_buftomem; else - pc_buffer= (u_long *) 0; + pc_buffer = NULL; if (pc_buffer) { pc_bufptr = pc_buffer; @@ -120,54 +184,56 @@ pcsamples_bootstrap() } -pcsamples_reinit() +int +pcsamples_reinit(void) { -int x; -int ret=0; + int ret=0; - pcsample_enable = 0; + pcsample_enable = 0; if (pc_bufsize && pc_buffer) - kmem_free(kernel_map,pc_buffer,pc_bufsize); + kmem_free(kernel_map, (vm_offset_t)pc_buffer, pc_bufsize); ret= pcsamples_bootstrap(); return(ret); } -pcsamples_clear() +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,pc_buffer,pc_bufsize); - pc_buffer = (u_long *)0; - pc_bufptr = (u_long *)0; - pc_buflast = (u_long *)0; + 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; bzero((void *)pcsample_comm, sizeof(pcsample_comm)); - (void)clr_be_bit(); + (void)disable_branch_tracing(); + pc_sample_pid = 0; + pc_trace_frameworks = FALSE; } -pcsamples_control(name, namelen, where, sizep) -int *name; -u_int namelen; -char *where; -size_t *sizep; +int +pcsamples_control(int *name, __unused u_int namelen, user_addr_t where, size_t *sizep) { -int ret=0; -int size=*sizep; -unsigned int value = name[1]; -pcinfo_t pc_bufinfo; - -pid_t curpid; -struct proc *p, *curproc; - - if (name[0] != PCSAMPLE_GETNUMBUF) - { - if(curproc = current_proc()) + 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); @@ -186,29 +252,29 @@ struct proc *p, *curproc; /* The global pid exists, deny this request */ return(EBUSY); } - } - } + } + } switch(name[0]) { - case PCSAMPLE_DISABLE: /* used to disable */ + 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; + case PCSAMPLE_SETNUMBUF: + /* The buffer size is bounded by a min and max number of samples */ + if (value < pc_trace_cnt) { + ret=EINVAL; break; } if (value <= MAX_PCSAMPLES) - /* npcbufs = value & ~(PC_TRACE_CNT-1); */ - npcbufs = value; + /* npcbufs = value & ~(PC_TRACE_CNT-1); */ + npcbufs = value; else - npcbufs = MAX_PCSAMPLES; + npcbufs = MAX_PCSAMPLES; break; - case PCSAMPLE_GETNUMBUF: - if(size < sizeof(pcinfo_t)) { - ret=EINVAL; + case PCSAMPLE_GETNUMBUF: + if (size < sizeof(pc_bufinfo)) { + ret=EINVAL; break; } pc_bufinfo.npcbufs = npcbufs; @@ -221,20 +287,20 @@ struct proc *p, *curproc; ret=EINVAL; } break; - case PCSAMPLE_SETUP: + case PCSAMPLE_SETUP: ret=pcsamples_reinit(); break; - case PCSAMPLE_REMOVE: + case PCSAMPLE_REMOVE: pcsamples_clear(); break; - case PCSAMPLE_READBUF: + 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)clr_be_bit(); + (void)disable_branch_tracing(); ret = pcsamples_read(where, sizep); break; } @@ -246,9 +312,9 @@ struct proc *p, *curproc; } /* Turn on branch tracing */ - if (!set_be_bit()) + if (!enable_branch_tracing()) { - ret = ENOTSUP;; + ret = ENOTSUP; break; } @@ -257,7 +323,7 @@ struct proc *p, *curproc; ret = tsleep(&pcsample_enable, PRIBIO | PCATCH, "pcsample", 0); pcsample_enable = 0; - (void)clr_be_bit(); + (void)disable_branch_tracing(); if (ret) { @@ -276,13 +342,13 @@ struct proc *p, *curproc; } break; - case PCSAMPLE_SETREG: - if (size < sizeof(pcinfo_t)) + case PCSAMPLE_SETREG: + if (size < sizeof(pc_bufinfo)) { ret = EINVAL; break; } - if (copyin(where, &pc_bufinfo, sizeof(pcinfo_t))) + if (copyin(where, &pc_bufinfo, sizeof(pc_bufinfo))) { ret = EINVAL; break; @@ -291,20 +357,41 @@ struct proc *p, *curproc; pcsample_beg = pc_bufinfo.pcsample_beg; pcsample_end = pc_bufinfo.pcsample_end; 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; - } + 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 + { + pidcheck = (pid_t *)pcsample_comm; + pc_sample_pid = pidcheck[1]; + } + } break; - default: - ret= EOPNOTSUPP; + default: + ret= ENOTSUP; break; } return(ret); @@ -318,13 +405,13 @@ struct proc *p, *curproc; to fill the buffer and throw the rest away. This buffer never wraps. */ -pcsamples_read(u_long *buffer, size_t *number) +int +pcsamples_read(user_addr_t buffer, size_t *number) { -int count=0; -int ret=0; -int copycount; + size_t count=0; + size_t copycount; - count = (*number)/sizeof(u_long); + count = (*number)/sizeof(* pc_buffer); if (count && pc_bufsize && pc_buffer) { @@ -340,7 +427,7 @@ int copycount; copycount = count; /* We actually have data to send up */ - if(copyout(pc_buffer, buffer, copycount * sizeof(u_long))) + if(copyout(pc_buffer, buffer, copycount * sizeof(* pc_buffer))) { *number = 0; return(EINVAL); @@ -356,6 +443,3 @@ int copycount; } } - - -