diff --git a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp --- a/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp +++ b/lldb/source/Plugins/ABI/AArch64/ABIAArch64.cpp @@ -13,6 +13,8 @@ #include "lldb/Core/PluginManager.h" #include "lldb/Target/Process.h" +#include + LLDB_PLUGIN_DEFINE(ABIAArch64) void ABIAArch64::Initialize() { @@ -71,14 +73,81 @@ .Default(LLDB_INVALID_REGNUM); } +static void addPartialRegisters( + std::vector ®s, + llvm::ArrayRef> full_reg_indices, + uint32_t full_reg_size, const char *partial_reg_format, + uint32_t partial_reg_size, lldb::Encoding encoding, lldb::Format format) { + for (auto it : llvm::enumerate(full_reg_indices)) { + llvm::Optional full_reg_index = it.value(); + if (!full_reg_index || + regs[full_reg_index.getValue()].byte_size != full_reg_size) + return; + + lldb_private::DynamicRegisterInfo::Register partial_reg{ + lldb_private::ConstString( + llvm::formatv(partial_reg_format, it.index()).str()), + lldb_private::ConstString(), + lldb_private::ConstString("supplementary registers"), + partial_reg_size, + LLDB_INVALID_INDEX32, + encoding, + format, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + LLDB_INVALID_REGNUM, + {full_reg_index.getValue()}, + {}}; + addSupplementaryRegister(regs, partial_reg); + } +} + void ABIAArch64::AugmentRegisterInfo( std::vector ®s) { lldb_private::MCBasedABI::AugmentRegisterInfo(regs); lldb_private::ConstString sp_string{"sp"}; - for (lldb_private::DynamicRegisterInfo::Register &info : regs) { + + std::array, 32> x_regs; + std::array, 32> v_regs; + std::bitset<32> have_w_regs; + std::bitset<32> have_s_regs; + std::bitset<32> have_d_regs; + + for (auto it : llvm::enumerate(regs)) { + lldb_private::DynamicRegisterInfo::Register &info = it.value(); // GDB sends x31 as "sp". Add the "x31" alt_name for convenience. if (info.name == sp_string && !info.alt_name) info.alt_name.SetCString("x31"); + + unsigned int reg_num; + auto get_reg = [&info, ®_num](const char *prefix) { + llvm::StringRef reg_name = info.name.GetStringRef(); + llvm::StringRef alt_name = info.alt_name.GetStringRef(); + return (reg_name.consume_front(prefix) && + llvm::to_integer(reg_name, reg_num, 10) && reg_num < 32) || + (alt_name.consume_front(prefix) && + llvm::to_integer(alt_name, reg_num, 10) && reg_num < 32); + }; + + if (get_reg("x")) + x_regs[reg_num] = it.index(); + if (get_reg("v")) + v_regs[reg_num] = it.index(); + if (get_reg("w")) + have_w_regs[reg_num] = true; + if (get_reg("s")) + have_s_regs[reg_num] = true; + if (get_reg("d")) + have_d_regs[reg_num] = true; } + + // Create aliases for partial registers: wN for xN, and sN/dN for vN. + addPartialRegisters(regs, x_regs, 8, "w{0}", 4, lldb::eEncodingUint, + lldb::eFormatHex); + addPartialRegisters(regs, v_regs, 16, "s{0}", 4, lldb::eEncodingIEEE754, + lldb::eFormatFloat); + addPartialRegisters(regs, v_regs, 16, "d{0}", 8, lldb::eEncodingIEEE754, + lldb::eFormatFloat); } diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py b/lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py --- a/lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestGDBServerTargetXML.py @@ -270,27 +270,27 @@ @skipIfLLVMTargetMissing("AArch64") def test_aarch64_regs(self): """Test grabbing various aarch64 registers from gdbserver.""" - reg_data = [ - "0102030405060708", # x0 - "1112131415161718", # x1 - ] + 27 * [ - "2122232425262728", # x2..x28 - ] + [ - "3132333435363738", # x29 (fp) - "4142434445464748", # x30 (lr) - "5152535455565758", # x31 (sp) - "6162636465666768", # pc - "71727374", # cpsr - "8182838485868788898a8b8c8d8e8f90", # v0 - "9192939495969798999a9b9c9d9e9fa0", # v1 - ] + 30 * [ - "a1a2a3a4a5a6a7a8a9aaabacadaeafb0", # v2..v31 - ] + [ - "00000000", # fpsr - "00000000", # fpcr - ] - class MyResponder(MockGDBServerResponder): + reg_data = ( + "0102030405060708" # x0 + "1112131415161718" # x1 + ) + 27 * ( + "2122232425262728" # x2..x28 + ) + ( + "3132333435363738" # x29 (fp) + "4142434445464748" # x30 (lr) + "5152535455565758" # x31 (sp) + "6162636465666768" # pc + "71727374" # cpsr + "8182838485868788898a8b8c8d8e8f90" # v0 + "9192939495969798999a9b9c9d9e9fa0" # v1 + ) + 30 * ( + "a1a2a3a4a5a6a7a8a9aaabacadaeafb0" # v2..v31 + ) + ( + "00000000" # fpsr + "00000000" # fpcr + ) + def qXferRead(self, obj, annex, offset, length): if annex == "target.xml": return """ @@ -377,9 +377,10 @@ return "" def readRegisters(self): - return "".join(reg_data) + return self.reg_data def writeRegisters(self, reg_hex): + self.reg_data = reg_hex return "OK" def haltReason(self): @@ -429,3 +430,43 @@ ["v0 = {0x81 0x82 0x83 0x84 0x85 0x86 0x87 0x88 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 0x90}"]) self.match("register read v31", ["v31 = {0xa1 0xa2 0xa3 0xa4 0xa5 0xa6 0xa7 0xa8 0xa9 0xaa 0xab 0xac 0xad 0xae 0xaf 0xb0}"]) + + # test partial registers + self.match("register read w0", + ["w0 = 0x04030201"]) + self.runCmd("register write w0 0xfffefdfc") + self.match("register read x0", + ["x0 = 0x08070605fffefdfc"]) + + self.match("register read w1", + ["w1 = 0x14131211"]) + self.runCmd("register write w1 0xefeeedec") + self.match("register read x1", + ["x1 = 0x18171615efeeedec"]) + + self.match("register read w30", + ["w30 = 0x44434241"]) + self.runCmd("register write w30 0xdfdedddc") + self.match("register read x30", + ["x30 = 0x48474645dfdedddc"]) + + self.match("register read w31", + ["w31 = 0x54535251"]) + self.runCmd("register write w31 0xcfcecdcc") + self.match("register read x31", + ["sp = 0x58575655cfcecdcc"]) + + # test FPU registers (overlapping with vector registers) + self.runCmd("register write d0 16") + self.match("register read v0", + ["v0 = {0x00 0x00 0x00 0x00 0x00 0x00 0x30 0x40 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 0x90}"]) + self.runCmd("register write v31 '{0x00 0x00 0x00 0x00 0x00 0x00 0x50 0x40 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff}'") + self.match("register read d31", + ["d31 = 64"]) + + self.runCmd("register write s0 32") + self.match("register read v0", + ["v0 = {0x00 0x00 0x00 0x42 0x00 0x00 0x30 0x40 0x89 0x8a 0x8b 0x8c 0x8d 0x8e 0x8f 0x90}"]) + self.runCmd("register write v31 '{0x00 0x00 0x00 0x43 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff}'") + self.match("register read s31", + ["s31 = 128"])