labath created this revision. labath added reviewers: clayborg, jasonmolenda. Herald added a project: LLDB.
This packet is necessary to make lldb work with the remote-gdb stub in user mode qemu when running position-independent binaries. It reports the relative position (load bias) of the loaded executable wrt. the addresses in the file itself. Lldb needs to know this information in order to correctly set the load address of the executable. Normally, lldb would be able to find this out on its own by following the breadcrumbs in the process auxiliary vector, but we can't do this here because qemu does not support the qXfer:auxv:read packet. This patch does not implement full scope of the qOffsets packet (which supports having different biases for code, data and bss sections). This is because the relevant lldb interfaces (e.g., Module::SetLoadAddress) do not support passing different values for different sections, and it's not clear how would such a thing apply to typicall object files. And qemu will always (https://github.com/qemu/qemu/blob/master/linux-user/elfload.c#L2436) return the same value for code and data offsets. In fact, even gdb ignores the offset for the bss sections, and uses the "data" offset instead. So, until the we need more of this packet, I think it's best to stick to the simplest solution possible. This patch simply rejects replies with non-uniform offsets. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D74598 Files: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp lldb/test/API/functionalities/gdb_remote_client/TestqOffsets.py lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py lldb/test/API/functionalities/gdb_remote_client/qOffsets.yaml lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp
Index: lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp =================================================================== --- lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp +++ lldb/unittests/Process/gdb-remote/GDBRemoteCommunicationClientTest.cpp @@ -552,3 +552,24 @@ incorrect_custom_params2); ASSERT_FALSE(result4.get().Success()); } + +TEST_F(GDBRemoteCommunicationClientTest, GetOffsets) { + const auto &GetExecutableOffset = [&](llvm::StringRef response) { + std::future<Optional<addr_t>> result = std::async( + std::launch::async, [&] { return client.GetExecutableOffset(); }); + + HandlePacket(server, "qOffsets", response); + return result.get(); + }; + EXPECT_EQ(addr_t(0x1234), GetExecutableOffset("Text=1234;Data=1234")); + EXPECT_EQ(addr_t(0x1234), + GetExecutableOffset("Text=1234;Data=1234;Bss=1234")); + EXPECT_EQ(addr_t(0x1234), GetExecutableOffset("TextSeg=1234;DataSeg=1234")); + + EXPECT_EQ(llvm::None, GetExecutableOffset("E05")); + EXPECT_EQ(llvm::None, GetExecutableOffset("Text=bogus")); + + // NB: These are technically correct responses, but we don't handle them yet. + EXPECT_EQ(llvm::None, GetExecutableOffset("Text=1234;Data=4321")); + EXPECT_EQ(llvm::None, GetExecutableOffset("TextSeg=1234;DataSeg=4321")); +} Index: lldb/test/API/functionalities/gdb_remote_client/qOffsets.yaml =================================================================== --- /dev/null +++ lldb/test/API/functionalities/gdb_remote_client/qOffsets.yaml @@ -0,0 +1,19 @@ +!ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_AARCH64 +Sections: + - Name: .text + Type: SHT_PROGBITS + Flags: [ SHF_ALLOC, SHF_EXECINSTR ] + Address: 0x1000 + AddressAlign: 0x4 + Content: "c3c3c3c3" + - Name: .note.ABI-tag + Type: SHT_NOTE + Flags: [ SHF_ALLOC ] + Address: 0x1004 + AddressAlign: 0x4 + Content: 040000001000000001000000474e550000000000030000000700000000000000 Index: lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py =================================================================== --- lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py +++ lldb/test/API/functionalities/gdb_remote_client/gdbclientutils.py @@ -172,6 +172,8 @@ return self.qHostInfo() if packet == "qGetWorkingDir": return self.qGetWorkingDir() + if packet == "qOffsets": + return self.qOffsets(); if packet == "qsProcessInfo": return self.qsProcessInfo() if packet.startswith("qfProcessInfo"): @@ -188,6 +190,9 @@ def qGetWorkingDir(self): return "2f" + def qOffsets(self): + return "" + def qHostInfo(self): return "ptrsize:8;endian:little;" Index: lldb/test/API/functionalities/gdb_remote_client/TestqOffsets.py =================================================================== --- /dev/null +++ lldb/test/API/functionalities/gdb_remote_client/TestqOffsets.py @@ -0,0 +1,28 @@ +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from gdbclientutils import * + + +class TestqOffsets(GDBRemoteTestBase): + + class Responder(MockGDBServerResponder): + def qOffsets(self): + return 'Text=470000;Data=470000' + + def setUp(self): + super(TestqOffsets, self).setUp() + self._initial_platform = lldb.DBG.GetSelectedPlatform() + + def tearDown(self): + lldb.DBG.SetSelectedPlatform(self._initial_platform) + super(TestqOffsets, self).tearDown() + + def test(self): + self.server.responder = TestqOffsets.Responder() + target = self.createTarget("qOffsets.yaml") + text = target.modules[0].FindSection(".text") + self.assertEquals(text.GetLoadAddress(target), lldb.LLDB_INVALID_ADDRESS) + + process = self.connect(target) + self.assertEquals(text.GetLoadAddress(target), 0x471000) Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -1102,6 +1102,19 @@ } } + if (ModuleSP module_sp = GetTarget().GetExecutableModule()) { + if (llvm::Optional<addr_t> offset = m_gdb_comm.GetExecutableOffset()) { + bool changed = false; + module_sp->SetLoadAddress(GetTarget(), *offset, /*value_is_offset=*/true, + changed); + if (changed) { + ModuleList list; + list.Append(module_sp); + m_process->GetTarget().ModulesDidLoad(list); + } + } + } + // Find out which StructuredDataPlugins are supported by the debug monitor. // These plugins transmit data over async $J packets. if (StructuredData::Array *supported_packets = Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -425,6 +425,9 @@ bool GetSharedCacheInfoSupported(); + /// qOffsets + llvm::Optional<lldb::addr_t> GetExecutableOffset(); + bool GetModuleInfo(const FileSpec &module_file_spec, const ArchSpec &arch_spec, ModuleSpec &module_spec); Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -3531,6 +3531,31 @@ return error; } +llvm::Optional<addr_t> GDBRemoteCommunicationClient::GetExecutableOffset() { + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse( + "qOffsets", response, /*send_async=*/false) != PacketResult::Success) + return llvm::None; + if (!response.IsNormalResponse()) + return llvm::None; + + llvm::Optional<addr_t> offset; + llvm::SmallVector<llvm::StringRef, 3> pairs; + response.GetStringRef().split(pairs, ';'); + for (llvm::StringRef pair : pairs) { + llvm::StringRef name, value; + std::tie(name, value) = pair.split('='); + + addr_t cur_offset; + if (!to_integer(value, cur_offset, 16)) + return llvm::None; + if (offset && *offset != cur_offset) + return llvm::None; + offset = cur_offset; + } + return offset; +} + bool GDBRemoteCommunicationClient::GetModuleInfo( const FileSpec &module_file_spec, const lldb_private::ArchSpec &arch_spec, ModuleSpec &module_spec) {
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits