blob: 56ceb7935e4952ae0424a99c347abf26981d1494 [file] [log] [blame]
// 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_