microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
arm_exidx_search.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 "address_space.hpp"
11#include <cstdint>
12
13namespace microfmt {
14
19public:
26 [[nodiscard]] static constexpr uintptr_t decode_prel31(uintptr_t entry_addr, uint32_t prel31) noexcept {
27 // PREL31 is a 31-bit signed offset relative to the address of the prel31
28 // word itself. Arithmetic right shift sign-extends from bit 30 to
29 // 32-bit/64-bit int32_t.
30 int32_t signed_offset = static_cast<int32_t>(prel31 << 1) >> 1;
31 return detail::add_address_offset(entry_addr, signed_offset);
32 }
33
48 [[nodiscard]] static bool find_exidx_entry(address_space_ref space, uintptr_t table_base, size_t num_entries,
49 uintptr_t target_pc, uint32_t &out_unwind_data) noexcept {
50 if (num_entries == 0 || table_base == 0)
51 return false;
52
53 size_t low = 0;
54 size_t high = num_entries;
55 size_t match_index = num_entries;
56
57 // Iterative binary search: find the highest function address <= target_pc
58 while (low < high) {
59 size_t mid = low + (high - low) / 2;
60 uintptr_t entry_addr = table_base + (mid * 8); // Each entry is 2 words (8 bytes)
61
62 uint32_t prel31 = 0;
63 if (!space.read_bytes(entry_addr, &prel31, 4)) {
64 return false;
65 }
66
67 uintptr_t fn_addr = decode_prel31(entry_addr, prel31);
68
69 if (fn_addr <= target_pc) {
70 match_index = mid; // Candidate found, try looking for a closer (higher)
71 // function start
72 low = mid + 1;
73 } else {
74 high = mid;
75 }
76 }
77
78 if (match_index == num_entries) {
79 return false; // Target PC precedes all entries in the table
80 }
81
82 // Read the second word (unwind descriptor or pointer to .ARM.extab)
83 uintptr_t matched_entry_addr = table_base + (match_index * 8);
84 uint32_t unwind_data = 0;
85 if (!space.read_bytes(matched_entry_addr + 4, &unwind_data, 4)) {
86 return false;
87 }
88
89 // Check for EXIDX_CANTUNWIND sentinel value (0x1)
90 if (unwind_data == 0x1) {
91 return false;
92 }
93
94 out_unwind_data = unwind_data;
95 return true;
96 }
97};
98
99} // namespace microfmt
Type-erased remote address-space access and remote string/object views.
Type-erased, two-word handle to a remote address space.
Definition address_space.hpp:204
Binary search over sorted .ARM.exidx unwind tables.
Definition arm_exidx_search.hpp:18
static bool find_exidx_entry(address_space_ref space, uintptr_t table_base, size_t num_entries, uintptr_t target_pc, uint32_t &out_unwind_data) noexcept
Locates the unwind descriptor covering target_pc.
Definition arm_exidx_search.hpp:48
static constexpr uintptr_t decode_prel31(uintptr_t entry_addr, uint32_t prel31) noexcept
Decodes a 31-bit program-relative (PREL31) offset.
Definition arm_exidx_search.hpp:26
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Definition assert.hpp:19