/*++ Function: SetThreadContextOnPort Helper for CONTEXT_SetThreadContext --*/ kern_return_t CONTEXT_SetThreadContextOnPort( mach_port_t Port, IN CONST CONTEXT *lpContext) { kern_return_t MachRet = KERN_SUCCESS; mach_msg_type_number_t StateCount; thread_state_flavor_t StateFlavor; if (lpContext->ContextFlags & (CONTEXT_CONTROL|CONTEXT_INTEGER)) { #ifdef _X86_ x86_thread_state32_t State; StateFlavor = x86_THREAD_STATE32; State.eax = lpContext->Eax; State.ebx = lpContext->Ebx; State.ecx = lpContext->Ecx; State.edx = lpContext->Edx; State.edi = lpContext->Edi; State.esi = lpContext->Esi; State.ebp = lpContext->Ebp; State.esp = lpContext->Esp; State.ss = lpContext->SegSs; State.eflags = lpContext->EFlags; State.eip = lpContext->Eip; State.cs = lpContext->SegCs; State.ds = lpContext->SegDs_PAL_Undefined; State.es = lpContext->SegEs_PAL_Undefined; State.fs = lpContext->SegFs_PAL_Undefined; State.gs = lpContext->SegGs_PAL_Undefined; #elif defined(_AMD64_) x86_thread_state64_t State; StateFlavor = x86_THREAD_STATE64; State.__rax = lpContext->Rax; State.__rbx = lpContext->Rbx; State.__rcx = lpContext->Rcx; State.__rdx = lpContext->Rdx; State.__rdi = lpContext->Rdi; State.__rsi = lpContext->Rsi; State.__rbp = lpContext->Rbp; State.__rsp = lpContext->Rsp; State.__r8 = lpContext->R8; State.__r9 = lpContext->R9; State.__r10 = lpContext->R10; State.__r11 = lpContext->R11; State.__r12 = lpContext->R12; State.__r13 = lpContext->R13; State.__r14 = lpContext->R14; State.__r15 = lpContext->R15; // State.ss = lpContext->SegSs; State.__rflags = lpContext->EFlags; State.__rip = lpContext->Rip; State.__cs = lpContext->SegCs; // State.ds = lpContext->SegDs_PAL_Undefined; // State.es = lpContext->SegEs_PAL_Undefined; State.__fs = lpContext->SegFs; State.__gs = lpContext->SegGs; #else #error Unexpected architecture. #endif StateCount = sizeof(State) / sizeof(natural_t); MachRet = thread_set_state(Port, StateFlavor, (thread_state_t)&State, StateCount); if (MachRet != KERN_SUCCESS) { ASSERT("thread_set_state(THREAD_STATE) failed: %d\n", MachRet); goto EXIT; } } if (lpContext->ContextFlags & CONTEXT_ALL_FLOATING) { #ifdef _X86_ x86_float_state32_t State; StateFlavor = x86_FLOAT_STATE32; #elif defined(_AMD64_) x86_float_state64_t State; StateFlavor = x86_FLOAT_STATE64; #else #error Unexpected architecture. #endif StateCount = sizeof(State) / sizeof(natural_t); // If we're setting only one of the floating point or extended registers (of which Mach supports only // the xmm values) then we don't have values for the other set. This is a problem since Mach only // supports setting both groups as a single unit. So in this case we'll need to fetch the current // values first. if ((lpContext->ContextFlags & CONTEXT_ALL_FLOATING) != CONTEXT_ALL_FLOATING) { mach_msg_type_number_t StateCountGet = StateCount; MachRet = thread_get_state(Port, StateFlavor, (thread_state_t)&State, &StateCountGet); if (MachRet != KERN_SUCCESS) { ASSERT("thread_get_state(FLOAT_STATE) failed: %d\n", MachRet); goto EXIT; } _ASSERTE(StateCountGet == StateCount); } if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT) { #ifdef _X86_ *(DWORD*)&State.fpu_fcw = lpContext->FloatSave.ControlWord; *(DWORD*)&State.fpu_fsw = lpContext->FloatSave.StatusWord; State.fpu_ftw = lpContext->FloatSave.TagWord; State.fpu_ip = lpContext->FloatSave.ErrorOffset; State.fpu_cs = lpContext->FloatSave.ErrorSelector; State.fpu_dp = lpContext->FloatSave.DataOffset; State.fpu_ds = lpContext->FloatSave.DataSelector; State.fpu_mxcsr = lpContext->FloatSave.Cr0NpxState; // Windows stores the floating point registers in a packed layout (each 10-byte register end to // end for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably // for alignment purposes). So we can't just memcpy the registers over in a single block, we need // to copy them individually. for (int i = 0; i < 8; i++) memcpy((&State.fpu_stmm0)[i].mmst_reg, &lpContext->FloatSave.RegisterArea[i * 10], 10); #elif defined(_AMD64_) *(DWORD*)&State.__fpu_fcw = lpContext->FltSave.ControlWord; *(DWORD*)&State.__fpu_fsw = lpContext->FltSave.StatusWord; State.__fpu_ftw = lpContext->FltSave.TagWord; State.__fpu_ip = lpContext->FltSave.ErrorOffset; State.__fpu_cs = lpContext->FltSave.ErrorSelector; State.__fpu_dp = lpContext->FltSave.DataOffset; State.__fpu_ds = lpContext->FltSave.DataSelector; State.__fpu_mxcsr = lpContext->FltSave.MxCsr; State.__fpu_mxcsrmask = lpContext->FltSave.MxCsr_Mask; // note: we don't save the mask for x86 // Windows stores the floating point registers in a packed layout (each 10-byte register end to // end for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably // for alignment purposes). So we can't just memcpy the registers over in a single block, we need // to copy them individually. for (int i = 0; i < 8; i++) memcpy((&State.__fpu_stmm0)[i].__mmst_reg, &lpContext->FltSave.FloatRegisters[i], 10); memcpy(&State.__fpu_xmm0, &lpContext->Xmm0, 8 * 16); #else #error Unexpected architecture. #endif } #ifdef _X86_ if (lpContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS) { // The only extended register information that Mach will tell us about are the xmm register // values. Both Windows and Mach store the registers in a packed layout (each of the 8 registers // is 16 bytes) so we can simply memcpy them across. memcpy(&State.fpu_xmm0, lpContext->ExtendedRegisters + CONTEXT_EXREG_XMM_OFFSET, 8 * 16); } #endif // _X86_ MachRet = thread_set_state(Port, StateFlavor, (thread_state_t)&State, StateCount); if (MachRet != KERN_SUCCESS) { ASSERT("thread_set_state(FLOAT_STATE) failed: %d\n", MachRet); goto EXIT; } } EXIT: return MachRet; }
// Read/write from fake register segment. static int machregrw(Map *map, Seg *seg, uvlong addr, void *v, uint n, int isr) { uint nn, count, state; mach_port_t thread; int reg; char buf[100]; union { x86_thread_state64_t reg64; x86_thread_state32_t reg32; uchar p[1]; } u; uchar *p; if(n > 8){ werrstr("asked for %d-byte register", n); return -1; } thread = idtothread(map->pid); if(thread == -1){ werrstr("no such id"); return -1; } if(mach == &mi386) { count = x86_THREAD_STATE32_COUNT; state = x86_THREAD_STATE32; if((reg = go2darwin32(addr)) < 0 || reg+n > sizeof u){ if(isr){ memset(v, 0, n); return 0; } werrstr("register %llud not available", addr); return -1; } } else { count = x86_THREAD_STATE64_COUNT; state = x86_THREAD_STATE64; if((reg = go2darwin64(addr)) < 0 || reg+n > sizeof u){ if(isr){ memset(v, 0, n); return 0; } werrstr("register %llud not available", addr); return -1; } } if(!isr && me(thread_suspend(thread)) < 0){ werrstr("thread suspend %#x: %r", thread); return -1; } nn = count; if(me(thread_get_state(thread, state, (void*)u.p, &nn)) < 0){ if(!isr) thread_resume(thread); rerrstr(buf, sizeof buf); if(strcmp(buf, "send invalid dest") == 0) werrstr("process exited"); else werrstr("thread_get_state: %r"); return -1; } p = u.p+reg; if(isr) memmove(v, p, n); else{ memmove(p, v, n); nn = count; if(me(thread_set_state(thread, state, (void*)u.p, nn)) < 0){ thread_resume(thread); werrstr("thread_set_state: %r"); return -1; } if(me(thread_resume(thread)) < 0){ werrstr("thread_resume: %r"); return -1; } } return 0; }
static void i386_darwin_dr_set (int regnum, CORE_ADDR value) { int current_pid; thread_t current_thread; x86_debug_state_t dr_regs; kern_return_t ret; unsigned int dr_count; gdb_assert (regnum >= 0 && regnum <= DR_CONTROL); current_thread = ptid_get_tid (inferior_ptid); dr_regs.dsh.flavor = x86_DEBUG_STATE; dr_regs.dsh.count = x86_DEBUG_STATE_COUNT; dr_count = x86_DEBUG_STATE_COUNT; ret = thread_get_state (current_thread, x86_DEBUG_STATE, (thread_state_t) &dr_regs, &dr_count); MACH_CHECK_ERROR (ret); switch (dr_regs.dsh.flavor) { case x86_DEBUG_STATE32: switch (regnum) { case 0: dr_regs.uds.ds32.__dr0 = value; break; case 1: dr_regs.uds.ds32.__dr1 = value; break; case 2: dr_regs.uds.ds32.__dr2 = value; break; case 3: dr_regs.uds.ds32.__dr3 = value; break; case 4: dr_regs.uds.ds32.__dr4 = value; break; case 5: dr_regs.uds.ds32.__dr5 = value; break; case 6: dr_regs.uds.ds32.__dr6 = value; break; case 7: dr_regs.uds.ds32.__dr7 = value; break; } break; #ifdef BFD64 case x86_DEBUG_STATE64: switch (regnum) { case 0: dr_regs.uds.ds64.__dr0 = value; break; case 1: dr_regs.uds.ds64.__dr1 = value; break; case 2: dr_regs.uds.ds64.__dr2 = value; break; case 3: dr_regs.uds.ds64.__dr3 = value; break; case 4: dr_regs.uds.ds64.__dr4 = value; break; case 5: dr_regs.uds.ds64.__dr5 = value; break; case 6: dr_regs.uds.ds64.__dr6 = value; break; case 7: dr_regs.uds.ds64.__dr7 = value; break; } break; #endif } ret = thread_set_state (current_thread, dr_regs.dsh.flavor, (thread_state_t) &dr_regs.uds, dr_count); MACH_CHECK_ERROR (ret); }
static void i386_darwin_store_inferior_registers (struct target_ops *ops, struct regcache *regcache, int regno) { thread_t current_thread = ptid_get_tid (inferior_ptid); struct gdbarch *gdbarch = get_regcache_arch (regcache); #ifdef BFD64 if (gdbarch_ptr_bit (gdbarch) == 64) { if (regno == -1 || amd64_native_gregset_supplies_p (gdbarch, regno)) { x86_thread_state_t gp_regs; kern_return_t ret; unsigned int gp_count = x86_THREAD_STATE_COUNT; ret = thread_get_state (current_thread, x86_THREAD_STATE, (thread_state_t) &gp_regs, &gp_count); MACH_CHECK_ERROR (ret); gdb_assert (gp_regs.tsh.flavor == x86_THREAD_STATE64); gdb_assert (gp_regs.tsh.count == x86_THREAD_STATE64_COUNT); amd64_collect_native_gregset (regcache, &gp_regs.uts, regno); ret = thread_set_state (current_thread, x86_THREAD_STATE, (thread_state_t) &gp_regs, x86_THREAD_STATE_COUNT); MACH_CHECK_ERROR (ret); } if (regno == -1 || !amd64_native_gregset_supplies_p (gdbarch, regno)) { x86_float_state_t fp_regs; kern_return_t ret; unsigned int fp_count = x86_FLOAT_STATE_COUNT; ret = thread_get_state (current_thread, x86_FLOAT_STATE, (thread_state_t) & fp_regs, &fp_count); MACH_CHECK_ERROR (ret); gdb_assert (fp_regs.fsh.flavor == x86_FLOAT_STATE64); gdb_assert (fp_regs.fsh.count == x86_FLOAT_STATE64_COUNT); amd64_collect_fxsave (regcache, regno, &fp_regs.ufs.fs64.__fpu_fcw); ret = thread_set_state (current_thread, x86_FLOAT_STATE, (thread_state_t) & fp_regs, x86_FLOAT_STATE_COUNT); MACH_CHECK_ERROR (ret); } } else #endif { if (regno == -1 || regno < I386_NUM_GREGS) { x86_thread_state32_t gp_regs; kern_return_t ret; unsigned int gp_count = x86_THREAD_STATE32_COUNT; int i; ret = thread_get_state (current_thread, x86_THREAD_STATE32, (thread_state_t) &gp_regs, &gp_count); MACH_CHECK_ERROR (ret); for (i = 0; i < I386_NUM_GREGS; i++) if (regno == -1 || regno == i) regcache_raw_collect (regcache, i, (char *)&gp_regs + i386_darwin_thread_state_reg_offset[i]); ret = thread_set_state (current_thread, x86_THREAD_STATE32, (thread_state_t) &gp_regs, x86_THREAD_STATE32_COUNT); MACH_CHECK_ERROR (ret); } if (regno == -1 || (regno >= I386_ST0_REGNUM && regno < I386_SSE_NUM_REGS)) { x86_float_state32_t fp_regs; unsigned int fp_count = x86_FLOAT_STATE32_COUNT; kern_return_t ret; ret = thread_get_state (current_thread, x86_FLOAT_STATE32, (thread_state_t) & fp_regs, &fp_count); MACH_CHECK_ERROR (ret); i387_collect_fxsave (regcache, regno, &fp_regs.__fpu_fcw); ret = thread_set_state (current_thread, x86_FLOAT_STATE32, (thread_state_t) &fp_regs, x86_FLOAT_STATE32_COUNT); MACH_CHECK_ERROR (ret); } } }
void store_inferior_registers (register int regno) { thread_state_data_t state; kern_return_t ret; if (!MACH_PORT_VALID (current_thread)) error ("store inferior registers: Invalid thread"); /* Check for read only regs. * @@ If some of these is can be changed, fix this */ if (regno == ZERO_REGNUM || regno == PS_REGNUM || regno == BADVADDR_REGNUM || regno == CAUSE_REGNUM || regno == FCRIR_REGNUM) { message ("You can not alter read-only register `%s'", REGISTER_NAME (regno)); fetch_inferior_registers (regno); return; } if (regno == -1) { /* Don't allow these to change */ /* ZERO_REGNUM */ *(int *) registers = 0; fetch_inferior_registers (PS_REGNUM); fetch_inferior_registers (BADVADDR_REGNUM); fetch_inferior_registers (CAUSE_REGNUM); fetch_inferior_registers (FCRIR_REGNUM); } if (regno == -1 || (ZERO_REGNUM < regno && regno <= PC_REGNUM)) { #if 1 /* Mach 3.0 saves thread's FP to MACH_FP_REGNUM. * GDB wants assigns a pseudo register FP_REGNUM for frame pointer. * * @@@ Here I assume (!) that gdb's FP has the value that * should go to threads frame pointer. If not true, this * fails badly!!!!! */ memcpy (®isters[REGISTER_BYTE (MACH_FP_REGNUM)], ®isters[REGISTER_BYTE (FP_REGNUM)], REGISTER_RAW_SIZE (FP_REGNUM)); #endif /* Save gdb's regs 1..31 to thread saved regs 1..31 * Luckily, they are contiquous */ STORE_REGS (state, 1, 31); /* Save mdlo, mdhi */ STORE_REGS (state, LO_REGNUM, 2); /* Save PC */ STORE_REGS (state, PC_REGNUM, 1); ret = thread_set_state (current_thread, MIPS_THREAD_STATE, state, MIPS_FLOAT_STATE_COUNT); CHK ("store inferior regs : thread_set_state", ret); } if (regno == -1 || regno >= FP0_REGNUM) { /* If thread has floating state, save it */ if (read_register (PS_REGNUM) & MIPS_STATUS_USE_COP1) { /* Do NOT save FCRIR_REGNUM */ STORE_REGS (state, FP0_REGNUM, 33); ret = thread_set_state (current_thread, MIPS_FLOAT_STATE, state, MIPS_FLOAT_STATE_COUNT); CHK ("store inferior registers (floats): thread_set_state", ret); } else if (regno != -1) message ("Thread does not use floating point unit, floating regs not saved"); } }
/* Store our register values back into the inferior. * If REGNO is -1, do this for all registers. * Otherwise, REGNO specifies which register (so we can save time): */ void store_inferior_registers(int regno) { int current_pid; thread_t current_thread; kern_return_t ret; current_pid = ptid_get_pid(inferior_ptid); current_thread = (thread_t)ptid_get_tid(inferior_ptid); if (current_pid == 0) { ; /* do nothing; just silence '-Wunused-but-set-variable' */ } validate_inferior_registers(regno); if ((regno == -1) || ARM_MACOSX_IS_GP_RELATED_REGNUM(regno)) { struct gdb_arm_thread_state gp_regs; arm_macosx_store_gp_registers(&gp_regs); ret = thread_set_state(current_thread, GDB_ARM_THREAD_STATE, (thread_state_t)&gp_regs, GDB_ARM_THREAD_STATE_COUNT); MACH_CHECK_ERROR(ret); } if ((regno == -1) || ARM_MACOSX_IS_VFP_RELATED_REGNUM(regno)) { enum arm_vfp_version vfp_version; int fp_byte_size; vfp_version = new_gdbarch_tdep(current_gdbarch)->vfp_version; fp_byte_size = -1; switch (vfp_version) { case ARM_VFP_UNSUPPORTED: /* No VFP support, so nothing to do here: */ fp_byte_size = 0; break; case ARM_VFP_VERSION_1: { gdb_arm_thread_vfpv1_state_t fp_regs; arm_macosx_store_vfpv1_regs(&fp_regs); ret = thread_set_state(current_thread, GDB_ARM_THREAD_FPSTATE, (thread_state_t) & fp_regs, GDB_ARM_THREAD_FPSTATE_VFPV1_COUNT); MACH_CHECK_ERROR(ret); } break; case ARM_VFP_VERSION_3: { gdb_arm_thread_vfpv3_state_t fp_regs; arm_macosx_store_vfpv3_regs(&fp_regs); ret = thread_set_state(current_thread, GDB_ARM_THREAD_FPSTATE, (thread_state_t)&fp_regs, GDB_ARM_THREAD_FPSTATE_VFPV3_COUNT); MACH_CHECK_ERROR(ret); } break; default: error("store_inferior_registers: unable to store ARM_THREAD_FPSTATE: " "unsupported vfp version: %d", (int)vfp_version); #ifndef __clang__ break; #endif /* !__clang__ */ } if (fp_byte_size >= 0) { ; /* ??? */ } } }