1dda28197Spatrick //===-- NativeProcessELF.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick
9061da546Spatrick #include "NativeProcessELF.h"
10061da546Spatrick
11061da546Spatrick #include "lldb/Utility/DataExtractor.h"
12*f6aab3d8Srobert #include <optional>
13061da546Spatrick
14061da546Spatrick namespace lldb_private {
15061da546Spatrick
16*f6aab3d8Srobert std::optional<uint64_t>
GetAuxValue(enum AuxVector::EntryType type)17061da546Spatrick NativeProcessELF::GetAuxValue(enum AuxVector::EntryType type) {
18061da546Spatrick if (m_aux_vector == nullptr) {
19061da546Spatrick auto buffer_or_error = GetAuxvData();
20061da546Spatrick if (!buffer_or_error)
21*f6aab3d8Srobert return std::nullopt;
22061da546Spatrick DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(),
23061da546Spatrick buffer_or_error.get()->getBufferSize(),
24061da546Spatrick GetByteOrder(), GetAddressByteSize());
25061da546Spatrick m_aux_vector = std::make_unique<AuxVector>(auxv_data);
26061da546Spatrick }
27061da546Spatrick
28061da546Spatrick return m_aux_vector->GetAuxValue(type);
29061da546Spatrick }
30061da546Spatrick
GetSharedLibraryInfoAddress()31061da546Spatrick lldb::addr_t NativeProcessELF::GetSharedLibraryInfoAddress() {
32*f6aab3d8Srobert if (!m_shared_library_info_addr) {
33061da546Spatrick if (GetAddressByteSize() == 8)
34061da546Spatrick m_shared_library_info_addr =
35061da546Spatrick GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr,
36061da546Spatrick llvm::ELF::Elf64_Dyn>();
37061da546Spatrick else
38061da546Spatrick m_shared_library_info_addr =
39061da546Spatrick GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr,
40061da546Spatrick llvm::ELF::Elf32_Dyn>();
41061da546Spatrick }
42061da546Spatrick
43*f6aab3d8Srobert return *m_shared_library_info_addr;
44061da546Spatrick }
45061da546Spatrick
46061da546Spatrick template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
GetELFImageInfoAddress()47061da546Spatrick lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() {
48*f6aab3d8Srobert std::optional<uint64_t> maybe_phdr_addr =
49061da546Spatrick GetAuxValue(AuxVector::AUXV_AT_PHDR);
50*f6aab3d8Srobert std::optional<uint64_t> maybe_phdr_entry_size =
51061da546Spatrick GetAuxValue(AuxVector::AUXV_AT_PHENT);
52*f6aab3d8Srobert std::optional<uint64_t> maybe_phdr_num_entries =
53061da546Spatrick GetAuxValue(AuxVector::AUXV_AT_PHNUM);
54061da546Spatrick if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries)
55061da546Spatrick return LLDB_INVALID_ADDRESS;
56061da546Spatrick lldb::addr_t phdr_addr = *maybe_phdr_addr;
57061da546Spatrick size_t phdr_entry_size = *maybe_phdr_entry_size;
58061da546Spatrick size_t phdr_num_entries = *maybe_phdr_num_entries;
59061da546Spatrick
60061da546Spatrick // Find the PT_DYNAMIC segment (.dynamic section) in the program header and
61061da546Spatrick // what the load bias by calculating the difference of the program header
62061da546Spatrick // load address and its virtual address.
63061da546Spatrick lldb::offset_t load_bias;
64061da546Spatrick bool found_load_bias = false;
65061da546Spatrick lldb::addr_t dynamic_section_addr = 0;
66061da546Spatrick uint64_t dynamic_section_size = 0;
67061da546Spatrick bool found_dynamic_section = false;
68061da546Spatrick ELF_PHDR phdr_entry;
69061da546Spatrick for (size_t i = 0; i < phdr_num_entries; i++) {
70061da546Spatrick size_t bytes_read;
71061da546Spatrick auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry,
72061da546Spatrick sizeof(phdr_entry), bytes_read);
73061da546Spatrick if (!error.Success())
74061da546Spatrick return LLDB_INVALID_ADDRESS;
75061da546Spatrick if (phdr_entry.p_type == llvm::ELF::PT_PHDR) {
76061da546Spatrick load_bias = phdr_addr - phdr_entry.p_vaddr;
77061da546Spatrick found_load_bias = true;
78061da546Spatrick }
79061da546Spatrick
80061da546Spatrick if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) {
81061da546Spatrick dynamic_section_addr = phdr_entry.p_vaddr;
82061da546Spatrick dynamic_section_size = phdr_entry.p_memsz;
83061da546Spatrick found_dynamic_section = true;
84061da546Spatrick }
85061da546Spatrick }
86061da546Spatrick
87061da546Spatrick if (!found_load_bias || !found_dynamic_section)
88061da546Spatrick return LLDB_INVALID_ADDRESS;
89061da546Spatrick
90061da546Spatrick // Find the DT_DEBUG entry in the .dynamic section
91061da546Spatrick dynamic_section_addr += load_bias;
92061da546Spatrick ELF_DYN dynamic_entry;
93061da546Spatrick size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry);
94061da546Spatrick for (size_t i = 0; i < dynamic_num_entries; i++) {
95061da546Spatrick size_t bytes_read;
96061da546Spatrick auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry),
97061da546Spatrick &dynamic_entry, sizeof(dynamic_entry), bytes_read);
98061da546Spatrick if (!error.Success())
99061da546Spatrick return LLDB_INVALID_ADDRESS;
100061da546Spatrick // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the
101061da546Spatrick // link_map.
102061da546Spatrick if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) {
103061da546Spatrick return dynamic_section_addr + i * sizeof(dynamic_entry) +
104061da546Spatrick sizeof(dynamic_entry.d_tag);
105061da546Spatrick }
106061da546Spatrick }
107061da546Spatrick
108061da546Spatrick return LLDB_INVALID_ADDRESS;
109061da546Spatrick }
110061da546Spatrick
111dda28197Spatrick template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
112dda28197Spatrick llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
113dda28197Spatrick template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
114dda28197Spatrick llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>();
115dda28197Spatrick
116061da546Spatrick template <typename T>
117061da546Spatrick llvm::Expected<SVR4LibraryInfo>
ReadSVR4LibraryInfo(lldb::addr_t link_map_addr)118061da546Spatrick NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) {
119061da546Spatrick ELFLinkMap<T> link_map;
120061da546Spatrick size_t bytes_read;
121061da546Spatrick auto error =
122061da546Spatrick ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read);
123061da546Spatrick if (!error.Success())
124061da546Spatrick return error.ToError();
125061da546Spatrick
126061da546Spatrick char name_buffer[PATH_MAX];
127061da546Spatrick llvm::Expected<llvm::StringRef> string_or_error = ReadCStringFromMemory(
128061da546Spatrick link_map.l_name, &name_buffer[0], sizeof(name_buffer), bytes_read);
129061da546Spatrick if (!string_or_error)
130061da546Spatrick return string_or_error.takeError();
131061da546Spatrick
132061da546Spatrick SVR4LibraryInfo info;
133061da546Spatrick info.name = string_or_error->str();
134061da546Spatrick info.link_map = link_map_addr;
135061da546Spatrick info.base_addr = link_map.l_addr;
136061da546Spatrick info.ld_addr = link_map.l_ld;
137061da546Spatrick info.next = link_map.l_next;
138061da546Spatrick
139061da546Spatrick return info;
140061da546Spatrick }
141061da546Spatrick
142061da546Spatrick llvm::Expected<std::vector<SVR4LibraryInfo>>
GetLoadedSVR4Libraries()143061da546Spatrick NativeProcessELF::GetLoadedSVR4Libraries() {
144061da546Spatrick // Address of DT_DEBUG.d_ptr which points to r_debug
145061da546Spatrick lldb::addr_t info_address = GetSharedLibraryInfoAddress();
146061da546Spatrick if (info_address == LLDB_INVALID_ADDRESS)
147061da546Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
148061da546Spatrick "Invalid shared library info address");
149061da546Spatrick // Address of r_debug
150061da546Spatrick lldb::addr_t address = 0;
151061da546Spatrick size_t bytes_read;
152061da546Spatrick auto status =
153061da546Spatrick ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read);
154061da546Spatrick if (!status.Success())
155061da546Spatrick return status.ToError();
156061da546Spatrick if (address == 0)
157061da546Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
158061da546Spatrick "Invalid r_debug address");
159061da546Spatrick // Read r_debug.r_map
160061da546Spatrick lldb::addr_t link_map = 0;
161061da546Spatrick status = ReadMemory(address + GetAddressByteSize(), &link_map,
162061da546Spatrick GetAddressByteSize(), bytes_read);
163061da546Spatrick if (!status.Success())
164061da546Spatrick return status.ToError();
165*f6aab3d8Srobert if (link_map == 0)
166061da546Spatrick return llvm::createStringError(llvm::inconvertibleErrorCode(),
167061da546Spatrick "Invalid link_map address");
168061da546Spatrick
169061da546Spatrick std::vector<SVR4LibraryInfo> library_list;
170061da546Spatrick while (link_map) {
171061da546Spatrick llvm::Expected<SVR4LibraryInfo> info =
172061da546Spatrick GetAddressByteSize() == 8 ? ReadSVR4LibraryInfo<uint64_t>(link_map)
173061da546Spatrick : ReadSVR4LibraryInfo<uint32_t>(link_map);
174061da546Spatrick if (!info)
175061da546Spatrick return info.takeError();
176061da546Spatrick if (!info->name.empty() && info->base_addr != 0)
177061da546Spatrick library_list.push_back(*info);
178061da546Spatrick link_map = info->next;
179061da546Spatrick }
180061da546Spatrick
181061da546Spatrick return library_list;
182061da546Spatrick }
183061da546Spatrick
NotifyDidExec()184*f6aab3d8Srobert void NativeProcessELF::NotifyDidExec() {
185*f6aab3d8Srobert NativeProcessProtocol::NotifyDidExec();
186*f6aab3d8Srobert m_shared_library_info_addr.reset();
187*f6aab3d8Srobert }
188*f6aab3d8Srobert
189061da546Spatrick } // namespace lldb_private
190