microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
register_view.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
11#include "../microfmt.hpp"
12#include "dwarf_abi.hpp"
13#include "dwarf_registers.hpp"
14#include "register_context.hpp"
15#include <cstddef>
16#include <cstdint>
17
18namespace microfmt {
19
25template <typename AbiTraits> class RELOCO_POINTER register_context_view {
26public:
27 constexpr explicit register_context_view(register_context_ref reg_ctx) noexcept : reg_ctx_(reg_ctx) {}
28
29 [[nodiscard]] constexpr register_context_ref reg_context() const noexcept { return reg_ctx_; }
30
31private:
32 register_context_ref reg_ctx_;
33};
34
35namespace detail {
36
37inline void write_register_separator(const sink &out, size_t printed, size_t columns) noexcept {
38 if (printed == 0)
39 return;
40 out.write((printed % columns) == 0 ? "\n" : " ");
41}
42
43} // namespace detail
44
45// ============================================================================
46// x86_64 (AMD64) Formatter
47// ============================================================================
49 constexpr void parse(format_parse_context &) noexcept {}
50
51 void format(const register_context_view<x86_64_abi_traits> &view, const sink &out) const noexcept {
52 register_context_ref reg_ctx = view.reg_context();
53 if (!reg_ctx) {
54 out.write("<null register context>");
55 return;
56 }
57
58 using register_traits = x86_64_abi_traits::register_traits;
59 uint64_t val = 0;
60 size_t printed = 0;
61
62 const auto format_registers = [&reg_ctx, &val, &out, &printed](const auto &registers) noexcept {
63 for (const auto &reg : registers) {
64 if (!reg_ctx.read_raw(reg.index, &val, sizeof(val)))
65 continue;
66 detail::write_register_separator(out, printed, 2);
67 microfmt::format_to(out, "{}={:#018x}", reg.name, val);
68 ++printed;
69 }
70 };
71
72 format_registers(register_traits::gpr_registers);
73 format_registers(register_traits::system_registers);
74 }
75};
76
77// ============================================================================
78// x86 (IA-32) Formatter
79// ============================================================================
81 constexpr void parse(format_parse_context &) noexcept {}
82
83 void format(const register_context_view<x86_abi_traits> &view, const sink &out) const noexcept {
84 register_context_ref reg_ctx = view.reg_context();
85 if (!reg_ctx) {
86 out.write("<null register context>");
87 return;
88 }
89
90 using register_traits = x86_abi_traits::register_traits;
91 uint32_t val = 0;
92 size_t printed = 0;
93
94 const auto format_registers = [&reg_ctx, &val, &out, &printed](const auto &registers) noexcept {
95 for (const auto &reg : registers) {
96 if (!reg_ctx.read_raw(reg.index, &val, sizeof(val)))
97 continue;
98 detail::write_register_separator(out, printed, 3);
99 microfmt::format_to(out, "{}={:#010x}", reg.name, val);
100 ++printed;
101 }
102 };
103
104 format_registers(register_traits::gpr_registers);
105 format_registers(register_traits::system_registers);
106 }
107};
108
109// ============================================================================
110// AArch64 (64-bit ARM) Formatter
111// ============================================================================
113 constexpr void parse(format_parse_context &) noexcept {}
114
115 void format(const register_context_view<aarch64_abi_traits> &view, const sink &out) const noexcept {
116 register_context_ref reg_ctx = view.reg_context();
117 if (!reg_ctx) {
118 out.write("<null register context>");
119 return;
120 }
121
122 using register_traits = aarch64_abi_traits::register_traits;
123 uint64_t val = 0;
124 size_t printed = 0;
125
126 const auto format_registers = [&reg_ctx, &val, &out, &printed](const auto &registers) noexcept {
127 for (const auto &reg : registers) {
128 if (!reg_ctx.read_raw(reg.index, &val, sizeof(val)))
129 continue;
130 detail::write_register_separator(out, printed, 2);
131
132 uint64_t display_val = val;
133 if (reg.index == dwarf::aarch64::lr || reg.index == dwarf::aarch64::pc) {
134 display_val = static_cast<uint64_t>(aarch64_abi_traits::normalize_pc(static_cast<uintptr_t>(val)));
135 }
136 microfmt::format_to(out, "{}={:#018x}", reg.name, display_val);
137 ++printed;
138 }
139 };
140
141 format_registers(register_traits::gpr_registers);
142 format_registers(register_traits::system_registers);
143 }
144};
145
146// ============================================================================
147// ARM32 (32-bit ARM EABI) Formatter
148// ============================================================================
150 constexpr void parse(format_parse_context &) noexcept {}
151
152 void format(const register_context_view<arm_abi_traits> &view, const sink &out) const noexcept {
153 register_context_ref reg_ctx = view.reg_context();
154 if (!reg_ctx) {
155 out.write("<null register context>");
156 return;
157 }
158
159 using register_traits = arm_abi_traits::register_traits;
160 uint32_t val = 0;
161 size_t printed = 0;
162
163 const auto format_registers = [&reg_ctx, &val, &out, &printed](const auto &registers) noexcept {
164 for (const auto &reg : registers) {
165 if (!reg_ctx.read_raw(reg.index, &val, sizeof(val)))
166 continue;
167 detail::write_register_separator(out, printed, 3);
168 microfmt::format_to(out, "{}={:#010x}", reg.name, val);
169 ++printed;
170 }
171 };
172
173 format_registers(register_traits::gpr_registers);
174 format_registers(register_traits::system_registers);
175 }
176};
177
178// ============================================================================
179// RISC-V 32-bit Formatter
180// ============================================================================
182 constexpr void parse(format_parse_context &) noexcept {}
183
184 void format(const register_context_view<riscv32_abi_traits> &view, const sink &out) const noexcept {
185 register_context_ref reg_ctx = view.reg_context();
186 if (!reg_ctx) {
187 out.write("<null register context>");
188 return;
189 }
190
191 using register_traits = riscv32_abi_traits::register_traits;
192 uint32_t val = 0;
193 size_t printed = 0;
194
195 const auto format_registers = [&reg_ctx, &val, &out, &printed](const auto &registers) noexcept {
196 for (const auto &reg : registers) {
197 if (!reg_ctx.read_raw(reg.index, &val, sizeof(val)))
198 continue;
199 detail::write_register_separator(out, printed, 3);
200 microfmt::format_to(out, "{}={:#010x}", reg.name, val);
201 ++printed;
202 }
203 };
204
205 format_registers(register_traits::gpr_registers);
206 format_registers(register_traits::system_registers);
207 }
208};
209
210// ============================================================================
211// RISC-V 64-bit Formatter
212// ============================================================================
214 constexpr void parse(format_parse_context &) noexcept {}
215
216 void format(const register_context_view<riscv64_abi_traits> &view, const sink &out) const noexcept {
217 register_context_ref reg_ctx = view.reg_context();
218 if (!reg_ctx) {
219 out.write("<null register context>");
220 return;
221 }
222
223 using register_traits = riscv64_abi_traits::register_traits;
224 uint64_t val = 0;
225 size_t printed = 0;
226
227 const auto format_registers = [&reg_ctx, &val, &out, &printed](const auto &registers) noexcept {
228 for (const auto &reg : registers) {
229 if (!reg_ctx.read_raw(reg.index, &val, sizeof(val)))
230 continue;
231 detail::write_register_separator(out, printed, 2);
232 microfmt::format_to(out, "{}={:#018x}", reg.name, val);
233 ++printed;
234 }
235 };
236
237 format_registers(register_traits::gpr_registers);
238 format_registers(register_traits::system_registers);
239 }
240};
241
242} // namespace microfmt
Definition microfmt.hpp:881
Zero-allocation, type-erased handle for inspecting and modifying CPU registers from a frame context.
Definition register_context.hpp:118
bool read_raw(uint32_t dwarf_reg_index, void *dest, size_t size) const noexcept
Reads raw register bytes into a buffer.
Definition register_context.hpp:157
bool write(uint32_t dwarf_reg_index, const T &value) const noexcept
Writes a typed value into a register by its DWARF index.
Definition register_context.hpp:166
Formattable view wrapping a register_context_ref for a specific architecture ABI.
Definition register_view.hpp:25
constexpr register_context_view(register_context_ref reg_ctx) noexcept
Definition register_view.hpp:27
constexpr register_context_ref reg_context() const noexcept
Definition register_view.hpp:29
Per-architecture ABI traits describing registers used during DWARF unwinding.
@ lr
Definition dwarf_registers.hpp:268
@ pc
Definition dwarf_registers.hpp:264
Definition assert.hpp:19
reloco::sink sink
Type-erased, zero-allocation output sink.
Definition microfmt.hpp:46
RELOCO_CONSTEXPR20 void format_to(const sink &out, microfmt::string_view fmt, const Args &...args) noexcept
Definition microfmt.hpp:1766
DWARF unwind ABI traits for AArch64 (64-bit ARM).
Definition dwarf_abi.hpp:168
static constexpr uintptr_t normalize_pc(uintptr_t raw_ra) noexcept
Definition dwarf_abi.hpp:201
dwarf::aarch64::register_traits register_traits
Architecture register name/index catalog.
Definition dwarf_abi.hpp:172
DWARF unwind ABI traits for ARM / Thumb (32-bit EABI).
Definition dwarf_abi.hpp:27
dwarf::arm32::register_traits register_traits
Architecture register name/index catalog.
Definition dwarf_abi.hpp:31
constexpr void parse(format_parse_context &) noexcept
Definition register_view.hpp:113
void format(const register_context_view< aarch64_abi_traits > &view, const sink &out) const noexcept
Definition register_view.hpp:115
constexpr void parse(format_parse_context &) noexcept
Definition register_view.hpp:150
void format(const register_context_view< arm_abi_traits > &view, const sink &out) const noexcept
Definition register_view.hpp:152
void format(const register_context_view< riscv32_abi_traits > &view, const sink &out) const noexcept
Definition register_view.hpp:184
constexpr void parse(format_parse_context &) noexcept
Definition register_view.hpp:182
constexpr void parse(format_parse_context &) noexcept
Definition register_view.hpp:214
void format(const register_context_view< riscv64_abi_traits > &view, const sink &out) const noexcept
Definition register_view.hpp:216
constexpr void parse(format_parse_context &) noexcept
Definition register_view.hpp:49
void format(const register_context_view< x86_64_abi_traits > &view, const sink &out) const noexcept
Definition register_view.hpp:51
void format(const register_context_view< x86_abi_traits > &view, const sink &out) const noexcept
Definition register_view.hpp:83
constexpr void parse(format_parse_context &) noexcept
Definition register_view.hpp:81
Definition microfmt.hpp:985
DWARF unwind ABI traits for RISC-V 32-bit (RV32).
Definition dwarf_abi.hpp:226
dwarf::riscv::register_traits register_traits
Architecture register name/index catalog.
Definition dwarf_abi.hpp:230
DWARF unwind ABI traits for RISC-V 64-bit (RV64).
Definition dwarf_abi.hpp:272
dwarf::riscv::register_traits register_traits
Architecture register name/index catalog.
Definition dwarf_abi.hpp:276
DWARF unwind ABI traits for x86-64 (AMD64 / x86_64).
Definition dwarf_abi.hpp:361
dwarf::x86_64::register_traits register_traits
Architecture register name/index catalog.
Definition dwarf_abi.hpp:365
DWARF unwind ABI traits for x86 (32-bit IA-32).
Definition dwarf_abi.hpp:315
dwarf::x86::register_traits register_traits
Architecture register name/index catalog.
Definition dwarf_abi.hpp:319