X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..cf03f5cdc65293b4cb5eba3ed23fed26dad903c9:/bsd/kern/kdebug.c diff --git a/bsd/kern/kdebug.c b/bsd/kern/kdebug.c index 89fff7000..1e09d8bce 100644 --- a/bsd/kern/kdebug.c +++ b/bsd/kern/kdebug.c @@ -3,19 +3,22 @@ * * @APPLE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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. 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 OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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_HEADER_END@ */ @@ -39,6 +42,16 @@ #include #include +/* trace enable status */ +unsigned int kdebug_enable = 0; + +/* track timestamps for security server's entropy needs */ +mach_timespec_t * kd_entropy_buffer = 0; +unsigned int kd_entropy_bufsize = 0; +unsigned int kd_entropy_count = 0; +unsigned int kd_entropy_indx = 0; +unsigned int kd_entropy_buftomem = 0; + /* kd_buf kd_buffer[kd_bufsize/sizeof(kd_buf)]; */ kd_buf * kd_bufptr; unsigned int kd_buftomem=0; @@ -48,7 +61,6 @@ kd_buf * kd_readlast; unsigned int nkdbufs = 8192; unsigned int kd_bufsize = 0; unsigned int kdebug_flags = 0; -unsigned int kdebug_enable=0; unsigned int kdebug_nolog=1; unsigned int kdlog_beg=0; unsigned int kdlog_end=0; @@ -82,16 +94,32 @@ struct kdebug_args { int arg5; }; +/* task to string structure */ +struct tts +{ + task_t *task; + char task_comm[20]; /* from procs p_comm */ +}; + +typedef struct tts tts_t; + struct krt { kd_threadmap *map; /* pointer to the map buffer */ int count; int maxcount; - struct proc *p; + struct tts *atts; }; typedef struct krt krt_t; +/* This is for the CHUD toolkit call */ +typedef void (*kd_chudhook_fn) (unsigned int debugid, unsigned int arg1, + unsigned int arg2, unsigned int arg3, + unsigned int arg4, unsigned int arg5); + +kd_chudhook_fn kdebug_chudhook = 0; /* pointer to CHUD toolkit function */ + /* Support syscall SYS_kdebug_trace */ kdebug_trace(p, uap, retval) struct proc *p; @@ -116,15 +144,39 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; unsigned long long now; mach_timespec_t *tsp; + if (kdebug_enable & KDEBUG_ENABLE_CHUD) { + if (kdebug_chudhook) + kdebug_chudhook(debugid, arg1, arg2, arg3, arg4, arg5); + + if (!((kdebug_enable & KDEBUG_ENABLE_ENTROPY) || + (kdebug_enable & KDEBUG_ENABLE_TRACE))) + return; + } + s = ml_set_interrupts_enabled(FALSE); + if (kdebug_enable & KDEBUG_ENABLE_ENTROPY) + { + if (kd_entropy_indx < kd_entropy_count) + { + ml_get_timebase((unsigned long long *) &kd_entropy_buffer [ kd_entropy_indx]); + kd_entropy_indx++; + } + + if (kd_entropy_indx == kd_entropy_count) + { + /* Disable entropy collection */ + kdebug_enable &= ~KDEBUG_ENABLE_ENTROPY; + } + } + if (kdebug_nolog) { ml_set_interrupts_enabled(s); return; } - simple_lock(&kd_trace_lock); + usimple_lock(&kd_trace_lock); if (kdebug_flags & KDBG_PIDCHECK) { /* If kdebug flag is not set for current proc, return */ @@ -132,7 +184,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; if ((curproc && !(curproc->p_flag & P_KDEBUG)) && ((debugid&0xffff0000) != (MACHDBG_CODE(DBG_MACH_SCHED, 0) | DBG_FUNC_NONE))) { - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); return; } @@ -144,7 +196,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; if ((curproc && (curproc->p_flag & P_KDEBUG)) && ((debugid&0xffff0000) != (MACHDBG_CODE(DBG_MACH_SCHED, 0) | DBG_FUNC_NONE))) { - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); return; } @@ -155,7 +207,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; if ((debugid < kdlog_beg) || (debugid > kdlog_end) && (debugid >> 24 != DBG_TRACE)) { - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); return; } @@ -168,7 +220,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; (debugid & DBG_FUNC_MASK) != kdlog_value4 && (debugid >> 24 != DBG_TRACE)) { - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); return; } @@ -213,7 +265,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; kdebug_nolog = 1; kdebug_flags |= KDBG_WRAPPED; } - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); } @@ -227,6 +279,15 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; unsigned long long now; mach_timespec_t *tsp; + if (kdebug_enable & KDEBUG_ENABLE_CHUD) { + if (kdebug_chudhook) + (void)kdebug_chudhook(debugid, arg1, arg2, arg3, arg4, arg5); + + if (!((kdebug_enable & KDEBUG_ENABLE_ENTROPY) || + (kdebug_enable & KDEBUG_ENABLE_TRACE))) + return; + } + s = ml_set_interrupts_enabled(FALSE); if (kdebug_nolog) @@ -235,7 +296,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; return; } - simple_lock(&kd_trace_lock); + usimple_lock(&kd_trace_lock); if (kdebug_flags & KDBG_PIDCHECK) { /* If kdebug flag is not set for current proc, return */ @@ -243,7 +304,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; if ((curproc && !(curproc->p_flag & P_KDEBUG)) && ((debugid&0xffff0000) != (MACHDBG_CODE(DBG_MACH_SCHED, 0) | DBG_FUNC_NONE))) { - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); return; } @@ -255,7 +316,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; if ((curproc && (curproc->p_flag & P_KDEBUG)) && ((debugid&0xffff0000) != (MACHDBG_CODE(DBG_MACH_SCHED, 0) | DBG_FUNC_NONE))) { - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); return; } @@ -266,7 +327,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; if ((debugid < kdlog_beg) || (debugid > kdlog_end) && (debugid >> 24 != DBG_TRACE)) { - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); return; } @@ -279,7 +340,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; (debugid & DBG_FUNC_MASK) != kdlog_value4 && (debugid >> 24 != DBG_TRACE)) { - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); return; } @@ -321,7 +382,7 @@ unsigned int debugid, arg1, arg2, arg3, arg4, arg5; kdebug_nolog = 1; kdebug_flags |= KDBG_WRAPPED; } - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); } @@ -355,7 +416,8 @@ kdbg_reinit() int x; int ret=0; - kdebug_enable = 0; + /* Disable trace collecting */ + kdebug_enable &= ~KDEBUG_ENABLE_TRACE; kdebug_nolog = 1; if ((kdebug_flags & KDBG_INIT) && (kdebug_flags & KDBG_BUFINIT) && kd_bufsize && kd_buffer) @@ -424,9 +486,9 @@ kdbg_resolve_map(thread_act_t th_act, krt_t *t) mapptr=&t->map[t->count]; mapptr->thread = (unsigned int)getshuttle_thread(th_act); mapptr->valid = 1; - (void) strncpy (mapptr->command, t->p->p_comm, - sizeof(t->p->p_comm)-1); - mapptr->command[sizeof(t->p->p_comm)-1] = '\0'; + (void) strncpy (mapptr->command, t->atts->task_comm, + sizeof(t->atts->task_comm)-1); + mapptr->command[sizeof(t->atts->task_comm)-1] = '\0'; t->count++; } } @@ -435,17 +497,33 @@ void kdbg_mapinit() { struct proc *p; struct krt akrt; + int tts_count; /* number of task-to-string structures */ + struct tts *tts_mapptr; + unsigned int tts_mapsize = 0; + unsigned int tts_maptomem=0; + int i; + if (kdebug_flags & KDBG_MAPINIT) return; - /* Calculate size of thread map buffer */ - for (p = allproc.lh_first, kd_mapcount=0; p; + /* Calculate the sizes of map buffers*/ + for (p = allproc.lh_first, kd_mapcount=0, tts_count=0; p; p = p->p_list.le_next) { kd_mapcount += get_task_numacts((task_t)p->task); + tts_count++; } + /* + * The proc count could change during buffer allocation, + * so introduce a small fudge factor to bump up the + * buffer sizes. This gives new tasks some chance of + * making into the tables. Bump up by 10%. + */ + kd_mapcount += kd_mapcount/10; + tts_count += tts_count/10; + kd_mapsize = kd_mapcount * sizeof(kd_threadmap); if((kmem_alloc(kernel_map, & kd_maptomem, (vm_size_t)kd_mapsize) == KERN_SUCCESS)) @@ -453,7 +531,37 @@ void kdbg_mapinit() else kd_mapptr = (kd_threadmap *) 0; - if (kd_mapptr) + tts_mapsize = tts_count * sizeof(struct tts); + if((kmem_alloc(kernel_map, & tts_maptomem, + (vm_size_t)tts_mapsize) == KERN_SUCCESS)) + tts_mapptr = (struct tts *) tts_maptomem; + else + tts_mapptr = (struct tts *) 0; + + + /* + * We need to save the procs command string + * and take a reference for each task associated + * with a valid process + */ + + if (tts_mapptr) { + for (p = allproc.lh_first, i=0; p && i < tts_count; + p = p->p_list.le_next) { + if (p->p_flag & P_WEXIT) + continue; + + if (task_reference_try(p->task)) { + tts_mapptr[i].task = p->task; + (void)strncpy(&tts_mapptr[i].task_comm, p->p_comm, sizeof(tts_mapptr[i].task_comm) - 1); + i++; + } + } + tts_count = i; + } + + + if (kd_mapptr && tts_mapptr) { kdebug_flags |= KDBG_MAPINIT; /* Initialize thread map data */ @@ -461,11 +569,13 @@ void kdbg_mapinit() akrt.count = 0; akrt.maxcount = kd_mapcount; - for (p = allproc.lh_first; p; p = p->p_list.le_next) + for (i=0; i < tts_count; i++) { - akrt.p = p; - task_act_iterate_wth_args((task_t)p->task, kdbg_resolve_map, &akrt); - } + akrt.atts = &tts_mapptr[i]; + task_act_iterate_wth_args(tts_mapptr[i].task, kdbg_resolve_map, &akrt); + task_deallocate(tts_mapptr[i].task); + } + kmem_free(kernel_map, (char *)tts_mapptr, tts_mapsize); } } @@ -475,7 +585,7 @@ int x; /* Clean up the trace buffer */ global_state_pid = -1; - kdebug_enable = 0; + kdebug_enable &= ~KDEBUG_ENABLE_TRACE; kdebug_nolog = 1; kdebug_flags &= ~KDBG_BUFINIT; kdebug_flags &= (unsigned int)~KDBG_CKTYPES; @@ -719,7 +829,92 @@ kdbg_readmap(kd_threadmap *buffer, size_t *number) return(ret); } +kdbg_getentropy (mach_timespec_t * buffer, size_t *number, int ms_timeout) +{ + int avail = *number; + int ret = 0; + int count = 0; /* The number of timestamp entries that will fill buffer */ + + if (kd_entropy_buffer) + return(EBUSY); + kd_entropy_count = avail/sizeof(mach_timespec_t); + kd_entropy_bufsize = kd_entropy_count * sizeof(mach_timespec_t); + kd_entropy_indx = 0; + + /* Enforce maximum entropy entries here if needed */ + + /* allocate entropy buffer */ + if (kmem_alloc(kernel_map, &kd_entropy_buftomem, + (vm_size_t)kd_entropy_bufsize) == KERN_SUCCESS) + { + kd_entropy_buffer = (mach_timespec_t *)kd_entropy_buftomem; + } + else + { + kd_entropy_buffer = (mach_timespec_t *) 0; + kd_entropy_count = 0; + kd_entropy_indx = 0; + return (EINVAL); + } + + if (ms_timeout < 10) + ms_timeout = 10; + + /* Enable entropy sampling */ + kdebug_enable |= KDEBUG_ENABLE_ENTROPY; + + ret = tsleep (kdbg_getentropy, PRIBIO | PCATCH, "kd_entropy", (ms_timeout/(1000/HZ))); + + /* Disable entropy sampling */ + kdebug_enable &= ~KDEBUG_ENABLE_ENTROPY; + + *number = 0; + ret = 0; + + if (kd_entropy_indx > 0) + { + /* copyout the buffer */ + if (copyout(kd_entropy_buffer, buffer, kd_entropy_indx * sizeof(mach_timespec_t))) + ret = EINVAL; + else + *number = kd_entropy_indx; + } + + /* Always cleanup */ + kd_entropy_count = 0; + kd_entropy_indx = 0; + kd_entropy_buftomem = 0; + kmem_free(kernel_map, (char *)kd_entropy_buffer, kd_entropy_bufsize); + kd_entropy_buffer = (mach_timespec_t *) 0; + return(ret); +} + + +/* + * This function is provided for the CHUD toolkit only. + * int val: + * zero disables kdebug_chudhook function call + * non-zero enables kdebug_chudhook function call + * char *fn: + * address of the enabled kdebug_chudhook function +*/ + +void kdbg_control_chud(int val, void *fn) +{ + if (val) { + /* enable chudhook */ + kdebug_enable |= KDEBUG_ENABLE_CHUD; + kdebug_chudhook = fn; + } + else { + /* disable chudhook */ + kdebug_enable &= ~KDEBUG_ENABLE_CHUD; + kdebug_chudhook = 0; + } +} + + kdbg_control(name, namelen, where, sizep) int *name; u_int namelen; @@ -736,6 +931,48 @@ kbufinfo_t kd_bufinfo; pid_t curpid; struct proc *p, *curproc; + if (name[0] == KERN_KDGETBUF) { + /* + Does not alter the global_state_pid + This is a passive request. + */ + if (size < sizeof(kd_bufinfo.nkdbufs)) { + /* + There is not enough room to return even + the first element of the info structure. + */ + return(EINVAL); + } + + kd_bufinfo.nkdbufs = nkdbufs; + kd_bufinfo.nkdthreads = kd_mapsize / sizeof(kd_threadmap); + kd_bufinfo.nolog = kdebug_nolog; + kd_bufinfo.flags = kdebug_flags; + kd_bufinfo.bufid = global_state_pid; + + if(size >= sizeof(kbufinfo_t)) { + /* Provide all the info we have */ + if(copyout (&kd_bufinfo, where, sizeof(kbufinfo_t))) + return(EINVAL); + } + else { + /* + For backwards compatibility, only provide + as much info as there is room for. + */ + if(copyout (&kd_bufinfo, where, size)) + return(EINVAL); + } + return(0); + } + else if (name[0] == KERN_KDGETENTROPY) { + if (kd_entropy_buffer) + return(EBUSY); + else + ret = kdbg_getentropy((mach_timespec_t *)where, sizep, value); + return (ret); + } + if(curproc = current_proc()) curpid = curproc->p_pid; else @@ -776,33 +1013,26 @@ struct proc *p, *curproc; break; } } - kdebug_enable=(value)?1:0; + + if (value) + kdebug_enable |= KDEBUG_ENABLE_TRACE; + else + kdebug_enable &= ~KDEBUG_ENABLE_TRACE; + kdebug_nolog = (value)?0:1; - if (kdebug_enable) + + if (kdebug_enable & KDEBUG_ENABLE_TRACE) kdbg_mapinit(); break; case KERN_KDSETBUF: - /* We allow a maximum buffer size of 25% of memory */ + /* We allow a maximum buffer size of 25% of either ram or max mapped address, whichever is smaller */ /* 'value' is the desired number of trace entries */ - max_entries = (mem_size/4) / sizeof(kd_buf); + max_entries = (sane_size/4) / sizeof(kd_buf); if (value <= max_entries) nkdbufs = value; else nkdbufs = max_entries; break; - case KERN_KDGETBUF: - if(size < sizeof(kbufinfo_t)) { - ret=EINVAL; - break; - } - kd_bufinfo.nkdbufs = nkdbufs; - kd_bufinfo.nkdthreads = kd_mapsize / sizeof(kd_threadmap); - kd_bufinfo.nolog = kdebug_nolog; - kd_bufinfo.flags = kdebug_flags; - if(copyout (&kd_bufinfo, where, sizeof(kbufinfo_t))) { - ret=EINVAL; - } - break; case KERN_KDSETUP: ret=kdbg_reinit(); break; @@ -887,10 +1117,10 @@ unsigned int my_kdebug_flags; kd_buf * my_kd_bufptr; s = ml_set_interrupts_enabled(FALSE); - simple_lock(&kd_trace_lock); + usimple_lock(&kd_trace_lock); my_kdebug_flags = kdebug_flags; my_kd_bufptr = kd_bufptr; - simple_unlock(&kd_trace_lock); + usimple_unlock(&kd_trace_lock); ml_set_interrupts_enabled(s); count = avail/sizeof(kd_buf); @@ -974,3 +1204,10 @@ kd_buf * my_kd_bufptr; } /* end if count */ return (EINVAL); } + +unsigned char *getProcName(struct proc *proc); +unsigned char *getProcName(struct proc *proc) { + + return &proc->p_comm; /* Return pointer to the proc name */ + +}