microfmt
Zero-allocation C++ formatting for constrained environments
Loading...
Searching...
No Matches
register_context.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
7#include "../microfmt.hpp"
8#include "../reloco.hpp"
9#include "address_space.hpp"
10#include "dwarf_registers.hpp"
11#include <cstddef>
12#include <cstdint>
13#include <cstring>
14#include <type_traits>
15#include <utility>
16
17namespace microfmt {
18
26template <typename Tag> struct register_context_traits;
27
28template <typename State, auto Read> struct read_only_register_context_tag {};
29
30template <typename State, auto Write> struct write_only_register_context_tag {};
31
32template <typename State, auto Read, auto Write> struct read_write_register_context_tag {};
33
34template <typename State> struct empty_register_context_tag {};
35
36template <typename State> struct register_context_traits<empty_register_context_tag<State>> {
37 using context_type = State;
38};
39
40template <typename State, auto Read> struct register_context_traits<read_only_register_context_tag<State, Read>> {
41 using context_type = State;
42
43 // decodes raw bytes of a target address space; casts, pointers and offsets are bounded by the explicit lengths
44 // checked here.
45 RELOCO_BEGIN_UNSAFE_CODE
46 static bool read_register(value_ref<const context_type> context, address_space_ref space, uint32_t index,
47 void *destination, size_t size) noexcept {
48 return Read(context.get(), space, index, destination, size);
49 }
51};
52
53template <typename State, auto Write> struct register_context_traits<write_only_register_context_tag<State, Write>> {
54 using context_type = State;
55
56 // decodes raw bytes of a target address space; casts, pointers and offsets are bounded by the explicit lengths
57 // checked here.
58 RELOCO_BEGIN_UNSAFE_CODE
59 static bool write_register(value_ref<context_type> context, address_space_ref space, uint32_t index,
60 const void *source, size_t size) noexcept {
61 return Write(context.get(), space, index, source, size);
62 }
64};
65
66template <typename State, auto Read, auto Write>
68 using context_type = State;
69
70 // decodes raw bytes of a target address space; casts, pointers and offsets are bounded by the explicit lengths
71 // checked here.
72 RELOCO_BEGIN_UNSAFE_CODE
73 static bool read_register(value_ref<const context_type> context, address_space_ref space, uint32_t index,
74 void *destination, size_t size) noexcept {
75 return Read(context.get(), space, index, destination, size);
76 }
78
79 // decodes raw bytes of a target address space; casts, pointers and offsets are bounded by the explicit lengths
80 // checked here.
81 RELOCO_BEGIN_UNSAFE_CODE
82 static bool write_register(value_ref<context_type> context, address_space_ref space, uint32_t index,
83 const void *source, size_t size) noexcept {
84 return Write(context.get(), space, index, source, size);
85 }
87};
88
89namespace detail {
90
91template <typename Tag, typename = void> struct has_register_context_read : std::false_type {};
92
93template <typename Tag>
95 Tag,
96 std::void_t<decltype(register_context_traits<Tag>::read_register(
97 std::declval<value_ref<const typename register_context_traits<Tag>::context_type>>(),
98 std::declval<address_space_ref>(), std::declval<uint32_t>(), std::declval<void *>(), std::declval<size_t>()))>>
99 : std::true_type {};
100
101template <typename Tag, typename = void> struct has_register_context_write : std::false_type {};
102
103template <typename Tag>
105 std::void_t<decltype(register_context_traits<Tag>::write_register(
106 std::declval<value_ref<typename register_context_traits<Tag>::context_type>>(),
107 std::declval<address_space_ref>(), std::declval<uint32_t>(),
108 std::declval<const void *>(), std::declval<size_t>()))>> : std::true_type {};
109
110template <typename State, typename... FieldTraits> struct mapped_register_context_tag {};
111
112} // namespace detail
113
119public:
120 constexpr register_context_ref() noexcept = default;
121
122 template <typename Tag, typename State, typename Traits = register_context_traits<Tag>,
123 std::enable_if_t<std::is_convertible_v<State *, typename Traits::context_type *>, int> = 0>
124 constexpr register_context_ref(Tag, State &state RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS,
125 address_space_ref space,
126 span<std::byte> scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
127 : state_(&state), mutable_state_(&state), vtable_(&s_vtable<Tag>), space_(space), scratch_(scratch) {}
128
129 template <typename Tag, typename State, typename Traits = register_context_traits<Tag>,
130 std::enable_if_t<std::is_convertible_v<const State *, const typename Traits::context_type *>, int> = 0>
131 constexpr register_context_ref(Tag, const State &state RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS,
132 address_space_ref space,
133 span<std::byte> scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
134 : state_(&state), vtable_(&s_vtable<Tag>), space_(space), scratch_(scratch) {}
135
136 template <typename Tag, typename State, std::enable_if_t<!std::is_lvalue_reference_v<State>, int> = 0>
137 constexpr register_context_ref(Tag, State &&, address_space_ref, span<std::byte>) = delete;
138
139 [[nodiscard]] constexpr bool is_null() const noexcept {
140 return !state_ || vtable_ == nullptr || (vtable_->read_register == nullptr && vtable_->write_register == nullptr);
141 }
142
143 [[nodiscard]] constexpr explicit operator bool() const noexcept { return !is_null(); }
144
148 template <typename T> [[nodiscard]] bool read(uint32_t dwarf_reg_index, T &out_value) const noexcept {
149 if (vtable_ == nullptr || vtable_->read_register == nullptr)
150 return false;
151 return vtable_->read_register(state_.get(), space_, dwarf_reg_index, &out_value, sizeof(T));
152 }
153
157 [[nodiscard]] bool read_raw(uint32_t dwarf_reg_index, void *dest, size_t size) const noexcept {
158 if (vtable_ == nullptr || vtable_->read_register == nullptr)
159 return false;
160 return vtable_->read_register(state_.get(), space_, dwarf_reg_index, dest, size);
161 }
162
166 template <typename T> [[nodiscard]] bool write(uint32_t dwarf_reg_index, const T &value) const noexcept {
167 if (vtable_ == nullptr || vtable_->write_register == nullptr)
168 return false;
169 if (!mutable_state_)
170 return false;
171 return vtable_->write_register(mutable_state_.get(), space_, dwarf_reg_index, &value, sizeof(T));
172 }
173
177 [[nodiscard]] bool write_raw(uint32_t dwarf_reg_index, const void *src, size_t size) const noexcept {
178 if (vtable_ == nullptr || vtable_->write_register == nullptr)
179 return false;
180 if (!mutable_state_)
181 return false;
182 return vtable_->write_register(mutable_state_.get(), space_, dwarf_reg_index, src, size);
183 }
184
185 [[nodiscard]] constexpr address_space_ref space() const noexcept { return space_; }
186 [[nodiscard]] constexpr span<std::byte> scratch() const noexcept RELOCO_LIFETIMEBOUND { return scratch_; }
187
188private:
189 struct vtable {
190 bool (*read_register)(const void *, address_space_ref, uint32_t, void *, size_t) noexcept = nullptr;
191 bool (*write_register)(void *, address_space_ref, uint32_t, const void *, size_t) noexcept = nullptr;
192 };
193
194 template <typename Tag> [[nodiscard]] static constexpr auto read_entry() noexcept {
195 if constexpr (detail::has_register_context_read<Tag>::value) {
196 return +[](const void *state, address_space_ref space, uint32_t index, void *destination, size_t size) noexcept {
197 using context_type = typename register_context_traits<Tag>::context_type;
198 const auto &context = *static_cast<const context_type *>(state);
199 return register_context_traits<Tag>::read_register(value_ref<const context_type>(context), space, index,
200 destination, size);
201 };
202 } else {
203 return static_cast<bool (*)(const void *, address_space_ref, uint32_t, void *, size_t) noexcept>(nullptr);
204 }
205 }
206
207 template <typename Tag> [[nodiscard]] static constexpr auto write_entry() noexcept {
208 if constexpr (detail::has_register_context_write<Tag>::value) {
209 return +[](void *state, address_space_ref space, uint32_t index, const void *source, size_t size) noexcept {
210 using context_type = typename register_context_traits<Tag>::context_type;
211 auto &context = *static_cast<context_type *>(state);
212 return register_context_traits<Tag>::write_register(value_ref<context_type>(context), space, index, source,
213 size);
214 };
215 } else {
216 return static_cast<bool (*)(void *, address_space_ref, uint32_t, const void *, size_t) noexcept>(nullptr);
217 }
218 }
219
220 template <typename Tag> static constexpr vtable s_vtable{read_entry<Tag>(), write_entry<Tag>()};
221
222 value_ptr<const void> state_{};
223 value_ptr<void> mutable_state_{};
224 const vtable *vtable_{nullptr};
225 address_space_ref space_{};
226 span<std::byte> scratch_{};
227};
228
229template <auto Read, typename State>
230[[nodiscard]] constexpr register_context_ref
231make_read_only_register_context_ref(State &state RELOCO_LIFETIMEBOUND, address_space_ref space,
232 span<std::byte> scratch RELOCO_LIFETIMEBOUND) noexcept {
233 using state_type = std::remove_const_t<State>;
235 return register_context_ref(tag{}, state, space, scratch);
236}
237
238template <auto Read, auto Write, typename State>
239[[nodiscard]] constexpr register_context_ref
240make_register_context_ref(State &state RELOCO_LIFETIMEBOUND, address_space_ref space,
241 span<std::byte> scratch RELOCO_LIFETIMEBOUND) noexcept {
242 using state_type = std::remove_const_t<State>;
244 return register_context_ref(tag{}, state, space, scratch);
245}
246
250template <typename Tag> class RELOCO_OWNER register_context {
251public:
253 using context_type = typename traits_type::context_type;
254
256 span<std::byte> scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
257 : context_(std::move(context)), space_(space), scratch_(scratch) {}
258
259 [[nodiscard]] constexpr value_ref<context_type> context() & noexcept RELOCO_LIFETIMEBOUND {
260 return value_ref<context_type>(context_);
261 }
262
263 [[nodiscard]] constexpr value_ref<const context_type> context() const & noexcept RELOCO_LIFETIMEBOUND {
264 return value_ref<const context_type>(context_);
265 }
266
267 [[nodiscard]] constexpr register_context_ref ref() & noexcept RELOCO_LIFETIMEBOUND {
268 return register_context_ref(Tag{}, context_, space_, scratch_);
269 }
270
271 [[nodiscard]] constexpr register_context_ref ref() const & noexcept RELOCO_LIFETIMEBOUND {
272 return register_context_ref(Tag{}, context_, space_, scratch_);
273 }
274
275 value_ref<context_type> context() && = delete;
276 value_ref<const context_type> context() const && = delete;
277 register_context_ref ref() && = delete;
278 register_context_ref ref() const && = delete;
279
280private:
281 context_type context_;
282 address_space_ref space_;
283 span<std::byte> scratch_;
284};
285
286namespace detail {
287
288template <typename T> struct register_member_pointer_traits;
289
290template <typename Value, typename State> struct register_member_pointer_traits<Value State::*> {
291 using state_type = State;
292 using value_type = Value;
293};
294
295template <typename Field, typename State, typename = void> struct has_mutable_register_field_get : std::false_type {};
296
297template <typename Field, typename State>
298struct has_mutable_register_field_get<
299 Field, State, std::void_t<decltype(Field::get(std::declval<State &>(), std::declval<uint32_t>()))>>
300 : std::is_convertible<decltype(Field::get(std::declval<State &>(), std::declval<uint32_t>())),
301 typename Field::value_type *> {};
302
303template <typename Field, typename State, typename = void> struct has_register_field_read : std::false_type {};
304
305template <typename Field, typename State>
306struct has_register_field_read<
307 Field, State,
308 std::void_t<decltype(Field::read(std::declval<const State &>(), std::declval<address_space_ref>(),
309 std::declval<uint32_t>(), std::declval<typename Field::value_type &>()))>>
310 : std::is_same<decltype(Field::read(std::declval<const State &>(), std::declval<address_space_ref>(),
311 std::declval<uint32_t>(), std::declval<typename Field::value_type &>())),
312 bool> {};
313
314template <typename Field, typename State, typename = void> struct has_register_field_write : std::false_type {};
315
316template <typename Field, typename State>
317struct has_register_field_write<
318 Field, State,
319 std::void_t<decltype(Field::write(std::declval<State &>(), std::declval<address_space_ref>(),
320 std::declval<uint32_t>(), std::declval<const typename Field::value_type &>()))>>
321 : std::is_same<decltype(Field::write(std::declval<State &>(), std::declval<address_space_ref>(),
322 std::declval<uint32_t>(), std::declval<const typename Field::value_type &>())),
323 bool> {};
324
325} // namespace detail
326
337template <auto Member, uint32_t... Registers> struct register_member_field {
338 using member_traits = detail::register_member_pointer_traits<decltype(Member)>;
339 using state_type = typename member_traits::state_type;
340 using value_type = typename member_traits::value_type;
341
342 static_assert(sizeof...(Registers) != 0, "a register member field must bind at least one register");
343 static_assert(std::is_trivially_copyable<value_type>::value, "register fields must be trivially copyable");
344
345 [[nodiscard]] static constexpr bool matches(uint32_t index) noexcept { return ((index == Registers) || ...); }
346
347 [[nodiscard]] static constexpr const value_type *get(const state_type &state, uint32_t) noexcept {
348 return &(state.*Member);
349 }
350
351 [[nodiscard]] static constexpr value_type *get(state_type &state, uint32_t) noexcept { return &(state.*Member); }
352};
353
369template <typename State, typename Value, typename Selector, uint32_t... Registers> struct register_selected_field {
370 using state_type = State;
371 using value_type = Value;
372
373 static_assert(sizeof...(Registers) != 0, "a selected register field must bind at least one register");
374 static_assert(std::is_trivially_copyable<value_type>::value, "register fields must be trivially copyable");
375 static_assert(std::is_nothrow_default_constructible<Selector>::value,
376 "selector must be nothrow default constructible");
377 static_assert(std::is_nothrow_invocable_r<const value_type *, Selector, const state_type &, uint32_t>::value,
378 "selector must be noexcept and return a value_type pointer");
379
380 [[nodiscard]] static constexpr bool matches(uint32_t index) noexcept { return ((index == Registers) || ...); }
381
382 [[nodiscard]] static constexpr const value_type *get(const state_type &state, uint32_t index) noexcept {
383 return Selector{}(state, index);
384 }
385
386 [[nodiscard]] static constexpr auto get(state_type &state, uint32_t index) noexcept
387 -> decltype(Selector{}(state, index)) {
388 return Selector{}(state, index);
389 }
390};
391
406template <typename State, typename Value, auto ReadCallback, auto WriteCallback, uint32_t... Registers>
408 using state_type = State;
409 using value_type = Value;
410
411 static_assert(sizeof...(Registers) != 0, "a callback register field must bind at least one register");
412 static_assert(std::is_trivially_copyable<value_type>::value, "register fields must be trivially copyable");
413 static_assert(std::is_nothrow_default_constructible<value_type>::value,
414 "callback register fields must be nothrow default "
415 "constructible");
416 static_assert(std::is_nothrow_invocable_r<bool, decltype(ReadCallback), const state_type &, address_space_ref,
417 uint32_t, value_type &>::value,
418 "read callback must be noexcept and return bool");
419 static_assert(WriteCallback == nullptr ||
420 std::is_nothrow_invocable_r<bool, decltype(WriteCallback), state_type &, address_space_ref,
421 uint32_t, const value_type &>::value,
422 "write callback must be nullptr or noexcept and return bool");
423
424 [[nodiscard]] static constexpr bool matches(uint32_t index) noexcept { return ((index == Registers) || ...); }
425
426 [[nodiscard]] static bool read(const state_type &state, address_space_ref space, uint32_t index,
427 value_type &value) noexcept {
428 return ReadCallback(state, space, index, value);
429 }
430
431 template <auto Callback = WriteCallback, typename std::enable_if<Callback != nullptr, int>::type = 0>
432 [[nodiscard]] static bool write(state_type &state, address_space_ref space, uint32_t index,
433 const value_type &value) noexcept {
434 return Callback(state, space, index, value);
435 }
436};
437
457template <typename State, typename... FieldTraits> class RELOCO_POINTER register_context_ref_with {
458public:
459 static_assert(sizeof...(FieldTraits) != 0, "at least one register field trait is required");
460 static_assert((std::is_same<typename FieldTraits::state_type, State>::value && ...),
461 "all register field traits must bind the wrapper state type");
462 static_assert((std::is_trivially_copyable<typename FieldTraits::value_type>::value && ...),
463 "register field values must be trivially copyable");
464
465 constexpr register_context_ref_with(State &state RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS,
466 address_space_ref space,
467 span<std::byte> scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS,
468 register_context_ref fallback = {}) noexcept
469 : state_(state), mutable_state_(&state), space_(space), scratch_(scratch), fallback_(fallback) {}
470
471 constexpr register_context_ref_with(const State &state RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS,
472 address_space_ref space,
473 span<std::byte> scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS,
474 register_context_ref fallback = {}) noexcept
475 : state_(state), space_(space), scratch_(scratch), fallback_(fallback) {}
476
477 register_context_ref_with(State &&, address_space_ref, span<std::byte>, register_context_ref = {}) = delete;
478 register_context_ref_with(const State &&, address_space_ref, span<std::byte>, register_context_ref = {}) = delete;
479
486 [[nodiscard]] constexpr register_context_ref ref() & noexcept RELOCO_LIFETIMEBOUND {
487 using tag = detail::mapped_register_context_tag<State, FieldTraits...>;
488 return register_context_ref(tag{}, *this, space_, scratch_);
489 }
490
491 [[nodiscard]] explicit constexpr operator register_context_ref() & noexcept RELOCO_LIFETIMEBOUND { return ref(); }
492
494 operator register_context_ref() && = delete;
495
496private:
497 // decodes raw bytes of a target address space; casts, pointers and offsets are bounded by the explicit lengths
498 // checked here.
499 RELOCO_BEGIN_UNSAFE_CODE
500 template <typename Field>
501 [[nodiscard]] bool try_read(uint32_t index, void *destination, size_t size, bool &handled) const noexcept {
502 if (handled || !Field::matches(index))
503 return false;
504
505 handled = true;
506 if (destination == nullptr || size != sizeof(typename Field::value_type))
507 return false;
508
509 if constexpr (detail::has_register_field_read<Field, State>::value) {
510 typename Field::value_type value{};
511 if (!Field::read(*state_, space_, index, value))
512 return false;
513 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
514 std::memcpy(destination, &value, sizeof(value));
515 RELOCO_END_UNSAFE_BUFFER_USAGE;
516 return true;
517 } else {
518 const auto *value = Field::get(*state_, index);
519 if (!value)
520 return false;
521 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
522 std::memcpy(destination, value, sizeof(*value));
523 RELOCO_END_UNSAFE_BUFFER_USAGE;
524 return true;
525 }
526 }
528
529 // decodes raw bytes of a target address space; casts, pointers and offsets are bounded by the explicit lengths
530 // checked here.
531 RELOCO_BEGIN_UNSAFE_CODE
532 template <typename Field>
533 [[nodiscard]] bool try_write(uint32_t index, const void *source, size_t size, bool &handled) noexcept {
534 if (handled || !Field::matches(index))
535 return false;
536
537 handled = true;
538 if (!mutable_state_ || source == nullptr || size != sizeof(typename Field::value_type))
539 return false;
540
541 if constexpr (detail::has_register_field_write<Field, State>::value) {
542 typename Field::value_type value{};
543 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
544 std::memcpy(&value, source, sizeof(value));
545 RELOCO_END_UNSAFE_BUFFER_USAGE;
546 return Field::write(*mutable_state_, space_, index, value);
547 } else if constexpr (detail::has_mutable_register_field_get<Field, State>::value) {
548 auto *value = Field::get(*mutable_state_, index);
549 if (!value)
550 return false;
551 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
552 std::memcpy(value, source, sizeof(*value));
553 RELOCO_END_UNSAFE_BUFFER_USAGE;
554 return true;
555 } else {
556 return false;
557 }
558 }
560
561 [[nodiscard]] bool read(uint32_t index, void *destination, size_t size) const noexcept {
562 bool handled = false;
563 bool result = false;
564 using expand = int[];
565 static_cast<void>(
566 expand{0, (handled ? 0 : (result = try_read<FieldTraits>(index, destination, size, handled), 0))...});
567 if (handled)
568 return result;
569 return fallback_.read_raw(index, destination, size);
570 }
571
572 [[nodiscard]] bool write(uint32_t index, const void *source, size_t size) noexcept {
573 bool handled = false;
574 bool result = false;
575 using expand = int[];
576 static_cast<void>(expand{0, (handled ? 0 : (result = try_write<FieldTraits>(index, source, size, handled), 0))...});
577 if (handled)
578 return result;
579 return fallback_.write_raw(index, source, size);
580 }
581
582 friend struct register_context_traits<detail::mapped_register_context_tag<State, FieldTraits...>>;
583
584 value_ref<const State> state_;
585 value_ptr<State> mutable_state_;
586 address_space_ref space_;
587 span<std::byte> scratch_;
588 register_context_ref fallback_;
589};
590
591template <typename State, typename... FieldTraits>
592struct register_context_traits<detail::mapped_register_context_tag<State, FieldTraits...>> {
593 using context_type = register_context_ref_with<State, FieldTraits...>;
594
595 // decodes raw bytes of a target address space; casts, pointers and offsets are bounded by the explicit lengths
596 // checked here.
597 RELOCO_BEGIN_UNSAFE_CODE
598 static bool read_register(value_ref<const context_type> context, address_space_ref, uint32_t index, void *destination,
599 size_t size) noexcept {
600 return context->read(index, destination, size);
601 }
603
604 // decodes raw bytes of a target address space; casts, pointers and offsets are bounded by the explicit lengths
605 // checked here.
606 RELOCO_BEGIN_UNSAFE_CODE
607 static bool write_register(value_ref<context_type> context, address_space_ref, uint32_t index, const void *source,
608 size_t size) noexcept {
609 return context->write(index, source, size);
610 }
612};
613
614} // 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
Typed owner that exposes a C/C++ register structure as a register_context_ref.
Definition register_context.hpp:457
register_context_ref_with(const State &&, address_space_ref, span< std::byte >, register_context_ref={})=delete
constexpr register_context_ref_with(const State &state RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS, address_space_ref space, span< std::byte > scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS, register_context_ref fallback={}) noexcept
Definition register_context.hpp:471
constexpr register_context_ref_with(State &state RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS, address_space_ref space, span< std::byte > scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS, register_context_ref fallback={}) noexcept
Definition register_context.hpp:465
register_context_ref_with(State &&, address_space_ref, span< std::byte >, register_context_ref={})=delete
constexpr register_context_ref ref() &noexcept RELOCO_LIFETIMEBOUND
Creates a type-erased reference borrowing this wrapper.
Definition register_context.hpp:486
register_context_ref ref() &&=delete
Zero-allocation, type-erased handle for inspecting and modifying CPU registers from a frame context.
Definition register_context.hpp:118
constexpr span< std::byte > scratch() const noexcept RELOCO_LIFETIMEBOUND
Definition register_context.hpp:186
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_raw(uint32_t dwarf_reg_index, const void *src, size_t size) const noexcept
Writes raw bytes from a source buffer into a register.
Definition register_context.hpp:177
constexpr register_context_ref(Tag, const State &state RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS, address_space_ref space, span< std::byte > scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
Definition register_context.hpp:131
constexpr register_context_ref() noexcept=default
constexpr address_space_ref space() const noexcept
Definition register_context.hpp:185
constexpr bool is_null() const noexcept
Definition register_context.hpp:139
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
constexpr register_context_ref(Tag, State &&, address_space_ref, span< std::byte >)=delete
bool read(uint32_t dwarf_reg_index, T &out_value) const noexcept
Reads a register directly into a typed integer or float variable.
Definition register_context.hpp:148
Typed owner for a register-context traits specialization.
Definition register_context.hpp:250
constexpr value_ref< const context_type > context() const &noexcept RELOCO_LIFETIMEBOUND
Definition register_context.hpp:263
value_ref< context_type > context() &&=delete
typename traits_type::context_type context_type
Definition register_context.hpp:253
constexpr register_context_ref ref() const &noexcept RELOCO_LIFETIMEBOUND
Definition register_context.hpp:271
constexpr register_context_ref ref() &noexcept RELOCO_LIFETIMEBOUND
Definition register_context.hpp:267
value_ref< const context_type > context() const &&=delete
constexpr value_ref< context_type > context() &noexcept RELOCO_LIFETIMEBOUND
Definition register_context.hpp:259
constexpr register_context(context_type context, address_space_ref space, span< std::byte > scratch RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
Definition register_context.hpp:255
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Definition assert.hpp:19
RELOCO_END_UNSAFE_CODE
Definition remote_object.hpp:132
constexpr register_context_ref make_register_context_ref(State &state RELOCO_LIFETIMEBOUND, address_space_ref space, span< std::byte > scratch RELOCO_LIFETIMEBOUND) noexcept
Definition register_context.hpp:240
constexpr register_context_ref make_read_only_register_context_ref(State &state RELOCO_LIFETIMEBOUND, address_space_ref space, span< std::byte > scratch RELOCO_LIFETIMEBOUND) noexcept
Definition register_context.hpp:231
Definition register_context.hpp:91
Definition register_context.hpp:101
Definition register_context.hpp:110
Definition register_context.hpp:34
Definition register_context.hpp:28
Definition register_context.hpp:32
Compile-time register field queried through typed callbacks.
Definition register_context.hpp:407
State state_type
Definition register_context.hpp:408
static constexpr bool matches(uint32_t index) noexcept
Definition register_context.hpp:424
static bool write(state_type &state, address_space_ref space, uint32_t index, const value_type &value) noexcept
Definition register_context.hpp:432
static bool read(const state_type &state, address_space_ref space, uint32_t index, value_type &value) noexcept
Definition register_context.hpp:426
Value value_type
Definition register_context.hpp:409
RELOCO_END_UNSAFE_CODE static RELOCO_BEGIN_UNSAFE_CODE bool write_register(value_ref< context_type > context, address_space_ref, uint32_t index, const void *source, size_t size) noexcept
Definition register_context.hpp:607
static RELOCO_BEGIN_UNSAFE_CODE bool read_register(value_ref< const context_type > context, address_space_ref, uint32_t index, void *destination, size_t size) noexcept
Definition register_context.hpp:598
static RELOCO_BEGIN_UNSAFE_CODE bool read_register(value_ref< const context_type > context, address_space_ref space, uint32_t index, void *destination, size_t size) noexcept
Definition register_context.hpp:46
RELOCO_END_UNSAFE_CODE static RELOCO_BEGIN_UNSAFE_CODE bool write_register(value_ref< context_type > context, address_space_ref space, uint32_t index, const void *source, size_t size) noexcept
Definition register_context.hpp:82
static RELOCO_BEGIN_UNSAFE_CODE bool read_register(value_ref< const context_type > context, address_space_ref space, uint32_t index, void *destination, size_t size) noexcept
Definition register_context.hpp:73
static RELOCO_BEGIN_UNSAFE_CODE bool write_register(value_ref< context_type > context, address_space_ref space, uint32_t index, const void *source, size_t size) noexcept
Definition register_context.hpp:59
Static customization point for a register-context provider.
Definition register_context.hpp:26
Compile-time register-field trait backed by a pointer to member.
Definition register_context.hpp:337
static constexpr bool matches(uint32_t index) noexcept
Definition register_context.hpp:345
typename member_traits::value_type value_type
Definition register_context.hpp:340
typename member_traits::state_type state_type
Definition register_context.hpp:339
static constexpr const value_type * get(const state_type &state, uint32_t) noexcept
Definition register_context.hpp:347
static constexpr value_type * get(state_type &state, uint32_t) noexcept
Definition register_context.hpp:351
detail::register_member_pointer_traits< decltype(Member)> member_traits
Definition register_context.hpp:338
Compile-time field trait with state-dependent member selection.
Definition register_context.hpp:369
State state_type
Definition register_context.hpp:370
Value value_type
Definition register_context.hpp:371
static constexpr const value_type * get(const state_type &state, uint32_t index) noexcept
Definition register_context.hpp:382
static constexpr auto get(state_type &state, uint32_t index) noexcept -> decltype(Selector{}(state, index))
Definition register_context.hpp:386
static constexpr bool matches(uint32_t index) noexcept
Definition register_context.hpp:380
Definition register_context.hpp:30