31 uint32_t trap_level{0};
35 uintptr_t trap_frame_addr{0};
55 uint64_t vector_or_reason{0};
59 bool is_user_mode{
false};
88 bool (*decode)(
const void *ctx, uintptr_t trap_frame_addr,
trap_context &out_trap)
noexcept;
93 bool (*next_trap_frame)(
const void *ctx, uintptr_t current_trap_frame_addr,
94 uintptr_t &next_trap_frame_addr)
noexcept;
99 microfmt::string_view (*describe_reason)(
const void *ctx, uint64_t vector_or_reason)
noexcept;
113 std::enable_if_t<std::is_void_v<typename Traits::context_type>,
int> = 0>
124 template <
typename ArchTag,
typename Context,
typename Traits = exception_frame_traits<ArchTag>,
125 std::enable_if_t<!std::is_
void_v<
typename Traits::context_type> &&
126 std::is_convertible_v<const Context *, const
typename Traits::context_type *>,
129 const Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
130 : ctx_(&ctx), vtbl_(&s_vtbl<ArchTag>) {}
132 template <
typename ArchTag,
typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>,
int> = 0>
141 template <
typename ArchTag,
typename Traits = exception_frame_traits<ArchTag>,
142 std::enable_if_t<std::is_
void_v<
typename Traits::context_type>,
int> = 0>
155 template <
typename ArchTag,
typename Context,
typename Traits = exception_frame_traits<ArchTag>,
156 std::enable_if_t<!std::is_
void_v<
typename Traits::context_type>,
int> = 0>
161 template <
typename ArchTag,
typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>,
int> = 0>
174 return vtbl_->decode(ctx_.get(), trap_frame_addr, out_trap);
184 uintptr_t &next_trap_frame_addr)
const noexcept {
187 return vtbl_->next_trap_frame(ctx_.get(), current_trap_frame_addr, next_trap_frame_addr);
195 [[nodiscard]] microfmt::string_view
describe_reason(uint64_t vector_or_reason)
const noexcept {
196 if (!vtbl_ || !vtbl_->describe_reason)
198 return vtbl_->describe_reason(ctx_.get(), vector_or_reason);
205 [[nodiscard]]
constexpr explicit operator bool() const noexcept {
return vtbl_ !=
nullptr; }
208 template <
typename ArchTag>
209 static bool decode_entry(
const void *context, uintptr_t address,
trap_context &trap)
noexcept {
211 if constexpr (std::is_void_v<context_type>) {
214 const auto &typed_context = *
static_cast<const context_type *
>(context);
215 return exception_frame_traits<ArchTag>::decode(value_ref<const context_type>(typed_context), address, trap);
219 template <
typename ArchTag>
220 static bool next_entry(
const void *context, uintptr_t address, uintptr_t &next_address)
noexcept {
221 using context_type =
typename exception_frame_traits<ArchTag>::context_type;
222 if constexpr (std::is_void_v<context_type>) {
223 return exception_frame_traits<ArchTag>::next_trap_frame(address, next_address);
225 const auto &typed_context = *
static_cast<const context_type *
>(context);
226 return exception_frame_traits<ArchTag>::next_trap_frame(value_ref<const context_type>(typed_context), address,
231 template <
typename ArchTag>
232 static microfmt::string_view describe_entry(
const void *context, uint64_t reason)
noexcept {
233 using context_type =
typename exception_frame_traits<ArchTag>::context_type;
234 if constexpr (std::is_void_v<context_type>) {
235 return microfmt::string_view(exception_frame_traits<ArchTag>::describe_reason(reason));
237 const auto &typed_context = *
static_cast<const context_type *
>(context);
238 return microfmt::string_view(
239 exception_frame_traits<ArchTag>::describe_reason(value_ref<const context_type>(typed_context), reason));
243 template <
typename ArchTag>
244 static constexpr vtable s_vtbl{&decode_entry<ArchTag>, &next_entry<ArchTag>, &describe_entry<ArchTag>};
246 value_ptr<const void> ctx_{};
247 const vtable *vtbl_{
nullptr};
250template <typename Tag, bool Stateless = std::is_void_v<typename exception_frame_traits<Tag>::context_type>>
260 [[nodiscard]]
constexpr value_ref<context_type>
context() &
noexcept RELOCO_LIFETIMEBOUND {
261 return value_ref<context_type>(context_);
264 [[nodiscard]]
constexpr value_ref<const context_type>
context() const & noexcept RELOCO_LIFETIMEBOUND {
265 return value_ref<const context_type>(context_);
272 value_ref<context_type>
context() && =
delete;
273 value_ref<const context_type>
context() const && = delete;
305 : decoder_(decoder), raw_frame_addr_(initial_trap_frame_addr), is_valid_(initial_trap_frame_addr != 0) {
326 [[nodiscard]]
constexpr bool has_value() const noexcept {
return is_valid_; }
331 [[nodiscard]]
constexpr explicit operator bool() const noexcept {
return is_valid_; }
341 uintptr_t next_raw_addr = 0;
342 if (!decoder_.next_trap_frame(raw_frame_addr_, next_raw_addr) || next_raw_addr == 0) {
347 raw_frame_addr_ = next_raw_addr;
349 return load_current();
368 template <
typename Visitor>
void for_each_trap(Visitor &&visitor, uint32_t max_traps = 8) noexcept {
369 while (is_valid_ && current_.trap_level < max_traps) {
370 if (!visitor(current_)) {
378 bool load_current() noexcept {
379 if (!decoder_.decode(raw_frame_addr_, current_)) {
383 current_.trap_level = current_level_;
384 current_.trap_frame_addr = raw_frame_addr_;
389 exception_frame_ref decoder_{};
391 uintptr_t raw_frame_addr_{};
393 trap_context current_{};
395 uint32_t current_level_{0};
397 bool is_valid_{
false};
418 : trap_(trap), decoder_(decoder), resolver_(resolver), symbol_context_(&symbol_context) {}
424 [[nodiscard]]
constexpr const trap_context &
trap() const noexcept RELOCO_LIFETIMEBOUND {
return trap_; }
436 return *symbol_context_;
443 exception_frame_ref decoder_{};
445 symbol_resolver_ref resolver_{};
447 value_ptr<symbol_resolution_context> symbol_context_{};
468 auto spec = ctx.spec();
469 if (!spec.empty() && spec.front() ==
'#') {
480 const auto &trap = view.trap();
481 microfmt::string_view desc = view.decoder().describe_reason(trap.vector_or_reason);
483 microfmt::format_to(out,
"[Trap Level {} @ {:#x}] Mode: {}\n", trap.trap_level, trap.trap_frame_addr,
484 trap.is_user_mode ?
"User" :
"Kernel");
488 }
else if (trap.vector_or_reason != 0) {
493 remote_fn_ptr pc_sym(trap.pc, view.resolver(), view.symbol_context());
504 remote_fn_ptr lr_sym(trap.lr, view.resolver(), view.symbol_context());
Type-erased remote address-space access and remote string/object views.
constexpr value_ref< const context_type > context() const &noexcept RELOCO_LIFETIMEBOUND
Definition exception_frame.hpp:264
constexpr value_ref< context_type > context() &noexcept RELOCO_LIFETIMEBOUND
Definition exception_frame.hpp:260
constexpr exception_frame(context_type context) noexcept
Definition exception_frame.hpp:258
value_ref< context_type > context() &&=delete
typename traits_type::context_type context_type
Definition exception_frame.hpp:256
constexpr exception_frame_ref ref() const &noexcept RELOCO_LIFETIMEBOUND
Definition exception_frame.hpp:268
value_ref< const context_type > context() const &&=delete
static constexpr exception_frame_ref ref() noexcept
Definition exception_frame.hpp:282
Forward-only cursor iterating over a chain of trap frames.
Definition exception_frame.hpp:292
constexpr bool has_value() const noexcept
Reports whether the iterator is positioned on a trap frame.
Definition exception_frame.hpp:326
constexpr exception_frame_iterator() noexcept=default
Constructs an empty (invalid) iterator.
constexpr const trap_context * operator->() const noexcept
Returns the current decoded trap context.
Definition exception_frame.hpp:320
bool next() noexcept
Advances to the next (outer/nested) trap frame.
Definition exception_frame.hpp:337
exception_frame_iterator & operator++() noexcept
Pre-increment advancing to the next trap frame.
Definition exception_frame.hpp:356
constexpr const trap_context & operator*() const noexcept
Returns the current decoded trap context.
Definition exception_frame.hpp:315
void for_each_trap(Visitor &&visitor, uint32_t max_traps=8) noexcept
Visitor-style traversal over the trap chain.
Definition exception_frame.hpp:368
Type-erased, two-word handle decoding exception/trap frames.
Definition exception_frame.hpp:79
bool decode(uintptr_t trap_frame_addr, trap_context &out_trap) const noexcept
Decodes raw trap frame memory into a uniform trap_context.
Definition exception_frame.hpp:171
microfmt::string_view describe_reason(uint64_t vector_or_reason) const noexcept
Returns a textual description of a vector/reason code.
Definition exception_frame.hpp:195
constexpr exception_frame_ref(ArchTag, const Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
Constructs a handle for a stateful architecture tag.
Definition exception_frame.hpp:128
constexpr exception_frame_ref() noexcept=default
Constructs an empty (invalid) handle.
static exception_frame_ref make(Context &&)=delete
static constexpr exception_frame_ref make(const Context &ctx RELOCO_LIFETIMEBOUND) noexcept
Creates a handle for a stateful architecture tag.
Definition exception_frame.hpp:157
bool next_trap_frame(uintptr_t current_trap_frame_addr, uintptr_t &next_trap_frame_addr) const noexcept
Follows links to outer/nested trap frames.
Definition exception_frame.hpp:183
static constexpr exception_frame_ref make() noexcept
Creates a handle for a stateless architecture tag.
Definition exception_frame.hpp:143
constexpr exception_frame_ref(ArchTag, Context &&)=delete
Definition exception_frame.hpp:251
Definition microfmt.hpp:881
Symbolic view of a remote function / code pointer.
Definition remote_diagnostics.hpp:82
Formattable summary view of a trap context.
Definition exception_frame.hpp:407
constexpr const trap_context & trap() const noexcept RELOCO_LIFETIMEBOUND
Returns the wrapped trap context.
Definition exception_frame.hpp:424
constexpr remote_trap_view(const trap_context &trap, exception_frame_ref decoder, symbol_resolver_ref resolver, symbol_resolution_context &symbol_context RELOCO_LIFETIMEBOUND) noexcept
Constructs a trap summary view.
Definition exception_frame.hpp:416
constexpr symbol_resolver_ref resolver() const noexcept
Returns the symbol resolver handle.
Definition exception_frame.hpp:434
constexpr exception_frame_ref decoder() const noexcept
Returns the trap-frame decoder handle.
Definition exception_frame.hpp:429
constexpr symbol_resolution_context & symbol_context() const noexcept RELOCO_LIFETIMEBOUND
Definition exception_frame.hpp:435
Type-erased, two-word handle to a symbol resolver.
Definition symbol_resolver.hpp:132
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Type-erased frame unwinder handles, frame cursor iteration, and backtrace views.
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
Virtual table of trap-frame operations.
Definition exception_frame.hpp:84
Static customization point for decoding architecture trap frames.
Definition exception_frame.hpp:70
Caller-owned temporary storage for one symbol resolution.
Definition symbol_resolver.hpp:100
Normalized, architecture-independent snapshot of a trap context.
Definition exception_frame.hpp:27
Type-erased symbol resolution for remote addresses and formattable symbol views.