+extern void * find_user_regs(thread_t);
+extern x86_saved_state32_t *find_kern_regs(thread_t);
+
+static kern_return_t do_backtrace32(
+ task_t task,
+ thread_t thread,
+ x86_saved_state32_t *regs,
+ uint64_t *frames,
+ mach_msg_type_number_t *start_idx,
+ mach_msg_type_number_t max_idx,
+ boolean_t supervisor)
+{
+ uint32_t tmpWord = 0UL;
+ uint64_t currPC = (uint64_t) regs->eip;
+ uint64_t currFP = (uint64_t) regs->ebp;
+ uint64_t prevPC = 0ULL;
+ uint64_t prevFP = 0ULL;
+ uint64_t kernStackMin = thread->kernel_stack;
+ uint64_t kernStackMax = kernStackMin + KERNEL_STACK_SIZE;
+ mach_msg_type_number_t ct = *start_idx;
+ kern_return_t kr = KERN_FAILURE;
+
+ if(ct >= max_idx)
+ return KERN_RESOURCE_SHORTAGE; // no frames traced
+
+ frames[ct++] = currPC;
+
+ // build a backtrace of this 32 bit state.
+ while(VALID_STACK_ADDRESS(supervisor, currFP, kernStackMin, kernStackMax)) {
+ cframe_t *fp = (cframe_t *) (uint32_t) currFP;
+
+ if(!currFP) {
+ currPC = 0;
+ break;
+ }
+
+ if(ct >= max_idx) {
+ *start_idx = ct;
+ return KERN_RESOURCE_SHORTAGE;
+ }
+
+ /* read our caller */
+ if(supervisor) {
+ kr = chudxnu_kern_read(&tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t));
+ } else {
+ kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t) &fp->caller, sizeof(uint32_t));
+ }
+
+ if(kr != KERN_SUCCESS) {
+ currPC = 0ULL;
+ break;
+ }
+
+ currPC = (uint64_t) tmpWord; // promote 32 bit address
+
+ /*
+ * retrive contents of the frame pointer and advance to the next stack
+ * frame if it's valid
+ */
+ prevFP = 0;
+ if(supervisor) {
+ kr = chudxnu_kern_read(&tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t));
+ } else {
+ kr = chudxnu_task_read(task, &tmpWord, (vm_offset_t)&fp->prev, sizeof(uint32_t));
+ }
+ prevFP = (uint64_t) tmpWord; // promote 32 bit address
+
+ if(prevFP) {
+ frames[ct++] = currPC;
+ prevPC = currPC;
+ }
+ if(prevFP < currFP) {
+ break;
+ } else {
+ currFP = prevFP;
+ }
+ }
+
+ *start_idx = ct;
+ return KERN_SUCCESS;
+}
+
+static kern_return_t do_backtrace64(
+ task_t task,
+ thread_t thread,
+ x86_saved_state64_t *regs,
+ uint64_t *frames,
+ mach_msg_type_number_t *start_idx,
+ mach_msg_type_number_t max_idx,
+ boolean_t supervisor)
+{
+ uint64_t currPC = regs->isf.rip;
+ uint64_t currFP = regs->rbp;
+ uint64_t prevPC = 0ULL;
+ uint64_t prevFP = 0ULL;
+ uint64_t kernStackMin = (uint64_t)thread->kernel_stack;
+ uint64_t kernStackMax = (uint64_t)kernStackMin + KERNEL_STACK_SIZE;
+ mach_msg_type_number_t ct = *start_idx;
+ kern_return_t kr = KERN_FAILURE;
+
+ if(*start_idx >= max_idx)
+ return KERN_RESOURCE_SHORTAGE; // no frames traced
+
+ frames[ct++] = currPC;
+
+ // build a backtrace of this 32 bit state.
+ while(VALID_STACK_ADDRESS64(supervisor, currFP, kernStackMin, kernStackMax)) {
+ // this is the address where caller lives in the user thread
+ uint64_t caller = currFP + sizeof(uint64_t);
+
+ if(!currFP) {
+ currPC = 0;
+ break;
+ }
+
+ if(ct >= max_idx) {
+ *start_idx = ct;
+ return KERN_RESOURCE_SHORTAGE;
+ }
+
+ /* read our caller */
+ if(supervisor) {
+ kr = KERN_FAILURE;
+ } else {
+ kr = chudxnu_task_read(task, &currPC, caller, sizeof(uint64_t));
+ }
+
+ if(kr != KERN_SUCCESS) {
+ currPC = 0ULL;
+ break;
+ }
+
+ /*
+ * retrive contents of the frame pointer and advance to the next stack
+ * frame if it's valid
+ */
+ prevFP = 0;
+ if(supervisor) {
+ kr = KERN_FAILURE;
+ } else {
+ kr = chudxnu_task_read(task, &prevFP, currFP, sizeof(uint64_t));
+ }
+
+ if(VALID_STACK_ADDRESS64(supervisor, prevFP, kernStackMin, kernStackMax)) {
+ frames[ct++] = currPC;
+ prevPC = currPC;
+ }
+ if(prevFP < currFP) {
+ break;
+ } else {
+ currFP = prevFP;
+ }
+ }
+
+ *start_idx = ct;
+ return KERN_SUCCESS;
+}
+