12#include "../formatters/hexdump.hpp"
13#include "../microfmt.hpp"
35 std::enable_if_t<std::is_convertible_v<const Context *, const typename Traits::context_type *>,
int> = 0>
36 constexpr
address_source_ref(Tag, const Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
37 : ctx_(&ctx), next_fn_(&next_entry<Tag>) {}
39 template <
typename Tag,
typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>,
int> = 0>
42 template <
typename Tag,
typename Context,
typename Traits = address_source_traits<Tag>>
47 template <
typename Tag,
typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>,
int> = 0>
50 [[nodiscard]]
bool next(uintptr_t &out_addr)
const noexcept {
51 if (next_fn_ ==
nullptr || !ctx_)
53 return next_fn_(ctx_.get(), out_addr);
56 [[nodiscard]]
constexpr explicit operator bool() const noexcept {
return next_fn_ !=
nullptr; }
59 template <
typename Tag>
static bool next_entry(
const void *context, uintptr_t &out_addr)
noexcept {
61 const auto &typed_context = *
static_cast<const context_type *
>(context);
65 value_ptr<const void> ctx_{};
66 bool (*next_fn_)(
const void *ctx, uintptr_t &out_addr)
noexcept {
nullptr};
76 [[nodiscard]]
constexpr value_ref<context_type>
context() &
noexcept RELOCO_LIFETIMEBOUND {
77 return value_ref<context_type>(context_);
80 [[nodiscard]]
constexpr value_ref<const context_type>
context() const & noexcept RELOCO_LIFETIMEBOUND {
81 return value_ref<const context_type>(context_);
88 value_ref<context_type>
context() && =
delete;
89 value_ref<const context_type>
context() const && = delete;
104 size_t dump_bytes{80};
108 bool demangle_symbols{
true};
121 span<char> symbol_scratch{};
127 uint8_t dump_line_buffer[16]{};
142 template <
typename AbiTraits>
145 const sink &out)
noexcept {
151 for (
const auto ®_desc : AbiTraits::register_traits::address_registers()) {
152 typename AbiTraits::register_type reg_val = 0;
153 if (reg_ctx.read_raw(reg_desc.index, ®_val,
sizeof(reg_val)) && reg_val != 0) {
155 process_address(space, classifier, index++,
static_cast<uintptr_t
>(reg_val), context, out);
161 for (uintptr_t addr : raw_addresses) {
162 process_address(space, classifier, index++, addr, context, out);
177 while (source.next(addr)) {
178 process_address(space, classifier, index++, addr, context, out);
185 context.region_info = {};
186 const bool classified = classifier && classifier.classify_address(addr, context.region_info);
187 const auto &info = context.region_info;
192 print_region_type(out, info.type);
195 out.write(
"unknown/unmapped");
198 if (classified && context.options.symbol_resolver && is_symbolic_region(
info.type)) {
199 context.resolved_symbol = {};
200 if (context.options.symbol_resolver.resolve(addr, context.symbol_scratch, context.raw_symbol,
201 context.resolved_symbol) &&
202 context.resolved_symbol.has_symbol()) {
203 const auto &symbol = context.resolved_symbol;
204 out.write(
" | symbol=");
205 if (context.options.demangle_symbols) {
208 out.write(symbol.symbol_name);
210 if (symbol.offset_from_symbol != 0) {
218 bool allow_deref = classified &&
info.readable;
221 case memory_region_type::kernel_code:
222 case memory_region_type::direct_map:
223 case memory_region_type::user_code:
224 case memory_region_type::device_mmio:
225 case memory_region_type::guard_page:
226 case memory_region_type::ns_map:
227 case memory_region_type::ns_device_mmio:
231 case memory_region_type::unknown:
232 case memory_region_type::kernel_data:
233 case memory_region_type::kernel_stack:
234 case memory_region_type::process_stack:
235 case memory_region_type::struct_pages:
236 case memory_region_type::kernel_heap:
237 case memory_region_type::user_data:
245 if (!space || context.options.dump_bytes == 0 || !allow_deref)
248 size_t bytes_to_dump = (context.options.dump_bytes > 80) ? 80 : context.options.dump_bytes;
249 if (classified &&
info.end_address > addr) {
250 const size_t bytes_in_region =
static_cast<size_t>(
info.end_address - addr);
251 if (bytes_to_dump > bytes_in_region)
252 bytes_to_dump = bytes_in_region;
255 const auto reader = [](
void *reader_context, uintptr_t source_address, uint8_t *buffer,
256 size_t size)
noexcept ->
size_t {
257 if (reader_context ==
nullptr)
259 const auto &target_space = *
static_cast<const address_space_ref *
>(reader_context);
260 return target_space.read_bytes(source_address, buffer, size) ? size : 0;
262 context.reader_space = space;
263 context.dump_view =
hexdump_checked(addr, bytes_to_dump, reader, &context.reader_space, 16,
true);
264 format_hexdump(context.dump_view, {context.dump_line_buffer, sizeof(context.dump_line_buffer)}, out);
267 [[nodiscard]]
static constexpr bool is_symbolic_region(memory_region_type type)
noexcept {
269 case memory_region_type::kernel_code:
270 case memory_region_type::kernel_data:
271 case memory_region_type::user_code:
272 case memory_region_type::user_data:
274 case memory_region_type::unknown:
275 case memory_region_type::kernel_stack:
276 case memory_region_type::process_stack:
277 case memory_region_type::direct_map:
278 case memory_region_type::struct_pages:
279 case memory_region_type::kernel_heap:
280 case memory_region_type::device_mmio:
281 case memory_region_type::guard_page:
282 case memory_region_type::ns_map:
283 case memory_region_type::ns_device_mmio:
289 static void print_region_type(
const sink &out, memory_region_type type)
noexcept {
291 case memory_region_type::kernel_code:
292 out.write(
"kernel_code");
294 case memory_region_type::kernel_data:
295 out.write(
"kernel_data");
297 case memory_region_type::kernel_stack:
298 out.write(
"kernel_stack");
300 case memory_region_type::process_stack:
301 out.write(
"process_stack");
303 case memory_region_type::direct_map:
304 out.write(
"direct_map");
306 case memory_region_type::struct_pages:
307 out.write(
"struct_pages");
309 case memory_region_type::kernel_heap:
310 out.write(
"kernel_heap");
312 case memory_region_type::user_code:
313 out.write(
"user_code");
315 case memory_region_type::user_data:
316 out.write(
"user_data");
318 case memory_region_type::device_mmio:
319 out.write(
"device_mmio");
321 case memory_region_type::guard_page:
322 out.write(
"guard_page");
324 case memory_region_type::ns_map:
327 case memory_region_type::ns_device_mmio:
328 out.write(
"ns_device_mmio");
330 case memory_region_type::unknown:
332 out.write(
"unknown");
Type-erased remote address-space access and remote string/object views.
Type-erased abstract source iterator providing addresses to scan.
Definition memory_scanner.hpp:30
static constexpr address_source_ref make(const Context &ctx RELOCO_LIFETIMEBOUND) noexcept
Definition memory_scanner.hpp:43
constexpr address_source_ref(Tag, Context &&)=delete
static address_source_ref make(Context &&)=delete
bool next(uintptr_t &out_addr) const noexcept
Definition memory_scanner.hpp:50
constexpr address_source_ref() noexcept=default
Definition memory_scanner.hpp:69
typename traits_type::context_type context_type
Definition memory_scanner.hpp:72
value_ref< const context_type > context() const &&=delete
value_ref< context_type > context() &&=delete
constexpr address_source(context_type context) noexcept
Definition memory_scanner.hpp:74
constexpr value_ref< context_type > context() &noexcept RELOCO_LIFETIMEBOUND
Definition memory_scanner.hpp:76
constexpr value_ref< const context_type > context() const &noexcept RELOCO_LIFETIMEBOUND
Definition memory_scanner.hpp:80
constexpr address_source_ref ref() const &noexcept RELOCO_LIFETIMEBOUND
Definition memory_scanner.hpp:84
Type-erased, two-word handle to a remote address space.
Definition address_space.hpp:204
Type-erased, two-word handle for classifying memory regions and addresses.
Definition memory_classifier.hpp:81
Utility scanner for inspecting, classifying, and conditionally hex-dumping memory addresses.
Definition memory_scanner.hpp:135
static void scan_and_dump(address_space_ref space, memory_classifier_ref classifier, register_context_ref reg_ctx, span< const uintptr_t > raw_addresses, memory_scanner_context &context, const sink &out) noexcept
Scans architecture-specific register candidates followed by a sequence of explicit raw addresses.
Definition memory_scanner.hpp:143
static void scan_and_dump(address_space_ref space, memory_classifier_ref classifier, address_source_ref source, memory_scanner_context &context, const sink &out) noexcept
Scans addresses dynamically pulled from a type-erased abstract source.
Definition memory_scanner.hpp:170
Zero-allocation, type-erased handle for inspecting and modifying CPU registers from a frame context.
Definition register_context.hpp:118
Type-erased, two-word handle to a symbol resolver.
Definition symbol_resolver.hpp:132
Definition symbol_resolver.hpp:286
#define MICROFMT_API_CLASS
Definition compat.hpp:181
Per-architecture ABI traits describing registers used during DWARF unwinding.
Type-erased memory region classifier for system and kernel introspection.
void info(microfmt::string_view fmt, const Args &...args) noexcept
Definition logger.hpp:347
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
RELOCO_BEGIN_UNSAFE_CODE constexpr hexdump_view hexdump_checked(uintptr_t base_addr, size_t total_len, memory_reader_fn_t reader, void *ctx=nullptr, uint8_t bytes_per_line=16, bool show_ascii=true) noexcept
Helper for dumping memory via a fault-checked accessor probe.
Definition hexdump.hpp:64
RELOCO_END_UNSAFE_CODE MICROFMT_API void format_hexdump(const hexdump_view &h, span< uint8_t > line_buffer, const sink &out) noexcept
Formats a hex dump using caller-provided line storage.
constexpr auto as_demangled(microfmt::string_view sym) noexcept
Wraps a symbol for demangled formatting.
Definition demangle.hpp:523
Definition memory_scanner.hpp:25
Definition hexdump.hpp:37
Detailed description of a classified memory region or address.
Definition memory_classifier.hpp:42
Caller-owned reusable storage for memory scanning.
Definition memory_scanner.hpp:118
Optional memory-scanner behavior and caller-owned symbol storage.
Definition memory_scanner.hpp:102
Raw resolution result as returned by a resolver backend.
Definition symbol_resolver.hpp:26
Derived symbol info with precomputed relative offsets.
Definition symbol_resolver.hpp:53
Type-erased symbol resolution for remote addresses and formattable symbol views.