microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
elf_enumerator.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2026 Jarosław Pelczar <jarek@jpelczar.com>
2//
3// SPDX-License-Identifier: BSD-2-Clause
4
5#pragma once
6
10#include "../microfmt.hpp"
11#include "../reloco.hpp"
12#include <cstdint>
13#include <string_view>
14#include <type_traits>
15#include <utility>
16
17namespace microfmt {
18
19template <typename Tag> struct elf_image_enumerator_traits;
20template <size_t MaxImages> class multi_elf_registry_context;
21template <size_t MaxImages = 16> struct multi_elf_registry_tag {};
22
23// ============================================================================
24// ELF Image Record with EXIDX and Module Boundaries
25// ============================================================================
26
30struct RELOCO_POINTER elf_image_info {
34 microfmt::string_view image_name{""};
38 uintptr_t load_base{0};
42 uintptr_t image_size{0};
43
47 uintptr_t exidx_start{0};
51 uintptr_t exidx_end{0};
52
61 uintptr_t debug_frame_start{0};
68 uintptr_t debug_frame_end{0};
69
75 [[nodiscard]] constexpr bool contains(uintptr_t addr) const noexcept {
76 return addr >= load_base && addr < (load_base + image_size);
77 }
78
83 [[nodiscard]] constexpr bool has_exidx() const noexcept { return exidx_start != 0 && exidx_end > exidx_start; }
84
90 [[nodiscard]] constexpr bool has_debug_frame() const noexcept {
91 return debug_frame_start != 0 && debug_frame_end > debug_frame_start;
92 }
93};
94
95// ============================================================================
96// Type-Erased ELF Image Enumerator Handle
97// ============================================================================
98
105public:
109 struct vtable {
114 bool (*enumerate)(const void *ctx, span<elf_image_info> out_buffer, size_t &out_count) noexcept = nullptr;
119 bool (*find_by_pc)(const void *ctx, uintptr_t pc, elf_image_info &out_info) noexcept = nullptr;
120 };
121
125 constexpr elf_image_enumerator_ref() noexcept = default;
126
134 template <typename Tag, typename Context, typename Traits = elf_image_enumerator_traits<Tag>,
135 std::enable_if_t<std::is_convertible_v<const Context *, const typename Traits::context_type *>, int> = 0>
137 const Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
138 : ctx_(&ctx), vtbl_(&s_vtbl<Tag>) {}
139
140 template <typename Tag, typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>, int> = 0>
141 constexpr elf_image_enumerator_ref(Tag, Context &&) = delete;
142
143 template <typename Tag, typename Context, typename Traits = elf_image_enumerator_traits<Tag>>
144 [[nodiscard]] static constexpr elf_image_enumerator_ref make(const Context &ctx RELOCO_LIFETIMEBOUND) noexcept {
145 return elf_image_enumerator_ref(Tag{}, ctx);
146 }
147
148 template <typename Tag, typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>, int> = 0>
149 static elf_image_enumerator_ref make(Context &&) = delete;
150
157 [[nodiscard]] bool enumerate(span<elf_image_info> out_buffer, size_t &out_count) const noexcept {
158 if (vtbl_ == nullptr)
159 return false;
160 return vtbl_->enumerate(ctx_.get(), out_buffer, out_count);
161 }
162
169 [[nodiscard]] bool find_by_pc(uintptr_t pc, elf_image_info &out_info) const noexcept {
170 if (vtbl_ == nullptr)
171 return false;
172 return vtbl_->find_by_pc(ctx_.get(), pc, out_info);
173 }
174
179 [[nodiscard]] constexpr explicit operator bool() const noexcept { return vtbl_ != nullptr; }
180
181private:
182 template <typename Tag>
183 static constexpr vtable s_vtbl{
184 [](const void *context, span<elf_image_info> buffer, size_t &count) noexcept {
185 using context_type = typename elf_image_enumerator_traits<Tag>::context_type;
186 const auto &typed_context = *static_cast<const context_type *>(context);
187 return elf_image_enumerator_traits<Tag>::enumerate(value_ref<const context_type>(typed_context), buffer, count);
188 },
189 [](const void *context, uintptr_t pc, elf_image_info &info) noexcept {
190 using context_type = typename elf_image_enumerator_traits<Tag>::context_type;
191 const auto &typed_context = *static_cast<const context_type *>(context);
192 return elf_image_enumerator_traits<Tag>::find_by_pc(value_ref<const context_type>(typed_context), pc, info);
193 }};
194
195 value_ptr<const void> ctx_{};
196 const vtable *vtbl_{nullptr};
197};
198
202template <typename Tag> class RELOCO_OWNER elf_image_enumerator {
203public:
205 using context_type = typename traits_type::context_type;
206
207 constexpr explicit elf_image_enumerator(context_type context) noexcept : context_(std::move(context)) {}
208
209 [[nodiscard]] constexpr value_ref<context_type> context() & noexcept RELOCO_LIFETIMEBOUND {
210 return value_ref<context_type>(context_);
211 }
212
213 [[nodiscard]] constexpr value_ref<const context_type> context() const & noexcept RELOCO_LIFETIMEBOUND {
214 return value_ref<const context_type>(context_);
215 }
216
217 [[nodiscard]] constexpr elf_image_enumerator_ref ref() const & noexcept RELOCO_LIFETIMEBOUND {
218 return elf_image_enumerator_ref(Tag{}, context_);
219 }
220
221 [[nodiscard]] explicit constexpr operator elf_image_enumerator_ref() const & noexcept RELOCO_LIFETIMEBOUND {
222 return ref();
223 }
224
225 value_ref<context_type> context() && = delete;
226 value_ref<const context_type> context() const && = delete;
227 elf_image_enumerator_ref ref() const && = delete;
228 operator elf_image_enumerator_ref() const && = delete;
229
230private:
231 context_type context_;
232};
233
234// ============================================================================
235// Concrete Fixed-Capacity Multi-ELF Registry Context (Zero Allocation)
236// ============================================================================
237
243template <size_t MaxImages> class RELOCO_OWNER multi_elf_registry_context {
244public:
248 constexpr multi_elf_registry_context() noexcept = default;
249
255 constexpr bool register_image(const elf_image_info &info) noexcept {
256 if (image_count_ >= MaxImages)
257 return false;
258 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
259
260 images_[image_count_++] = info;
261
262 RELOCO_END_UNSAFE_BUFFER_USAGE;
263
264 return true;
265 }
266
273 [[nodiscard]] constexpr bool enumerate(span<elf_image_info> out_buffer, size_t &out_count) const noexcept {
274 size_t copy_count = (image_count_ < out_buffer.size()) ? image_count_ : out_buffer.size();
275 for (size_t i = 0; i < copy_count; ++i) {
276 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
277
278 out_buffer[i] = images_[i];
279
280 RELOCO_END_UNSAFE_BUFFER_USAGE;
281 }
282 out_count = copy_count;
283 return true;
284 }
285
292 [[nodiscard]] constexpr bool find_by_pc(uintptr_t pc, elf_image_info &out_info) const noexcept {
293 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
294
295 for (size_t i = 0; i < image_count_; ++i) {
296 if (images_[i].contains(pc)) {
297 out_info = images_[i];
298 return true;
299 }
300 }
301
302 RELOCO_END_UNSAFE_BUFFER_USAGE;
303
304 return false;
305 }
306
311 [[nodiscard]] constexpr size_t size() const noexcept { return image_count_; }
312
313private:
315 elf_image_info images_[MaxImages]{};
317 size_t image_count_{0};
318};
319
324template <size_t MaxImages> struct elf_image_enumerator_traits<multi_elf_registry_tag<MaxImages>> {
326
327 static bool enumerate(value_ref<const context_type> context, span<elf_image_info> buffer, size_t &count) noexcept {
328 return context->enumerate(buffer, count);
329 }
330
331 static bool find_by_pc(value_ref<const context_type> context, uintptr_t pc, elf_image_info &info) noexcept {
332 return context->find_by_pc(pc, info);
333 }
334};
335
336} // namespace microfmt
Type-erased, two-word handle to an ELF image enumerator.
Definition elf_enumerator.hpp:104
constexpr elf_image_enumerator_ref(Tag, Context &&)=delete
bool enumerate(span< elf_image_info > out_buffer, size_t &out_count) const noexcept
Fills a caller-provided buffer with registered ELF images.
Definition elf_enumerator.hpp:157
static elf_image_enumerator_ref make(Context &&)=delete
bool find_by_pc(uintptr_t pc, elf_image_info &out_info) const noexcept
Locates the ELF image containing the given PC address.
Definition elf_enumerator.hpp:169
constexpr elf_image_enumerator_ref() noexcept=default
Constructs an empty (invalid) handle.
static constexpr elf_image_enumerator_ref make(const Context &ctx RELOCO_LIFETIMEBOUND) noexcept
Definition elf_enumerator.hpp:144
Typed owner for an ELF image-enumerator traits specialization.
Definition elf_enumerator.hpp:202
typename traits_type::context_type context_type
Definition elf_enumerator.hpp:205
value_ref< const context_type > context() const &&=delete
constexpr value_ref< context_type > context() &noexcept RELOCO_LIFETIMEBOUND
Definition elf_enumerator.hpp:209
constexpr elf_image_enumerator_ref ref() const &noexcept RELOCO_LIFETIMEBOUND
Definition elf_enumerator.hpp:217
constexpr value_ref< const context_type > context() const &noexcept RELOCO_LIFETIMEBOUND
Definition elf_enumerator.hpp:213
value_ref< context_type > context() &&=delete
constexpr elf_image_enumerator(context_type context) noexcept
Definition elf_enumerator.hpp:207
Fixed-capacity, zero-allocation registry of ELF images.
Definition elf_enumerator.hpp:243
constexpr bool enumerate(span< elf_image_info > out_buffer, size_t &out_count) const noexcept
Copies registered images into a caller buffer.
Definition elf_enumerator.hpp:273
constexpr size_t size() const noexcept
Returns the number of registered images.
Definition elf_enumerator.hpp:311
constexpr bool find_by_pc(uintptr_t pc, elf_image_info &out_info) const noexcept
Locates the registered image containing pc.
Definition elf_enumerator.hpp:292
constexpr multi_elf_registry_context() noexcept=default
Constructs an empty registry.
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Definition assert.hpp:19
Virtual table of image enumeration operations.
Definition elf_enumerator.hpp:109
static bool enumerate(value_ref< const context_type > context, span< elf_image_info > buffer, size_t &count) noexcept
Definition elf_enumerator.hpp:327
static bool find_by_pc(value_ref< const context_type > context, uintptr_t pc, elf_image_info &info) noexcept
Definition elf_enumerator.hpp:331
Definition elf_enumerator.hpp:19
Describes a loaded ELF image and the locations of its unwind tables.
Definition elf_enumerator.hpp:30
constexpr bool has_debug_frame() const noexcept
Reports whether a usable DWARF CFI unwind-record table (.debug_frame or .eh_frame,...
Definition elf_enumerator.hpp:90
constexpr bool has_exidx() const noexcept
Reports whether a usable .ARM.exidx section is present.
Definition elf_enumerator.hpp:83
constexpr bool contains(uintptr_t addr) const noexcept
Reports whether addr falls within the image range.
Definition elf_enumerator.hpp:75
Definition elf_enumerator.hpp:21