From ce815e4588fd02d5ba0d5ec0bf9ceeb2e616eb6e Mon Sep 17 00:00:00 2001 From: Sagar Thakur Date: Wed, 3 Jun 2015 10:14:24 +0000 Subject: [MIPS][lldb-server] Add 32-bit register context and read/write FP registers on mips64 - Added support for read/write FP registers in FR1 mode. - Added 32 bit register context for mips32. Reviewers: clayborg, tberghammer, jaydeep Subscribers: emaste, nitesh.jain, bhushan, mohit.bhakkad, lldb-commits Differential Revision: http://reviews.llvm.org/D10029 llvm-svn: 238914 --- .../Linux/NativeRegisterContextLinux_mips64.cpp | 438 ++++++++++++++++++--- 1 file changed, 386 insertions(+), 52 deletions(-) (limited to 'lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp') diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp index 1e7a1fa9f1f..9bce8a80a22 100644 --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp @@ -17,10 +17,14 @@ // Other libraries and framework includes #include "lldb/Core/Error.h" #include "lldb/Core/RegisterValue.h" +#include "lldb/Core/Log.h" +#include "lldb/Core/DataBufferHeap.h" +#include "lldb/Host/HostInfo.h" #include "Plugins/Process/Linux/NativeProcessLinux.h" #include "Plugins/Process/Linux/Procfs.h" #include "Plugins/Process/Utility/RegisterContextLinux_mips64.h" +#include "Plugins/Process/Utility/RegisterContextLinux_mips.h" using namespace lldb_private; using namespace lldb_private::process_linux; @@ -31,65 +35,212 @@ using namespace lldb_private::process_linux; namespace { + // mips general purpose registers. + const uint32_t + g_gp_regnums_mips[] = + { + gpr_zero_mips, + gpr_r1_mips, + gpr_r2_mips, + gpr_r3_mips, + gpr_r4_mips, + gpr_r5_mips, + gpr_r6_mips, + gpr_r7_mips, + gpr_r8_mips, + gpr_r9_mips, + gpr_r10_mips, + gpr_r11_mips, + gpr_r12_mips, + gpr_r13_mips, + gpr_r14_mips, + gpr_r15_mips, + gpr_r16_mips, + gpr_r17_mips, + gpr_r18_mips, + gpr_r19_mips, + gpr_r20_mips, + gpr_r21_mips, + gpr_r22_mips, + gpr_r23_mips, + gpr_r24_mips, + gpr_r25_mips, + gpr_r26_mips, + gpr_r27_mips, + gpr_gp_mips, + gpr_sp_mips, + gpr_r30_mips, + gpr_ra_mips, + gpr_mullo_mips, + gpr_mulhi_mips, + gpr_pc_mips, + gpr_badvaddr_mips, + gpr_sr_mips, + gpr_cause_mips, + LLDB_INVALID_REGNUM // register sets need to end with this flag + }; + + static_assert((sizeof(g_gp_regnums_mips) / sizeof(g_gp_regnums_mips[0])) - 1 == k_num_gpr_registers_mips, + "g_gp_regnums_mips has wrong number of register infos"); + + // mips floating point registers. + const uint32_t + g_fp_regnums_mips[] = + { + fpr_f0_mips, + fpr_f1_mips, + fpr_f2_mips, + fpr_f3_mips, + fpr_f4_mips, + fpr_f5_mips, + fpr_f6_mips, + fpr_f7_mips, + fpr_f8_mips, + fpr_f9_mips, + fpr_f10_mips, + fpr_f11_mips, + fpr_f12_mips, + fpr_f13_mips, + fpr_f14_mips, + fpr_f15_mips, + fpr_f16_mips, + fpr_f17_mips, + fpr_f18_mips, + fpr_f19_mips, + fpr_f20_mips, + fpr_f21_mips, + fpr_f22_mips, + fpr_f23_mips, + fpr_f24_mips, + fpr_f25_mips, + fpr_f26_mips, + fpr_f27_mips, + fpr_f28_mips, + fpr_f29_mips, + fpr_f30_mips, + fpr_f31_mips, + fpr_fcsr_mips, + fpr_fir_mips, + LLDB_INVALID_REGNUM // register sets need to end with this flag + }; + + static_assert((sizeof(g_fp_regnums_mips) / sizeof(g_fp_regnums_mips[0])) - 1 == k_num_fpr_registers_mips, + "g_fp_regnums_mips has wrong number of register infos"); + // mips64 general purpose registers. const uint32_t g_gp_regnums_mips64[] = { - gp_reg_r0_mips64, - gp_reg_r1_mips64, - gp_reg_r2_mips64, - gp_reg_r3_mips64, - gp_reg_r4_mips64, - gp_reg_r5_mips64, - gp_reg_r6_mips64, - gp_reg_r7_mips64, - gp_reg_r8_mips64, - gp_reg_r9_mips64, - gp_reg_r10_mips64, - gp_reg_r11_mips64, - gp_reg_r12_mips64, - gp_reg_r13_mips64, - gp_reg_r14_mips64, - gp_reg_r15_mips64, - gp_reg_r16_mips64, - gp_reg_r17_mips64, - gp_reg_r18_mips64, - gp_reg_r19_mips64, - gp_reg_r20_mips64, - gp_reg_r21_mips64, - gp_reg_r22_mips64, - gp_reg_r23_mips64, - gp_reg_r24_mips64, - gp_reg_r25_mips64, - gp_reg_r26_mips64, - gp_reg_r27_mips64, - gp_reg_r28_mips64, - gp_reg_r29_mips64, - gp_reg_r30_mips64, - gp_reg_r31_mips64, - gp_reg_mullo_mips64, - gp_reg_mulhi_mips64, - gp_reg_pc_mips64, - gp_reg_badvaddr_mips64, - gp_reg_sr_mips64, - gp_reg_cause_mips64, + gpr_zero_mips64, + gpr_r1_mips64, + gpr_r2_mips64, + gpr_r3_mips64, + gpr_r4_mips64, + gpr_r5_mips64, + gpr_r6_mips64, + gpr_r7_mips64, + gpr_r8_mips64, + gpr_r9_mips64, + gpr_r10_mips64, + gpr_r11_mips64, + gpr_r12_mips64, + gpr_r13_mips64, + gpr_r14_mips64, + gpr_r15_mips64, + gpr_r16_mips64, + gpr_r17_mips64, + gpr_r18_mips64, + gpr_r19_mips64, + gpr_r20_mips64, + gpr_r21_mips64, + gpr_r22_mips64, + gpr_r23_mips64, + gpr_r24_mips64, + gpr_r25_mips64, + gpr_r26_mips64, + gpr_r27_mips64, + gpr_gp_mips64, + gpr_sp_mips64, + gpr_r30_mips64, + gpr_ra_mips64, + gpr_mullo_mips64, + gpr_mulhi_mips64, + gpr_pc_mips64, + gpr_badvaddr_mips64, + gpr_sr_mips64, + gpr_cause_mips64, + gpr_ic_mips64, + gpr_dummy_mips64, LLDB_INVALID_REGNUM // register sets need to end with this flag }; - static_assert((sizeof(g_gp_regnums_mips64) / sizeof(g_gp_regnums_mips64[0])) - 1 == k_num_gp_reg_mips64, + static_assert((sizeof(g_gp_regnums_mips64) / sizeof(g_gp_regnums_mips64[0])) - 1 == k_num_gpr_registers_mips64, "g_gp_regnums_mips64 has wrong number of register infos"); + // mips64 floating point registers. + const uint32_t + g_fp_regnums_mips64[] = + { + fpr_f0_mips64, + fpr_f1_mips64, + fpr_f2_mips64, + fpr_f3_mips64, + fpr_f4_mips64, + fpr_f5_mips64, + fpr_f6_mips64, + fpr_f7_mips64, + fpr_f8_mips64, + fpr_f9_mips64, + fpr_f10_mips64, + fpr_f11_mips64, + fpr_f12_mips64, + fpr_f13_mips64, + fpr_f14_mips64, + fpr_f15_mips64, + fpr_f16_mips64, + fpr_f17_mips64, + fpr_f18_mips64, + fpr_f19_mips64, + fpr_f20_mips64, + fpr_f21_mips64, + fpr_f22_mips64, + fpr_f23_mips64, + fpr_f24_mips64, + fpr_f25_mips64, + fpr_f26_mips64, + fpr_f27_mips64, + fpr_f28_mips64, + fpr_f29_mips64, + fpr_f30_mips64, + fpr_f31_mips64, + fpr_fcsr_mips64, + fpr_fir_mips64, + LLDB_INVALID_REGNUM // register sets need to end with this flag + }; + + static_assert((sizeof(g_fp_regnums_mips64) / sizeof(g_fp_regnums_mips64[0])) - 1 == k_num_fpr_registers_mips64, + "g_fp_regnums_mips64 has wrong number of register infos"); + // Number of register sets provided by this context. enum { - k_num_register_sets = 1 + k_num_register_sets = 2 + }; + + // Register sets for mips. + static const RegisterSet + g_reg_sets_mips[k_num_register_sets] = + { + { "General Purpose Registers", "gpr", k_num_gpr_registers_mips, g_gp_regnums_mips }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_mips, g_fp_regnums_mips } }; // Register sets for mips64. static const RegisterSet g_reg_sets_mips64[k_num_register_sets] = { - { "General Purpose Registers", "gpr", k_num_gp_reg_mips64, g_gp_regnums_mips64 } + { "General Purpose Registers", "gpr", k_num_gpr_registers_mips64, g_gp_regnums_mips64 }, + { "Floating Point Registers", "fpu", k_num_fpr_registers_mips64, g_fp_regnums_mips64 } }; class ReadRegOperation : public NativeProcessLinux::Operation @@ -167,15 +318,61 @@ NativeRegisterContextLinux::CreateHostNativeRegisterContextLinux(const ArchSpec& return new NativeRegisterContextLinux_mips64(target_arch, native_thread, concrete_frame_idx); } +#define REG_CONTEXT_SIZE (GetRegisterInfoInterface ().GetGPRSize () + sizeof(FPR_mips)) + // ---------------------------------------------------------------------------- // NativeRegisterContextLinux_mips64 members. // ---------------------------------------------------------------------------- +static RegisterInfoInterface* +CreateRegisterInfoInterface(const ArchSpec& target_arch) +{ + if (HostInfo::GetArchitecture().GetAddressByteSize() == 4) + { + // 32-bit hosts run with a RegisterContextLinux_mips context. + return new RegisterContextLinux_mips(target_arch); + } + else + { + assert((HostInfo::GetArchitecture().GetAddressByteSize() == 8) && + "Register setting path assumes this is a 64-bit host"); + // mips64 hosts know how to work with 64-bit and 32-bit EXEs using the mips64 register context. + return new RegisterContextLinux_mips64 (target_arch); + } +} + NativeRegisterContextLinux_mips64::NativeRegisterContextLinux_mips64 (const ArchSpec& target_arch, NativeThreadProtocol &native_thread, uint32_t concrete_frame_idx) : - NativeRegisterContextLinux (native_thread, concrete_frame_idx, new RegisterContextLinux_mips64 (target_arch)) + NativeRegisterContextLinux (native_thread, concrete_frame_idx, CreateRegisterInfoInterface(target_arch)) { + switch (target_arch.GetMachine ()) + { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + m_reg_info.num_registers = k_num_registers_mips; + m_reg_info.num_gpr_registers = k_num_gpr_registers_mips; + m_reg_info.num_fpr_registers = k_num_fpr_registers_mips; + m_reg_info.last_gpr = k_last_gpr_mips; + m_reg_info.first_fpr = k_first_fpr_mips; + m_reg_info.last_fpr = k_last_fpr_mips; + break; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + m_reg_info.num_registers = k_num_registers_mips64; + m_reg_info.num_gpr_registers = k_num_gpr_registers_mips64; + m_reg_info.num_fpr_registers = k_num_fpr_registers_mips64; + m_reg_info.last_gpr = k_last_gpr_mips64; + m_reg_info.first_fpr = k_first_fpr_mips64; + m_reg_info.last_fpr = k_last_fpr_mips64; + break; + default: + assert(false && "Unhandled target architecture."); + break; + } + + // Clear out the FPR state. + ::memset(&m_fpr, 0, sizeof(FPR_mips)); } uint32_t @@ -195,6 +392,9 @@ NativeRegisterContextLinux_mips64::GetRegisterSet (uint32_t set_index) const case llvm::Triple::mips64: case llvm::Triple::mips64el: return &g_reg_sets_mips64[set_index]; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + return &g_reg_sets_mips[set_index]; default: assert (false && "Unhandled target architecture."); return nullptr; @@ -222,14 +422,40 @@ NativeRegisterContextLinux_mips64::ReadRegister (const RegisterInfo *reg_info, R return error; } - error = ReadRegisterRaw(reg, reg_value); - - if (error.Success ()) + if (IsFPR(reg)) + { + error = ReadFPR(); + if (!error.Success()) + { + error.SetErrorString ("failed to read floating point register"); + return error; + } + assert (reg_info->byte_offset < sizeof(FPR_mips)); + uint8_t *src = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 4: + reg_value.SetUInt32(*(uint32_t *)src); + break; + case 8: + reg_value.SetUInt64(*(uint64_t *)src); + break; + default: + assert(false && "Unhandled data size."); + error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); + break; + } + } + else { - // If our return byte size was greater than the return value reg size, then - // use the type specified by reg_info rather than the uint64_t default - if (reg_value.GetByteSize() > reg_info->byte_size) - reg_value.SetType(reg_info); + error = ReadRegisterRaw(reg, reg_value); + if (error.Success()) + { + // If our return byte size was greater than the return value reg size, then + // use the type specified by reg_info rather than the uint64_t default + if (reg_value.GetByteSize() > reg_info->byte_size) + reg_value.SetType(reg_info); + } } return error; @@ -238,6 +464,8 @@ NativeRegisterContextLinux_mips64::ReadRegister (const RegisterInfo *reg_info, R lldb_private::Error NativeRegisterContextLinux_mips64::WriteRegister (const RegisterInfo *reg_info, const RegisterValue ®_value) { + Error error; + assert (reg_info && "reg_info is null"); const uint32_t reg_index = reg_info->kinds[lldb::eRegisterKindLLDB]; @@ -245,14 +473,76 @@ NativeRegisterContextLinux_mips64::WriteRegister (const RegisterInfo *reg_info, if (reg_index == LLDB_INVALID_REGNUM) return Error ("no lldb regnum for %s", reg_info && reg_info->name ? reg_info->name : ""); - return WriteRegisterRaw(reg_index, reg_value); + if (IsFPR(reg_index)) + { + assert (reg_info->byte_offset < sizeof(FPR_mips)); + uint8_t *dst = (uint8_t *)&m_fpr + reg_info->byte_offset; + switch (reg_info->byte_size) + { + case 4: + *(uint32_t *)dst = reg_value.GetAsUInt32(); + break; + case 8: + *(uint64_t *)dst = reg_value.GetAsUInt64(); + break; + default: + assert(false && "Unhandled data size."); + error.SetErrorStringWithFormat ("unhandled byte size: %" PRIu32, reg_info->byte_size); + break; + } + error = WriteFPR(); + if (!error.Success()) + { + error.SetErrorString ("failed to write floating point register"); + return error; + } + } + else + { + error = WriteRegisterRaw(reg_index, reg_value); + } + + return error; } Error NativeRegisterContextLinux_mips64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp) { Error error; - error.SetErrorString ("MIPS TODO: NativeRegisterContextLinux_mips64::ReadAllRegisterValues not implemented"); + + data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0)); + if (!data_sp) + { + error.SetErrorStringWithFormat ("failed to allocate DataBufferHeap instance of size %" PRIu64, REG_CONTEXT_SIZE); + return error; + } + + error = ReadGPR(); + if (!error.Success()) + { + error.SetErrorString ("ReadGPR() failed"); + return error; + } + + error = ReadFPR(); + if (!error.Success()) + { + error.SetErrorString ("ReadFPR() failed"); + return error; + } + + uint8_t *dst = data_sp->GetBytes (); + if (dst == nullptr) + { + error.SetErrorStringWithFormat ("DataBufferHeap instance of size %" PRIu64 " returned a null pointer", REG_CONTEXT_SIZE); + return error; + } + + ::memcpy (dst, &m_gpr_mips64, GetRegisterInfoInterface ().GetGPRSize ()); + dst += GetRegisterInfoInterface ().GetGPRSize (); + + ::memcpy (dst, &m_fpr, sizeof(FPR_mips)); + return error; } @@ -260,10 +550,54 @@ Error NativeRegisterContextLinux_mips64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp) { Error error; - error.SetErrorString ("MIPS TODO: NativeRegisterContextLinux_mips64::WriteAllRegisterValues not implemented"); + + if (!data_sp) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s invalid data_sp provided", __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize () != REG_CONTEXT_SIZE) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s data_sp contained mismatched data size, expected %" PRIu64 ", actual %" PRIu64, __FUNCTION__, REG_CONTEXT_SIZE, data_sp->GetByteSize ()); + return error; + } + + + uint8_t *src = data_sp->GetBytes (); + if (src == nullptr) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s DataBuffer::GetBytes() returned a null pointer", __FUNCTION__); + return error; + } + ::memcpy (&m_gpr_mips64, src, GetRegisterInfoInterface ().GetGPRSize ()); + src += GetRegisterInfoInterface ().GetGPRSize (); + + ::memcpy (&m_fpr, src, sizeof(FPR_mips)); + + error = WriteGPR(); + if (!error.Success()) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s WriteGPR() failed", __FUNCTION__); + return error; + } + + error = WriteFPR(); + if (!error.Success()) + { + error.SetErrorStringWithFormat ("NativeRegisterContextLinux_mips64::%s WriteFPR() failed", __FUNCTION__); + return error; + } + return error; } +bool +NativeRegisterContextLinux_mips64::IsFPR(uint32_t reg_index) const +{ + return (m_reg_info.first_fpr <= reg_index && reg_index <= m_reg_info.last_fpr); +} + Error NativeRegisterContextLinux_mips64::IsWatchpointHit (uint32_t wp_index, bool &is_hit) { -- cgit v1.2.3