diff options
Diffstat (limited to 'tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp')
-rw-r--r-- | tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp b/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp new file mode 100644 index 0000000000000..c6f1a718ac92e --- /dev/null +++ b/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp @@ -0,0 +1,569 @@ +//===-- DNBArchImpl.cpp -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Created by Greg Clayton on 6/25/07. +// +//===----------------------------------------------------------------------===// + +#if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) + +#if __DARWIN_UNIX03 +#define PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(reg) __##reg +#else +#define PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(reg) reg +#endif + +#include "MacOSX/ppc/DNBArchImpl.h" +#include "MacOSX/MachThread.h" +#include "DNBBreakpoint.h" +#include "DNBLog.h" +#include "DNBRegisterInfo.h" + +static const uint8_t g_breakpoint_opcode[] = { 0x7F, 0xC0, 0x00, 0x08 }; + +const uint8_t * +DNBArchMachPPC::SoftwareBreakpointOpcode (nub_size_t size) +{ + if (size == 4) + return g_breakpoint_opcode; + return NULL; +} + +uint32_t +DNBArchMachPPC::GetCPUType() +{ + return CPU_TYPE_POWERPC; +} + +uint64_t +DNBArchMachPPC::GetPC(uint64_t failValue) +{ + // Get program counter + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0); + return failValue; +} + +kern_return_t +DNBArchMachPPC::SetPC(uint64_t value) +{ + // Get program counter + kern_return_t err = GetGPRState(false); + if (err == KERN_SUCCESS) + { + m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0) = value; + err = SetGPRState(); + } + return err == KERN_SUCCESS; +} + +uint64_t +DNBArchMachPPC::GetSP(uint64_t failValue) +{ + // Get stack pointer + if (GetGPRState(false) == KERN_SUCCESS) + return m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(r1); + return failValue; +} + +kern_return_t +DNBArchMachPPC::GetGPRState(bool force) +{ + if (force || m_state.GetError(e_regSetGPR, Read)) + { + mach_msg_type_number_t count = e_regSetWordSizeGPR; + m_state.SetError(e_regSetGPR, Read, ::thread_get_state(m_thread->MachPortNumber(), e_regSetGPR, (thread_state_t)&m_state.gpr, &count)); + } + return m_state.GetError(e_regSetGPR, Read); +} + +kern_return_t +DNBArchMachPPC::GetFPRState(bool force) +{ + if (force || m_state.GetError(e_regSetFPR, Read)) + { + mach_msg_type_number_t count = e_regSetWordSizeFPR; + m_state.SetError(e_regSetFPR, Read, ::thread_get_state(m_thread->MachPortNumber(), e_regSetFPR, (thread_state_t)&m_state.fpr, &count)); + } + return m_state.GetError(e_regSetFPR, Read); +} + +kern_return_t +DNBArchMachPPC::GetEXCState(bool force) +{ + if (force || m_state.GetError(e_regSetEXC, Read)) + { + mach_msg_type_number_t count = e_regSetWordSizeEXC; + m_state.SetError(e_regSetEXC, Read, ::thread_get_state(m_thread->MachPortNumber(), e_regSetEXC, (thread_state_t)&m_state.exc, &count)); + } + return m_state.GetError(e_regSetEXC, Read); +} + +kern_return_t +DNBArchMachPPC::GetVECState(bool force) +{ + if (force || m_state.GetError(e_regSetVEC, Read)) + { + mach_msg_type_number_t count = e_regSetWordSizeVEC; + m_state.SetError(e_regSetVEC, Read, ::thread_get_state(m_thread->MachPortNumber(), e_regSetVEC, (thread_state_t)&m_state.vec, &count)); + } + return m_state.GetError(e_regSetVEC, Read); +} + +kern_return_t +DNBArchMachPPC::SetGPRState() +{ + m_state.SetError(e_regSetGPR, Write, ::thread_set_state(m_thread->MachPortNumber(), e_regSetGPR, (thread_state_t)&m_state.gpr, e_regSetWordSizeGPR)); + return m_state.GetError(e_regSetGPR, Write); +} + +kern_return_t +DNBArchMachPPC::SetFPRState() +{ + m_state.SetError(e_regSetFPR, Write, ::thread_set_state(m_thread->MachPortNumber(), e_regSetFPR, (thread_state_t)&m_state.fpr, e_regSetWordSizeFPR)); + return m_state.GetError(e_regSetFPR, Write); +} + +kern_return_t +DNBArchMachPPC::SetEXCState() +{ + m_state.SetError(e_regSetEXC, Write, ::thread_set_state(m_thread->MachPortNumber(), e_regSetEXC, (thread_state_t)&m_state.exc, e_regSetWordSizeEXC)); + return m_state.GetError(e_regSetEXC, Write); +} + +kern_return_t +DNBArchMachPPC::SetVECState() +{ + m_state.SetError(e_regSetVEC, Write, ::thread_set_state(m_thread->MachPortNumber(), e_regSetVEC, (thread_state_t)&m_state.vec, e_regSetWordSizeVEC)); + return m_state.GetError(e_regSetVEC, Write); +} + +bool +DNBArchMachPPC::ThreadWillResume() +{ + bool success = true; + + // Do we need to step this thread? If so, let the mach thread tell us so. + if (m_thread->IsStepping()) + { + // This is the primary thread, let the arch do anything it needs + success = EnableHardwareSingleStep(true) == KERN_SUCCESS; + } + return success; +} + +bool +DNBArchMachPPC::ThreadDidStop() +{ + bool success = true; + + m_state.InvalidateAllRegisterStates(); + + // Are we stepping a single instruction? + if (GetGPRState(true) == KERN_SUCCESS) + { + // We are single stepping, was this the primary thread? + if (m_thread->IsStepping()) + { + // This was the primary thread, we need to clear the trace + // bit if so. + success = EnableHardwareSingleStep(false) == KERN_SUCCESS; + } + else + { + // The MachThread will automatically restore the suspend count + // in ThreadDidStop(), so we don't need to do anything here if + // we weren't the primary thread the last time + } + } + return success; +} + + +// Set the single step bit in the processor status register. +kern_return_t +DNBArchMachPPC::EnableHardwareSingleStep (bool enable) +{ + DNBLogThreadedIf(LOG_STEP, "DNBArchMachPPC::EnableHardwareSingleStep( enable = %d )", enable); + if (GetGPRState(false) == KERN_SUCCESS) + { + const uint32_t trace_bit = 0x400; + if (enable) + m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr1) |= trace_bit; + else + m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr1) &= ~trace_bit; + return SetGPRState(); + } + return m_state.GetError(e_regSetGPR, Read); +} + +//---------------------------------------------------------------------- +// Register information definitions for 32 bit PowerPC. +//---------------------------------------------------------------------- + +enum gpr_regnums +{ + e_regNumGPR_srr0, + e_regNumGPR_srr1, + e_regNumGPR_r0, + e_regNumGPR_r1, + e_regNumGPR_r2, + e_regNumGPR_r3, + e_regNumGPR_r4, + e_regNumGPR_r5, + e_regNumGPR_r6, + e_regNumGPR_r7, + e_regNumGPR_r8, + e_regNumGPR_r9, + e_regNumGPR_r10, + e_regNumGPR_r11, + e_regNumGPR_r12, + e_regNumGPR_r13, + e_regNumGPR_r14, + e_regNumGPR_r15, + e_regNumGPR_r16, + e_regNumGPR_r17, + e_regNumGPR_r18, + e_regNumGPR_r19, + e_regNumGPR_r20, + e_regNumGPR_r21, + e_regNumGPR_r22, + e_regNumGPR_r23, + e_regNumGPR_r24, + e_regNumGPR_r25, + e_regNumGPR_r26, + e_regNumGPR_r27, + e_regNumGPR_r28, + e_regNumGPR_r29, + e_regNumGPR_r30, + e_regNumGPR_r31, + e_regNumGPR_cr, + e_regNumGPR_xer, + e_regNumGPR_lr, + e_regNumGPR_ctr, + e_regNumGPR_mq, + e_regNumGPR_vrsave +}; + + + + +// General purpose registers +static DNBRegisterInfo g_gpr_registers[] = +{ + { "srr0" , Uint, 4, Hex }, + { "srr1" , Uint, 4, Hex }, + { "r0" , Uint, 4, Hex }, + { "r1" , Uint, 4, Hex }, + { "r2" , Uint, 4, Hex }, + { "r3" , Uint, 4, Hex }, + { "r4" , Uint, 4, Hex }, + { "r5" , Uint, 4, Hex }, + { "r6" , Uint, 4, Hex }, + { "r7" , Uint, 4, Hex }, + { "r8" , Uint, 4, Hex }, + { "r9" , Uint, 4, Hex }, + { "r10" , Uint, 4, Hex }, + { "r11" , Uint, 4, Hex }, + { "r12" , Uint, 4, Hex }, + { "r13" , Uint, 4, Hex }, + { "r14" , Uint, 4, Hex }, + { "r15" , Uint, 4, Hex }, + { "r16" , Uint, 4, Hex }, + { "r17" , Uint, 4, Hex }, + { "r18" , Uint, 4, Hex }, + { "r19" , Uint, 4, Hex }, + { "r20" , Uint, 4, Hex }, + { "r21" , Uint, 4, Hex }, + { "r22" , Uint, 4, Hex }, + { "r23" , Uint, 4, Hex }, + { "r24" , Uint, 4, Hex }, + { "r25" , Uint, 4, Hex }, + { "r26" , Uint, 4, Hex }, + { "r27" , Uint, 4, Hex }, + { "r28" , Uint, 4, Hex }, + { "r29" , Uint, 4, Hex }, + { "r30" , Uint, 4, Hex }, + { "r31" , Uint, 4, Hex }, + { "cr" , Uint, 4, Hex }, + { "xer" , Uint, 4, Hex }, + { "lr" , Uint, 4, Hex }, + { "ctr" , Uint, 4, Hex }, + { "mq" , Uint, 4, Hex }, + { "vrsave", Uint, 4, Hex }, +}; + +// Floating point registers +static DNBRegisterInfo g_fpr_registers[] = +{ + { "fp0" , IEEE754, 8, Float }, + { "fp1" , IEEE754, 8, Float }, + { "fp2" , IEEE754, 8, Float }, + { "fp3" , IEEE754, 8, Float }, + { "fp4" , IEEE754, 8, Float }, + { "fp5" , IEEE754, 8, Float }, + { "fp6" , IEEE754, 8, Float }, + { "fp7" , IEEE754, 8, Float }, + { "fp8" , IEEE754, 8, Float }, + { "fp9" , IEEE754, 8, Float }, + { "fp10" , IEEE754, 8, Float }, + { "fp11" , IEEE754, 8, Float }, + { "fp12" , IEEE754, 8, Float }, + { "fp13" , IEEE754, 8, Float }, + { "fp14" , IEEE754, 8, Float }, + { "fp15" , IEEE754, 8, Float }, + { "fp16" , IEEE754, 8, Float }, + { "fp17" , IEEE754, 8, Float }, + { "fp18" , IEEE754, 8, Float }, + { "fp19" , IEEE754, 8, Float }, + { "fp20" , IEEE754, 8, Float }, + { "fp21" , IEEE754, 8, Float }, + { "fp22" , IEEE754, 8, Float }, + { "fp23" , IEEE754, 8, Float }, + { "fp24" , IEEE754, 8, Float }, + { "fp25" , IEEE754, 8, Float }, + { "fp26" , IEEE754, 8, Float }, + { "fp27" , IEEE754, 8, Float }, + { "fp28" , IEEE754, 8, Float }, + { "fp29" , IEEE754, 8, Float }, + { "fp30" , IEEE754, 8, Float }, + { "fp31" , IEEE754, 8, Float }, + { "fpscr" , Uint, 4, Hex } +}; + +// Exception registers + +static DNBRegisterInfo g_exc_registers[] = +{ + { "dar" , Uint, 4, Hex }, + { "dsisr" , Uint, 4, Hex }, + { "exception" , Uint, 4, Hex } +}; + +// Altivec registers +static DNBRegisterInfo g_vec_registers[] = +{ + { "vr0" , Vector, 16, VectorOfFloat32 }, + { "vr1" , Vector, 16, VectorOfFloat32 }, + { "vr2" , Vector, 16, VectorOfFloat32 }, + { "vr3" , Vector, 16, VectorOfFloat32 }, + { "vr4" , Vector, 16, VectorOfFloat32 }, + { "vr5" , Vector, 16, VectorOfFloat32 }, + { "vr6" , Vector, 16, VectorOfFloat32 }, + { "vr7" , Vector, 16, VectorOfFloat32 }, + { "vr8" , Vector, 16, VectorOfFloat32 }, + { "vr9" , Vector, 16, VectorOfFloat32 }, + { "vr10" , Vector, 16, VectorOfFloat32 }, + { "vr11" , Vector, 16, VectorOfFloat32 }, + { "vr12" , Vector, 16, VectorOfFloat32 }, + { "vr13" , Vector, 16, VectorOfFloat32 }, + { "vr14" , Vector, 16, VectorOfFloat32 }, + { "vr15" , Vector, 16, VectorOfFloat32 }, + { "vr16" , Vector, 16, VectorOfFloat32 }, + { "vr17" , Vector, 16, VectorOfFloat32 }, + { "vr18" , Vector, 16, VectorOfFloat32 }, + { "vr19" , Vector, 16, VectorOfFloat32 }, + { "vr20" , Vector, 16, VectorOfFloat32 }, + { "vr21" , Vector, 16, VectorOfFloat32 }, + { "vr22" , Vector, 16, VectorOfFloat32 }, + { "vr23" , Vector, 16, VectorOfFloat32 }, + { "vr24" , Vector, 16, VectorOfFloat32 }, + { "vr25" , Vector, 16, VectorOfFloat32 }, + { "vr26" , Vector, 16, VectorOfFloat32 }, + { "vr27" , Vector, 16, VectorOfFloat32 }, + { "vr28" , Vector, 16, VectorOfFloat32 }, + { "vr29" , Vector, 16, VectorOfFloat32 }, + { "vr30" , Vector, 16, VectorOfFloat32 }, + { "vr31" , Vector, 16, VectorOfFloat32 }, + { "vscr" , Uint, 16, Hex }, + { "vrvalid" , Uint, 4, Hex } +}; + +// Number of registers in each register set +const size_t k_num_gpr_registers = sizeof(g_gpr_registers)/sizeof(DNBRegisterInfo); +const size_t k_num_fpr_registers = sizeof(g_fpr_registers)/sizeof(DNBRegisterInfo); +const size_t k_num_exc_registers = sizeof(g_exc_registers)/sizeof(DNBRegisterInfo); +const size_t k_num_vec_registers = sizeof(g_vec_registers)/sizeof(DNBRegisterInfo); +// Total number of registers for this architecture +const size_t k_num_ppc_registers = k_num_gpr_registers + k_num_fpr_registers + k_num_exc_registers + k_num_vec_registers; + +//---------------------------------------------------------------------- +// Register set definitions. The first definitions at register set index +// of zero is for all registers, followed by other registers sets. The +// register information for the all register set need not be filled in. +//---------------------------------------------------------------------- +static const DNBRegisterSetInfo g_reg_sets[] = +{ + { "PowerPC Registers", NULL, k_num_ppc_registers }, + { "General Purpose Registers", g_gpr_registers, k_num_gpr_registers }, + { "Floating Point Registers", g_fpr_registers, k_num_fpr_registers }, + { "Exception State Registers", g_exc_registers, k_num_exc_registers }, + { "Altivec Registers", g_vec_registers, k_num_vec_registers } +}; +// Total number of register sets for this architecture +const size_t k_num_register_sets = sizeof(g_reg_sets)/sizeof(DNBRegisterSetInfo); + + +const DNBRegisterSetInfo * +DNBArchMachPPC::GetRegisterSetInfo(nub_size_t *num_reg_sets) const +{ + *num_reg_sets = k_num_register_sets; + return g_reg_sets; +} + +bool +DNBArchMachPPC::GetRegisterValue(uint32_t set, uint32_t reg, DNBRegisterValue *value) const +{ + if (set == REGISTER_SET_GENERIC) + { + switch (reg) + { + case GENERIC_REGNUM_PC: // Program Counter + set = e_regSetGPR; + reg = e_regNumGPR_srr0; + break; + + case GENERIC_REGNUM_SP: // Stack Pointer + set = e_regSetGPR; + reg = e_regNumGPR_r1; + break; + + case GENERIC_REGNUM_FP: // Frame Pointer + // Return false for now instead of returning r30 as gcc 3.x would + // use a variety of registers for the FP and it takes inspecting + // the stack to make sure there is a frame pointer before we can + // determine the FP. + return false; + + case GENERIC_REGNUM_RA: // Return Address + set = e_regSetGPR; + reg = e_regNumGPR_lr; + break; + + case GENERIC_REGNUM_FLAGS: // Processor flags register + set = e_regSetGPR; + reg = e_regNumGPR_srr1; + break; + + default: + return false; + } + } + + if (!m_state.RegsAreValid(set)) + return false; + + const DNBRegisterInfo *regInfo = m_thread->GetRegisterInfo(set, reg); + if (regInfo) + { + value->info = *regInfo; + switch (set) + { + case e_regSetGPR: + if (reg < k_num_gpr_registers) + { + value->value.uint32 = (&m_state.gpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(srr0))[reg]; + return true; + } + break; + + case e_regSetFPR: + if (reg < 32) + { + value->value.float64 = m_state.fpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(fpregs)[reg]; + return true; + } + else if (reg == 32) + { + value->value.uint32 = m_state.fpr.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(fpscr); + return true; + } + break; + + case e_regSetEXC: + if (reg < k_num_exc_registers) + { + value->value.uint32 = (&m_state.exc.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(dar))[reg]; + return true; + } + break; + + case e_regSetVEC: + if (reg < k_num_vec_registers) + { + if (reg < 33) // FP0 - FP31 and VSCR + { + // Copy all 4 uint32 values for this vector register + value->value.v_uint32[0] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][0]; + value->value.v_uint32[1] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][1]; + value->value.v_uint32[2] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][2]; + value->value.v_uint32[3] = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vr)[reg][3]; + return true; + } + else if (reg == 34) // VRVALID + { + value->value.uint32 = m_state.vec.PREFIX_DOUBLE_UNDERSCORE_DARWIN_UNIX03(save_vrvalid); + return true; + } + } + break; + } + } + return false; +} + + +kern_return_t +DNBArchMachPPC::GetRegisterState(int set, bool force) +{ + switch (set) + { + case e_regSetALL: + return GetGPRState(force) | + GetFPRState(force) | + GetEXCState(force) | + GetVECState(force); + case e_regSetGPR: return GetGPRState(force); + case e_regSetFPR: return GetFPRState(force); + case e_regSetEXC: return GetEXCState(force); + case e_regSetVEC: return GetVECState(force); + default: break; + } + return KERN_INVALID_ARGUMENT; +} + +kern_return_t +DNBArchMachPPC::SetRegisterState(int set) +{ + // Make sure we have a valid context to set. + kern_return_t err = GetRegisterState(set, false); + if (err != KERN_SUCCESS) + return err; + + switch (set) + { + case e_regSetALL: return SetGPRState() | SetFPRState() | SetEXCState() | SetVECState(); + case e_regSetGPR: return SetGPRState(); + case e_regSetFPR: return SetFPRState(); + case e_regSetEXC: return SetEXCState(); + case e_regSetVEC: return SetVECState(); + default: break; + } + return KERN_INVALID_ARGUMENT; +} + +bool +DNBArchMachPPC::RegisterSetStateIsValid (int set) const +{ + return m_state.RegsAreValid(set); +} + + +#endif // #if defined (__powerpc__) || defined (__ppc__) || defined (__ppc64__) + |