mgorny updated this revision to Diff 369421.
mgorny added a comment.
Add writing tests.
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D108831/new/
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,32 @@
@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."""
+ reg_data = [
+ "0102030405060708", # rcx
+ "1112131415161718", # rdx
+ "2122232425262728", # rsi
+ "3132333435363738", # rdi
+ "4142434445464748", # rbp
+ "5152535455565758", # rsp
+ "6162636465666768", # r8
+ "7172737475767778", # r9
+ "8182838485868788", # rip
+ "91929394", # eflags
+ "0102030405060708090a", # st0
+ "1112131415161718191a", # st1
+ ] + 6 * [
+ "2122232425262728292a" # st2..st7
+ ] + [
+ "8182838485868788898a8b8c8d8e8f90", # xmm0
+ "9192939495969798999a9b9c9d9e9fa0", # xmm1
+ ] + 14 * [
+ "a1a2a3a4a5a6a7a8a9aaabacadaeafb0", # xmm2..xmm15
+ ] + [
+ "00000000", # mxcsr
+ ]
+
class MyResponder(MockGDBServerResponder):
def qXferRead(self, obj, annex, offset, length):
if annex == "target.xml":
@@ -66,25 +90,10 @@
return ""
def readRegisters(self):
- return (
- "0102030405060708" # rcx
- "1112131415161718" # rdx
- "2122232425262728" # rsi
- "3132333435363738" # rdi
- "4142434445464748" # rbp
- "5152535455565758" # rsp
- "6162636465666768" # r8
- "7172737475767778" # r9
- "8182838485868788" # rip
- "91929394" # eflags
- "0102030405060708090a" # st0
- "1112131415161718191a" + # st1
- "2122232425262728292a" * 6 + # st2..st7
- "8182838485868788898a8b8c8d8e8f90" # xmm0
- "9192939495969798999a9b9c9d9e9fa0" # xmm1
- "a1a2a3a4a5a6a7a8a9aaabacadaeafb0" * 14 + # xmm2..xmm15
- "00000000" # mxcsr
- )
+ return "".join(reg_data)
+
+ def writeRegisters(self, reg_hex):
+ return "OK"
def haltReason(self):
return "T02thread:1ff0d;threads:1ff0d;thread-pcs:000000010001bc00;07:0102030405060708;10:1112131415161718;"
@@ -113,8 +122,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",
@@ -124,6 +131,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}"])
@@ -135,3 +162,20 @@
self.match("register read xmm1",
["xmm1 = {0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 "
"0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 0xa0}"])
+
+ # test writing into pseudo-registers
+ self.runCmd("register write ecx 0xfffefdfc")
+ reg_data[0] = "fcfdfeff05060708"
+ self.assertPacketLogContains(["G" + "".join(reg_data)])
+ self.runCmd("register write cx 0xfbfa")
+ reg_data[0] = "fafbfeff05060708"
+ self.assertPacketLogContains(["G" + "".join(reg_data)])
+ self.runCmd("register write ch 0xf9")
+ reg_data[0] = "faf9feff05060708"
+ self.assertPacketLogContains(["G" + "".join(reg_data)])
+ self.runCmd("register write cl 0xf8")
+ reg_data[0] = "f8f9feff05060708"
+ self.assertPacketLogContains(["G" + "".join(reg_data)])
+ self.runCmd("register write mm0 0xfffefdfcfbfaf9f8")
+ reg_data[10] = "f8f9fafbfcfdfeff090a"
+ self.assertPacketLogContains(["G" + "".join(reg_data)])
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,193 @@
+//===-- 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"
+
+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 ® : 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 ®_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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits