1*0b57cec5SDimitry Andric //===-- NativeProcessELF.cpp ----------------------------------------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric 
9*0b57cec5SDimitry Andric #include "NativeProcessELF.h"
10*0b57cec5SDimitry Andric 
11*0b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h"
12*0b57cec5SDimitry Andric #include <optional>
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric namespace lldb_private {
15*0b57cec5SDimitry Andric 
16*0b57cec5SDimitry Andric std::optional<uint64_t>
GetAuxValue(enum AuxVector::EntryType type)17*0b57cec5SDimitry Andric NativeProcessELF::GetAuxValue(enum AuxVector::EntryType type) {
18*0b57cec5SDimitry Andric   if (m_aux_vector == nullptr) {
19*0b57cec5SDimitry Andric     auto buffer_or_error = GetAuxvData();
20*0b57cec5SDimitry Andric     if (!buffer_or_error)
21*0b57cec5SDimitry Andric       return std::nullopt;
22*0b57cec5SDimitry Andric     DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(),
23*0b57cec5SDimitry Andric                             buffer_or_error.get()->getBufferSize(),
24*0b57cec5SDimitry Andric                             GetByteOrder(), GetAddressByteSize());
25*0b57cec5SDimitry Andric     m_aux_vector = std::make_unique<AuxVector>(auxv_data);
26*0b57cec5SDimitry Andric   }
27*0b57cec5SDimitry Andric 
28*0b57cec5SDimitry Andric   return m_aux_vector->GetAuxValue(type);
29*0b57cec5SDimitry Andric }
30*0b57cec5SDimitry Andric 
GetSharedLibraryInfoAddress()31*0b57cec5SDimitry Andric lldb::addr_t NativeProcessELF::GetSharedLibraryInfoAddress() {
32*0b57cec5SDimitry Andric   if (!m_shared_library_info_addr) {
33*0b57cec5SDimitry Andric     if (GetAddressByteSize() == 8)
34*0b57cec5SDimitry Andric       m_shared_library_info_addr =
35*0b57cec5SDimitry Andric           GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr,
36*0b57cec5SDimitry Andric                                  llvm::ELF::Elf64_Dyn>();
37*0b57cec5SDimitry Andric     else
38*0b57cec5SDimitry Andric       m_shared_library_info_addr =
39*0b57cec5SDimitry Andric           GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr,
40*0b57cec5SDimitry Andric                                  llvm::ELF::Elf32_Dyn>();
41*0b57cec5SDimitry Andric   }
42*0b57cec5SDimitry Andric 
43*0b57cec5SDimitry Andric   return *m_shared_library_info_addr;
44*0b57cec5SDimitry Andric }
45*0b57cec5SDimitry Andric 
46*0b57cec5SDimitry Andric template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
GetELFImageInfoAddress()47*0b57cec5SDimitry Andric lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() {
48*0b57cec5SDimitry Andric   std::optional<uint64_t> maybe_phdr_addr =
49*0b57cec5SDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHDR);
50*0b57cec5SDimitry Andric   std::optional<uint64_t> maybe_phdr_entry_size =
51*0b57cec5SDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHENT);
52*0b57cec5SDimitry Andric   std::optional<uint64_t> maybe_phdr_num_entries =
53*0b57cec5SDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHNUM);
54*0b57cec5SDimitry Andric   if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries)
55*0b57cec5SDimitry Andric     return LLDB_INVALID_ADDRESS;
56*0b57cec5SDimitry Andric   lldb::addr_t phdr_addr = *maybe_phdr_addr;
57*0b57cec5SDimitry Andric   size_t phdr_entry_size = *maybe_phdr_entry_size;
58*0b57cec5SDimitry Andric   size_t phdr_num_entries = *maybe_phdr_num_entries;
59*0b57cec5SDimitry Andric 
60*0b57cec5SDimitry Andric   // Find the PT_DYNAMIC segment (.dynamic section) in the program header and
61*0b57cec5SDimitry Andric   // what the load bias by calculating the difference of the program header
62*0b57cec5SDimitry Andric   // load address and its virtual address.
63*0b57cec5SDimitry Andric   lldb::offset_t load_bias;
64*0b57cec5SDimitry Andric   bool found_load_bias = false;
65*0b57cec5SDimitry Andric   lldb::addr_t dynamic_section_addr = 0;
66*0b57cec5SDimitry Andric   uint64_t dynamic_section_size = 0;
67*0b57cec5SDimitry Andric   bool found_dynamic_section = false;
68*0b57cec5SDimitry Andric   ELF_PHDR phdr_entry;
69*0b57cec5SDimitry Andric   for (size_t i = 0; i < phdr_num_entries; i++) {
70*0b57cec5SDimitry Andric     size_t bytes_read;
71*0b57cec5SDimitry Andric     auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry,
72*0b57cec5SDimitry Andric                             sizeof(phdr_entry), bytes_read);
73*0b57cec5SDimitry Andric     if (!error.Success())
74*0b57cec5SDimitry Andric       return LLDB_INVALID_ADDRESS;
75*0b57cec5SDimitry Andric     if (phdr_entry.p_type == llvm::ELF::PT_PHDR) {
76*0b57cec5SDimitry Andric       load_bias = phdr_addr - phdr_entry.p_vaddr;
77*0b57cec5SDimitry Andric       found_load_bias = true;
78*0b57cec5SDimitry Andric     }
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric     if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) {
81*0b57cec5SDimitry Andric       dynamic_section_addr = phdr_entry.p_vaddr;
82*0b57cec5SDimitry Andric       dynamic_section_size = phdr_entry.p_memsz;
83*0b57cec5SDimitry Andric       found_dynamic_section = true;
84*0b57cec5SDimitry Andric     }
85*0b57cec5SDimitry Andric   }
86*0b57cec5SDimitry Andric 
87*0b57cec5SDimitry Andric   if (!found_load_bias || !found_dynamic_section)
88*0b57cec5SDimitry Andric     return LLDB_INVALID_ADDRESS;
89*0b57cec5SDimitry Andric 
90*0b57cec5SDimitry Andric   // Find the DT_DEBUG entry in the .dynamic section
91*0b57cec5SDimitry Andric   dynamic_section_addr += load_bias;
92*0b57cec5SDimitry Andric   ELF_DYN dynamic_entry;
93*0b57cec5SDimitry Andric   size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry);
94*0b57cec5SDimitry Andric   for (size_t i = 0; i < dynamic_num_entries; i++) {
95*0b57cec5SDimitry Andric     size_t bytes_read;
96*0b57cec5SDimitry Andric     auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry),
97*0b57cec5SDimitry Andric                             &dynamic_entry, sizeof(dynamic_entry), bytes_read);
98*0b57cec5SDimitry Andric     if (!error.Success())
99*0b57cec5SDimitry Andric       return LLDB_INVALID_ADDRESS;
100*0b57cec5SDimitry Andric     // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the
101*0b57cec5SDimitry Andric     // link_map.
102*0b57cec5SDimitry Andric     if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) {
103*0b57cec5SDimitry Andric       return dynamic_section_addr + i * sizeof(dynamic_entry) +
104*0b57cec5SDimitry Andric              sizeof(dynamic_entry.d_tag);
105*0b57cec5SDimitry Andric     }
106*0b57cec5SDimitry Andric   }
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric   return LLDB_INVALID_ADDRESS;
109*0b57cec5SDimitry Andric }
110*0b57cec5SDimitry Andric 
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>
ReadSVR4LibraryInfo(lldb::addr_t link_map_addr)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>>
GetLoadedSVR4Libraries()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 
NotifyDidExec()184 void NativeProcessELF::NotifyDidExec() {
185   NativeProcessProtocol::NotifyDidExec();
186   m_shared_library_info_addr.reset();
187 }
188 
189 } // namespace lldb_private
190