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