mgorny created this revision.
mgorny added reviewers: krytarowski, jasonmolenda, JDevlieghere, labath, emaste.
Herald added a subscriber: pengfei.
mgorny requested review of this revision.

Add a pre- and post-finalize hooks to GDBRemoteRegisterContext that add
missing pseudo-register on x86_64.  This is necessary since -- unlike
lldb-server -- gdbserver does not include pseudo-registers in its target
definitions.  Both hooks are implemented in a separate file for x86_64,
and can be easily defined for other architectures.

The pre-finalize hook checks whether appropriate x86_64 pseudo-registers
are defined (e.g. the EAX, AX, AH, AL, MMi registers, etc.).  If they
are not, it defines them referring to the full registers via value_regs
field.

Then, the already-present logic in the finalize function sets
appropriate offsets based on the value_regs linking.  The exception to
that are the AH..DH registers which carry the offsets of AL..DL at this
point due to the limitation of value_regs logic.

Finally, the post-finalize hook takes care of adjusting the offsets
of AH..DH registers.  While technically this could be resolved via some
generic logic in RegisterInfo, given it applies only to a 4 very
specific registers, it seemed cleaner not to require global LLDB changes
and instead perform the fixup in a hook.


https://reviews.llvm.org/D108831

Files:
  lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext_x86_64.cpp
  lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py

Index: lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py
===================================================================
--- lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py
+++ lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py
@@ -9,8 +9,8 @@
 
     @skipIfXmlSupportMissing
     @skipIfRemote
-    def test_x86_64_vec_regs(self):
-        """Test rendering of x86_64 vector registers from gdbserver."""
+    def test_x86_64_regs(self):
+        """Test grabbing various x86_64 registers from gdbserver."""
         class MyResponder(MockGDBServerResponder):
             def qXferRead(self, obj, annex, offset, length):
                 if annex == "target.xml":
@@ -112,8 +112,6 @@
                    ["rdi = 0x3837363534333231"])
         self.match("register read fp",
                    ["rbp = 0x4847464544434241"])
-        self.match("register read sp",
-                   ["rsp = 0x5857565554535251"])
         self.match("register read arg5",
                    ["r8 = 0x6867666564636261"])
         self.match("register read arg6",
@@ -123,6 +121,26 @@
         self.match("register read flags",
                    ["eflags = 0x94939291"])
 
+        # test pseudo-registers
+        self.match("register read ecx",
+                   ["ecx = 0x04030201"])
+        self.match("register read cx",
+                   ["cx = 0x0201"])
+        self.match("register read ch",
+                   ["ch = 0x02"])
+        self.match("register read cl",
+                   ["cl = 0x01"])
+        self.match("register read r8d",
+                   ["r8d = 0x64636261"])
+        self.match("register read r8w",
+                   ["r8w = 0x6261"])
+        self.match("register read r8l",
+                   ["r8l = 0x61"])
+        self.match("register read mm0",
+                   ["mm0 = 0x0807060504030201"])
+        self.match("register read mm1",
+                   ["mm1 = 0x1817161514131211"])
+
         # both stX and xmmX should be displayed as vectors
         self.match("register read st0",
                    ["st0 = {0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a}"])
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext_x86_64.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext_x86_64.cpp
@@ -0,0 +1,195 @@
+//===-- GDBRemoteRegisterContext.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteRegisterContext.h"
+
+#include "Plugins/Process/Utility/lldb-x86-register-enums.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+
+enum PartialGPRRegKind {
+  eRegKind32,
+  eRegKind16,
+  eRegKind8h,
+  eRegKind8l,
+
+  eRegKindCount
+};
+
+struct PartialGPRReg {
+  const char *name;
+
+  // extra storage used for pointers
+  uint32_t value_regs[2];
+  uint32_t invalidate_regs[eRegKindCount];
+};
+
+struct PartialGPRRegSet {
+  const char *reg64;
+  PartialGPRReg r[eRegKindCount];
+};
+
+static std::array<PartialGPRRegSet, 16> partial_gpr_regs = {{
+    {"rax", {{"eax"}, {"ax"}, {"ah"}, {"al"}}},
+    {"rbx", {{"ebx"}, {"bx"}, {"bh"}, {"bl"}}},
+    {"rcx", {{"ecx"}, {"cx"}, {"ch"}, {"cl"}}},
+    {"rdx", {{"edx"}, {"dx"}, {"dh"}, {"dl"}}},
+    {"rdi", {{"edi"}, {"di"}, {nullptr}, {"dil"}}},
+    {"rsi", {{"esi"}, {"si"}, {nullptr}, {"sil"}}},
+    {"rbp", {{"ebp"}, {"bp"}, {nullptr}, {"bpl"}}},
+    {"rsp", {{"esp"}, {"sp"}, {nullptr}, {"spl"}}},
+    {"r8", {{"r8d"}, {"r8w"}, {nullptr}, {"r8l"}}},
+    {"r9", {{"r9d"}, {"r9w"}, {nullptr}, {"r9l"}}},
+    {"r10", {{"r10d"}, {"r10w"}, {nullptr}, {"r10l"}}},
+    {"r11", {{"r11d"}, {"r11w"}, {nullptr}, {"r11l"}}},
+    {"r12", {{"r12d"}, {"r12w"}, {nullptr}, {"r12l"}}},
+    {"r13", {{"r13d"}, {"r13w"}, {nullptr}, {"r13l"}}},
+    {"r14", {{"r14d"}, {"r14w"}, {nullptr}, {"r14l"}}},
+    {"r15", {{"r15d"}, {"r15w"}, {nullptr}, {"r15l"}}},
+}};
+
+static uint32_t partial_gpr_sizes[eRegKindCount] = {4, 2, 1, 1};
+
+struct MMReg {
+  const char *streg;
+  const char *name;
+
+  // extra storage used for pointers
+  uint32_t value_regs[2];
+};
+
+static std::array<MMReg, 16> mm_regs = {{
+    {"st0", "mm0"},
+    {"st1", "mm1"},
+    {"st2", "mm2"},
+    {"st3", "mm3"},
+    {"st4", "mm4"},
+    {"st5", "mm5"},
+    {"st6", "mm6"},
+    {"st7", "mm7"},
+}};
+
+void GDBRemoteDynamicRegisterInfo::PreFinalize_x86_64() {
+  uint32_t max_regnum = 0;
+  uint32_t next_regindex = m_regs.size();
+  for (const RegisterInfo &reg : m_regs)
+    max_regnum = std::max(max_regnum, reg.kinds[eRegisterKindProcessPlugin]);
+
+  ConstString group;
+  group.SetCString("partial registers");
+
+  for (PartialGPRRegSet &partial_regset : partial_gpr_regs) {
+    const RegisterInfo *reg64 = GetRegisterInfo(partial_regset.reg64);
+    if (!reg64)
+      continue;
+    assert(reg64->byte_size == 8);
+
+    const RegisterInfo *reginfo[eRegKindCount];
+    uint32_t regno[eRegKindCount];
+
+    for (int i = 0; i < eRegKindCount; i++) {
+      if (!partial_regset.r[i].name)
+        continue;
+
+      reginfo[i] = GetRegisterInfo(partial_regset.r[i].name);
+      if (reginfo[i])
+        regno[i] = reginfo[i]->kinds[eRegisterKindProcessPlugin];
+      else
+        regno[i] = ++max_regnum;
+    }
+
+    for (int i = 0; i < eRegKindCount; i++) {
+      if (!partial_regset.r[i].name)
+        continue;
+
+      partial_regset.r[i].value_regs[0] =
+          reg64->kinds[eRegisterKindProcessPlugin];
+      partial_regset.r[i].value_regs[1] = LLDB_INVALID_REGNUM;
+
+      int k = 0;
+      for (int j = 0; j < eRegKindCount; j++) {
+        if (i != j && partial_regset.r[j].name)
+          partial_regset.r[i].invalidate_regs[k++] = regno[j];
+      }
+      partial_regset.r[i].invalidate_regs[k] = LLDB_INVALID_REGNUM;
+
+      struct RegisterInfo new_reg {
+        partial_regset.r[i].name, nullptr, partial_gpr_sizes[i],
+            LLDB_INVALID_INDEX32, reg64->encoding, reg64->format,
+            {
+                LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+                LLDB_INVALID_REGNUM, regno[i],
+                next_regindex++,
+            },
+            partial_regset.r[i].value_regs, partial_regset.r[i].invalidate_regs,
+            nullptr, 0
+      };
+
+      ConstString name;
+      ConstString alt_name;
+      name.SetCString(new_reg.name);
+      AddRegister(new_reg, name, alt_name, group);
+    }
+  }
+
+  for (MMReg &mmreg : mm_regs) {
+    const RegisterInfo *streg = GetRegisterInfo(mmreg.streg);
+    if (!streg)
+      continue;
+    assert(streg->byte_size == 10);
+
+    if (GetRegisterInfo(mmreg.name))
+      continue;
+
+    mmreg.value_regs[0] = streg->kinds[eRegisterKindProcessPlugin];
+    mmreg.value_regs[1] = LLDB_INVALID_REGNUM;
+
+    struct RegisterInfo new_reg {
+      mmreg.name, nullptr, 8, LLDB_INVALID_INDEX32, eEncodingUint, eFormatHex,
+          {
+              LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,
+              ++max_regnum,        next_regindex++,
+          },
+          mmreg.value_regs, nullptr, nullptr, 0
+    };
+
+    ConstString name;
+    ConstString alt_name;
+    name.SetCString(new_reg.name);
+    AddRegister(new_reg, name, alt_name, group);
+  }
+}
+
+void GDBRemoteDynamicRegisterInfo::PostFinalize_x86_64() {
+  for (PartialGPRRegSet &partial_regset : partial_gpr_regs) {
+    if (!partial_regset.r[eRegKind8h].name)
+      continue;
+
+    llvm::StringRef reg8h_name = partial_regset.r[eRegKind8h].name;
+    const RegisterInfo *reg8h = GetRegisterInfo(reg8h_name);
+    const RegisterInfo *reg8l =
+        GetRegisterInfo(partial_regset.r[eRegKind8l].name);
+    if (!reg8h || !reg8l)
+      continue;
+    assert(reg8h->byte_size == 1);
+    assert(reg8l->byte_size == 1);
+
+    // we currently have no way of indicating offset via value_regs, so we
+    // instead increment it after Finalize() assigns byte offsets
+    if (reg8h->byte_offset == reg8l->byte_offset) {
+      for (auto &reg_info : m_regs) {
+        if (reg_info.name == reg8h_name) {
+          reg_info.byte_offset++;
+          break;
+        }
+      }
+    }
+  }
+}
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -40,6 +40,10 @@
 
   void HardcodeARMRegisters(bool from_scratch);
   bool UpdateARM64SVERegistersInfos(uint64_t vg);
+  void Finalize(const lldb_private::ArchSpec &arch);
+
+  void PreFinalize_x86_64();
+  void PostFinalize_x86_64();
 };
 
 class GDBRemoteRegisterContext : public RegisterContext {
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -1064,3 +1064,28 @@
     }
   }
 }
+
+void GDBRemoteDynamicRegisterInfo::Finalize(const ArchSpec &arch) {
+  if (m_finalized)
+    return;
+
+  switch (arch.GetMachine()) {
+  case llvm::Triple::x86_64:
+    PreFinalize_x86_64();
+    break;
+
+  default:
+    break;
+  }
+
+  DynamicRegisterInfo::Finalize(arch);
+
+  switch (arch.GetMachine()) {
+  case llvm::Triple::x86_64:
+    PostFinalize_x86_64();
+    break;
+
+  default:
+    break;
+  }
+}
Index: lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt
+++ lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt
@@ -26,6 +26,7 @@
   GDBRemoteCommunicationServerLLGS.cpp
   GDBRemoteCommunicationServerPlatform.cpp
   GDBRemoteRegisterContext.cpp
+  GDBRemoteRegisterContext_x86_64.cpp
   ProcessGDBRemote.cpp
   ProcessGDBRemoteLog.cpp
   ThreadGDBRemote.cpp
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to