xref: /freebsd-src/contrib/llvm-project/lldb/source/Plugins/Process/POSIX/NativeProcessELF.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
15ffd83dbSDimitry Andric //===-- NativeProcessELF.cpp ----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "NativeProcessELF.h"
100b57cec5SDimitry Andric 
110b57cec5SDimitry Andric #include "lldb/Utility/DataExtractor.h"
12*bdd1243dSDimitry Andric #include <optional>
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric namespace lldb_private {
150b57cec5SDimitry Andric 
16*bdd1243dSDimitry Andric std::optional<uint64_t>
GetAuxValue(enum AuxVector::EntryType type)170b57cec5SDimitry Andric NativeProcessELF::GetAuxValue(enum AuxVector::EntryType type) {
180b57cec5SDimitry Andric   if (m_aux_vector == nullptr) {
190b57cec5SDimitry Andric     auto buffer_or_error = GetAuxvData();
200b57cec5SDimitry Andric     if (!buffer_or_error)
21*bdd1243dSDimitry Andric       return std::nullopt;
220b57cec5SDimitry Andric     DataExtractor auxv_data(buffer_or_error.get()->getBufferStart(),
230b57cec5SDimitry Andric                             buffer_or_error.get()->getBufferSize(),
240b57cec5SDimitry Andric                             GetByteOrder(), GetAddressByteSize());
259dba64beSDimitry Andric     m_aux_vector = std::make_unique<AuxVector>(auxv_data);
260b57cec5SDimitry Andric   }
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric   return m_aux_vector->GetAuxValue(type);
290b57cec5SDimitry Andric }
300b57cec5SDimitry Andric 
GetSharedLibraryInfoAddress()310b57cec5SDimitry Andric lldb::addr_t NativeProcessELF::GetSharedLibraryInfoAddress() {
3281ad6265SDimitry Andric   if (!m_shared_library_info_addr) {
330b57cec5SDimitry Andric     if (GetAddressByteSize() == 8)
340b57cec5SDimitry Andric       m_shared_library_info_addr =
350b57cec5SDimitry Andric           GetELFImageInfoAddress<llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr,
360b57cec5SDimitry Andric                                  llvm::ELF::Elf64_Dyn>();
370b57cec5SDimitry Andric     else
380b57cec5SDimitry Andric       m_shared_library_info_addr =
390b57cec5SDimitry Andric           GetELFImageInfoAddress<llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr,
400b57cec5SDimitry Andric                                  llvm::ELF::Elf32_Dyn>();
410b57cec5SDimitry Andric   }
420b57cec5SDimitry Andric 
4381ad6265SDimitry Andric   return *m_shared_library_info_addr;
440b57cec5SDimitry Andric }
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric template <typename ELF_EHDR, typename ELF_PHDR, typename ELF_DYN>
GetELFImageInfoAddress()470b57cec5SDimitry Andric lldb::addr_t NativeProcessELF::GetELFImageInfoAddress() {
48*bdd1243dSDimitry Andric   std::optional<uint64_t> maybe_phdr_addr =
490b57cec5SDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHDR);
50*bdd1243dSDimitry Andric   std::optional<uint64_t> maybe_phdr_entry_size =
510b57cec5SDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHENT);
52*bdd1243dSDimitry Andric   std::optional<uint64_t> maybe_phdr_num_entries =
530b57cec5SDimitry Andric       GetAuxValue(AuxVector::AUXV_AT_PHNUM);
540b57cec5SDimitry Andric   if (!maybe_phdr_addr || !maybe_phdr_entry_size || !maybe_phdr_num_entries)
550b57cec5SDimitry Andric     return LLDB_INVALID_ADDRESS;
560b57cec5SDimitry Andric   lldb::addr_t phdr_addr = *maybe_phdr_addr;
570b57cec5SDimitry Andric   size_t phdr_entry_size = *maybe_phdr_entry_size;
580b57cec5SDimitry Andric   size_t phdr_num_entries = *maybe_phdr_num_entries;
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   // Find the PT_DYNAMIC segment (.dynamic section) in the program header and
610b57cec5SDimitry Andric   // what the load bias by calculating the difference of the program header
620b57cec5SDimitry Andric   // load address and its virtual address.
630b57cec5SDimitry Andric   lldb::offset_t load_bias;
640b57cec5SDimitry Andric   bool found_load_bias = false;
650b57cec5SDimitry Andric   lldb::addr_t dynamic_section_addr = 0;
660b57cec5SDimitry Andric   uint64_t dynamic_section_size = 0;
670b57cec5SDimitry Andric   bool found_dynamic_section = false;
680b57cec5SDimitry Andric   ELF_PHDR phdr_entry;
690b57cec5SDimitry Andric   for (size_t i = 0; i < phdr_num_entries; i++) {
700b57cec5SDimitry Andric     size_t bytes_read;
710b57cec5SDimitry Andric     auto error = ReadMemory(phdr_addr + i * phdr_entry_size, &phdr_entry,
720b57cec5SDimitry Andric                             sizeof(phdr_entry), bytes_read);
730b57cec5SDimitry Andric     if (!error.Success())
740b57cec5SDimitry Andric       return LLDB_INVALID_ADDRESS;
750b57cec5SDimitry Andric     if (phdr_entry.p_type == llvm::ELF::PT_PHDR) {
760b57cec5SDimitry Andric       load_bias = phdr_addr - phdr_entry.p_vaddr;
770b57cec5SDimitry Andric       found_load_bias = true;
780b57cec5SDimitry Andric     }
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric     if (phdr_entry.p_type == llvm::ELF::PT_DYNAMIC) {
810b57cec5SDimitry Andric       dynamic_section_addr = phdr_entry.p_vaddr;
820b57cec5SDimitry Andric       dynamic_section_size = phdr_entry.p_memsz;
830b57cec5SDimitry Andric       found_dynamic_section = true;
840b57cec5SDimitry Andric     }
850b57cec5SDimitry Andric   }
860b57cec5SDimitry Andric 
870b57cec5SDimitry Andric   if (!found_load_bias || !found_dynamic_section)
880b57cec5SDimitry Andric     return LLDB_INVALID_ADDRESS;
890b57cec5SDimitry Andric 
900b57cec5SDimitry Andric   // Find the DT_DEBUG entry in the .dynamic section
910b57cec5SDimitry Andric   dynamic_section_addr += load_bias;
920b57cec5SDimitry Andric   ELF_DYN dynamic_entry;
930b57cec5SDimitry Andric   size_t dynamic_num_entries = dynamic_section_size / sizeof(dynamic_entry);
940b57cec5SDimitry Andric   for (size_t i = 0; i < dynamic_num_entries; i++) {
950b57cec5SDimitry Andric     size_t bytes_read;
960b57cec5SDimitry Andric     auto error = ReadMemory(dynamic_section_addr + i * sizeof(dynamic_entry),
970b57cec5SDimitry Andric                             &dynamic_entry, sizeof(dynamic_entry), bytes_read);
980b57cec5SDimitry Andric     if (!error.Success())
990b57cec5SDimitry Andric       return LLDB_INVALID_ADDRESS;
1000b57cec5SDimitry Andric     // Return the &DT_DEBUG->d_ptr which points to r_debug which contains the
1010b57cec5SDimitry Andric     // link_map.
1020b57cec5SDimitry Andric     if (dynamic_entry.d_tag == llvm::ELF::DT_DEBUG) {
1030b57cec5SDimitry Andric       return dynamic_section_addr + i * sizeof(dynamic_entry) +
1040b57cec5SDimitry Andric              sizeof(dynamic_entry.d_tag);
1050b57cec5SDimitry Andric     }
1060b57cec5SDimitry Andric   }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   return LLDB_INVALID_ADDRESS;
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric 
1115ffd83dbSDimitry Andric template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
1125ffd83dbSDimitry Andric     llvm::ELF::Elf32_Ehdr, llvm::ELF::Elf32_Phdr, llvm::ELF::Elf32_Dyn>();
1135ffd83dbSDimitry Andric template lldb::addr_t NativeProcessELF::GetELFImageInfoAddress<
1145ffd83dbSDimitry Andric     llvm::ELF::Elf64_Ehdr, llvm::ELF::Elf64_Phdr, llvm::ELF::Elf64_Dyn>();
1155ffd83dbSDimitry Andric 
1169dba64beSDimitry Andric template <typename T>
1179dba64beSDimitry Andric llvm::Expected<SVR4LibraryInfo>
ReadSVR4LibraryInfo(lldb::addr_t link_map_addr)1189dba64beSDimitry Andric NativeProcessELF::ReadSVR4LibraryInfo(lldb::addr_t link_map_addr) {
1199dba64beSDimitry Andric   ELFLinkMap<T> link_map;
1209dba64beSDimitry Andric   size_t bytes_read;
1219dba64beSDimitry Andric   auto error =
1229dba64beSDimitry Andric       ReadMemory(link_map_addr, &link_map, sizeof(link_map), bytes_read);
1239dba64beSDimitry Andric   if (!error.Success())
1249dba64beSDimitry Andric     return error.ToError();
1259dba64beSDimitry Andric 
1269dba64beSDimitry Andric   char name_buffer[PATH_MAX];
1279dba64beSDimitry Andric   llvm::Expected<llvm::StringRef> string_or_error = ReadCStringFromMemory(
1289dba64beSDimitry Andric       link_map.l_name, &name_buffer[0], sizeof(name_buffer), bytes_read);
1299dba64beSDimitry Andric   if (!string_or_error)
1309dba64beSDimitry Andric     return string_or_error.takeError();
1319dba64beSDimitry Andric 
1329dba64beSDimitry Andric   SVR4LibraryInfo info;
1339dba64beSDimitry Andric   info.name = string_or_error->str();
1349dba64beSDimitry Andric   info.link_map = link_map_addr;
1359dba64beSDimitry Andric   info.base_addr = link_map.l_addr;
1369dba64beSDimitry Andric   info.ld_addr = link_map.l_ld;
1379dba64beSDimitry Andric   info.next = link_map.l_next;
1389dba64beSDimitry Andric 
1399dba64beSDimitry Andric   return info;
1409dba64beSDimitry Andric }
1419dba64beSDimitry Andric 
1429dba64beSDimitry Andric llvm::Expected<std::vector<SVR4LibraryInfo>>
GetLoadedSVR4Libraries()1439dba64beSDimitry Andric NativeProcessELF::GetLoadedSVR4Libraries() {
1449dba64beSDimitry Andric   // Address of DT_DEBUG.d_ptr which points to r_debug
1459dba64beSDimitry Andric   lldb::addr_t info_address = GetSharedLibraryInfoAddress();
1469dba64beSDimitry Andric   if (info_address == LLDB_INVALID_ADDRESS)
1479dba64beSDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
1489dba64beSDimitry Andric                                    "Invalid shared library info address");
1499dba64beSDimitry Andric   // Address of r_debug
1509dba64beSDimitry Andric   lldb::addr_t address = 0;
1519dba64beSDimitry Andric   size_t bytes_read;
1529dba64beSDimitry Andric   auto status =
1539dba64beSDimitry Andric       ReadMemory(info_address, &address, GetAddressByteSize(), bytes_read);
1549dba64beSDimitry Andric   if (!status.Success())
1559dba64beSDimitry Andric     return status.ToError();
1569dba64beSDimitry Andric   if (address == 0)
1579dba64beSDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
1589dba64beSDimitry Andric                                    "Invalid r_debug address");
1599dba64beSDimitry Andric   // Read r_debug.r_map
1609dba64beSDimitry Andric   lldb::addr_t link_map = 0;
1619dba64beSDimitry Andric   status = ReadMemory(address + GetAddressByteSize(), &link_map,
1629dba64beSDimitry Andric                       GetAddressByteSize(), bytes_read);
1639dba64beSDimitry Andric   if (!status.Success())
1649dba64beSDimitry Andric     return status.ToError();
165*bdd1243dSDimitry Andric   if (link_map == 0)
1669dba64beSDimitry Andric     return llvm::createStringError(llvm::inconvertibleErrorCode(),
1679dba64beSDimitry Andric                                    "Invalid link_map address");
1689dba64beSDimitry Andric 
1699dba64beSDimitry Andric   std::vector<SVR4LibraryInfo> library_list;
1709dba64beSDimitry Andric   while (link_map) {
1719dba64beSDimitry Andric     llvm::Expected<SVR4LibraryInfo> info =
1729dba64beSDimitry Andric         GetAddressByteSize() == 8 ? ReadSVR4LibraryInfo<uint64_t>(link_map)
1739dba64beSDimitry Andric                                   : ReadSVR4LibraryInfo<uint32_t>(link_map);
1749dba64beSDimitry Andric     if (!info)
1759dba64beSDimitry Andric       return info.takeError();
1769dba64beSDimitry Andric     if (!info->name.empty() && info->base_addr != 0)
1779dba64beSDimitry Andric       library_list.push_back(*info);
1789dba64beSDimitry Andric     link_map = info->next;
1799dba64beSDimitry Andric   }
1809dba64beSDimitry Andric 
1819dba64beSDimitry Andric   return library_list;
1829dba64beSDimitry Andric }
1839dba64beSDimitry Andric 
NotifyDidExec()18481ad6265SDimitry Andric void NativeProcessELF::NotifyDidExec() {
18581ad6265SDimitry Andric   NativeProcessProtocol::NotifyDidExec();
18681ad6265SDimitry Andric   m_shared_library_info_addr.reset();
18781ad6265SDimitry Andric }
18881ad6265SDimitry Andric 
1890b57cec5SDimitry Andric } // namespace lldb_private
190