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