labath updated this revision to Diff 246397.
labath added a comment.

Fully parse the qOffsets response


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D74598/new/

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/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
  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,30 @@
       incorrect_custom_params2);
   ASSERT_FALSE(result4.get().Success());
 }
+
+TEST_F(GDBRemoteCommunicationClientTest, GetExecutableOffsets) {
+  const auto &GetExecutableOffsets = [&](llvm::StringRef response) {
+    std::future<Optional<ExecutableOffsets>> result = std::async(
+        std::launch::async, [&] { return client.GetExecutableOffsets(); });
+
+    HandlePacket(server, "qOffsets", response);
+    return result.get();
+  };
+  EXPECT_EQ((ExecutableOffsets{false, {0x1234, 0x1234}}),
+            GetExecutableOffsets("Text=1234;Data=1234"));
+  EXPECT_EQ((ExecutableOffsets{false, {0x1234, 0x1234, 0x1234}}),
+            GetExecutableOffsets("Text=1234;Data=1234;Bss=1234"));
+  EXPECT_EQ((ExecutableOffsets{true, {0x1234}}),
+            GetExecutableOffsets("TextSeg=1234"));
+  EXPECT_EQ((ExecutableOffsets{true, {0x1234, 0x2345}}),
+            GetExecutableOffsets("TextSeg=1234;DataSeg=2345"));
+
+  EXPECT_EQ(llvm::None, GetExecutableOffsets("E05"));
+  EXPECT_EQ(llvm::None, GetExecutableOffsets("Text=bogus"));
+  EXPECT_EQ(llvm::None, GetExecutableOffsets("Text=1234"));
+  EXPECT_EQ(llvm::None, GetExecutableOffsets("Text=1234;Data=1234;"));
+  EXPECT_EQ(llvm::None, GetExecutableOffsets("Text=1234;Data=1234;Bss=1234;"));
+  EXPECT_EQ(llvm::None, GetExecutableOffsets("TEXTSEG=1234"));
+  EXPECT_EQ(llvm::None, GetExecutableOffsets("TextSeg=0x1234"));
+  EXPECT_EQ(llvm::None, GetExecutableOffsets("TextSeg=12345678123456789"));
+}
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.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -377,6 +377,7 @@
   bool UpdateThreadIDList();
 
   void DidLaunchOrAttach(ArchSpec &process_arch);
+  void MaybeLoadExecutableModule();
 
   Status ConnectToDebugserver(llvm::StringRef host_port);
 
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,8 @@
     }
   }
 
+  MaybeLoadExecutableModule();
+
   // Find out which StructuredDataPlugins are supported by the debug monitor.
   // These plugins transmit data over async $J packets.
   if (StructuredData::Array *supported_packets =
@@ -1109,6 +1111,31 @@
     MapSupportedStructuredDataPlugins(*supported_packets);
 }
 
+void ProcessGDBRemote::MaybeLoadExecutableModule() {
+  ModuleSP module_sp = GetTarget().GetExecutableModule();
+  if (!module_sp)
+    return;
+
+  llvm::Optional<QOffsets> offsets = m_gdb_comm.GetQOffsets();
+  if (!offsets)
+    return;
+
+  bool is_uniform =
+      size_t(llvm::count(offsets->offsets, offsets->offsets[0])) ==
+      offsets->offsets.size();
+  if (!is_uniform)
+    return; // TODO: Handle non-uniform responses.
+
+  bool changed = false;
+  module_sp->SetLoadAddress(GetTarget(), offsets->offsets[0],
+                            /*value_is_offset=*/true, changed);
+  if (changed) {
+    ModuleList list;
+    list.Append(module_sp);
+    m_process->GetTarget().ModulesDidLoad(list);
+  }
+}
+
 void ProcessGDBRemote::DidLaunch() {
   ArchSpec process_arch;
   DidLaunchOrAttach(process_arch);
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
@@ -31,6 +31,22 @@
 namespace lldb_private {
 namespace process_gdb_remote {
 
+/// The offsets used by the target when relocating the executable. Decoded from
+/// qOffsets packet response.
+struct QOffsets {
+  /// If true, the offsets field describes segments. Otherwise, it describes
+  /// sections.
+  bool segments;
+
+  /// The individual offsets. Section offsets have two or three members.
+  /// Segment offsets have either one of two.
+  std::vector<uint64_t> offsets;
+};
+inline bool operator==(const QOffsets &a, const QOffsets &b) {
+  return a.segments == b.segments && a.offsets == b.offsets;
+}
+llvm::raw_ostream &operator<<(llvm::raw_ostream &os, const QOffsets &offsets);
+
 class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
 public:
   GDBRemoteCommunicationClient();
@@ -425,6 +441,11 @@
 
   bool GetSharedCacheInfoSupported();
 
+  /// Use qOffsets to query the offset used when relocating the target
+  /// executable. If successful, the returned structure will contain at least
+  /// one value in the offsets field.
+  llvm::Optional<QOffsets> GetQOffsets();
+
   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
@@ -45,6 +45,13 @@
 using namespace lldb_private;
 using namespace std::chrono;
 
+llvm::raw_ostream &process_gdb_remote::operator<<(llvm::raw_ostream &os,
+                                                  const QOffsets &offsets) {
+  return os << llvm::formatv(
+             "QOffsets({0}, [{1:@[x]}])", offsets.segments,
+             llvm::make_range(offsets.offsets.begin(), offsets.offsets.end()));
+}
+
 // GDBRemoteCommunicationClient constructor
 GDBRemoteCommunicationClient::GDBRemoteCommunicationClient()
     : GDBRemoteClientBase("gdb-remote.client", "gdb-remote.client.rx_packet"),
@@ -3531,6 +3538,46 @@
   return error;
 }
 
+llvm::Optional<QOffsets> GDBRemoteCommunicationClient::GetQOffsets() {
+  StringExtractorGDBRemote response;
+  if (SendPacketAndWaitForResponse(
+          "qOffsets", response, /*send_async=*/false) != PacketResult::Success)
+    return llvm::None;
+  if (!response.IsNormalResponse())
+    return llvm::None;
+
+  QOffsets result;
+  llvm::StringRef ref = response.GetStringRef();
+  const auto &GetOffset = [&] {
+    addr_t offset;
+    if (ref.consumeInteger(16, offset))
+      return false;
+    result.offsets.push_back(offset);
+    return true;
+  };
+
+  if (ref.consume_front("Text=")) {
+    result.segments = false;
+    if (!GetOffset())
+      return llvm::None;
+    if (!ref.consume_front(";Data=") || !GetOffset())
+      return llvm::None;
+    if (ref.empty())
+      return result;
+    if (ref.consume_front(";Bss=") && GetOffset() && ref.empty())
+      return result;
+  } else if (ref.consume_front("TextSeg=")) {
+    result.segments = true;
+    if (!GetOffset())
+      return llvm::None;
+    if (ref.empty())
+      return result;
+    if (ref.consume_front(";DataSeg=") && GetOffset() && ref.empty())
+      return result;
+  }
+  return llvm::None;
+}
+
 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

Reply via email to