/* * Duplicate parent state in child * for U**X fork. */ kern_return_t machine_thread_dup( thread_t parent, thread_t child ) { pcb_t parent_pcb; pcb_t child_pcb; if ((child_pcb = child->machine.pcb) == NULL || (parent_pcb = parent->machine.pcb) == NULL) return (KERN_FAILURE); /* * Copy over the x86_saved_state registers */ if (cpu_mode_is64bit()) { if (thread_is_64bit(parent)) bcopy(USER_REGS64(parent), USER_REGS64(child), sizeof(x86_saved_state64_t)); else bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state_compat32_t)); } else bcopy(USER_REGS32(parent), USER_REGS32(child), sizeof(x86_saved_state32_t)); /* * Check to see if parent is using floating point * and if so, copy the registers to the child */ fpu_dup_fxstate(parent, child); #ifdef MACH_BSD /* * Copy the parent's cthread id and USER_CTHREAD descriptor, if 32-bit. */ child_pcb->cthread_self = parent_pcb->cthread_self; if (!thread_is_64bit(parent)) child_pcb->cthread_desc = parent_pcb->cthread_desc; /* * FIXME - should a user specified LDT, TSS and V86 info * be duplicated as well?? - probably not. */ // duplicate any use LDT entry that was set I think this is appropriate. if (parent_pcb->uldt_selector!= 0) { child_pcb->uldt_selector = parent_pcb->uldt_selector; child_pcb->uldt_desc = parent_pcb->uldt_desc; } #endif return (KERN_SUCCESS); }
kern_return_t thread_setsinglestep(thread_t thread, int on) { pal_register_cache_state(thread, DIRTY); if (thread_is_64bit(thread)) { x86_saved_state64_t *iss64; iss64 = USER_REGS64(thread); if (on) iss64->isf.rflags |= EFL_TF; else iss64->isf.rflags &= ~EFL_TF; } else { x86_saved_state32_t *iss32; iss32 = USER_REGS32(thread); if (on) { iss32->efl |= EFL_TF; /* Ensure IRET */ if (iss32->cs == SYSENTER_CS) iss32->cs = SYSENTER_TF_CS; } else iss32->efl &= ~EFL_TF; } return (KERN_SUCCESS); }
/* * thread_setentrypoint: * * Sets the user PC into the machine * dependent thread state info. */ void thread_setentrypoint(thread_t thread, mach_vm_address_t entry) { if (thread_is_64bit(thread)) { x86_saved_state64_t *iss64; iss64 = USER_REGS64(thread); iss64->isf.rip = (uint64_t)entry; } else { x86_saved_state32_t *iss32; iss32 = USER_REGS32(thread); iss32->eip = CAST_DOWN_EXPLICIT(unsigned int, entry); } }
/* * thread_setuserstack: * * Sets the user stack pointer into the machine * dependent thread state info. */ void thread_setuserstack( thread_t thread, mach_vm_address_t user_stack) { if (thread_is_64bit(thread)) { x86_saved_state64_t *iss64; iss64 = USER_REGS64(thread); iss64->isf.rsp = (uint64_t)user_stack; } else { x86_saved_state32_t *iss32; iss32 = USER_REGS32(thread); iss32->uesp = CAST_DOWN_EXPLICIT(unsigned int, user_stack); } }
void thread_set_parent(thread_t parent, int pid) { if (thread_is_64bit(parent)) { x86_saved_state64_t *iss64; iss64 = USER_REGS64(parent); iss64->rax = pid; iss64->rdx = 0; iss64->isf.rflags &= ~EFL_CF; } else { x86_saved_state32_t *iss32; iss32 = USER_REGS32(parent); iss32->eax = pid; iss32->edx = 0; iss32->efl &= ~EFL_CF; } }
void thread_set_child(thread_t child, int pid) { if (thread_is_64bit(child)) { x86_saved_state64_t *iss64; iss64 = USER_REGS64(child); iss64->rax = pid; iss64->rdx = 1; iss64->isf.rflags &= ~EFL_CF; } else { x86_saved_state32_t *iss32; iss32 = USER_REGS32(child); iss32->eax = pid; iss32->edx = 1; iss32->efl &= ~EFL_CF; } }
/* * thread_adjuserstack: * * Returns the adjusted user stack pointer from the machine * dependent thread state info. Used for small (<2G) deltas. */ uint64_t thread_adjuserstack( thread_t thread, int adjust) { if (thread_is_64bit(thread)) { x86_saved_state64_t *iss64; iss64 = USER_REGS64(thread); iss64->isf.rsp += adjust; return iss64->isf.rsp; } else { x86_saved_state32_t *iss32; iss32 = USER_REGS32(thread); iss32->uesp += adjust; return CAST_USER_ADDR_T(iss32->uesp); } }
int machine_trace_thread(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p) { uint32_t *tracebuf = (uint32_t *)tracepos; uint32_t fence = 0; uint32_t stackptr = 0; uint32_t stacklimit = 0xfc000000; int framecount = 0; uint32_t init_eip = 0; uint32_t prevsp = 0; uint32_t framesize = 2 * sizeof(vm_offset_t); if (user_p) { x86_saved_state32_t *iss32; iss32 = USER_REGS32(thread); init_eip = iss32->eip; stackptr = iss32->ebp; stacklimit = 0xffffffff; kdp_pmap = thread->task->map->pmap; } else panic("32-bit trace attempted on 64-bit kernel"); *tracebuf++ = init_eip; for (framecount = 0; framecount < nframes; framecount++) { if ((tracebound - ((char *)tracebuf)) < (4 * framesize)) { tracebuf--; break; } *tracebuf++ = stackptr; /* Invalid frame, or hit fence */ if (!stackptr || (stackptr == fence)) { break; } /* Unaligned frame */ if (stackptr & 0x0000003) { break; } if (stackptr <= prevsp) { break; } if (stackptr > stacklimit) { break; } if (kdp_machine_vm_read((mach_vm_address_t)(stackptr + RETURN_OFFSET), (caddr_t) tracebuf, sizeof(*tracebuf)) != sizeof(*tracebuf)) { break; } tracebuf++; prevsp = stackptr; if (kdp_machine_vm_read((mach_vm_address_t)stackptr, (caddr_t) &stackptr, sizeof(stackptr)) != sizeof(stackptr)) { *tracebuf++ = 0; break; } } kdp_pmap = 0; return (uint32_t) (((char *) tracebuf) - tracepos); }
int machine_trace_thread(thread_t thread, char * tracepos, char * tracebound, int nframes, boolean_t user_p, boolean_t trace_fp, uint32_t * thread_trace_flags) { uint32_t * tracebuf = (uint32_t *)tracepos; uint32_t framesize = (trace_fp ? 2 : 1) * sizeof(uint32_t); uint32_t fence = 0; uint32_t stackptr = 0; uint32_t stacklimit = 0xfc000000; int framecount = 0; uint32_t prev_eip = 0; uint32_t prevsp = 0; vm_offset_t kern_virt_addr = 0; vm_map_t bt_vm_map = VM_MAP_NULL; nframes = (tracebound > tracepos) ? MIN(nframes, (int)((tracebound - tracepos) / framesize)) : 0; if (thread->machine.iss == NULL) { // no register states to backtrace, probably thread is terminating return 0; } if (user_p) { x86_saved_state32_t *iss32; iss32 = USER_REGS32(thread); prev_eip = iss32->eip; stackptr = iss32->ebp; stacklimit = 0xffffffff; bt_vm_map = thread->task->map; } else panic("32-bit trace attempted on 64-bit kernel"); for (framecount = 0; framecount < nframes; framecount++) { *tracebuf++ = prev_eip; if (trace_fp) { *tracebuf++ = stackptr; } /* Invalid frame, or hit fence */ if (!stackptr || (stackptr == fence)) { break; } /* Unaligned frame */ if (stackptr & 0x0000003) { break; } if (stackptr <= prevsp) { break; } if (stackptr > stacklimit) { break; } kern_virt_addr = machine_trace_thread_get_kva(stackptr + RETURN_OFFSET, bt_vm_map, thread_trace_flags); if (!kern_virt_addr) { if (thread_trace_flags) { *thread_trace_flags |= kThreadTruncatedBT; } break; } prev_eip = *(uint32_t *)kern_virt_addr; prevsp = stackptr; kern_virt_addr = machine_trace_thread_get_kva(stackptr, bt_vm_map, thread_trace_flags); if (kern_virt_addr) { stackptr = *(uint32_t *)kern_virt_addr; } else { stackptr = 0; if (thread_trace_flags) { *thread_trace_flags |= kThreadTruncatedBT; } } } machine_trace_thread_clear_validation_cache(); return (uint32_t) (((char *) tracebuf) - tracepos); }
int machine_trace_thread(thread_t thread, char *tracepos, char *tracebound, int nframes, boolean_t user_p) { uint32_t *tracebuf = (uint32_t *)tracepos; uint32_t fence = 0; uint32_t stackptr = 0; uint32_t stacklimit = 0xfc000000; int framecount = 0; uint32_t init_eip = 0; uint32_t prevsp = 0; uint32_t framesize = 2 * sizeof(vm_offset_t); if (user_p) { x86_saved_state32_t *iss32; iss32 = USER_REGS32(thread); init_eip = iss32->eip; stackptr = iss32->ebp; /* This bound isn't useful, but it doesn't hinder us*/ stacklimit = 0xffffffff; kdp_pmap = thread->task->map->pmap; } else { /*Examine the i386_saved_state at the base of the kernel stack*/ stackptr = STACK_IKS(thread->kernel_stack)->k_ebp; init_eip = STACK_IKS(thread->kernel_stack)->k_eip; } *tracebuf++ = init_eip; for (framecount = 0; framecount < nframes; framecount++) { if ((uint32_t)(tracebound - ((char *)tracebuf)) < (4 * framesize)) { tracebuf--; break; } *tracebuf++ = stackptr; /* Invalid frame, or hit fence */ if (!stackptr || (stackptr == fence)) { break; } /* Unaligned frame */ if (stackptr & 0x0000003) { break; } if (stackptr > stacklimit) { break; } if (stackptr <= prevsp) { break; } if (kdp_machine_vm_read((mach_vm_address_t)(stackptr + RETURN_OFFSET), (caddr_t) tracebuf, sizeof(caddr_t)) != sizeof(caddr_t)) { break; } tracebuf++; prevsp = stackptr; if (kdp_machine_vm_read((mach_vm_address_t)stackptr, (caddr_t) &stackptr, sizeof(caddr_t)) != sizeof(caddr_t)) { *tracebuf++ = 0; break; } } kdp_pmap = 0; return (uint32_t) (((char *) tracebuf) - tracepos); }