xref: /src/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
1cfca06d7SDimitry Andric //===-- NativeProcessELF.cpp ----------------------------------------------===//
25f29bb8aSDimitry Andric //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f29bb8aSDimitry Andric //
75f29bb8aSDimitry Andric //===----------------------------------------------------------------------===//
85f29bb8aSDimitry Andric 
95f29bb8aSDimitry Andric #include "NativeProcessELF.h"
105f29bb8aSDimitry Andric 
115f29bb8aSDimitry Andric #include "lldb/Utility/DataExtractor.h"
12e3b55780SDimitry Andric #include <optional>
135f29bb8aSDimitry Andric 
145f29bb8aSDimitry Andric namespace lldb_private {
155f29bb8aSDimitry Andric 
16e3b55780SDimitry Andric std::optional<uint64_t>
GetAuxValue(enum AuxVector::EntryType type)175f29bb8aSDimitry Andric NativeProcessELF::GetAuxValue(enum AuxVector::EntryType type) {
185f29bb8aSDimitry Andric   if (m_aux_vector == nullptr) {
195f29bb8aSDimitry Andric     auto buffer_or_error = GetAuxvData();
205f29bb8aSDimitry Andric     if (!buffer_or_error)
21e3b55780SDimitry Andric       return std::nullopt;
225f29bb8aSDimitry Andric     DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(),
235f29bb8aSDimitry Andric                             buffer_or_error.get()->getBufferSize(),
245f29bb8aSDimitry Andric                             GetByteOrder(), GetAddressByteSize());
25ead24645SDimitry Andric     m_aux_vector = std::make_unique<AuxVector>(auxv_data);
265f29bb8aSDimitry Andric   }
275f29bb8aSDimitry Andric 
285f29bb8aSDimitry Andric   return m_aux_vector->GetAuxValue(type);
295f29bb8aSDimitry Andric }
305f29bb8aSDimitry Andric 
GetSharedLibraryInfoAddress()315f29bb8aSDimitry Andric lldb::addr_t NativeProcessELF::GetSharedLibraryInfoAddress() {
32145449b1SDimitry Andric   if (!m_shared_library_info_addr) {
335f29bb8aSDimitry Andric     if (GetAddressByteSize() == 8)
345f29bb8aSDimitry Andric       m_shared_library_info_addr =
355f29bb8aSDimitry Andric           GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr,
365f29bb8aSDimitry Andric                                  llvm::ELF::Elf64_Dyn>();
375f29bb8aSDimitry Andric     else
385f29bb8aSDimitry Andric       m_shared_library_info_addr =
395f29bb8aSDimitry Andric           GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr,
405f29bb8aSDimitry Andric                                  llvm::ELF::Elf32_Dyn>();
415f29bb8aSDimitry Andric   }
425f29bb8aSDimitry Andric 
43145449b1SDimitry Andric   return *m_shared_library_info_addr;
445f29bb8aSDimitry Andric }
455f29bb8aSDimitry Andric 
465f29bb8aSDimitry Andric template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
GetELFImageInfoAddress()475f29bb8aSDimitry Andric lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() {
48e3b55780SDimitry Andric   std::optional<uint64_t> maybe_phdr_addr =
495f29bb8aSDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHDR);
50e3b55780SDimitry Andric   std::optional<uint64_t> maybe_phdr_entry_size =
515f29bb8aSDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHENT);
52e3b55780SDimitry Andric   std::optional<uint64_t> maybe_phdr_num_entries =
535f29bb8aSDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHNUM);
545f29bb8aSDimitry Andric   if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries)
555f29bb8aSDimitry Andric     return LLDB_INVALID_ADDRESS;
565f29bb8aSDimitry Andric   lldb::addr_t phdr_addr = *maybe_phdr_addr;
575f29bb8aSDimitry Andric   size_t phdr_entry_size = *maybe_phdr_entry_size;
585f29bb8aSDimitry Andric   size_t phdr_num_entries = *maybe_phdr_num_entries;
595f29bb8aSDimitry Andric 
605f29bb8aSDimitry Andric   // Find the PT_DYNAMIC segment (.dynamic section) in the program header and
615f29bb8aSDimitry Andric   // what the load bias by calculating the difference of the program header
625f29bb8aSDimitry Andric   // load address and its virtual address.
635f29bb8aSDimitry Andric   lldb::offset_t load_bias;
645f29bb8aSDimitry Andric   bool found_load_bias = false;
655f29bb8aSDimitry Andric   lldb::addr_t dynamic_section_addr = 0;
665f29bb8aSDimitry Andric   uint64_t dynamic_section_size = 0;
675f29bb8aSDimitry Andric   bool found_dynamic_section = false;
685f29bb8aSDimitry Andric   ELF_PHDR phdr_entry;
695f29bb8aSDimitry Andric   for (size_t i = 0; i < phdr_num_entries; i++) {
705f29bb8aSDimitry Andric     size_t bytes_read;
715f29bb8aSDimitry Andric     auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry,
725f29bb8aSDimitry Andric                             sizeof(phdr_entry), bytes_read);
735f29bb8aSDimitry Andric     if (!error.Success())
745f29bb8aSDimitry Andric       return LLDB_INVALID_ADDRESS;
755f29bb8aSDimitry Andric     if (phdr_entry.p_type == llvm::ELF::PT_PHDR) {
765f29bb8aSDimitry Andric       load_bias = phdr_addr - phdr_entry.p_vaddr;
775f29bb8aSDimitry Andric       found_load_bias = true;
785f29bb8aSDimitry Andric     }
795f29bb8aSDimitry Andric 
805f29bb8aSDimitry Andric     if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) {
815f29bb8aSDimitry Andric       dynamic_section_addr = phdr_entry.p_vaddr;
825f29bb8aSDimitry Andric       dynamic_section_size = phdr_entry.p_memsz;
835f29bb8aSDimitry Andric       found_dynamic_section = true;
845f29bb8aSDimitry Andric     }
855f29bb8aSDimitry Andric   }
865f29bb8aSDimitry Andric 
875f29bb8aSDimitry Andric   if (!found_load_bias || !found_dynamic_section)
885f29bb8aSDimitry Andric     return LLDB_INVALID_ADDRESS;
895f29bb8aSDimitry Andric 
905f29bb8aSDimitry Andric   // Find the DT_DEBUG entry in the .dynamic section
915f29bb8aSDimitry Andric   dynamic_section_addr += load_bias;
925f29bb8aSDimitry Andric   ELF_DYN dynamic_entry;
935f29bb8aSDimitry Andric   size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry);
945f29bb8aSDimitry Andric   for (size_t i = 0; i < dynamic_num_entries; i++) {
955f29bb8aSDimitry Andric     size_t bytes_read;
965f29bb8aSDimitry Andric     auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry),
975f29bb8aSDimitry Andric                             &dynamic_entry, sizeof(dynamic_entry), bytes_read);
985f29bb8aSDimitry Andric     if (!error.Success())
995f29bb8aSDimitry Andric       return LLDB_INVALID_ADDRESS;
1005f29bb8aSDimitry Andric     // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the
1015f29bb8aSDimitry Andric     // link_map.
1025f29bb8aSDimitry Andric     if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) {
1035f29bb8aSDimitry Andric       return dynamic_section_addr + i * sizeof(dynamic_entry) +
1045f29bb8aSDimitry Andric              sizeof(dynamic_entry.d_tag);
1055f29bb8aSDimitry Andric     }
1065f29bb8aSDimitry Andric   }
1075f29bb8aSDimitry Andric 
1085f29bb8aSDimitry Andric   return LLDB_INVALID_ADDRESS;
1095f29bb8aSDimitry Andric }
1105f29bb8aSDimitry Andric 
111cfca06d7SDimitry Andric template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
112cfca06d7SDimitry Andric     llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
113cfca06d7SDimitry Andric template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
114cfca06d7SDimitry Andric     llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>();
115cfca06d7SDimitry Andric 
116ead24645SDimitry Andric template <typename T>
117ead24645SDimitry Andric llvm::Expected<SVR4LibraryInfo>
ReadSVR4LibraryInfo(lldb::addr_t link_map_addr)118ead24645SDimitry Andric NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) {
119ead24645SDimitry Andric   ELFLinkMap<T> link_map;
120ead24645SDimitry Andric   size_t bytes_read;
121ead24645SDimitry Andric   auto error =
122ead24645SDimitry Andric       ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read);
123ead24645SDimitry Andric   if (!error.Success())
124ead24645SDimitry Andric     return error.ToError();
125ead24645SDimitry Andric 
126ead24645SDimitry Andric   char name_buffer[PATH_MAX];
127ead24645SDimitry Andric   llvm::Expected<llvm::StringRef> string_or_error = ReadCStringFromMemory(
128ead24645SDimitry Andric       link_map.l_name, &name_buffer[0], sizeof(name_buffer), bytes_read);
129ead24645SDimitry Andric   if (!string_or_error)
130ead24645SDimitry Andric     return string_or_error.takeError();
131ead24645SDimitry Andric 
132ead24645SDimitry Andric   SVR4LibraryInfo info;
133ead24645SDimitry Andric   info.name = string_or_error->str();
134ead24645SDimitry Andric   info.link_map = link_map_addr;
135ead24645SDimitry Andric   info.base_addr = link_map.l_addr;
136ead24645SDimitry Andric   info.ld_addr = link_map.l_ld;
137ead24645SDimitry Andric   info.next = link_map.l_next;
138ead24645SDimitry Andric 
139ead24645SDimitry Andric   return info;
140ead24645SDimitry Andric }
141ead24645SDimitry Andric 
142ead24645SDimitry Andric llvm::Expected<std::vector<SVR4LibraryInfo>>
GetLoadedSVR4Libraries()143ead24645SDimitry Andric NativeProcessELF::GetLoadedSVR4Libraries() {
144ead24645SDimitry Andric   // Address of DT_DEBUG.d_ptr which points to r_debug
145ead24645SDimitry Andric   lldb::addr_t info_address = GetSharedLibraryInfoAddress();
146ead24645SDimitry Andric   if (info_address == LLDB_INVALID_ADDRESS)
147ead24645SDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
148ead24645SDimitry Andric                                    "Invalid shared library info address");
149ead24645SDimitry Andric   // Address of r_debug
150ead24645SDimitry Andric   lldb::addr_t address = 0;
151ead24645SDimitry Andric   size_t bytes_read;
152ead24645SDimitry Andric   auto status =
153ead24645SDimitry Andric       ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read);
154ead24645SDimitry Andric   if (!status.Success())
155ead24645SDimitry Andric     return status.ToError();
156ead24645SDimitry Andric   if (address == 0)
157ead24645SDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
158ead24645SDimitry Andric                                    "Invalid r_debug address");
159ead24645SDimitry Andric   // Read r_debug.r_map
160ead24645SDimitry Andric   lldb::addr_t link_map = 0;
161ead24645SDimitry Andric   status = ReadMemory(address + GetAddressByteSize(), &link_map,
162ead24645SDimitry Andric                       GetAddressByteSize(), bytes_read);
163ead24645SDimitry Andric   if (!status.Success())
164ead24645SDimitry Andric     return status.ToError();
165e3b55780SDimitry Andric   if (link_map == 0)
166ead24645SDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
167ead24645SDimitry Andric                                    "Invalid link_map address");
168ead24645SDimitry Andric 
169ead24645SDimitry Andric   std::vector<SVR4LibraryInfo> library_list;
170ead24645SDimitry Andric   while (link_map) {
171ead24645SDimitry Andric     llvm::Expected<SVR4LibraryInfo> info =
172ead24645SDimitry Andric         GetAddressByteSize() == 8 ? ReadSVR4LibraryInfo<uint64_t>(link_map)
173ead24645SDimitry Andric                                   : ReadSVR4LibraryInfo<uint32_t>(link_map);
174ead24645SDimitry Andric     if (!info)
175ead24645SDimitry Andric       return info.takeError();
176ead24645SDimitry Andric     if (!info->name.empty() && info->base_addr != 0)
177ead24645SDimitry Andric       library_list.push_back(*info);
178ead24645SDimitry Andric     link_map = info->next;
179ead24645SDimitry Andric   }
180ead24645SDimitry Andric 
181ead24645SDimitry Andric   return library_list;
182ead24645SDimitry Andric }
183ead24645SDimitry Andric 
NotifyDidExec()184145449b1SDimitry Andric void NativeProcessELF::NotifyDidExec() {
185145449b1SDimitry Andric   NativeProcessProtocol::NotifyDidExec();
186145449b1SDimitry Andric   m_shared_library_info_addr.reset();
187145449b1SDimitry Andric }
188145449b1SDimitry Andric 
1895f29bb8aSDimitry Andric } // namespace lldb_private
190