| //===-- Implementation of dl_iterate_phdr --------------------------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===---------------------------------------------------------------------===// | |
| /// | |
| /// \file | |
| /// The dl_iterate_phdr implementation. | |
| /// | |
| //===----------------------------------------------------------------------===/ | |
| #include "dl_iterate_phdr.h" | |
| #include "llvm-libc-macros/link-macros.h" | |
| #include "src/__support/CPP/span.h" | |
| #include "src/__support/OSUtil/linux/auxv.h" | |
| #include "src/__support/common.h" | |
| #include "src/__support/macros/config.h" | |
| #include <elf.h> | |
| extern "C" void *__ehdr_start; | |
| namespace LIBC_NAMESPACE_DECL { | |
| struct dl_phdr_info create_executable_info(ElfW(Ehdr) * executable_header) { | |
| // TODO: Calculate dlpi_addr in the PIE case and set dlpi_name for VDSO. | |
| struct dl_phdr_info to_return; | |
| to_return.dlpi_addr = 0; | |
| to_return.dlpi_name = ""; | |
| to_return.dlpi_phdr = reinterpret_cast<ElfW(Phdr) *>( | |
| reinterpret_cast<uintptr_t>(executable_header) + | |
| executable_header->e_phoff); | |
| to_return.dlpi_phnum = executable_header->e_phnum; | |
| to_return.dlpi_adds = 0; | |
| to_return.dlpi_subs = 0; | |
| to_return.dlpi_tls_modid = 0; | |
| to_return.dlpi_tls_data = nullptr; | |
| return to_return; | |
| } | |
| LLVM_LIBC_FUNCTION(int, dl_iterate_phdr, | |
| (__dl_iterate_phdr_callback_t callback, void *arg)) { | |
| ElfW(Ehdr) *executable_header = reinterpret_cast<ElfW(Ehdr) *>(&__ehdr_start); | |
| struct dl_phdr_info executable_info = | |
| create_executable_info(executable_header); | |
| int executable_return_code = | |
| callback(&executable_info, sizeof(executable_info), arg); | |
| if (executable_return_code != 0) | |
| return executable_return_code; | |
| cpp::optional<unsigned long> vdso_start_address = auxv::get(AT_SYSINFO_EHDR); | |
| if (!vdso_start_address) | |
| return 0; | |
| ElfW(Ehdr) *vdso_header = reinterpret_cast<ElfW(Ehdr) *>(*vdso_start_address); | |
| if (vdso_header == nullptr) | |
| return 0; | |
| struct dl_phdr_info vdso_info = create_executable_info(vdso_header); | |
| for (auto elf_headers : | |
| cpp::span<const ElfW(Phdr)>(vdso_info.dlpi_phdr, vdso_info.dlpi_phnum)) { | |
| if (elf_headers.p_type == PT_LOAD) { | |
| vdso_info.dlpi_addr = | |
| reinterpret_cast<ElfW(Addr)>(vdso_header) - elf_headers.p_vaddr; | |
| break; | |
| } | |
| } | |
| return callback(&vdso_info, sizeof(vdso_info), arg); | |
| } | |
| } // namespace LIBC_NAMESPACE_DECL |