1//===-- NativeProcessELF.cpp ---------------------------------- -*- C++ -*-===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9#include "NativeProcessELF.h" 10 11#include "lldb/Utility/DataExtractor.h" 12 13namespace lldb_private { 14 15llvm::Optional<uint64_t> 16NativeProcessELF::GetAuxValue(enum AuxVector::EntryType type) { 17 if (m_aux_vector == nullptr) { 18 auto buffer_or_error = GetAuxvData(); 19 if (!buffer_or_error) 20 return llvm::None; 21 DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(), 22 buffer_or_error.get()->getBufferSize(), 23 GetByteOrder(), GetAddressByteSize()); 24 m_aux_vector = std::make_unique<AuxVector>(auxv_data); 25 } 26 27 return m_aux_vector->GetAuxValue(type); 28} 29 30lldb::addr_t NativeProcessELF::GetSharedLibraryInfoAddress() { 31 if (!m_shared_library_info_addr.hasValue()) { 32 if (GetAddressByteSize() == 8) 33 m_shared_library_info_addr = 34 GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, 35 llvm::ELF::Elf64_Dyn>(); 36 else 37 m_shared_library_info_addr = 38 GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, 39 llvm::ELF::Elf32_Dyn>(); 40 } 41 42 return m_shared_library_info_addr.getValue(); 43} 44 45template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN> 46lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() { 47 llvm::Optional<uint64_t> maybe_phdr_addr = 48 GetAuxValue(AuxVector::AUXV_AT_PHDR); 49 llvm::Optional<uint64_t> maybe_phdr_entry_size = 50 GetAuxValue(AuxVector::AUXV_AT_PHENT); 51 llvm::Optional<uint64_t> maybe_phdr_num_entries = 52 GetAuxValue(AuxVector::AUXV_AT_PHNUM); 53 if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries) 54 return LLDB_INVALID_ADDRESS; 55 lldb::addr_t phdr_addr = *maybe_phdr_addr; 56 size_t phdr_entry_size = *maybe_phdr_entry_size; 57 size_t phdr_num_entries = *maybe_phdr_num_entries; 58 59 // Find the PT_DYNAMIC segment (.dynamic section) in the program header and 60 // what the load bias by calculating the difference of the program header 61 // load address and its virtual address. 62 lldb::offset_t load_bias; 63 bool found_load_bias = false; 64 lldb::addr_t dynamic_section_addr = 0; 65 uint64_t dynamic_section_size = 0; 66 bool found_dynamic_section = false; 67 ELF_PHDR phdr_entry; 68 for (size_t i = 0; i < phdr_num_entries; i++) { 69 size_t bytes_read; 70 auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry, 71 sizeof(phdr_entry), bytes_read); 72 if (!error.Success()) 73 return LLDB_INVALID_ADDRESS; 74 if (phdr_entry.p_type == llvm::ELF::PT_PHDR) { 75 load_bias = phdr_addr - phdr_entry.p_vaddr; 76 found_load_bias = true; 77 } 78 79 if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) { 80 dynamic_section_addr = phdr_entry.p_vaddr; 81 dynamic_section_size = phdr_entry.p_memsz; 82 found_dynamic_section = true; 83 } 84 } 85 86 if (!found_load_bias || !found_dynamic_section) 87 return LLDB_INVALID_ADDRESS; 88 89 // Find the DT_DEBUG entry in the .dynamic section 90 dynamic_section_addr += load_bias; 91 ELF_DYN dynamic_entry; 92 size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry); 93 for (size_t i = 0; i < dynamic_num_entries; i++) { 94 size_t bytes_read; 95 auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry), 96 &dynamic_entry, sizeof(dynamic_entry), bytes_read); 97 if (!error.Success()) 98 return LLDB_INVALID_ADDRESS; 99 // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the 100 // link_map. 101 if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) { 102 return dynamic_section_addr + i * sizeof(dynamic_entry) + 103 sizeof(dynamic_entry.d_tag); 104 } 105 } 106 107 return LLDB_INVALID_ADDRESS; 108} 109 110template <typename T> 111llvm::Expected<SVR4LibraryInfo> 112NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) { 113 ELFLinkMap<T> link_map; 114 size_t bytes_read; 115 auto error = 116 ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read); 117 if (!error.Success()) 118 return error.ToError(); 119 120 char name_buffer[PATH_MAX]; 121 llvm::Expected<llvm::StringRef> string_or_error = ReadCStringFromMemory( 122 link_map.l_name, &name_buffer[0], sizeof(name_buffer), bytes_read); 123 if (!string_or_error) 124 return string_or_error.takeError(); 125 126 SVR4LibraryInfo info; 127 info.name = string_or_error->str(); 128 info.link_map = link_map_addr; 129 info.base_addr = link_map.l_addr; 130 info.ld_addr = link_map.l_ld; 131 info.next = link_map.l_next; 132 133 return info; 134} 135 136llvm::Expected<std::vector<SVR4LibraryInfo>> 137NativeProcessELF::GetLoadedSVR4Libraries() { 138 // Address of DT_DEBUG.d_ptr which points to r_debug 139 lldb::addr_t info_address = GetSharedLibraryInfoAddress(); 140 if (info_address == LLDB_INVALID_ADDRESS) 141 return llvm::createStringError(llvm::inconvertibleErrorCode(), 142 "Invalid shared library info address"); 143 // Address of r_debug 144 lldb::addr_t address = 0; 145 size_t bytes_read; 146 auto status = 147 ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read); 148 if (!status.Success()) 149 return status.ToError(); 150 if (address == 0) 151 return llvm::createStringError(llvm::inconvertibleErrorCode(), 152 "Invalid r_debug address"); 153 // Read r_debug.r_map 154 lldb::addr_t link_map = 0; 155 status = ReadMemory(address + GetAddressByteSize(), &link_map, 156 GetAddressByteSize(), bytes_read); 157 if (!status.Success()) 158 return status.ToError(); 159 if (address == 0) 160 return llvm::createStringError(llvm::inconvertibleErrorCode(), 161 "Invalid link_map address"); 162 163 std::vector<SVR4LibraryInfo> library_list; 164 while (link_map) { 165 llvm::Expected<SVR4LibraryInfo> info = 166 GetAddressByteSize() == 8 ? ReadSVR4LibraryInfo<uint64_t>(link_map) 167 : ReadSVR4LibraryInfo<uint32_t>(link_map); 168 if (!info) 169 return info.takeError(); 170 if (!info->name.empty() && info->base_addr != 0) 171 library_list.push_back(*info); 172 link_map = info->next; 173 } 174 175 return library_list; 176} 177 178} // namespace lldb_private 179