180814287SRaphael Isemann //===-- NativeProcessELF.cpp ----------------------------------------------===//
2f4335b8eSAntonio Afonso //
3f4335b8eSAntonio Afonso // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4f4335b8eSAntonio Afonso // See https://llvm.org/LICENSE.txt for license information.
5f4335b8eSAntonio Afonso // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6f4335b8eSAntonio Afonso //
7f4335b8eSAntonio Afonso //===----------------------------------------------------------------------===//
8f4335b8eSAntonio Afonso 
9f4335b8eSAntonio Afonso #include "NativeProcessELF.h"
10f4335b8eSAntonio Afonso 
11f4335b8eSAntonio Afonso #include "lldb/Utility/DataExtractor.h"
12f4335b8eSAntonio Afonso 
13f4335b8eSAntonio Afonso namespace lldb_private {
14f4335b8eSAntonio Afonso 
15f4335b8eSAntonio Afonso llvm::Optional<uint64_t>
GetAuxValue(enum AuxVector::EntryType type)16f4335b8eSAntonio Afonso NativeProcessELF::GetAuxValue(enum AuxVector::EntryType type) {
17f4335b8eSAntonio Afonso   if (m_aux_vector == nullptr) {
18f4335b8eSAntonio Afonso     auto buffer_or_error = GetAuxvData();
19f4335b8eSAntonio Afonso     if (!buffer_or_error)
20f4335b8eSAntonio Afonso       return llvm::None;
21f4335b8eSAntonio Afonso     DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(),
22f4335b8eSAntonio Afonso                             buffer_or_error.get()->getBufferSize(),
23f4335b8eSAntonio Afonso                             GetByteOrder(), GetAddressByteSize());
24a8f3ae7cSJonas Devlieghere     m_aux_vector = std::make_unique<AuxVector>(auxv_data);
25f4335b8eSAntonio Afonso   }
26f4335b8eSAntonio Afonso 
27f4335b8eSAntonio Afonso   return m_aux_vector->GetAuxValue(type);
28f4335b8eSAntonio Afonso }
29f4335b8eSAntonio Afonso 
GetSharedLibraryInfoAddress()30f4335b8eSAntonio Afonso lldb::addr_t NativeProcessELF::GetSharedLibraryInfoAddress() {
315413bf1bSKazu Hirata   if (!m_shared_library_info_addr) {
32f4335b8eSAntonio Afonso     if (GetAddressByteSize() == 8)
33f4335b8eSAntonio Afonso       m_shared_library_info_addr =
34f4335b8eSAntonio Afonso           GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr,
35f4335b8eSAntonio Afonso                                  llvm::ELF::Elf64_Dyn>();
36f4335b8eSAntonio Afonso     else
37f4335b8eSAntonio Afonso       m_shared_library_info_addr =
38f4335b8eSAntonio Afonso           GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr,
39f4335b8eSAntonio Afonso                                  llvm::ELF::Elf32_Dyn>();
40f4335b8eSAntonio Afonso   }
41f4335b8eSAntonio Afonso 
42*ed8fceaaSKazu Hirata   return *m_shared_library_info_addr;
43f4335b8eSAntonio Afonso }
44f4335b8eSAntonio Afonso 
45f4335b8eSAntonio Afonso template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
GetELFImageInfoAddress()46f4335b8eSAntonio Afonso lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() {
47f4335b8eSAntonio Afonso   llvm::Optional<uint64_t> maybe_phdr_addr =
48f4335b8eSAntonio Afonso       GetAuxValue(AuxVector::AUXV_AT_PHDR);
49f4335b8eSAntonio Afonso   llvm::Optional<uint64_t> maybe_phdr_entry_size =
50f4335b8eSAntonio Afonso       GetAuxValue(AuxVector::AUXV_AT_PHENT);
51f4335b8eSAntonio Afonso   llvm::Optional<uint64_t> maybe_phdr_num_entries =
52f4335b8eSAntonio Afonso       GetAuxValue(AuxVector::AUXV_AT_PHNUM);
53f4335b8eSAntonio Afonso   if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries)
54f4335b8eSAntonio Afonso     return LLDB_INVALID_ADDRESS;
55f4335b8eSAntonio Afonso   lldb::addr_t phdr_addr = *maybe_phdr_addr;
56f4335b8eSAntonio Afonso   size_t phdr_entry_size = *maybe_phdr_entry_size;
57f4335b8eSAntonio Afonso   size_t phdr_num_entries = *maybe_phdr_num_entries;
58f4335b8eSAntonio Afonso 
59f4335b8eSAntonio Afonso   // Find the PT_DYNAMIC segment (.dynamic section) in the program header and
60f4335b8eSAntonio Afonso   // what the load bias by calculating the difference of the program header
61f4335b8eSAntonio Afonso   // load address and its virtual address.
62f4335b8eSAntonio Afonso   lldb::offset_t load_bias;
63f4335b8eSAntonio Afonso   bool found_load_bias = false;
64f4335b8eSAntonio Afonso   lldb::addr_t dynamic_section_addr = 0;
65f4335b8eSAntonio Afonso   uint64_t dynamic_section_size = 0;
66f4335b8eSAntonio Afonso   bool found_dynamic_section = false;
67f4335b8eSAntonio Afonso   ELF_PHDR phdr_entry;
68f4335b8eSAntonio Afonso   for (size_t i = 0; i < phdr_num_entries; i++) {
69f4335b8eSAntonio Afonso     size_t bytes_read;
70f4335b8eSAntonio Afonso     auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry,
71f4335b8eSAntonio Afonso                             sizeof(phdr_entry), bytes_read);
72f4335b8eSAntonio Afonso     if (!error.Success())
73f4335b8eSAntonio Afonso       return LLDB_INVALID_ADDRESS;
74f4335b8eSAntonio Afonso     if (phdr_entry.p_type == llvm::ELF::PT_PHDR) {
75f4335b8eSAntonio Afonso       load_bias = phdr_addr - phdr_entry.p_vaddr;
76f4335b8eSAntonio Afonso       found_load_bias = true;
77f4335b8eSAntonio Afonso     }
78f4335b8eSAntonio Afonso 
79f4335b8eSAntonio Afonso     if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) {
80f4335b8eSAntonio Afonso       dynamic_section_addr = phdr_entry.p_vaddr;
81f4335b8eSAntonio Afonso       dynamic_section_size = phdr_entry.p_memsz;
82f4335b8eSAntonio Afonso       found_dynamic_section = true;
83f4335b8eSAntonio Afonso     }
84f4335b8eSAntonio Afonso   }
85f4335b8eSAntonio Afonso 
86f4335b8eSAntonio Afonso   if (!found_load_bias || !found_dynamic_section)
87f4335b8eSAntonio Afonso     return LLDB_INVALID_ADDRESS;
88f4335b8eSAntonio Afonso 
89f4335b8eSAntonio Afonso   // Find the DT_DEBUG entry in the .dynamic section
90f4335b8eSAntonio Afonso   dynamic_section_addr += load_bias;
91f4335b8eSAntonio Afonso   ELF_DYN dynamic_entry;
92f4335b8eSAntonio Afonso   size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry);
93f4335b8eSAntonio Afonso   for (size_t i = 0; i < dynamic_num_entries; i++) {
94f4335b8eSAntonio Afonso     size_t bytes_read;
95f4335b8eSAntonio Afonso     auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry),
96f4335b8eSAntonio Afonso                             &dynamic_entry, sizeof(dynamic_entry), bytes_read);
97f4335b8eSAntonio Afonso     if (!error.Success())
98f4335b8eSAntonio Afonso       return LLDB_INVALID_ADDRESS;
99f4335b8eSAntonio Afonso     // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the
100f4335b8eSAntonio Afonso     // link_map.
101f4335b8eSAntonio Afonso     if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) {
102f4335b8eSAntonio Afonso       return dynamic_section_addr + i * sizeof(dynamic_entry) +
103f4335b8eSAntonio Afonso              sizeof(dynamic_entry.d_tag);
104f4335b8eSAntonio Afonso     }
105f4335b8eSAntonio Afonso   }
106f4335b8eSAntonio Afonso 
107f4335b8eSAntonio Afonso   return LLDB_INVALID_ADDRESS;
108f4335b8eSAntonio Afonso }
109f4335b8eSAntonio Afonso 
110fbef6c55SJordan Rupprecht template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
111fbef6c55SJordan Rupprecht     llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
112fbef6c55SJordan Rupprecht template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
113fbef6c55SJordan Rupprecht     llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>();
114fbef6c55SJordan Rupprecht 
11505e32badSAntonio Afonso template <typename T>
11605e32badSAntonio Afonso llvm::Expected<SVR4LibraryInfo>
ReadSVR4LibraryInfo(lldb::addr_t link_map_addr)11705e32badSAntonio Afonso NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) {
11805e32badSAntonio Afonso   ELFLinkMap<T> link_map;
11905e32badSAntonio Afonso   size_t bytes_read;
12005e32badSAntonio Afonso   auto error =
12105e32badSAntonio Afonso       ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read);
12205e32badSAntonio Afonso   if (!error.Success())
12305e32badSAntonio Afonso     return error.ToError();
12405e32badSAntonio Afonso 
12505e32badSAntonio Afonso   char name_buffer[PATH_MAX];
12670795c1eSAntonio Afonso   llvm::Expected<llvm::StringRef> string_or_error = ReadCStringFromMemory(
12770795c1eSAntonio Afonso       link_map.l_name, &name_buffer[0], sizeof(name_buffer), bytes_read);
12870795c1eSAntonio Afonso   if (!string_or_error)
12970795c1eSAntonio Afonso     return string_or_error.takeError();
13005e32badSAntonio Afonso 
13105e32badSAntonio Afonso   SVR4LibraryInfo info;
13270795c1eSAntonio Afonso   info.name = string_or_error->str();
13305e32badSAntonio Afonso   info.link_map = link_map_addr;
13405e32badSAntonio Afonso   info.base_addr = link_map.l_addr;
13505e32badSAntonio Afonso   info.ld_addr = link_map.l_ld;
13605e32badSAntonio Afonso   info.next = link_map.l_next;
13705e32badSAntonio Afonso 
13805e32badSAntonio Afonso   return info;
13905e32badSAntonio Afonso }
14005e32badSAntonio Afonso 
14105e32badSAntonio Afonso llvm::Expected<std::vector<SVR4LibraryInfo>>
GetLoadedSVR4Libraries()14205e32badSAntonio Afonso NativeProcessELF::GetLoadedSVR4Libraries() {
14305e32badSAntonio Afonso   // Address of DT_DEBUG.d_ptr which points to r_debug
14405e32badSAntonio Afonso   lldb::addr_t info_address = GetSharedLibraryInfoAddress();
14505e32badSAntonio Afonso   if (info_address == LLDB_INVALID_ADDRESS)
14605e32badSAntonio Afonso     return llvm::createStringError(llvm::inconvertibleErrorCode(),
14705e32badSAntonio Afonso                                    "Invalid shared library info address");
14805e32badSAntonio Afonso   // Address of r_debug
14905e32badSAntonio Afonso   lldb::addr_t address = 0;
15005e32badSAntonio Afonso   size_t bytes_read;
15105e32badSAntonio Afonso   auto status =
15205e32badSAntonio Afonso       ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read);
15305e32badSAntonio Afonso   if (!status.Success())
15405e32badSAntonio Afonso     return status.ToError();
15505e32badSAntonio Afonso   if (address == 0)
15605e32badSAntonio Afonso     return llvm::createStringError(llvm::inconvertibleErrorCode(),
15705e32badSAntonio Afonso                                    "Invalid r_debug address");
15805e32badSAntonio Afonso   // Read r_debug.r_map
15905e32badSAntonio Afonso   lldb::addr_t link_map = 0;
16005e32badSAntonio Afonso   status = ReadMemory(address + GetAddressByteSize(), &link_map,
16105e32badSAntonio Afonso                       GetAddressByteSize(), bytes_read);
16205e32badSAntonio Afonso   if (!status.Success())
16305e32badSAntonio Afonso     return status.ToError();
16405e32badSAntonio Afonso   if (address == 0)
16505e32badSAntonio Afonso     return llvm::createStringError(llvm::inconvertibleErrorCode(),
16605e32badSAntonio Afonso                                    "Invalid link_map address");
16705e32badSAntonio Afonso 
16805e32badSAntonio Afonso   std::vector<SVR4LibraryInfo> library_list;
16905e32badSAntonio Afonso   while (link_map) {
17005e32badSAntonio Afonso     llvm::Expected<SVR4LibraryInfo> info =
17105e32badSAntonio Afonso         GetAddressByteSize() == 8 ? ReadSVR4LibraryInfo<uint64_t>(link_map)
17205e32badSAntonio Afonso                                   : ReadSVR4LibraryInfo<uint32_t>(link_map);
17305e32badSAntonio Afonso     if (!info)
17405e32badSAntonio Afonso       return info.takeError();
17505e32badSAntonio Afonso     if (!info->name.empty() && info->base_addr != 0)
17605e32badSAntonio Afonso       library_list.push_back(*info);
17705e32badSAntonio Afonso     link_map = info->next;
17805e32badSAntonio Afonso   }
17905e32badSAntonio Afonso 
18005e32badSAntonio Afonso   return library_list;
18105e32badSAntonio Afonso }
18205e32badSAntonio Afonso 
NotifyDidExec()183cf2c8e41SPavel Labath void NativeProcessELF::NotifyDidExec() {
184cf2c8e41SPavel Labath   NativeProcessProtocol::NotifyDidExec();
185cf2c8e41SPavel Labath   m_shared_library_info_addr.reset();
186cf2c8e41SPavel Labath }
187cf2c8e41SPavel Labath 
188f4335b8eSAntonio Afonso } // namespace lldb_private
189