| // Copyright 2018 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. |
| |
| #include <string> |
| |
| #include "garnet/lib/elflib/elflib.h" |
| |
| namespace elflib { |
| |
| namespace { |
| |
| // Load the standard ELF string table format |
| void LoadStringTable(const std::vector<uint8_t>& content, |
| std::vector<std::string>* strings) { |
| const uint8_t* data = content.data(); |
| const uint8_t* end = data + content.size(); |
| |
| while (data != end) { |
| strings->emplace_back(reinterpret_cast<const char*>(data)); |
| data += strings->back().size() + 1; |
| } |
| } |
| |
| } // namespace |
| |
| ElfLib::ElfLib(std::unique_ptr<MemoryAccessor>&& memory) |
| : memory_(std::move(memory)) {} |
| |
| ElfLib::~ElfLib() = default; |
| |
| std::unique_ptr<ElfLib> ElfLib::Create( |
| std::unique_ptr<MemoryAccessor>&& memory) { |
| std::unique_ptr<ElfLib> out = std::make_unique<ElfLib>(std::move(memory)); |
| std::vector<uint8_t> header_data; |
| header_data.resize(sizeof(Elf64_Ehdr)); |
| |
| if (!out->memory_->GetMemory(0, &header_data)) { |
| return std::unique_ptr<ElfLib>(); |
| } |
| |
| out->header_ = *reinterpret_cast<Elf64_Ehdr*>(header_data.data()); |
| |
| // We don't support non-standard section header sizes. |
| if (out->header_.e_shentsize != sizeof(Elf64_Shdr)) { |
| return std::unique_ptr<ElfLib>(); |
| } |
| |
| return out; |
| } |
| |
| const Elf64_Shdr* ElfLib::GetSectionHeader(size_t section) { |
| if (sections_.empty()) { |
| std::vector<uint8_t> data; |
| data.resize(sizeof(Elf64_Shdr) * header_.e_shnum); |
| |
| if (!memory_->GetMemory(header_.e_shoff, &data)) { |
| return nullptr; |
| } |
| |
| Elf64_Shdr* header_array = reinterpret_cast<Elf64_Shdr*>(data.data()); |
| |
| std::copy(header_array, header_array + header_.e_shnum, |
| std::back_inserter(sections_)); |
| } |
| |
| if (section >= sections_.size()) { |
| return nullptr; |
| } |
| |
| return §ions_[section]; |
| } |
| |
| const std::vector<uint8_t>* ElfLib::GetSectionData(size_t section) { |
| const auto& iter = section_data_.find(section); |
| if (iter != section_data_.end()) { |
| return &iter->second; |
| } |
| |
| const Elf64_Shdr* header = GetSectionHeader(section); |
| |
| if (!header) { |
| return nullptr; |
| } |
| |
| size_t count = header->sh_size; |
| std::vector<uint8_t> data; |
| data.resize(count); |
| |
| if (!memory_->GetMappedMemory(header->sh_offset, header->sh_addr, &data)) { |
| return nullptr; |
| } |
| |
| section_data_[section] = data; |
| |
| return §ion_data_[section]; |
| } |
| |
| const std::vector<uint8_t>* ElfLib::GetSectionData(const std::string& name) { |
| if (section_names_.size() == 0) { |
| const std::vector<uint8_t>* section_name_data = |
| GetSectionData(header_.e_shstrndx); |
| |
| if (!section_name_data) { |
| return nullptr; |
| } |
| |
| std::vector<std::string> strings; |
| LoadStringTable(*section_name_data, &strings); |
| |
| size_t idx = 0; |
| // We know sections_ is populated from the GetSectionData above |
| for (const auto& section : sections_) { |
| if (section.sh_name < strings.size()) { |
| section_names_[strings[section.sh_name]] = idx; |
| } |
| |
| idx++; |
| } |
| } |
| |
| const auto& iter = section_names_.find(name); |
| |
| if (iter == section_names_.end()) { |
| return nullptr; |
| } |
| |
| return GetSectionData(iter->second); |
| } |
| |
| const std::string* ElfLib::GetString(size_t index) { |
| if (strings_.empty()) { |
| const std::vector<uint8_t>* string_data = GetSectionData(".strtab"); |
| |
| if (!string_data) { |
| return nullptr; |
| } |
| |
| LoadStringTable(*string_data, &strings_); |
| } |
| |
| if (index >= strings_.size()) { |
| return nullptr; |
| } |
| |
| return &strings_[index]; |
| } |
| |
| const Elf64_Sym* ElfLib::GetSymbol(const std::string& name) { |
| if (symbols_.empty()) { |
| const std::vector<uint8_t>* symbol_data = GetSectionData(".symtab"); |
| |
| if (!symbol_data) { |
| return nullptr; |
| } |
| |
| const Elf64_Sym* start = |
| reinterpret_cast<const Elf64_Sym*>(symbol_data->data()); |
| const Elf64_Sym* end = start + (symbol_data->size() / sizeof(Elf64_Sym)); |
| std::copy(start, end, std::back_inserter(symbols_)); |
| } |
| |
| for (const auto& symbol : symbols_) { |
| const std::string* got_name = GetString(symbol.st_name); |
| |
| if (got_name != nullptr && *got_name == name) { |
| return &symbol; |
| } |
| } |
| |
| return nullptr; |
| } |
| |
| bool ElfLib::GetSymbolValue(const std::string& name, uint64_t* out) { |
| const Elf64_Sym* sym = GetSymbol(name); |
| |
| if (sym) { |
| *out = sym->st_value; |
| } |
| |
| return sym != nullptr; |
| } |
| |
| } // namespace elflib |