diff --git a/lldb/include/lldb/Host/common/NativeRegisterContext.h b/lldb/include/lldb/Host/common/NativeRegisterContext.h --- a/lldb/include/lldb/Host/common/NativeRegisterContext.h +++ b/lldb/include/lldb/Host/common/NativeRegisterContext.h @@ -121,6 +121,8 @@ virtual std::vector GetExpeditedRegisters(ExpeditedRegs expType) const; + virtual bool RegisterOffsetIsDynamic() const { return false; } + const RegisterInfo *GetRegisterInfoByName(llvm::StringRef reg_name, uint32_t start_idx = 0); diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-server/gdbremote_testcase.py @@ -664,7 +664,10 @@ # Check the bare-minimum expected set of register info keys. self.assertTrue("name" in reg_info) self.assertTrue("bitsize" in reg_info) - self.assertTrue("offset" in reg_info) + + if not self.getArchitecture() == 'aarch64': + self.assertTrue("offset" in reg_info) + self.assertTrue("encoding" in reg_info) self.assertTrue("format" in reg_info) diff --git a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h --- a/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h +++ b/lldb/source/Plugins/Process/Linux/NativeRegisterContextLinux_arm64.h @@ -47,6 +47,8 @@ std::vector GetExpeditedRegisters(ExpeditedRegs expType) const override; + bool RegisterOffsetIsDynamic() const override { return true; } + // Hardware breakpoints/watchpoint management functions uint32_t NumSupportedHardwareBreakpoints() override; diff --git a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp --- a/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp +++ b/lldb/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp @@ -428,9 +428,6 @@ assert(set < m_set_reg_nums.size()); assert(set < m_set_names.size()); m_set_reg_nums[set].push_back(reg_num); - size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size; - if (m_reg_data_byte_size < end_reg_offset) - m_reg_data_byte_size = end_reg_offset; } void DynamicRegisterInfo::Finalize(const ArchSpec &arch) { @@ -445,6 +442,28 @@ m_sets[set].registers = m_set_reg_nums[set].data(); } + // We are going to create a map between remote (eRegisterKindProcessPlugin) + // and local (eRegisterKindLLDB) register numbers. This map will give us + // remote register numbers in increasing order for offset calculation. + std::map remote_to_local_regnum_map; + for (const auto ® : m_regs) + remote_to_local_regnum_map[reg.kinds[eRegisterKindProcessPlugin]] = + reg.kinds[eRegisterKindLLDB]; + + // At this stage we manually calculate g/G packet offsets of all primary + // registers, only if target XML or qRegisterInfo packet did not send + // an offset explicitly. + uint32_t reg_offset = 0; + for (auto const ®num_pair : remote_to_local_regnum_map) { + if (m_regs[regnum_pair.second].byte_offset == LLDB_INVALID_INDEX32 && + m_regs[regnum_pair.second].value_regs == nullptr) { + m_regs[regnum_pair.second].byte_offset = reg_offset; + + reg_offset = m_regs[regnum_pair.second].byte_offset + + m_regs[regnum_pair.second].byte_size; + } + } + // sort and unique all value registers and make sure each is terminated with // LLDB_INVALID_REGNUM @@ -466,10 +485,24 @@ // Now update all value_regs with each register info as needed const size_t num_regs = m_regs.size(); for (size_t i = 0; i < num_regs; ++i) { - if (m_value_regs_map.find(i) != m_value_regs_map.end()) + if (m_value_regs_map.find(i) != m_value_regs_map.end()) { m_regs[i].value_regs = m_value_regs_map[i].data(); - else + // Assign a valid offset to all pseudo registers if not assigned by stub. + // Pseudo registers with value_regs list populated will share same offset + // as that of their corresponding primary register in value_regs list. + if (m_regs[i].byte_offset == LLDB_INVALID_INDEX32) { + uint32_t value_regnum = m_regs[i].value_regs[0]; + if (value_regnum != LLDB_INVALID_INDEX32) + m_regs[i].byte_offset = + GetRegisterInfoAtIndex(remote_to_local_regnum_map[value_regnum]) + ->byte_offset; + } + } else m_regs[i].value_regs = nullptr; + + reg_offset = m_regs[i].byte_offset + m_regs[i].byte_size; + if (m_reg_data_byte_size < reg_offset) + m_reg_data_byte_size = reg_offset; } // Expand all invalidation dependencies diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -1788,8 +1788,10 @@ response.PutChar(';'); } - response.Printf("bitsize:%" PRIu32 ";offset:%" PRIu32 ";", - reg_info->byte_size * 8, reg_info->byte_offset); + response.Printf("bitsize:%" PRIu32 ";", reg_info->byte_size * 8); + + if (!reg_context.RegisterOffsetIsDynamic()) + response.Printf("offset:%" PRIu32 ";", reg_info->byte_offset); llvm::StringRef encoding = GetEncodingNameOrEmpty(*reg_info); if (!encoding.empty()) @@ -2861,10 +2863,11 @@ continue; } - response.Printf("name, reg_info->byte_size * 8, - reg_info->byte_offset, reg_index); + response.Printf("name, reg_info->byte_size * 8, reg_index); + + if (!reg_context.RegisterOffsetIsDynamic()) + response.Printf("offset=\"%" PRIu32 "\" ", reg_info->byte_offset); if (reg_info->alt_name && reg_info->alt_name[0]) response.Printf("altname=\"%s\" ", reg_info->alt_name); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -391,8 +391,8 @@ bool GetGDBServerRegisterInfoXMLAndProcess(ArchSpec &arch_to_use, std::string xml_filename, - uint32_t &cur_reg_num, - uint32_t ®_offset); + uint32_t &cur_reg_remote, + uint32_t &cur_reg_local); // Query remote GDBServer for register information bool GetGDBServerRegisterInfo(ArchSpec &arch); diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -451,7 +451,7 @@ return; char packet[128]; - uint32_t reg_offset = 0; + uint32_t reg_offset = LLDB_INVALID_INDEX32; uint32_t reg_num = 0; for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse; @@ -564,7 +564,7 @@ reg_info.byte_offset = reg_offset; assert(reg_info.byte_size != 0); - reg_offset += reg_info.byte_size; + reg_offset = LLDB_INVALID_INDEX32; if (!value_regs.empty()) { value_regs.push_back(LLDB_INVALID_REGNUM); reg_info.value_regs = value_regs.data(); @@ -4276,14 +4276,14 @@ bool ParseRegisters(XMLNode feature_node, GdbServerTargetInfo &target_info, GDBRemoteDynamicRegisterInfo &dyn_reg_info, ABISP abi_sp, - uint32_t &cur_reg_num, uint32_t ®_offset) { + uint32_t ®_num_remote, uint32_t ®_num_local) { if (!feature_node) return false; + uint32_t reg_offset = LLDB_INVALID_INDEX32; feature_node.ForEachChildElementWithName( - "reg", - [&target_info, &dyn_reg_info, &cur_reg_num, ®_offset, - &abi_sp](const XMLNode ®_node) -> bool { + "reg", [&target_info, &dyn_reg_info, ®_num_remote, ®_num_local, + ®_offset, &abi_sp](const XMLNode ®_node) -> bool { std::string gdb_group; std::string gdb_type; ConstString reg_name; @@ -4305,8 +4305,8 @@ LLDB_INVALID_REGNUM, // eh_frame reg num LLDB_INVALID_REGNUM, // DWARF reg num LLDB_INVALID_REGNUM, // generic reg num - cur_reg_num, // process plugin reg num - cur_reg_num // native register number + reg_num_remote, // process plugin reg num + reg_num_local // native register number }, nullptr, nullptr, @@ -4433,7 +4433,7 @@ reg_info.byte_offset = reg_offset; assert(reg_info.byte_size != 0); - reg_offset += reg_info.byte_size; + reg_offset = LLDB_INVALID_INDEX32; if (!value_regs.empty()) { value_regs.push_back(LLDB_INVALID_REGNUM); reg_info.value_regs = value_regs.data(); @@ -4443,7 +4443,8 @@ reg_info.invalidate_regs = invalidate_regs.data(); } - ++cur_reg_num; + reg_num_remote = reg_info.kinds[eRegisterKindProcessPlugin] + 1; + ++reg_num_local; reg_info.name = reg_name.AsCString(); if (abi_sp) abi_sp->AugmentRegisterInfo(reg_info); @@ -4462,8 +4463,8 @@ // for nested register definition files. It returns true if it was able // to fetch and parse an xml file. bool ProcessGDBRemote::GetGDBServerRegisterInfoXMLAndProcess( - ArchSpec &arch_to_use, std::string xml_filename, uint32_t &cur_reg_num, - uint32_t ®_offset) { + ArchSpec &arch_to_use, std::string xml_filename, uint32_t ®_num_remote, + uint32_t ®_num_local) { // request the target xml file std::string raw; lldb_private::Status lldberr; @@ -4567,12 +4568,12 @@ ABISP abi_to_use_sp = ABI::FindPlugin(shared_from_this(), arch_to_use); for (auto &feature_node : feature_nodes) { ParseRegisters(feature_node, target_info, this->m_register_info, - abi_to_use_sp, cur_reg_num, reg_offset); + abi_to_use_sp, reg_num_remote, reg_num_local); } for (const auto &include : target_info.includes) { - GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, cur_reg_num, - reg_offset); + GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, include, + reg_num_remote, reg_num_local); } } } else { @@ -4592,9 +4593,10 @@ if (!m_gdb_comm.GetQXferFeaturesReadSupported()) return false; - uint32_t cur_reg_num = 0; - uint32_t reg_offset = 0; - if (GetGDBServerRegisterInfoXMLAndProcess (arch_to_use, "target.xml", cur_reg_num, reg_offset)) + uint32_t reg_num_remote = 0; + uint32_t reg_num_local = 0; + if (GetGDBServerRegisterInfoXMLAndProcess(arch_to_use, "target.xml", + reg_num_remote, reg_num_local)) this->m_register_info.Finalize(arch_to_use); return m_register_info.GetNumRegisters() > 0; diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestAArch64XMLRegOffsets.py b/lldb/test/API/functionalities/gdb_remote_client/TestAArch64XMLRegOffsets.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/gdb_remote_client/TestAArch64XMLRegOffsets.py @@ -0,0 +1,151 @@ +from __future__ import print_function +from textwrap import dedent +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from gdbclientutils import * + + +class MyResponder(MockGDBServerResponder): + def qXferRead(self, obj, annex, offset, length): + if annex == "target.xml": + return dedent("""\ + + + aarch64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + """), False + else: + return None, + + def readRegister(self, regnum): + return "E01" + + def readRegisters(self): + return "20000000000000002000000000000000f0c154bfffff00005daa985a8fea0b48f0b954bfffff0000ad13cce570150b48380000000000000070456abfffff0000a700000000000000000000000000000001010101010101010000000000000000f0c154bfffff00000f2700000000000008e355bfffff0000080e55bfffff0000281041000000000010de61bfffff00005c05000000000000f0c154bfffff000090fcffffffff00008efcffffffff00008ffcffffffff00000000000000000000001000000000000090fcffffffff000000d06cbfffff0000f0c154bfffff00000100000000000000d0b954bfffff0000e407400000000000d0b954bfffff0000e40740000000000000100000" + + +class TestAArch64XMLRegOffsets(GDBRemoteTestBase): + + @skipIfXmlSupportMissing + @skipIfRemote + @skipIfLLVMTargetMissing("AArch64") + def test_register_gpacket_offsets(self): + """ + Test that we correctly associate the register info with the eh_frame + register numbers. + """ + + target = self.createTarget("basic_eh_frame-aarch64.yaml") + self.server.responder = MyResponder() + + if self.TraceOn(): + self.runCmd("log enable gdb-remote packets") + self.addTearDownHook( + lambda: self.runCmd("log disable gdb-remote packets")) + + process = self.connect(target) + lldbutil.expect_state_changes(self, self.dbg.GetListener(), process, + [lldb.eStateStopped]) + + registerSet = process.GetThreadAtIndex( + 0).GetFrameAtIndex(0).GetRegisters().GetValueAtIndex(0) + + reg_val_dict = { + "x0": 0x0000000000000020, "x1": 0x0000000000000020, + "x2": 0x0000ffffbf54c1f0, "x3": 0x480bea8f5a98aa5d, + "x4": 0x0000ffffbf54b9f0, "x5": 0x480b1570e5cc13ad, + "x6": 0x0000000000000038, "x7": 0x0000ffffbf6a4570, + "x8": 0x00000000000000a7, "x9": 0x0000000000000000, + "x10": 0x0101010101010101, "x11": 0x0000000000000000, + "x12": 0x0000ffffbf54c1f0, "x13": 0x000000000000270f, + "x14": 0x0000ffffbf55e308, "x15": 0x0000ffffbf550e08, + "x16": 0x0000000000411028, "x17": 0x0000ffffbf61de10, + "x18": 0x000000000000055c, "x19": 0x0000ffffbf54c1f0, + "x20": 0x0000fffffffffc90, "x21": 0x0000fffffffffc8e, + "x22": 0x0000fffffffffc8f, "x23": 0x0000000000000000, + "x24": 0x0000000000001000, "x25": 0x0000fffffffffc90, + "x26": 0x0000ffffbf6cd000, "x27": 0x0000ffffbf54c1f0, + "x28": 0x0000000000000001, "x29": 0x0000ffffbf54b9d0, + "x30": 0x00000000004007e4, "sp": 0x0000ffffbf54b9d0, + "pc": 0x00000000004007e4, "cpsr": 0x00001000, "w0": 0x00000020, + "w1": 0x00000020, "w2": 0xbf54c1f0, "w3": 0x5a98aa5d, + "w4": 0xbf54b9f0, "w5": 0xe5cc13ad, "w6": 0x00000038, + "w7": 0xbf6a4570, "w8": 0x000000a7, "w9": 0x00000000, + "w10": 0x01010101, "w11": 0x00000000, "w12": 0xbf54c1f0, + "w13": 0x0000270f, "w14": 0xbf55e308, "w15": 0xbf550e08, + "w16": 0x00411028, "w17": 0xbf61de10, "w18": 0x0000055c, + "w19": 0xbf54c1f0, "w20": 0xfffffc90, "w21": 0xfffffc8e, + "w22": 0xfffffc8f, "w23": 0x00000000, "w24": 0x00001000, + "w25": 0xfffffc90, "w26": 0xbf6cd000, "w27": 0xbf54c1f0, + "w28": 0x00000001 + } + + for reg in registerSet: + self.assertEqual(reg.GetValueAsUnsigned(), + reg_val_dict[reg.GetName()]) diff --git a/lldb/test/API/tools/lldb-server/registers-target-xml-reading/TestGdbRemoteTargetXmlPacket.py b/lldb/test/API/tools/lldb-server/registers-target-xml-reading/TestGdbRemoteTargetXmlPacket.py --- a/lldb/test/API/tools/lldb-server/registers-target-xml-reading/TestGdbRemoteTargetXmlPacket.py +++ b/lldb/test/API/tools/lldb-server/registers-target-xml-reading/TestGdbRemoteTargetXmlPacket.py @@ -65,5 +65,8 @@ self.assertEqual(q_info_reg["set"], xml_info_reg.get("group")) self.assertEqual(q_info_reg["format"], xml_info_reg.get("format")) self.assertEqual(q_info_reg["bitsize"], xml_info_reg.get("bitsize")) - self.assertEqual(q_info_reg["offset"], xml_info_reg.get("offset")) + + if not self.getArchitecture() == 'aarch64': + self.assertEqual(q_info_reg["offset"], xml_info_reg.get("offset")) + self.assertEqual(q_info_reg["encoding"], xml_info_reg.get("encoding")) diff --git a/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp b/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp --- a/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp +++ b/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp @@ -171,7 +171,7 @@ Info.byte_size /= CHAR_BIT; if (!to_integer(Elements["offset"], Info.byte_offset, 10)) - return make_parsing_error("qRegisterInfo: offset"); + Info.byte_offset = LLDB_INVALID_INDEX32; Info.encoding = Args::StringToEncoding(Elements["encoding"]); if (Info.encoding == eEncodingInvalid) diff --git a/lldb/unittests/tools/lldb-server/tests/TestClient.cpp b/lldb/unittests/tools/lldb-server/tests/TestClient.cpp --- a/lldb/unittests/tools/lldb-server/tests/TestClient.cpp +++ b/lldb/unittests/tools/lldb-server/tests/TestClient.cpp @@ -219,6 +219,7 @@ } Error TestClient::qRegisterInfos() { + uint32_t reg_offset = 0; for (unsigned int Reg = 0;; ++Reg) { std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str(); Expected InfoOr = SendMessage(Message); @@ -227,6 +228,12 @@ break; } m_register_infos.emplace_back(std::move(*InfoOr)); + + if (m_register_infos[Reg].byte_offset == LLDB_INVALID_INDEX32) + m_register_infos[Reg].byte_offset = reg_offset; + + reg_offset = + m_register_infos[Reg].byte_offset + m_register_infos[Reg].byte_size; if (m_register_infos[Reg].kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC) m_pc_register = Reg;