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