nitesh.jain created this revision.
nitesh.jain added reviewers: clayborg, labath, jaydeep.
nitesh.jain added subscribers: bhushan, slthakur, lldb-commits.
Herald added a subscriber: sdardis.

This patch add fix for reading and writing floating point register based on 
SR.FR bit. 

https://reviews.llvm.org/D24603

Files:
  source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
  source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h

Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
===================================================================
--- source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
+++ source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.h
@@ -76,11 +76,16 @@
   static bool IsMSAAvailable();
 
 protected:
-  Error DoReadRegisterValue(uint32_t offset, const char *reg_name,
-                            uint32_t size, RegisterValue &value) override;
+  Error Read_SR_Config(uint32_t offset, const char *reg_name, uint32_t size,
+                       RegisterValue &value);
 
-  Error DoWriteRegisterValue(uint32_t offset, const char *reg_name,
-                             const RegisterValue &value) override;
+  uint32_t GetPtraceOffset(uint32_t reg_index,
+                           const RegisterInfo *const reg_info);
+
+  Error ReadRegisterRaw(uint32_t reg_index, RegisterValue &value) override;
+
+  Error WriteRegisterRaw(uint32_t reg_index,
+                         const RegisterValue &value) override;
 
   Error DoReadWatchPointRegisterValue(lldb::tid_t tid, void *watch_readback);
 
Index: source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
===================================================================
--- source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
+++ source/Plugins/Process/Linux/NativeRegisterContextLinux_mips64.cpp
@@ -28,9 +28,16 @@
 #include "lldb/Host/HostInfo.h"
 #include "lldb/lldb-enumerations.h"
 #include "lldb/lldb-private-enumerations.h"
+
 #define NT_MIPS_MSA 0x600
 #define CONFIG5_FRE (1 << 8)
 #define SR_FR (1 << 26)
+#define FPR_BASE 32
+#define PC 64
+#define CAUSE 65
+#define BADVADDR 66
+#define MMHI 67
+#define MMLO 68
 #define NUM_REGISTERS 32
 
 #include <asm/ptrace.h>
@@ -466,21 +473,23 @@
   }
 
   if (IsFPR(reg_index) || IsMSA(reg_index)) {
-    uint8_t *dst;
-    uint64_t *src;
+    uint8_t *dst = nullptr;
+    uint64_t *src = nullptr;
+    uint8_t byte_size = reg_info->byte_size;
 
     // Initialise the FP and MSA buffers by reading all co-processor 1 registers
     ReadCP1();
 
     if (IsFPR(reg_index)) {
       assert(reg_info->byte_offset < sizeof(UserArea));
       dst = (uint8_t *)&m_fpr + reg_info->byte_offset - (sizeof(m_gpr));
+      byte_size = IsFR0() ? 4 : 8;
     } else {
       assert(reg_info->byte_offset < sizeof(UserArea));
       dst = (uint8_t *)&m_msa + reg_info->byte_offset -
             (sizeof(m_gpr) + sizeof(m_fpr));
     }
-    switch (reg_info->byte_size) {
+    switch (byte_size) {
     case 4:
       *(uint32_t *)dst = reg_value.GetAsUInt32();
       break;
@@ -611,11 +620,12 @@
 Error NativeRegisterContextLinux_mips64::ReadCP1() {
   Error error;
 
-  uint8_t *src, *dst;
+  uint8_t *src = nullptr;
+  uint8_t *dst = nullptr;
 
   lldb::ByteOrder byte_order = GetByteOrder();
 
-  uint32_t IsBigEndian = (byte_order == lldb::eByteOrderBig);
+  bool IsBigEndian = (byte_order == lldb::eByteOrderBig);
 
   if (IsMSAAvailable()) {
     error = NativeRegisterContextLinux::ReadRegisterSet(
@@ -637,11 +647,18 @@
 
   // TODO: Add support for FRE
   if (IsFR0()) {
-    src = (uint8_t *)&m_fpr + 4 + (IsBigEndian * 4);
-    dst = (uint8_t *)&m_fpr + 8 + (IsBigEndian * 4);
+    src = (uint8_t *)&m_fpr + (!IsBigEndian) * 4;
+    dst = (uint8_t *)&m_fpr + 8;
     for (int i = 0; i < (NUM_REGISTERS / 2); i++) {
       // copy odd single from top of neighbouring even double
+      // In case of little endian, 32 bit LSB store even FP register
+      // and 32 bit MSB store odd FP register
+      // vice-versa for big-endian
       *(uint32_t *)dst = *(uint32_t *)src;
+
+      if (IsBigEndian)
+        // Copy 32 bit MSB to 32 bit LSB
+        *(uint32_t *)src = *(uint32_t *)(src + 4);
       src = src + 16;
       dst = dst + 16;
     }
@@ -653,18 +670,23 @@
 Error NativeRegisterContextLinux_mips64::WriteCP1() {
   Error error;
 
-  uint8_t *src, *dst;
+  uint8_t *src = nullptr;
+  uint8_t *dst = nullptr;
 
   lldb::ByteOrder byte_order = GetByteOrder();
 
-  uint32_t IsBigEndian = (byte_order == lldb::eByteOrderBig);
+  bool IsBigEndian = (byte_order == lldb::eByteOrderBig);
 
   // TODO: Add support for FRE
   if (IsFR0()) {
-    src = (uint8_t *)&m_fpr + 8 + (IsBigEndian * 4);
-    dst = (uint8_t *)&m_fpr + 4 + (IsBigEndian * 4);
+    dst = (uint8_t *)&m_fpr + (!IsBigEndian) * 4;
+    src = dst + 8 - (!IsBigEndian) * 4;
     for (int i = 0; i < (NUM_REGISTERS / 2); i++) {
       // copy odd single to top of neighbouring even double
+      if (IsBigEndian)
+        // Copy 32 bit LSB to 32 bit MSB
+        *(uint32_t *)(dst + 4) = *(uint32_t *)dst;
+
       *(uint32_t *)dst = *(uint32_t *)src;
       src = src + 16;
       dst = dst + 16;
@@ -1132,50 +1154,92 @@
   }
   return num_valid;
 }
-Error NativeRegisterContextLinux_mips64::DoReadRegisterValue(
-    uint32_t offset, const char *reg_name, uint32_t size,
-    RegisterValue &value) {
-  GPR_linux_mips regs;
-  ::memset(&regs, 0, sizeof(GPR_linux_mips));
 
-  // Clear all bits in RegisterValue before writing actual value read from
-  // ptrace to avoid garbage value in 32-bit MSB
-  value.SetBytes((void *)(((unsigned char *)&regs) + offset), 8,
-                 GetByteOrder());
-  Error error = NativeProcessLinux::PtraceWrapper(
-      PTRACE_GETREGS, m_thread.GetID(), NULL, &regs, sizeof regs);
-  if (error.Success()) {
-    lldb_private::ArchSpec arch;
-    if (m_thread.GetProcess()->GetArchitecture(arch)) {
-      void *target_address = ((uint8_t *)&regs) + offset +
-                             4 * (arch.GetMachine() == llvm::Triple::mips);
-      uint32_t target_size;
-      if ((::strcmp(reg_name, "sr") == 0) ||
-          (::strcmp(reg_name, "cause") == 0) ||
-          (::strcmp(reg_name, "config5") == 0))
-        target_size = 4;
-      else
-        target_size =
-            arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8;
-      value.SetBytes(target_address, target_size, arch.GetByteOrder());
-    } else
-      error.SetErrorString("failed to get architecture");
+uint32_t NativeRegisterContextLinux_mips64::GetPtraceOffset(
+    uint32_t reg_index, const RegisterInfo *const reg_info) {
+  // In case of MIPS, the PTRACE_PEEKUSER/PTRACE_POKEUSER
+  // take register number has an offset
+  // Apart from GPR registers , the offset for other registers are
+  // FPR_BASE 32
+  // PC 64
+  // CAUSE 65
+  // BADVADDR 66
+  // MMHI 67
+  // MMLO 68
+
+  static_assert(dwarf_zero_mips == dwarf_zero_mips64 &&
+                    dwarf_pc_mips == dwarf_pc_mips64,
+                "MIPS and MIPS64 dwarf no. mismatch");
+
+  if (reg_index < dwarf_sr_mips)
+    return reg_index;
+
+  switch (reg_info->kinds[lldb::eRegisterKindDWARF]) {
+  case dwarf_pc_mips:
+    return PC;
+  case dwarf_sr_mips:
+  case dwarf_config5_mips:
+  case dwarf_config5_mips64:
+    return reg_info->byte_offset;
+  case dwarf_cause_mips:
+    return CAUSE;
+  case dwarf_bad_mips:
+    return BADVADDR;
+  case dwarf_hi_mips:
+    return MMHI;
+  case dwarf_lo_mips:
+    return MMLO;
+  default:
+    assert(false && "Invalid Register Kinds");
   }
-  return error;
+  return 0;
+}
+
+Error NativeRegisterContextLinux_mips64::ReadRegisterRaw(uint32_t reg_index,
+                                                         RegisterValue &value) {
+  const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+
+  if (!reg_info)
+    return Error("register %" PRIu32 " not found", reg_index);
+
+  uint32_t offset = GetPtraceOffset(reg_index, reg_info);
+
+  if ((reg_index == dwarf_sr_mips) || (strcmp(reg_info->name, "config5") == 0))
+    return Read_SR_Config(offset, reg_info->name, reg_info->byte_size, value);
+
+  return DoReadRegisterValue(offset, reg_info->name, reg_info->byte_size,
+                             value);
+}
+
+Error NativeRegisterContextLinux_mips64::WriteRegisterRaw(
+    uint32_t reg_index, const RegisterValue &value) {
+  const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+
+  if (!reg_info)
+    return Error("register %" PRIu32 " not found", reg_index);
+
+  if (reg_info->invalidate_regs)
+    assert(false && "In MIPS, reg_info->invalidate_regs is unhandled");
+
+  uint32_t offset = GetPtraceOffset(reg_index, reg_info);
+  return DoWriteRegisterValue(offset, reg_info->name, value);
 }
 
-Error NativeRegisterContextLinux_mips64::DoWriteRegisterValue(
-    uint32_t offset, const char *reg_name, const RegisterValue &value) {
+Error NativeRegisterContextLinux_mips64::Read_SR_Config(uint32_t offset,
+                                                        const char *reg_name,
+                                                        uint32_t size,
+                                                        RegisterValue &value) {
   GPR_linux_mips regs;
+  ::memset(&regs, 0, sizeof(GPR_linux_mips));
+
   Error error = NativeProcessLinux::PtraceWrapper(
       PTRACE_GETREGS, m_thread.GetID(), NULL, &regs, sizeof regs);
   if (error.Success()) {
     lldb_private::ArchSpec arch;
     if (m_thread.GetProcess()->GetArchitecture(arch)) {
-      ::memcpy((void *)(((unsigned char *)(&regs)) + offset), value.GetBytes(),
-               arch.GetFlags() & lldb_private::ArchSpec::eMIPSABI_O32 ? 4 : 8);
-      error = NativeProcessLinux::PtraceWrapper(
-          PTRACE_SETREGS, m_thread.GetID(), NULL, &regs, sizeof regs);
+      void *target_address = ((uint8_t *)&regs) + offset +
+                             4 * (arch.GetMachine() == llvm::Triple::mips);
+      value.SetUInt(*(uint32_t *)target_address, size);
     } else
       error.SetErrorString("failed to get architecture");
   }
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to