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,10 @@ static void Initialize(); static void Terminate(); +protected: + void AugmentRegisterInfo( + std::vector ®s) override; + 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,12 +6,16 @@ // //===----------------------------------------------------------------------===// -#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 "lldb/Target/Process.h" + +using namespace lldb; +using namespace lldb_private; LLDB_PLUGIN_DEFINE(ABIX86) @@ -28,3 +32,141 @@ ABISysV_x86_64::Terminate(); ABIWindows_x86_64::Terminate(); } + +enum class RegKind { + GPR32 = 0, + GPR16, + GPR8h, + GPR8, + + MM = 0, +}; + +typedef llvm::SmallDenseMap, 16> + RegisterMap; + +static void addPartialRegisters( + std::vector ®s, + llvm::ArrayRef base_reg_indices, RegisterMap reg_names, + uint32_t base_size, RegKind name_index, lldb::Encoding encoding, + lldb::Format format, uint32_t subreg_size, uint32_t subreg_offset = 0) { + for (uint32_t base_index : base_reg_indices) { + if (base_index == LLDB_INVALID_REGNUM) + break; + assert(base_index < regs.size()); + DynamicRegisterInfo::Register &full_reg = regs[base_index]; + const llvm::StringRef &subreg_name = + reg_names[full_reg.name.AsCString()][static_cast(name_index)]; + if (subreg_name.empty() || full_reg.byte_size != base_size) + continue; + + lldb_private::DynamicRegisterInfo::Register subreg{ + lldb_private::ConstString(subreg_name), + lldb_private::ConstString(), + lldb_private::ConstString("supplementary registers"), + subreg_size, + LLDB_INVALID_INDEX32, + encoding, + format, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + {base_index}, + {}, + subreg_offset}; + + addSupplementaryRegister(regs, subreg); + } +} + +void ABIX86::AugmentRegisterInfo( + std::vector ®s) { + MCBasedABI::AugmentRegisterInfo(regs); + + ProcessSP process_sp = GetProcessSP(); + if (!process_sp) + return; + + bool is64bit = + process_sp->GetTarget().GetArchitecture().GetAddressByteSize() == 8; + uint32_t gpr_base_size = is64bit ? 8 : 4; + + typedef RegisterMap::value_type RegPair; +#define GPR_BASE(basename) (is64bit ? "r" basename : "e" basename) + RegisterMap gpr_regs{{ + RegPair(GPR_BASE("ax"), {"eax", "ax", "ah", "al"}), + RegPair(GPR_BASE("bx"), {"ebx", "bx", "bh", "bl"}), + RegPair(GPR_BASE("cx"), {"ecx", "cx", "ch", "cl"}), + RegPair(GPR_BASE("dx"), {"edx", "dx", "dh", "dl"}), + RegPair(GPR_BASE("si"), {"esi", "si", "", "sil"}), + RegPair(GPR_BASE("di"), {"edi", "di", "", "dil"}), + RegPair(GPR_BASE("bp"), {"ebp", "bp", "", "bpl"}), + RegPair(GPR_BASE("sp"), {"esp", "sp", "", "spl"}), + }}; +#undef GPR_BASE + if (is64bit) { +#define R(base) RegPair(base, {base "d", base "w", "", base "l"}) + RegisterMap amd64_regs{{ + R("r8"), + R("r9"), + R("r10"), + R("r11"), + R("r12"), + R("r13"), + R("r14"), + R("r15"), + }}; +#undef R + gpr_regs.insert(amd64_regs.begin(), amd64_regs.end()); + } + + RegisterMap st_regs{{ + RegPair("st0", {"mm0"}), + RegPair("st1", {"mm1"}), + RegPair("st2", {"mm2"}), + RegPair("st3", {"mm3"}), + RegPair("st4", {"mm4"}), + RegPair("st5", {"mm5"}), + RegPair("st6", {"mm6"}), + RegPair("st7", {"mm7"}), + }}; + + // regs from gpr_basenames, in list order + std::vector gpr_base_reg_indices; + // st0..st7, in list order + std::vector st_reg_indices; + // map used for fast register lookups + llvm::SmallDenseSet subreg_name_set; + + // put all subreg names into the lookup set + for (const RegisterMap ®set : {gpr_regs, st_regs}) { + for (const RegPair &kv : regset) + subreg_name_set.insert(kv.second.begin(), kv.second.end()); + } + + for (const auto &x : llvm::enumerate(regs)) { + const char *reg_name = x.value().name.AsCString(); + // find expected base registers + if (gpr_regs.find(reg_name) != gpr_regs.end()) + gpr_base_reg_indices.push_back(x.index()); + else if (st_regs.find(reg_name) != st_regs.end()) + st_reg_indices.push_back(x.index()); + // abort if at least one sub-register is already present + else if (llvm::is_contained(subreg_name_set, reg_name)) + return; + } + + if (is64bit) + addPartialRegisters(regs, gpr_base_reg_indices, gpr_regs, gpr_base_size, + RegKind::GPR32, eEncodingUint, eFormatHex, 4); + addPartialRegisters(regs, gpr_base_reg_indices, gpr_regs, gpr_base_size, + RegKind::GPR16, eEncodingUint, eFormatHex, 2); + addPartialRegisters(regs, gpr_base_reg_indices, gpr_regs, gpr_base_size, + RegKind::GPR8h, eEncodingUint, eFormatHex, 1, 1); + addPartialRegisters(regs, gpr_base_reg_indices, gpr_regs, gpr_base_size, + RegKind::GPR8, eEncodingUint, eFormatHex, 1); + + addPartialRegisters(regs, st_reg_indices, st_regs, 10, RegKind::MM, + eEncodingUint, eFormatHex, 8); +} 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")