| // Copyright 2022 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_LOADINFO_MAPPED_MEMORY_H_ |
| #define SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_LOADINFO_MAPPED_MEMORY_H_ |
| |
| #include <lib/stdcompat/span.h> |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <optional> |
| |
| #include "memory.h" |
| |
| namespace elfldltl { |
| |
| // elfldltl::LoadInfoMappedMemory<LoadInfo, ...> adapts a Memory object with |
| // "addresses" that are essentially file offsets (e.g. MappedVmoFile, MappedFdFile) |
| // into a Memory object with proper file-relative addresses, as expected by the |
| // Memory API. |
| // |
| // Provided a reference to a Memory object and the LoadInfo associated with it, |
| // LoadInfoMappedMemory translates a file-relative memory address `ptr` into |
| // the exact segment offset to read from in the underlying Memory object. |
| template <class LoadInfo, class Memory> |
| class LoadInfoMappedMemory : public DirectMemory { |
| public: |
| LoadInfoMappedMemory(const LoadInfoMappedMemory&) = default; |
| |
| LoadInfoMappedMemory(const LoadInfo& load_info, Memory& mem) : load_info_(load_info), mem_(mem) {} |
| |
| template <typename T> |
| std::optional<cpp20::span<const T>> ReadArray(uintptr_t ptr, size_t count) { |
| return ReadArrayImpl<T>(ptr, count); |
| } |
| |
| template <typename T> |
| std::optional<cpp20::span<const T>> ReadArray(uintptr_t ptr) { |
| return ReadArrayImpl<T>(ptr, std::nullopt); |
| } |
| |
| private: |
| using size_type = typename LoadInfo::size_type; |
| |
| // Locate the segment that contains the `ptr` value in its `vaddr` range. |
| // `read_underyling` calculates the target offset to begin to read from using |
| // the segment's offset value, ensuring the `request_count` is within bounds. |
| template <typename T> |
| std::optional<cpp20::span<const T>> ReadArrayImpl(uintptr_t ptr, std::optional<size_t> count) { |
| auto target_vaddr = static_cast<size_type>(ptr); |
| auto segment = load_info_.FindSegment(static_cast<size_type>(target_vaddr)); |
| if (segment == load_info_.segments().end()) { |
| return std::nullopt; |
| } |
| |
| auto read_underlying = [this, target_vaddr, |
| count](const auto& segment) -> std::optional<cpp20::span<const T>> { |
| const size_type offset_in_segment = target_vaddr - segment.vaddr(); |
| if (segment.filesz() < offset_in_segment) [[unlikely]] { |
| return std::nullopt; |
| } |
| const size_t avail = static_cast<size_t>(segment.filesz() - offset_in_segment) / sizeof(T); |
| const size_t request_count = count.value_or(avail); |
| if (request_count <= avail) { |
| return mem_.template ReadArray<T>(segment.offset() + offset_in_segment, request_count); |
| } |
| return std::nullopt; |
| }; |
| |
| return std::visit(read_underlying, *segment); |
| } |
| |
| const LoadInfo& load_info_; |
| Memory& mem_; |
| }; |
| |
| // Deduction guide. |
| template <class LoadInfo, class Memory> |
| LoadInfoMappedMemory(const LoadInfo&, Memory&) -> LoadInfoMappedMemory<LoadInfo, Memory>; |
| |
| } // namespace elfldltl |
| |
| #endif // SRC_LIB_ELFLDLTL_INCLUDE_LIB_ELFLDLTL_LOADINFO_MAPPED_MEMORY_H_ |