diff --git a/lldb/include/lldb/Host/common/NativeProcessProtocol.h b/lldb/include/lldb/Host/common/NativeProcessProtocol.h --- a/lldb/include/lldb/Host/common/NativeProcessProtocol.h +++ b/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 diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -131,11 +131,14 @@ protected: llvm::Expected> GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + template + lldb::addr_t GetELFImageInfoAddress(); private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; std::unique_ptr m_aux_vector; + lldb::addr_t m_elf_image_info_addr = LLDB_INVALID_ADDRESS; LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector> m_mem_region_cache; diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/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(); + else + return GetELFImageInfoAddress(); } size_t NativeProcessLinux::UpdateThreads() { @@ -2097,3 +2102,77 @@ return m_aux_vector->GetAuxValue(type); } + +template +lldb::addr_t NativeProcessLinux::GetELFImageInfoAddress() { + if (m_elf_image_info_addr != LLDB_INVALID_ADDRESS) + return m_elf_image_info_addr; + + llvm::Optional maybe_phdr_addr = + GetAuxValue(AuxVector::AUXV_AT_PHDR); + llvm::Optional maybe_phdr_entry_size = + GetAuxValue(AuxVector::AUXV_AT_PHENT); + llvm::Optional maybe_phdr_num_entries = + GetAuxValue(AuxVector::AUXV_AT_PHNUM); + if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries) + return LLDB_INVALID_ADDRESS; + lldb::addr_t phdr_addr = *maybe_phdr_addr; + size_t phdr_entry_size = *maybe_phdr_entry_size; + size_t phdr_num_entries = *maybe_phdr_num_entries; + lldb::addr_t load_base = phdr_addr - sizeof(ELF_EHDR); + + // 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; +}