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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "NativeProcessELF.h"
10 
11 #include "lldb/Utility/DataExtractor.h"
12 #include <optional>
13 
14 namespace lldb_private {
15 
16 std::optional<uint64_t>
17 NativeProcessELF::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 
31 lldb::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     else
38       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 
46 template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
47 lldb::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 and
61   // what the load bias by calculating the difference of the program header
62   // 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 section
91   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 the
101     // 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 
111 template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
112     llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
113 template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
114     llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>();
115 
116 template <typename T>
117 llvm::Expected<SVR4LibraryInfo>
118 NativeProcessELF::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 
142 llvm::Expected<std::vector<SVR4LibraryInfo>>
143 NativeProcessELF::GetLoadedSVR4Libraries() {
144   // Address of DT_DEBUG.d_ptr which points to r_debug
145   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_debug
150   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_map
160   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 
184 void NativeProcessELF::NotifyDidExec() {
185   NativeProcessProtocol::NotifyDidExec();
186   m_shared_library_info_addr.reset();
187 }
188 
189 } // namespace lldb_private
190