36 for (
int i = 0; i < 10; ++i) {
37 if (!space.read_bytes(addr++, &
byte, 1))
39 result |=
static_cast<uint64_t
>(
byte & 0x7F) << shift;
53 for (
int i = 0; i < 10; ++i) {
54 if (!space.read_bytes(addr++, &
byte, 1))
56 result |=
static_cast<int64_t
>(
byte & 0x7F) << shift;
59 if ((shift < 64) && (
byte & 0x40)) {
60 result |= (~0ULL << shift);
115 void reset(uintptr_t initial_loc)
noexcept {
127 template <
size_t MaxStateStackDepth>
138 if (length == 0 || length == 0xFFFFFFFF)
141 uintptr_t entry_start = fde_addr + 4;
142 uintptr_t entry_end = entry_start + length;
144 uint32_t cie_pointer = 0;
145 if (!space.
read_bytes(entry_start, &cie_pointer, 4))
149 uint32_t initial_loc = 0;
150 uint32_t address_range = 0;
151 if (!space.
read_bytes(entry_start, &initial_loc, 4))
154 if (!space.
read_bytes(entry_start, &address_range, 4))
158 if (target_pc < initial_loc || target_pc >= (initial_loc + address_range)) {
162 scratch.reset(initial_loc);
163 auto &state = scratch.current_state;
166 uintptr_t inst_ptr = entry_start;
167 while (inst_ptr < entry_end && state.current_loc <= target_pc) {
173 state.current_loc += (op & 0x3F);
175 uint8_t reg = op & 0x3F;
179 int64_t mem_offset = -
static_cast<int64_t
>(offset * AbiTraits::pointer_size);
180 if (AbiTraits::is_return_address_register(reg)) {
182 }
else if (AbiTraits::is_frame_pointer_register(reg)) {
191 uint64_t target_reg = 0;
194 if (AbiTraits::is_return_address_register(
static_cast<uint32_t
>(reg))) {
196 }
else if (AbiTraits::is_frame_pointer_register(
static_cast<uint32_t
>(reg))) {
205 state.current_loc += delta;
213 state.current_loc += delta;
221 int64_t mem_offset = -
static_cast<int64_t
>(offset * AbiTraits::pointer_size);
222 if (AbiTraits::is_return_address_register(
static_cast<uint32_t
>(reg))) {
224 }
else if (AbiTraits::is_frame_pointer_register(
static_cast<uint32_t
>(reg))) {
234 if (AbiTraits::is_return_address_register(
static_cast<uint32_t
>(reg))) {
236 }
else if (AbiTraits::is_frame_pointer_register(
static_cast<uint32_t
>(reg))) {
242 if (scratch.stack_depth < MaxStateStackDepth) {
243 scratch.state_stack[scratch.stack_depth++] = state;
247 if (scratch.stack_depth > 0) {
248 state = scratch.state_stack[--scratch.stack_depth];
256 state.cfa_reg =
static_cast<uint32_t
>(reg);
257 state.cfa_offset =
static_cast<int64_t
>(offset);
264 state.cfa_reg =
static_cast<uint32_t
>(reg);
271 state.cfa_offset =
static_cast<int64_t
>(offset);
278 state.cfa_offset = offset;
290 if (!reg_ctx.read_raw(state.cfa_reg, &cfa_base_val, AbiTraits::pointer_size)) {
293 uintptr_t cfa =
static_cast<uintptr_t
>(cfa_base_val) + state.cfa_offset;
298 uintptr_t fp_addr = cfa + state.fp_loc.value;
299 space.
read_bytes(fp_addr, &saved_fp, AbiTraits::pointer_size);
303 reg_ctx.read_raw(
static_cast<uint32_t
>(state.fp_loc.value), &saved_fp, AbiTraits::pointer_size);
309 uintptr_t ra_addr = cfa + state.ra_loc.value;
310 if (!space.
read_bytes(ra_addr, &saved_ra, AbiTraits::pointer_size))
315 if (!reg_ctx.read_raw(
static_cast<uint32_t
>(state.ra_loc.value), &saved_ra, AbiTraits::pointer_size))
319 out_fp =
static_cast<uintptr_t
>(saved_fp);
320 out_pc = AbiTraits::normalize_pc(
static_cast<uintptr_t
>(saved_ra));
332 std::ignore = reg_ctx.write_raw(AbiTraits::sp_reg, &cfa_reg_val, AbiTraits::pointer_size);
333 std::ignore = reg_ctx.write_raw(AbiTraits::fp_reg, &saved_fp, AbiTraits::pointer_size);
334 std::ignore = reg_ctx.write_raw(AbiTraits::ra_reg, &saved_ra, AbiTraits::pointer_size);
377template <
typename AbiTraits,
size_t MaxStateStackDepth>
398 uintptr_t &next_fp, uintptr_t &next_pc)
noexcept {
402 if (!context->enumerator || !context->img_storage || !context->dwarf_scratch) {
406 uintptr_t fault_pc = AbiTraits::normalize_pc(current_pc);
411 if (!context->enumerator.find_by_pc(fault_pc, img) || !img.
has_debug_frame()) {
418 if (!context->space.read_bytes(curr, &len, 4))
423 if (decoder_type::execute_fde(reg_ctx, curr, fault_pc, next_fp, next_pc, *context->dwarf_scratch)) {
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
expected< void, address_space_error > read_bytes(uintptr_t addr, void *dest, size_t size) const noexcept
Reads raw bytes from the remote address space.
Definition address_space.hpp:294
Decoder executing DWARF CFI bytecode against an address space and selective register context.
Definition dwarf_decoder.hpp:28
static constexpr uint8_t DW_CFA_restore
Definition dwarf_decoder.hpp:74
typename AbiTraits::register_type register_type
Definition dwarf_decoder.hpp:30
static constexpr uint8_t DW_CFA_def_cfa_register
Definition dwarf_decoder.hpp:83
static constexpr uint8_t DW_CFA_def_cfa
Definition dwarf_decoder.hpp:82
static constexpr uint8_t DW_CFA_advance_loc2
Definition dwarf_decoder.hpp:78
static constexpr uint8_t DW_CFA_register
Definition dwarf_decoder.hpp:76
static bool execute_fde(register_context_ref reg_ctx, uintptr_t fde_addr, uintptr_t target_pc, uintptr_t &out_fp, uintptr_t &out_pc, scratch_context< MaxStateStackDepth > &scratch) noexcept
Executes FDE bytecode, selectively querying register_context_ref only when virtual registers are need...
Definition dwarf_decoder.hpp:128
static constexpr uint8_t DW_CFA_def_cfa_offset_sf
Definition dwarf_decoder.hpp:87
static constexpr uint8_t DW_CFA_offset_extended_sf
Definition dwarf_decoder.hpp:85
static constexpr uint8_t DW_CFA_offset_extended
Definition dwarf_decoder.hpp:79
static bool read_sleb128(address_space_ref space, uintptr_t &addr, int64_t &out_val) noexcept
Definition dwarf_decoder.hpp:49
static constexpr uint8_t DW_CFA_remember_state
Definition dwarf_decoder.hpp:80
reg_rule_type
Tracks location type for saved registers (Memory offset vs Live Register).
Definition dwarf_decoder.hpp:93
static constexpr uint8_t DW_CFA_def_cfa_offset
Definition dwarf_decoder.hpp:84
static constexpr uint8_t DW_CFA_restore_state
Definition dwarf_decoder.hpp:81
static constexpr uint8_t DW_CFA_def_cfa_sf
Definition dwarf_decoder.hpp:86
static constexpr uint8_t DW_CFA_offset
Definition dwarf_decoder.hpp:73
static constexpr uint8_t DW_CFA_advance_loc1
Definition dwarf_decoder.hpp:77
static bool read_uleb128(address_space_ref space, uintptr_t &addr, uint64_t &out_val) noexcept
Definition dwarf_decoder.hpp:32
static constexpr uint8_t DW_CFA_advance_loc
Definition dwarf_decoder.hpp:72
static constexpr uint8_t DW_CFA_nop
Definition dwarf_decoder.hpp:75
Type-erased, two-word handle to an ELF image enumerator.
Definition elf_enumerator.hpp:104
Type-erased, two-word handle to a frame unwinder.
Definition frame_pointer.hpp:68
Zero-allocation, type-erased handle for inspecting and modifying CPU registers from a frame context.
Definition register_context.hpp:118
Per-architecture ABI traits describing registers used during DWARF unwinding.
ELF image introspection, type-erased image enumeration, and fixed-capacity registries.
Type-erased frame unwinder handles, frame cursor iteration, and backtrace views.
Definition dwarf_decoder.hpp:100
reg_location ra_loc
Definition dwarf_decoder.hpp:104
int64_t cfa_offset
Definition dwarf_decoder.hpp:102
uintptr_t current_loc
Definition dwarf_decoder.hpp:107
uint32_t cfa_reg
Definition dwarf_decoder.hpp:101
reg_location fp_loc
Definition dwarf_decoder.hpp:105
Definition dwarf_decoder.hpp:95
reg_rule_type type
Definition dwarf_decoder.hpp:96
int64_t value
Definition dwarf_decoder.hpp:97
Definition dwarf_decoder.hpp:110
frame_state state_stack[MaxStateStackDepth]
Definition dwarf_decoder.hpp:112
frame_state current_state
Definition dwarf_decoder.hpp:111
void reset(uintptr_t initial_loc) noexcept
Definition dwarf_decoder.hpp:115
size_t stack_depth
Definition dwarf_decoder.hpp:113
Immutable context describing a DWARF unwinder back to the type-erased handle.
Definition dwarf_decoder.hpp:344
dwarf_cfi_decoder< AbiTraits >::template scratch_context< MaxStateStackDepth > * dwarf_scratch
Definition dwarf_decoder.hpp:348
elf_image_info * img_storage
Definition dwarf_decoder.hpp:347
address_space_ref space
Definition dwarf_decoder.hpp:345
elf_image_enumerator_ref enumerator
Definition dwarf_decoder.hpp:346
Definition dwarf_decoder.hpp:353
dwarf_unwinder_holder(dwarf_unwinder_holder &&)=delete
dwarf_unwinder_holder(const dwarf_unwinder_holder &)=delete
dwarf_unwinder_holder & operator=(dwarf_unwinder_holder &&)=delete
elf_image_info img_storage
Definition dwarf_decoder.hpp:354
dwarf_unwinder_context< AbiTraits, MaxStateStackDepth > ctx
Definition dwarf_decoder.hpp:356
frame_unwinder_ref make_ref() &noexcept
Definition dwarf_decoder.hpp:366
dwarf_unwinder_holder & operator=(const dwarf_unwinder_holder &)=delete
dwarf_unwinder_holder(address_space_ref space, elf_image_enumerator_ref enumerator) noexcept
Definition dwarf_decoder.hpp:358
dwarf_cfi_decoder< AbiTraits >::template scratch_context< MaxStateStackDepth > dwarf_scratch
Definition dwarf_decoder.hpp:355
Definition dwarf_decoder.hpp:351
Describes a loaded ELF image and the locations of its unwind tables.
Definition elf_enumerator.hpp:30
uintptr_t debug_frame_end
End of the DWARF CFI unwind-record table. May be UINTPTR_MAX when the backend can locate the table's ...
Definition elf_enumerator.hpp:68
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
uintptr_t debug_frame_start
Start of the DWARF CFI unwind-record table used by microfmt::dwarf_decoder for stack unwinding....
Definition elf_enumerator.hpp:61
static bool step(value_ref< const context_type > context, register_context_ref reg_ctx, uintptr_t current_pc, uintptr_t &next_fp, uintptr_t &next_pc) noexcept
Unwinds one frame using the module's DWARF CFI FDE and register_context_ref.
Definition dwarf_decoder.hpp:397
Static customization point describing a frame unwinder backend.
Definition frame_pointer.hpp:56