16#include "../microfmt.hpp"
17#include "../reloco.hpp"
50 static_assert(std::is_trivially_copyable_v<T>,
"Scanned type must be trivially copyable.");
53 expected<memory_scan_result, address_space_error> (*scan)(
const void *ctx, uintptr_t start_addr,
54 size_t search_length,
const T &min_val,
const T &max_val,
55 size_t stride)
noexcept;
61 std::enable_if_t<std::is_void_v<typename Traits::context_type>,
int> = 0>
64 template <
typename Tag,
typename Context,
typename Traits = value_range_scanner_traits<Tag, T>,
65 std::enable_if_t<!std::is_
void_v<
typename Traits::context_type> &&
66 std::is_convertible_v<const Context *, const
typename Traits::context_type *>,
69 const Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
70 : ctx_(&ctx), vtbl_(&s_vtbl<Tag>) {}
72 template <
typename Tag,
typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>,
int> = 0>
75 template <
typename Tag,
typename Traits = value_range_scanner_traits<Tag, T>,
76 std::enable_if_t<std::is_
void_v<
typename Traits::context_type>,
int> = 0>
81 template <
typename Tag,
typename Context,
typename Traits = value_range_scanner_traits<Tag, T>,
82 std::enable_if_t<!std::is_
void_v<
typename Traits::context_type>,
int> = 0>
95 [[nodiscard]] expected<memory_scan_result, address_space_error>
scan(uintptr_t start_addr,
size_t search_length,
96 const T &min_val,
const T &max_val,
97 size_t stride =
alignof(T))
const noexcept {
99 return unexpected(address_space_error::invalid_handle);
100 return vtbl_->scan(ctx_.get(), start_addr, search_length, min_val, max_val, stride);
103 [[nodiscard]]
constexpr explicit operator bool() const noexcept {
return vtbl_ !=
nullptr; }
106 template <
typename Tag>
107 static expected<memory_scan_result, address_space_error> scan_entry(
const void *context, uintptr_t start_addr,
108 size_t search_length,
const T &min_val,
109 const T &max_val,
size_t stride)
noexcept {
111 if constexpr (std::is_void_v<context_type>) {
114 const auto &typed_context = *
static_cast<const context_type *
>(context);
115 return value_range_scanner_traits<Tag, T>::scan(value_ref<const context_type>(typed_context), start_addr,
116 search_length, min_val, max_val, stride);
120 template <
typename Tag>
static constexpr vtable s_vtbl{&scan_entry<Tag>};
122 value_ptr<const void> ctx_{};
135template <
typename Tag,
typename T,
136 bool Stateless = std::is_void_v<typename value_range_scanner_traits<Tag, T>::context_type>>
146 [[nodiscard]]
constexpr value_ref<context_type>
context() &
noexcept RELOCO_LIFETIMEBOUND {
147 return value_ref<context_type>(context_);
150 [[nodiscard]]
constexpr value_ref<const context_type>
context() const & noexcept RELOCO_LIFETIMEBOUND {
151 return value_ref<const context_type>(context_);
162 value_ref<context_type>
context() && =
delete;
163 value_ref<const context_type>
context() const && = delete;
208 expected<memory_scan_result, address_space_error> (*scan)(
const void *ctx, uintptr_t start_addr,
209 size_t search_length,
size_t window_size,
size_t stride,
211 void *user_context)
noexcept =
nullptr;
217 std::enable_if_t<std::is_void_v<typename Traits::context_type>,
int> = 0>
220 template <
typename Tag,
typename Context,
typename Traits = dependent_value_scanner_traits<Tag>,
221 std::enable_if_t<!std::is_
void_v<
typename Traits::context_type> &&
222 std::is_convertible_v<const Context *, const
typename Traits::context_type *>,
225 Tag,
const Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
226 : ctx_(&ctx), vtbl_(&s_vtbl<Tag>) {}
228 template <
typename Tag,
typename Context, std::enable_if_t<!std::is_lvalue_reference_v<Context>,
int> = 0>
231 template <
typename Tag,
typename Traits = dependent_value_scanner_traits<Tag>,
232 std::enable_if_t<std::is_
void_v<
typename Traits::context_type>,
int> = 0>
237 template <
typename Tag,
typename Context,
typename Traits = dependent_value_scanner_traits<Tag>,
238 std::enable_if_t<!std::is_
void_v<
typename Traits::context_type>,
int> = 0>
240 make(
const Context &context RELOCO_LIFETIMEBOUND)
noexcept {
253 [[nodiscard]] expected<memory_scan_result, address_space_error>
scan(uintptr_t start_addr,
size_t search_length,
254 size_t window_size,
size_t stride,
256 void *user_context =
nullptr) const noexcept {
257 if (vtbl_ ==
nullptr)
258 return unexpected(address_space_error::invalid_handle);
259 return vtbl_->scan(ctx_.get(), start_addr, search_length, window_size, stride, predicate, user_context);
262 [[nodiscard]]
constexpr explicit operator bool() const noexcept {
return vtbl_ !=
nullptr; }
265 template <
typename Tag>
266 static expected<memory_scan_result, address_space_error>
267 scan_entry(
const void *context, uintptr_t start_addr,
size_t search_length,
size_t window_size,
size_t stride,
270 if constexpr (std::is_void_v<context_type>) {
274 const auto &typed_context = *
static_cast<const context_type *
>(context);
275 return dependent_value_scanner_traits<Tag>::scan(value_ref<const context_type>(typed_context), start_addr,
276 search_length, window_size, stride, predicate, user_context);
280 template <
typename Tag>
static constexpr vtable s_vtbl{&scan_entry<Tag>};
282 value_ptr<const void> ctx_{};
294template <typename Tag, bool Stateless = std::is_void_v<typename dependent_value_scanner_traits<Tag>::context_type>>
304 [[nodiscard]]
constexpr value_ref<context_type>
context() &
noexcept RELOCO_LIFETIMEBOUND {
305 return value_ref<context_type>(context_);
308 [[nodiscard]]
constexpr value_ref<const context_type>
context() const & noexcept RELOCO_LIFETIMEBOUND {
309 return value_ref<const context_type>(context_);
320 value_ref<context_type>
context() && =
delete;
321 value_ref<const context_type>
context() const && = delete;
352 RELOCO_BEGIN_UNSAFE_CODE
353 static expected<memory_scan_result, address_space_error>
scan(value_ref<const context_type> ctx, uintptr_t start_addr,
354 size_t search_length,
const T &min_val,
355 const T &max_val,
size_t stride)
noexcept {
358 const size_t window_size =
sizeof(T);
359 if (ctx->scratch.size() < window_size)
360 return unexpected(address_space_error::invalid_buffer);
362 return unexpected(address_space_error::invalid_handle);
364 uintptr_t current_addr = start_addr;
365 size_t remaining = search_length;
367 while (remaining >= window_size) {
368 size_t to_read = (remaining < ctx->scratch.size()) ? remaining : ctx->scratch.size();
369 auto read_res = ctx->space.read_bytes(current_addr, ctx->scratch.data(), to_read);
371 return unexpected(read_res.error());
373 size_t search_limit = to_read - window_size;
374 for (
size_t offset = 0; offset <= search_limit; offset += stride) {
376 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
377 std::memcpy(&val, ctx->scratch.data() + offset,
sizeof(T));
378 RELOCO_END_UNSAFE_BUFFER_USAGE;
379 if (val >= min_val && val <= max_val) {
380 if (current_addr > std::numeric_limits<uintptr_t>::max() - offset) {
381 return unexpected(address_space_error::invalid_address);
387 size_t advance = ((search_limit) / stride) * stride + stride;
388 if (current_addr > std::numeric_limits<uintptr_t>::max() - advance) {
389 return unexpected(address_space_error::invalid_address);
391 current_addr += advance;
392 remaining = (advance > remaining) ? 0 : remaining - advance;
405 RELOCO_BEGIN_UNSAFE_CODE
406 static expected<memory_scan_result, address_space_error>
scan(value_ref<const context_type> ctx, uintptr_t start_addr,
407 size_t search_length,
size_t window_size,
size_t stride,
409 void *user_context)
noexcept {
412 if (window_size == 0)
413 return unexpected(address_space_error::invalid_buffer);
414 if (ctx->scratch.size() < window_size)
415 return unexpected(address_space_error::invalid_buffer);
417 return unexpected(address_space_error::invalid_handle);
418 if (predicate ==
nullptr)
419 return unexpected(address_space_error::invalid_buffer);
421 uintptr_t current_addr = start_addr;
422 size_t remaining = search_length;
424 while (remaining >= window_size) {
425 const size_t to_read = (remaining < ctx->scratch.size()) ? remaining : ctx->scratch.size();
426 auto read_res = ctx->space.read_bytes(current_addr, ctx->scratch.data(), to_read);
428 return unexpected(read_res.error());
430 const size_t search_limit = to_read - window_size;
431 for (
size_t offset = 0; offset <= search_limit; offset += stride) {
432 RELOCO_BEGIN_UNSAFE_BUFFER_USAGE;
433 const void *window = ctx->scratch.data() + offset;
434 RELOCO_END_UNSAFE_BUFFER_USAGE;
435 if (predicate(window, user_context)) {
436 if (current_addr > std::numeric_limits<uintptr_t>::max() - offset) {
437 return unexpected(address_space_error::invalid_address);
443 const size_t advance = ((search_limit) / stride) * stride + stride;
444 if (current_addr > std::numeric_limits<uintptr_t>::max() - advance) {
445 return unexpected(address_space_error::invalid_address);
447 current_addr += advance;
448 remaining = (advance > remaining) ? 0 : remaining - advance;
Type-erased remote address-space access and remote string/object views.
constexpr value_ref< context_type > context() &noexcept RELOCO_LIFETIMEBOUND
Definition advanced_scanners.hpp:304
constexpr value_ref< const context_type > context() const &noexcept RELOCO_LIFETIMEBOUND
Definition advanced_scanners.hpp:308
value_ref< context_type > context() &&=delete
typename dependent_value_scanner_traits< Tag >::context_type context_type
Definition advanced_scanners.hpp:300
constexpr dependent_value_scanner(context_type context) noexcept
Definition advanced_scanners.hpp:302
constexpr dependent_value_scanner_ref ref() const &noexcept RELOCO_LIFETIMEBOUND
Definition advanced_scanners.hpp:312
value_ref< const context_type > context() const &&=delete
void context_type
Definition advanced_scanners.hpp:332
static constexpr dependent_value_scanner_ref ref() noexcept
Definition advanced_scanners.hpp:334
Type-erased reference for scanning memory using a custom logical predicate.
Definition advanced_scanners.hpp:205
static constexpr dependent_value_scanner_ref make(const Context &context RELOCO_LIFETIMEBOUND) noexcept
Definition advanced_scanners.hpp:240
constexpr dependent_value_scanner_ref() noexcept=default
constexpr dependent_value_scanner_ref(Tag, Context &&)=delete
expected< memory_scan_result, address_space_error > scan(uintptr_t start_addr, size_t search_length, size_t window_size, size_t stride, dependent_predicate_fn predicate, void *user_context=nullptr) const noexcept
Scans memory using a custom sliding-window callback.
Definition advanced_scanners.hpp:253
static constexpr dependent_value_scanner_ref make() noexcept
Definition advanced_scanners.hpp:233
constexpr dependent_value_scanner_ref(Tag, const Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
Definition advanced_scanners.hpp:224
Typed wrapper owning the context for a dependent value scanner.
Definition advanced_scanners.hpp:295
constexpr value_ref< const context_type > context() const &noexcept RELOCO_LIFETIMEBOUND
Definition advanced_scanners.hpp:150
constexpr value_ref< context_type > context() &noexcept RELOCO_LIFETIMEBOUND
Definition advanced_scanners.hpp:146
typename value_range_scanner_traits< Tag, T >::context_type context_type
Definition advanced_scanners.hpp:142
value_ref< const context_type > context() const &&=delete
value_ref< context_type > context() &&=delete
constexpr value_range_scanner_ref< T > ref() const &noexcept RELOCO_LIFETIMEBOUND
Definition advanced_scanners.hpp:154
constexpr value_range_scanner(context_type context) noexcept
Definition advanced_scanners.hpp:144
void context_type
Definition advanced_scanners.hpp:174
static constexpr value_range_scanner_ref< T > ref() noexcept
Definition advanced_scanners.hpp:176
Type-erased reference for scanning memory for a scalar value within a [min, max] range.
Definition advanced_scanners.hpp:48
static constexpr value_range_scanner_ref make() noexcept
Definition advanced_scanners.hpp:77
static constexpr value_range_scanner_ref make(const Context &context RELOCO_LIFETIMEBOUND) noexcept
Definition advanced_scanners.hpp:83
expected< memory_scan_result, address_space_error > scan(uintptr_t start_addr, size_t search_length, const T &min_val, const T &max_val, size_t stride=alignof(T)) const noexcept
Scans memory for a value falling within the inclusive bounds [min_val, max_val].
Definition advanced_scanners.hpp:95
constexpr value_range_scanner_ref(Tag, Context &&)=delete
constexpr value_range_scanner_ref() noexcept=default
constexpr value_range_scanner_ref(Tag, const Context &ctx RELOCO_LIFETIMEBOUND RELOCO_LIFETIME_CAPTURE_BY_THIS) noexcept
Definition advanced_scanners.hpp:68
Typed wrapper owning the context for a value range scanner.
Definition advanced_scanners.hpp:137
Type-erased, zero-allocation memory pattern scanner for exact and masked byte sequences.
bool(*)(const void *window_bytes, void *user_context) noexcept dependent_predicate_fn
Function pointer type for evaluating a logical predicate over a memory window.
Definition advanced_scanners.hpp:189
RELOCO_END_UNSAFE_CODE
Definition remote_object.hpp:132
Definition advanced_scanners.hpp:207
static RELOCO_BEGIN_UNSAFE_CODE expected< memory_scan_result, address_space_error > scan(value_ref< const context_type > ctx, uintptr_t start_addr, size_t search_length, size_t window_size, size_t stride, dependent_predicate_fn predicate, void *user_context) noexcept
Definition advanced_scanners.hpp:406
Static customization point for scanning memory using a sliding-window predicate.
Definition advanced_scanners.hpp:195
Definition advanced_scanners.hpp:344
State retained by the standard linear memory scanner.
Definition memory_pattern_scanner.hpp:209
Definition advanced_scanners.hpp:343
Result of a memory pattern scan operation.
Definition memory_pattern_scanner.hpp:30
Definition advanced_scanners.hpp:52
static RELOCO_BEGIN_UNSAFE_CODE expected< memory_scan_result, address_space_error > scan(value_ref< const context_type > ctx, uintptr_t start_addr, size_t search_length, const T &min_val, const T &max_val, size_t stride) noexcept
Definition advanced_scanners.hpp:353
Static customization point for scanning memory for a scalar within a specific range.
Definition advanced_scanners.hpp:38