summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
diff options
context:
space:
mode:
authorSagar Thakur <sagar.thakur@imgtec.com>2015-06-03 10:14:24 +0000
committerSagar Thakur <sagar.thakur@imgtec.com>2015-06-03 10:14:24 +0000
commitce815e4588fd02d5ba0d5ec0bf9ceeb2e616eb6e (patch)
treea3752dca1e22836007e01132243c959fbc8093fd /lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
parentfaed801f6e718fa2ec2f062b734c2f37f3d00dd0 (diff)
downloadbcm5719-llvm-ce815e4588fd02d5ba0d5ec0bf9ceeb2e616eb6e.tar.gz
bcm5719-llvm-ce815e4588fd02d5ba0d5ec0bf9ceeb2e616eb6e.zip
[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
Diffstat (limited to 'lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp')
-rw-r--r--lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp438
1 files changed, 386 insertions, 52 deletions
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 &reg_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 : "<unknown register>");
- 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)
{
OpenPOWER on IntegriCloud