blob: a1ae62594780f83be7b1f8d5d71d19efc88981ed [file]
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MPACT_SIM_UTIL_PROGRAM_LOADER_ELF_PROGRAM_LOADER_H_
#define MPACT_SIM_UTIL_PROGRAM_LOADER_ELF_PROGRAM_LOADER_H_
#include <cstdint>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/statusor.h"
#include "elfio/elfio.hpp"
#include "elfio/elfio_segment.hpp"
#include "elfio/elfio_symbols.hpp"
#include "mpact/sim/generic/core_debug_interface.h"
#include "mpact/sim/util/memory/memory_interface.h"
#include "mpact/sim/util/program_loader/program_loader_interface.h"
namespace mpact {
namespace sim {
namespace util {
struct AddressRange {
explicit AddressRange(uint64_t start) : start(start), end(start + 1) {}
AddressRange(uint64_t start, uint64_t size)
: start(start), end(start + size) {}
uint64_t start;
uint64_t end;
};
struct AddressRangeComp {
bool operator()(const AddressRange& lhs, const AddressRange& rhs) const {
if (lhs.end <= rhs.start) {
return true;
}
return false;
}
};
// This struct is used to describe a memory to be used by the elf program loader
// when there is more than one or two memories that have to be loaded.
struct MemoryDescriptor {
// Pointer to the memory interface.
util::MemoryInterface* memory;
// Predicate function that takes a segment and return true if it should be
// loaded into this memory.
absl::AnyInvocable<bool(const ELFIO::segment&) const> predicate_fcn;
// Function that takes a segment load address and returns the address it
// should be loaded at in the memory. If not specified, the load address is
// used unmodified.
absl::AnyInvocable<uint64_t(uint64_t) const> address_fcn;
};
// This class wraps the elfio class to provide an easy interface to load the
// segments of an elf executable file into memory. If both code and data
// memories are given, then executable segments are loaded into code memory and
// all other segments into data memory.
//
// TODO(): Allow for a multiple memories to be passed in to allow
// segments to be loaded into different memories, not just one big contiguous
// memory.
class ElfProgramLoader : public ProgramLoaderInterface {
public:
ElfProgramLoader(util::MemoryInterface* code_memory,
util::MemoryInterface* data_memory);
ElfProgramLoader(const std::vector<MemoryDescriptor>& memories);
explicit ElfProgramLoader(util::MemoryInterface* memory);
explicit ElfProgramLoader(generic::CoreDebugInterface* dbg_if);
ElfProgramLoader() = delete;
~ElfProgramLoader() override;
absl::StatusOr<uint64_t> LoadSymbols(const std::string& file_name) override;
absl::StatusOr<uint64_t> LoadProgram(const std::string& file_name) override;
// Return the value and size of the symbol 'name' if it exists in the symbol
// table.
absl::StatusOr<std::pair<uint64_t, uint64_t>> GetSymbol(
const std::string& name) const;
// If there is a function with symbol table value 'address' return its name.
absl::StatusOr<std::string> GetFcnSymbolName(uint64_t address) const;
// Looks up to see if the address is in the range of a function symbol, and
// if so, returns the functions name.
absl::StatusOr<std::string> GetFunctionName(uint64_t address) const;
// If the GNU stack size program header exists, return the memory size.
absl::StatusOr<uint64_t> GetStackSize() const;
void set_text_size_scale(uint64_t scale) { text_size_scale_ = scale; }
void set_data_size_scale(uint64_t scale) { data_size_scale_ = scale; }
const ELFIO::elfio* elf_reader() const { return &elf_reader_; }
private:
const std::vector<MemoryDescriptor>* memories_ = nullptr;
bool loaded_ = false;
ELFIO::elfio elf_reader_;
util::MemoryInterface* code_memory_ = nullptr;
util::MemoryInterface* data_memory_ = nullptr;
generic::CoreDebugInterface* dbg_if_ = nullptr;
std::vector<const ELFIO::symbol_section_accessor*> symbol_accessors_;
absl::flat_hash_map<uint64_t, std::string> fcn_symbol_map_;
std::map<AddressRange, std::string, AddressRangeComp> function_range_map_;
uint64_t has_stack_size_ = false;
uint64_t stack_size_ = 0;
uint64_t text_size_scale_ = 1;
uint64_t data_size_scale_ = 1;
};
} // namespace util
} // namespace sim
} // namespace mpact
#endif // MPACT_SIM_UTIL_PROGRAM_LOADER_ELF_PROGRAM_LOADER_H_