Index: lldb/source/Plugins/ABI/X86/ABIX86.h =================================================================== --- lldb/source/Plugins/ABI/X86/ABIX86.h +++ lldb/source/Plugins/ABI/X86/ABIX86.h @@ -17,6 +17,11 @@ static void Initialize(); static void Terminate(); +protected: + void AugmentRegisterInfo( + std::vector ®s, + bool is64bit); + private: using lldb_private::MCBasedABI::MCBasedABI; }; Index: lldb/source/Plugins/ABI/X86/ABIX86.cpp =================================================================== --- lldb/source/Plugins/ABI/X86/ABIX86.cpp +++ lldb/source/Plugins/ABI/X86/ABIX86.cpp @@ -6,13 +6,19 @@ // //===----------------------------------------------------------------------===// -#include "ABIX86.h" #include "ABIMacOSX_i386.h" #include "ABISysV_i386.h" #include "ABISysV_x86_64.h" #include "ABIWindows_x86_64.h" +#include "ABIX86.h" #include "lldb/Core/PluginManager.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; + LLDB_PLUGIN_DEFINE(ABIX86) void ABIX86::Initialize() { @@ -28,3 +34,224 @@ ABISysV_x86_64::Terminate(); ABIWindows_x86_64::Terminate(); } + +static void addPartialRegister(std::vector ®s, + uint32_t full_reg_index, uint32_t full_reg_size, + const std::string &partial_reg_name, + uint32_t partial_reg_size, + uint32_t offset = 0, + lldb::Encoding encoding = eEncodingInvalid, lldb::Format format = eFormatInvalid) { + DynamicRegisterInfo::Register &full_reg = regs[full_reg_index]; + if (full_reg.byte_size != full_reg_size) + return; + + lldb_private::DynamicRegisterInfo::Register partial_reg{ + lldb_private::ConstString(partial_reg_name), + lldb_private::ConstString(), + lldb_private::ConstString("supplementary registers"), + partial_reg_size, + LLDB_INVALID_INDEX32, + encoding != eEncodingInvalid ? encoding : full_reg.encoding, + format != eFormatInvalid ? format : full_reg.format, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + {full_reg_index}, + {}, + offset}; + + addSupplementaryRegister(regs, partial_reg); +} + +struct GPRReg { + uint32_t base_index = LLDB_INVALID_REGNUM; + std::string name32; + std::string name16; + std::string name8h; + std::string name8; + bool have32 = false; + bool have16 = false; + bool have8h = false; + bool have8 = false; +}; + +struct STReg { + uint32_t base_index = LLDB_INVALID_REGNUM; + std::string name_mm; + bool have_mm = false; +}; + +void ABIX86::AugmentRegisterInfo( + std::vector ®s, bool is64bit) { + MCBasedABI::AugmentRegisterInfo(regs); + + std::unordered_set gpr_basenames{ + {"ax", "bx", "cx", "dx", "si", "di", "bp", "sp"}}; + char gpr_base_reg_prefix = is64bit ? 'r' : 'e'; + uint32_t gpr_base_size = is64bit ? 8 : 4; + // regs from gpr_basenames, in list order + std::array gpr_base_reg_indices; + assert(gpr_base_reg_indices.size() == gpr_basenames.size()); + // r8..r15, sorted + std::array gpr_extra_reg_indices; + // st0..st7, sorted + std::array st_reg_indices; + // map used for fast register lookups + std::unordered_map reg_lookup_map; + + // find base registers and store their indices + // (note that with incorrect input we could get less than 8 regs) + size_t new_index = 0; + for (const auto &x : llvm::enumerate(regs)) { + const char *reg_name = x.value().name.AsCString(); + if (reg_name[0] == gpr_base_reg_prefix) { + // handle regs from gpr_basenames + auto in_basenames = gpr_basenames.find(reg_name + 1); + if (in_basenames != gpr_basenames.end() && + new_index < gpr_base_reg_indices.size()) { + GPRReg ®_rec = gpr_base_reg_indices[new_index++]; + reg_rec.base_index = x.index(); + + // construct derived register names + std::string new_regname{reg_name}; + if (is64bit) { + // 32-bit e* registers + new_regname[0] = 'e'; + reg_rec.name32 = new_regname; + reg_lookup_map[new_regname] = ®_rec.have32; + } + + // 16-bit * registers + new_regname.erase(new_regname.begin()); + reg_rec.name16 = new_regname; + reg_lookup_map[new_regname] = ®_rec.have16; + + if (new_regname[1] == 'x') { + // 8-bit [a-d]h registers + new_regname[1] = 'h'; + reg_rec.name8h = new_regname; + reg_lookup_map[new_regname] = ®_rec.have8h; + + // 8-bit [a-d]l registers + new_regname[1] = 'l'; + reg_rec.name8 = new_regname; + reg_lookup_map[new_regname] = ®_rec.have8; + } else { + // 8-bit sil/dil/spl/bpl registers + new_regname += 'l'; + reg_rec.name8 = new_regname; + reg_lookup_map[new_regname] = ®_rec.have8; + } + + continue; + } + + // handle r8..r15 regs + unsigned int suffix; + if (is64bit && llvm::to_integer(reg_name + 1, suffix, 10) && + suffix >= 8 && suffix < 16) { + GPRReg ®_rec = gpr_extra_reg_indices[suffix - 8]; + reg_rec.base_index = x.index(); + + // construct derived register names + std::string new_regname{reg_name}; + // 32-bit r*d registers + new_regname += 'd'; + reg_rec.name32 = new_regname; + reg_lookup_map[new_regname] = ®_rec.have32; + + // 16-bit r*w registers + new_regname.back() = 'w'; + reg_rec.name16 = new_regname; + reg_lookup_map[new_regname] = ®_rec.have16; + + // 8-bit r*l registers + new_regname.back() = 'l'; + reg_rec.name8 = new_regname; + reg_lookup_map[new_regname] = ®_rec.have8; + + continue; + } + } + + // st0..st7 regs + if (llvm::StringRef(reg_name).startswith("st")) { + unsigned int suffix; + if (llvm::to_integer(reg_name + 2, suffix, 10) && suffix < 8) { + STReg ®_rec = st_reg_indices[suffix]; + reg_rec.base_index = x.index(); + + std::string new_regname{"mm"}; + new_regname += llvm::utostr(suffix); + reg_rec.name_mm = new_regname; + reg_lookup_map[new_regname] = ®_rec.have_mm; + + continue; + } + } + } + + // find which registers we already have to avoid duplicates + for (const DynamicRegisterInfo::Register &x : regs) { + const char *reg_name = x.name.AsCString(); + auto found = reg_lookup_map.find(reg_name); + if (found != reg_lookup_map.end()) + *found->second = true; + } + + if (is64bit) { + // on amd64, add 32-bit e* registers + for (const GPRReg ® : gpr_base_reg_indices) { + if (reg.base_index != LLDB_INVALID_REGNUM && !reg.have32) + addPartialRegister(regs, reg.base_index, gpr_base_size, reg.name32, 4); + } + + // add 32-bit r*d registers + for (const GPRReg ® : gpr_extra_reg_indices) { + if (reg.base_index != LLDB_INVALID_REGNUM && !reg.have32) + addPartialRegister(regs, reg.base_index, gpr_base_size, reg.name32, 4); + } + } + + // add 16-bit * registers + for (const GPRReg ® : gpr_base_reg_indices) { + if (reg.base_index != LLDB_INVALID_REGNUM && !reg.have16) + addPartialRegister(regs, reg.base_index, gpr_base_size, reg.name16, 2); + } + + if (is64bit) { + // add 16-bit r*w registers + for (const GPRReg ® : gpr_extra_reg_indices) { + if (reg.base_index != LLDB_INVALID_REGNUM && !reg.have16) + addPartialRegister(regs, reg.base_index, gpr_base_size, reg.name16, 2); + } + } + + // add 8-bit *h registers + for (const GPRReg ® : gpr_base_reg_indices) { + if (reg.base_index != LLDB_INVALID_REGNUM && !reg.have8h && !reg.name8h.empty()) + addPartialRegister(regs, reg.base_index, gpr_base_size, reg.name8h, 1, 1); + } + + // add 8-bit *l registers + for (const GPRReg ® : gpr_base_reg_indices) { + if (reg.base_index != LLDB_INVALID_REGNUM && !reg.have8) + addPartialRegister(regs, reg.base_index, gpr_base_size, reg.name8, 1); + } + + if (is64bit) { + // add 8-bit r*l registers + for (const GPRReg ® : gpr_extra_reg_indices) { + if (reg.base_index != LLDB_INVALID_REGNUM && !reg.have8) + addPartialRegister(regs, reg.base_index, gpr_base_size, reg.name8, 1); + } + } + + // add mm registers + for (const STReg ® : st_reg_indices) { + if (reg.base_index != LLDB_INVALID_REGNUM && !reg.have_mm) + addPartialRegister(regs, reg.base_index, 10, reg.name_mm, 8, 0, + eEncodingUint, eFormatHex); + } +} Index: lldb/source/Plugins/ABI/X86/ABIX86_64.h =================================================================== --- lldb/source/Plugins/ABI/X86/ABIX86_64.h +++ lldb/source/Plugins/ABI/X86/ABIX86_64.h @@ -12,6 +12,11 @@ #include "Plugins/ABI/X86/ABIX86.h" class ABIX86_64 : public ABIX86 { + void AugmentRegisterInfo( + std::vector ®s) override { + ABIX86::AugmentRegisterInfo(regs, true); + } + protected: std::string GetMCName(std::string name) override { MapRegisterName(name, "stmm", "st"); Index: lldb/source/Plugins/ABI/X86/ABIX86_i386.h =================================================================== --- lldb/source/Plugins/ABI/X86/ABIX86_i386.h +++ lldb/source/Plugins/ABI/X86/ABIX86_i386.h @@ -15,6 +15,11 @@ public: uint32_t GetGenericNum(llvm::StringRef name) override; + void AugmentRegisterInfo( + std::vector ®s) override { + ABIX86::AugmentRegisterInfo(regs, false); + }; + private: using ABIX86::ABIX86; }; 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 @@ -163,6 +163,67 @@ ["xmm1 = {0x91 0x92 0x93 0x94 0x95 0x96 0x97 0x98 " "0x99 0x9a 0x9b 0x9c 0x9d 0x9e 0x9f 0xa0}"]) + # 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"]) + + # test writing into pseudo-registers + self.runCmd("register write ecx 0xfffefdfc") + reg_data[0] = "fcfdfeff05060708" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read rcx", + ["rcx = 0x08070605fffefdfc"]) + + self.runCmd("register write cx 0xfbfa") + reg_data[0] = "fafbfeff05060708" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read ecx", + ["ecx = 0xfffefbfa"]) + self.match("register read rcx", + ["rcx = 0x08070605fffefbfa"]) + + self.runCmd("register write ch 0xf9") + reg_data[0] = "faf9feff05060708" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read cx", + ["cx = 0xf9fa"]) + self.match("register read ecx", + ["ecx = 0xfffef9fa"]) + self.match("register read rcx", + ["rcx = 0x08070605fffef9fa"]) + + self.runCmd("register write cl 0xf8") + reg_data[0] = "f8f9feff05060708" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read cx", + ["cx = 0xf9f8"]) + self.match("register read ecx", + ["ecx = 0xfffef9f8"]) + self.match("register read rcx", + ["rcx = 0x08070605fffef9f8"]) + + self.runCmd("register write mm0 0xfffefdfcfbfaf9f8") + reg_data[10] = "f8f9fafbfcfdfeff090a" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read st0", + ["st0 = {0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff 0x09 0x0a}"]) + @skipIfXmlSupportMissing @skipIfRemote @skipIfLLVMTargetMissing("X86") @@ -272,11 +333,25 @@ # test generic aliases self.match("register read fp", ["ebp = 0x54535251"]) + self.match("register read sp", + ["esp = 0x44434241"]) self.match("register read pc", ["eip = 0x84838281"]) self.match("register read flags", ["eflags = 0x94939291"]) + # test pseudo-registers + self.match("register read cx", + ["cx = 0x1211"]) + self.match("register read ch", + ["ch = 0x12"]) + self.match("register read cl", + ["cl = 0x11"]) + 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}"]) @@ -289,6 +364,35 @@ ["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 cx 0xfbfa") + reg_data[1] = "fafb1314" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read ecx", + ["ecx = 0x1413fbfa"]) + + self.runCmd("register write ch 0xf9") + reg_data[1] = "faf91314" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read cx", + ["cx = 0xf9fa"]) + self.match("register read ecx", + ["ecx = 0x1413f9fa"]) + + self.runCmd("register write cl 0xf8") + reg_data[1] = "f8f91314" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read cx", + ["cx = 0xf9f8"]) + self.match("register read ecx", + ["ecx = 0x1413f9f8"]) + + self.runCmd("register write mm0 0xfffefdfcfbfaf9f8") + reg_data[10] = "f8f9fafbfcfdfeff090a" + self.assertPacketLogContains(["G" + "".join(reg_data)]) + self.match("register read st0", + ["st0 = {0xf8 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff 0x09 0x0a}"]) + @skipIfXmlSupportMissing @skipIfRemote @skipIfLLVMTargetMissing("AArch64")