aadsm created this revision.
aadsm added reviewers: clayborg, xiaobai.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
aadsm added a parent revision: D62500: Add support to read aux vector values.

This is the third patch to improve module loading in a series that started here 
(where I explain the motivation and solution): D62499 
<https://reviews.llvm.org/D62499>

Add functions to read the r_debug location to know where the linked list of 
loaded libraries are so I can generate the `xfer:libraries-svr4` packet.
I'm also using this function to implement `GetSharedLibraryInfoAddress` that 
was "not implemented" for linux.
Most of this code was inspired by the current ds2 implementation here: 
https://github.com/facebook/ds2/blob/master/Sources/Target/POSIX/ELFProcess.cpp.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D62501

Files:
  lldb/include/lldb/Host/common/NativeProcessProtocol.h
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.h

Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -130,11 +130,14 @@
 protected:
   llvm::Expected<llvm::ArrayRef<uint8_t>>
   GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;
+  template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
+  lldb::addr_t GetELFImageInfoAddress();
 
 private:
   MainLoop::SignalHandleUP m_sigchld_handle;
   ArchSpec m_arch;
   std::unique_ptr<ELFAuxVector> m_aux_vector;
+  lldb::addr_t m_elf_image_info_addr = LLDB_INVALID_ADDRESS;
 
   LazyBool m_supports_mem_region = eLazyBoolCalculate;
   std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -38,6 +38,7 @@
 #include "lldb/Utility/State.h"
 #include "lldb/Utility/Status.h"
 #include "lldb/Utility/StringExtractor.h"
+#include "llvm/BinaryFormat/ELF.h"
 #include "llvm/Support/Errno.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Threading.h"
@@ -1390,8 +1391,12 @@
 }
 
 lldb::addr_t NativeProcessLinux::GetSharedLibraryInfoAddress() {
-  // punt on this for now
-  return LLDB_INVALID_ADDRESS;
+  if (GetAddressByteSize() == 8)
+    return GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr,
+                                  llvm::ELF::Elf64_Dyn>();
+  else
+    return GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr,
+                                  llvm::ELF::Elf32_Dyn>();
 }
 
 size_t NativeProcessLinux::UpdateThreads() {
@@ -2096,3 +2101,71 @@
 
   return m_aux_vector->GetAuxValue(type);
 }
+
+template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
+lldb::addr_t NativeProcessLinux::GetELFImageInfoAddress() {
+  if (m_elf_image_info_addr != LLDB_INVALID_ADDRESS)
+    return m_elf_image_info_addr;
+
+  lldb::addr_t phdr_addr = GetAuxValue(ELFAuxVector::AUXV_AT_PHDR);
+  size_t phdr_entry_size = GetAuxValue(ELFAuxVector::AUXV_AT_PHENT);
+  size_t phdr_num_entries = GetAuxValue(ELFAuxVector::AUXV_AT_PHNUM);
+  lldb::addr_t load_base = phdr_addr - sizeof(ELF_EHDR);
+  if (phdr_addr == 0 || phdr_entry_size == 0 || phdr_num_entries == 0)
+    return LLDB_INVALID_ADDRESS;
+
+  // Find the PT_DYNAMIC segment (.dynamic section) in the program header and
+  // what the ELF believes to be the load base.
+  lldb::addr_t elf_load_base = 0;
+  bool found_elf_load_base = false;
+  lldb::addr_t dynamic_section_addr = 0;
+  uint64_t dynamic_section_size = 0;
+  bool found_dynamic_section = false;
+  ELF_PHDR phdr_entry;
+  for (size_t i = 0; i < phdr_num_entries; i++) {
+    size_t bytes_read;
+    auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry,
+                            sizeof(phdr_entry), bytes_read);
+    if (!error.Success())
+      return LLDB_INVALID_ADDRESS;
+
+    if ((!found_elf_load_base || phdr_entry.p_vaddr < elf_load_base) &&
+        phdr_entry.p_type == llvm::ELF::PT_LOAD) {
+      elf_load_base = phdr_entry.p_vaddr;
+      found_elf_load_base = true;
+    }
+
+    if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) {
+      dynamic_section_addr = phdr_entry.p_vaddr;
+      dynamic_section_size = phdr_entry.p_memsz;
+      found_dynamic_section = true;
+    }
+  }
+
+  if (!found_elf_load_base || !found_dynamic_section)
+    return LLDB_INVALID_ADDRESS;
+
+  // Find the DT_DEBUG entry in the .dynamic section
+  // The load base we got from the auxiliary vector is the source of truth. If
+  // we got a different load base from the ELF then we need to correct the
+  // .dynamic section address with the difference we found.
+  dynamic_section_addr += (load_base - elf_load_base);
+  ELF_DYN dynamic_entry;
+  size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry);
+  for (size_t i = 0; i < dynamic_num_entries; i++) {
+    size_t bytes_read;
+    auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry),
+                            &dynamic_entry, sizeof(dynamic_entry), bytes_read);
+    if (!error.Success())
+      return LLDB_INVALID_ADDRESS;
+    // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the
+    // link_map.
+    if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) {
+      m_elf_image_info_addr = dynamic_section_addr + i * sizeof(dynamic_entry) +
+                              sizeof(dynamic_entry.d_tag);
+      return m_elf_image_info_addr;
+    }
+  }
+
+  return LLDB_INVALID_ADDRESS;
+}
Index: lldb/include/lldb/Host/common/NativeProcessProtocol.h
===================================================================
--- lldb/include/lldb/Host/common/NativeProcessProtocol.h
+++ lldb/include/lldb/Host/common/NativeProcessProtocol.h
@@ -427,6 +427,8 @@
 
   NativeThreadProtocol *GetThreadByIDUnlocked(lldb::tid_t tid);
 
+  lldb::addr_t GetELFImageInfoAddress();
+
 private:
   void SynchronouslyNotifyProcessStateChanged(lldb::StateType state);
   llvm::Expected<SoftwareBreakpoint>
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to