summaryrefslogtreecommitdiff
path: root/tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp')
-rw-r--r--tools/debugserver/source/MacOSX/ppc/DNBArchImpl.cpp569
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__)
+