10#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && \
11 !defined(__DragonFly__)
12#error "microfmt/inspector/dl_elf_enumerator.hpp only supports Linux and BSD systems"
20#include "../microfmt.hpp"
33inline bool dl_phdr_image_bounds(
const dl_phdr_info &info, uintptr_t &out_base, uintptr_t &out_size)
noexcept {
34 uintptr_t min_vaddr = 0;
35 uintptr_t max_vaddr = 0;
36 bool have_load =
false;
38 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
40 for (
size_t i = 0; i < static_cast<size_t>(info.dlpi_phnum); ++i) {
41 const auto &phdr = info.dlpi_phdr[i];
42 if (phdr.p_type != PT_LOAD)
44 const auto start =
static_cast<uintptr_t
>(phdr.p_vaddr);
45 const auto end = start +
static_cast<uintptr_t
>(phdr.p_memsz);
46 if (!have_load || start < min_vaddr)
48 if (!have_load || end > max_vaddr)
53 RELOCO_END_UNSAFE_BUFFER_USAGE;
57 out_base =
static_cast<uintptr_t
>(info.dlpi_addr) + min_vaddr;
58 out_size = max_vaddr - min_vaddr;
62#if defined(PT_ARM_EXIDX)
71inline bool dl_phdr_exidx_bounds(
const dl_phdr_info &info, uintptr_t &out_start, uintptr_t &out_end)
noexcept {
74 bool have_exidx =
false;
76 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
78 for (
size_t i = 0; i < static_cast<size_t>(info.dlpi_phnum); ++i) {
79 const auto &phdr = info.dlpi_phdr[i];
80 if (phdr.p_type != PT_ARM_EXIDX)
82 start =
static_cast<uintptr_t
>(info.dlpi_addr) +
static_cast<uintptr_t
>(phdr.p_vaddr);
83 end = start +
static_cast<uintptr_t
>(phdr.p_memsz);
88 RELOCO_END_UNSAFE_BUFFER_USAGE;
90 if (!have_exidx || end <= start)
98#if defined(PT_GNU_EH_FRAME)
103inline constexpr unsigned char k_dw_eh_pe_omit = 0xff;
104inline constexpr unsigned char k_dw_eh_pe_format_mask = 0x0f;
105inline constexpr unsigned char k_dw_eh_pe_application_mask = 0x70;
106inline constexpr unsigned char k_dw_eh_pe_udata4 = 0x03;
107inline constexpr unsigned char k_dw_eh_pe_sdata4 = 0x0b;
108inline constexpr unsigned char k_dw_eh_pe_pcrel = 0x10;
109inline constexpr unsigned char k_dw_eh_pe_absptr_application = 0x00;
124RELOCO_BEGIN_UNSAFE_CODE
125inline bool decode_eh_frame_hdr(uintptr_t hdr_start, uintptr_t hdr_end, uintptr_t &out_eh_frame_start)
noexcept {
127 if (hdr_end < hdr_start || hdr_end - hdr_start < 8)
130 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
132 const auto *
bytes =
reinterpret_cast<const unsigned char *
>(hdr_start);
134 const unsigned char eh_frame_ptr_enc =
bytes[1];
135 RELOCO_END_UNSAFE_BUFFER_USAGE;
137 if (
version != 1 || eh_frame_ptr_enc == k_dw_eh_pe_omit)
140 const unsigned char format =
static_cast<unsigned char>(eh_frame_ptr_enc & k_dw_eh_pe_format_mask);
141 const unsigned char application =
static_cast<unsigned char>(eh_frame_ptr_enc & k_dw_eh_pe_application_mask);
142 if (application != k_dw_eh_pe_pcrel && application != k_dw_eh_pe_absptr_application)
144 if (
format != k_dw_eh_pe_udata4 &&
format != k_dw_eh_pe_sdata4)
147 const uintptr_t field_addr = hdr_start + 4;
148 int32_t raw_value = 0;
149 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
151 std::memcpy(&raw_value,
reinterpret_cast<const void *
>(field_addr),
sizeof(raw_value));
152 RELOCO_END_UNSAFE_BUFFER_USAGE;
154 const uintptr_t value = (
format == k_dw_eh_pe_udata4) ?
static_cast<uintptr_t
>(
static_cast<uint32_t
>(raw_value))
155 : static_cast<uintptr_t>(raw_value);
157 out_eh_frame_start = (application == k_dw_eh_pe_pcrel) ? field_addr + value : value;
182inline bool dl_phdr_eh_frame_bounds(
const dl_phdr_info &info, uintptr_t &out_start, uintptr_t &out_end)
noexcept {
183 uintptr_t hdr_start = 0;
184 uintptr_t hdr_end = 0;
185 bool have_eh_frame_hdr =
false;
187 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
189 for (
size_t i = 0; i < static_cast<size_t>(
info.dlpi_phnum); ++i) {
190 const auto &phdr =
info.dlpi_phdr[i];
191 if (phdr.p_type != PT_GNU_EH_FRAME)
193 hdr_start =
static_cast<uintptr_t
>(
info.dlpi_addr) +
static_cast<uintptr_t
>(phdr.p_vaddr);
194 hdr_end = hdr_start +
static_cast<uintptr_t
>(phdr.p_memsz);
195 have_eh_frame_hdr =
true;
199 RELOCO_END_UNSAFE_BUFFER_USAGE;
201 if (!have_eh_frame_hdr)
204 uintptr_t eh_frame_start = 0;
205 if (!decode_eh_frame_hdr(hdr_start, hdr_end, eh_frame_start))
208 out_start = eh_frame_start;
209 out_end = UINTPTR_MAX;
228RELOCO_BEGIN_UNSAFE_CODE
231 if (state.count >= state.buffer.size())
241 (info->dlpi_name !=
nullptr && info->dlpi_name[0] !=
'\0') ? string_view(info->dlpi_name) : string_view(
"");
242 entry.load_base = base;
243 entry.image_size = size;
244#if defined(PT_ARM_EXIDX)
245 dl_phdr_exidx_bounds(*info, entry.exidx_start, entry.exidx_end);
247#if defined(PT_GNU_EH_FRAME)
248 dl_phdr_eh_frame_bounds(*info, entry.debug_frame_start, entry.debug_frame_end);
250 state.buffer[state.count++] = entry;
265 out_count = state.count;
275 uintptr_t target_base{};
277 uintptr_t exidx_start{0};
278 uintptr_t exidx_end{0};
279 uintptr_t debug_frame_start{0};
280 uintptr_t debug_frame_end{0};
291RELOCO_BEGIN_UNSAFE_CODE
298 if (base == state.target_base) {
300#if defined(PT_ARM_EXIDX)
301 dl_phdr_exidx_bounds(*info, state.exidx_start, state.exidx_end);
303#if defined(PT_GNU_EH_FRAME)
304 dl_phdr_eh_frame_bounds(*info, state.debug_frame_start, state.debug_frame_end);
323RELOCO_BEGIN_UNSAFE_CODE
327 if (::dladdr(
reinterpret_cast<const void *
>(pc), &info) == 0 || info.dli_fbase ==
nullptr)
332 (info.dli_fname !=
nullptr && info.dli_fname[0] !=
'\0') ? string_view(info.dli_fname) : string_view(
"");
333 result.load_base =
reinterpret_cast<uintptr_t
>(info.dli_fbase);
337 if (size_state.found) {
338 result.image_size = size_state.size;
339 result.exidx_start = size_state.exidx_start;
340 result.exidx_end = size_state.exidx_end;
341 result.debug_frame_start = size_state.debug_frame_start;
342 result.debug_frame_end = size_state.debug_frame_end;
394 static bool enumerate(value_ref<const context_type>, span<elf_image_info> buffer,
size_t &count)
noexcept {
#define MICROFMT_API_CLASS
Definition compat.hpp:181
ELF image introspection, type-erased image enumeration, and fixed-capacity registries.
Definition bintime.hpp:22
RELOCO_BEGIN_UNSAFE_CODE int dl_find_size_callback(dl_phdr_info *info, size_t, void *data) noexcept
dl_iterate_phdr callback that records the mapped size (and, where available, the ....
Definition dl_elf_enumerator.hpp:292
RELOCO_BEGIN_UNSAFE_CODE int dl_enumerate_callback(dl_phdr_info *info, size_t, void *data) noexcept
dl_iterate_phdr callback that fills dl_enumerate_state::buffer with one elf_image_info per loaded ima...
Definition dl_elf_enumerator.hpp:229
bool dl_phdr_image_bounds(const dl_phdr_info &info, uintptr_t &out_base, uintptr_t &out_size) noexcept
Computes the runtime [base, base + size) range covered by an image's PT_LOAD segments.
Definition dl_elf_enumerator.hpp:33
RELOCO_END_UNSAFE_CODE RELOCO_BEGIN_UNSAFE_CODE bool dl_find_by_pc(uintptr_t pc, elf_image_info &out_info) noexcept
Resolves the image owning pc via dladdr, then cross-references dl_iterate_phdr to fill in the image's...
Definition dl_elf_enumerator.hpp:324
RELOCO_END_UNSAFE_CODE bool dl_enumerate_images(span< elf_image_info > out_buffer, size_t &out_count) noexcept
Fills out_buffer with every image currently reported by dl_iterate_phdr, up to its capacity.
Definition dl_elf_enumerator.hpp:262
void info(microfmt::string_view fmt, const Args &...args) noexcept
Definition logger.hpp:347
constexpr semver version(uint16_t major, uint16_t minor, uint16_t patch, microfmt::string_view prerelease="", microfmt::string_view build="", bool show_v=false) noexcept
Definition semver.hpp:34
RELOCO_CONSTEXPR20 buffer_sink< N > format(microfmt::string_view fmt, const Args &...args) noexcept
Definition microfmt.hpp:1786
constexpr bytes_view bytes(uint64_t count) noexcept
Definition format_helpers.hpp:82
RELOCO_END_UNSAFE_CODE
Definition remote_object.hpp:132
Mutable state threaded through dl_enumerate_callback.
Definition dl_elf_enumerator.hpp:217
span< elf_image_info > buffer
Definition dl_elf_enumerator.hpp:218
State used by dl_find_size_callback to locate the PT_LOAD (and, where available, PT_ARM_EXIDX/PT_GNU_...
Definition dl_elf_enumerator.hpp:274
uintptr_t size
Definition dl_elf_enumerator.hpp:276
Empty context for dl_elf_enumerator_tag: dladdr and dl_iterate_phdr query the dynamic linker directly...
Definition dl_elf_enumerator.hpp:365
Tag selecting the dlfcn.h/dl_iterate_phdr-backed elf_image_enumerator_traits specialization.
Definition dl_elf_enumerator.hpp:358
static bool enumerate(value_ref< const context_type >, span< elf_image_info > buffer, size_t &count) noexcept
Definition dl_elf_enumerator.hpp:394
static bool find_by_pc(value_ref< const context_type >, uintptr_t pc, elf_image_info &out_info) noexcept
Definition dl_elf_enumerator.hpp:398
Definition elf_enumerator.hpp:19
Describes a loaded ELF image and the locations of its unwind tables.
Definition elf_enumerator.hpp:30
microfmt::string_view image_name
Human-readable image/module name.
Definition elf_enumerator.hpp:34