123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- // Copyright 2018 The Chromium 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 COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_
- #define COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_
- #include <stdint.h>
- #include <algorithm>
- #include <deque>
- #include <memory>
- #include <string>
- #include <vector>
- #include "base/memory/raw_ptr.h"
- #include "components/zucchini/address_translator.h"
- #include "components/zucchini/buffer_view.h"
- #include "components/zucchini/disassembler.h"
- #include "components/zucchini/image_utils.h"
- #include "components/zucchini/rel32_finder.h"
- #include "components/zucchini/rel32_utils.h"
- #include "components/zucchini/reloc_elf.h"
- #include "components/zucchini/type_elf.h"
- namespace zucchini {
- struct ArmReferencePool {
- enum : uint8_t {
- kPoolReloc,
- kPoolAbs32,
- kPoolRel32,
- };
- };
- struct AArch32ReferenceType {
- enum : uint8_t {
- kReloc, // kPoolReloc
- kAbs32, // kPoolAbs32
- kRel32_A24, // kPoolRel32
- kRel32_T8,
- kRel32_T11,
- kRel32_T20,
- kRel32_T24,
- kTypeCount
- };
- };
- struct AArch64ReferenceType {
- enum : uint8_t {
- kReloc, // kPoolReloc
- kAbs32, // kPoolAbs32
- kRel32_Immd14, // kPoolRel32
- kRel32_Immd19,
- kRel32_Immd26,
- kTypeCount
- };
- };
- struct Elf32Traits {
- static constexpr uint16_t kVersion = 1;
- static constexpr Bitness kBitness = kBit32;
- static constexpr elf::FileClass kIdentificationClass = elf::ELFCLASS32;
- using Elf_Shdr = elf::Elf32_Shdr;
- using Elf_Phdr = elf::Elf32_Phdr;
- using Elf_Ehdr = elf::Elf32_Ehdr;
- using Elf_Rel = elf::Elf32_Rel;
- using Elf_Rela = elf::Elf32_Rela;
- };
- // Architecture-specific definitions.
- struct Elf32IntelTraits : public Elf32Traits {
- static constexpr ExecutableType kExeType = kExeTypeElfX86;
- static const char kExeTypeString[];
- static constexpr elf::MachineArchitecture kMachineValue = elf::EM_386;
- static constexpr uint32_t kRelType = elf::R_386_RELATIVE;
- enum : uint32_t { kVAWidth = 4 };
- using Rel32FinderUse = Rel32FinderX86;
- };
- struct ElfAArch32Traits : public Elf32Traits {
- static constexpr ExecutableType kExeType = kExeTypeElfAArch32;
- static const char kExeTypeString[];
- static constexpr elf::MachineArchitecture kMachineValue = elf::EM_ARM;
- static constexpr uint32_t kRelType = elf::R_ARM_RELATIVE;
- enum : uint32_t { kVAWidth = 4 };
- using ArmReferenceType = AArch32ReferenceType;
- using Rel32FinderUse = Rel32FinderAArch32;
- };
- struct Elf64Traits {
- static constexpr uint16_t kVersion = 1;
- static constexpr Bitness kBitness = kBit64;
- static constexpr elf::FileClass kIdentificationClass = elf::ELFCLASS64;
- using Elf_Shdr = elf::Elf64_Shdr;
- using Elf_Phdr = elf::Elf64_Phdr;
- using Elf_Ehdr = elf::Elf64_Ehdr;
- using Elf_Rel = elf::Elf64_Rel;
- using Elf_Rela = elf::Elf64_Rela;
- };
- // Architecture-specific definitions.
- struct Elf64IntelTraits : public Elf64Traits {
- static constexpr ExecutableType kExeType = kExeTypeElfX64;
- static const char kExeTypeString[];
- static constexpr elf::MachineArchitecture kMachineValue = elf::EM_X86_64;
- static constexpr uint32_t kRelType = elf::R_X86_64_RELATIVE;
- enum : uint32_t { kVAWidth = 8 };
- using Rel32FinderUse = Rel32FinderX64;
- };
- struct ElfAArch64Traits : public Elf64Traits {
- static constexpr ExecutableType kExeType = kExeTypeElfAArch64;
- static const char kExeTypeString[];
- static constexpr elf::MachineArchitecture kMachineValue = elf::EM_AARCH64;
- // TODO(huangs): See if R_AARCH64_GLOB_DAT and R_AARCH64_JUMP_SLOT should be
- // used.
- static constexpr uint32_t kRelType = elf::R_AARCH64_RELATIVE;
- enum : uint32_t { kVAWidth = 8 };
- using ArmReferenceType = AArch64ReferenceType;
- using Rel32FinderUse = Rel32FinderAArch64;
- };
- // Decides whether target |offset| is covered by a section in |sorted_headers|.
- template <class ELF_SHDR>
- bool IsTargetOffsetInElfSectionList(
- const std::vector<const ELF_SHDR*>& sorted_headers,
- offset_t offset) {
- // Use binary search to search in a list of intervals, in a fashion similar to
- // AddressTranslator::OffsetToUnit().
- auto comp = [](offset_t offset, const ELF_SHDR* header) -> bool {
- return offset < header->sh_offset;
- };
- auto it = std::upper_bound(sorted_headers.begin(), sorted_headers.end(),
- offset, comp);
- if (it == sorted_headers.begin())
- return false;
- --it;
- // Just check offset without worrying about width, since this is a target.
- // Not using RangeCovers() because |sh_offset| and |sh_size| can be 64-bit.
- return offset >= (*it)->sh_offset &&
- offset - (*it)->sh_offset < (*it)->sh_size;
- }
- // Disassembler for ELF.
- template <class TRAITS>
- class DisassemblerElf : public Disassembler {
- public:
- using Traits = TRAITS;
- static constexpr uint16_t kVersion = Traits::kVersion;
- // Applies quick checks to determine whether |image| *may* point to the start
- // of an executable. Returns true iff the check passes.
- static bool QuickDetect(ConstBufferView image);
- DisassemblerElf(const DisassemblerElf&) = delete;
- const DisassemblerElf& operator=(const DisassemblerElf&) = delete;
- ~DisassemblerElf() override;
- // Disassembler:
- ExecutableType GetExeType() const override;
- std::string GetExeTypeString() const override;
- std::vector<ReferenceGroup> MakeReferenceGroups() const override = 0;
- // Read/Write functions that are common among different architectures.
- std::unique_ptr<ReferenceReader> MakeReadRelocs(offset_t lo, offset_t hi);
- std::unique_ptr<ReferenceWriter> MakeWriteRelocs(MutableBufferView image);
- const AddressTranslator& translator() const { return translator_; }
- protected:
- friend Disassembler;
- DisassemblerElf();
- bool Parse(ConstBufferView image) override;
- // Returns the supported Elf_Ehdr::e_machine enum.
- static constexpr elf::MachineArchitecture supported_architecture() {
- return Traits::kMachineValue;
- }
- // Returns the type to look for in the reloc section.
- static constexpr uint32_t supported_relocation_type() {
- return Traits::kRelType;
- }
- // Performs architecture-specific parsing of an executable section, to extract
- // rel32 references.
- virtual void ParseExecSection(const typename Traits::Elf_Shdr& section) = 0;
- // Processes rel32 data after they are extracted from executable sections.
- virtual void PostProcessRel32() = 0;
- // Parses ELF header and section headers, and performs basic validation.
- // Returns whether parsing was successful.
- bool ParseHeader();
- // Extracts and stores section headers that we need.
- void ExtractInterestingSectionHeaders();
- // Parsing functions that extract references from various sections.
- void GetAbs32FromRelocSections();
- void GetRel32FromCodeSections();
- void ParseSections();
- // Main ELF header.
- raw_ptr<const typename Traits::Elf_Ehdr> header_ = nullptr;
- // Section header table, ordered by section id.
- elf::Elf32_Half sections_count_ = 0;
- raw_ptr<const typename Traits::Elf_Shdr> sections_ = nullptr;
- // Program header table.
- elf::Elf32_Half segments_count_ = 0;
- raw_ptr<const typename Traits::Elf_Phdr> segments_ = nullptr;
- // Bit fields to store the role each section may play.
- std::vector<int> section_judgements_;
- // Translator between offsets and RVAs.
- AddressTranslator translator_;
- // Identity translator for abs32 translation.
- AddressTranslator identity_translator_;
- // Extracted relocation section dimensions data, sorted by file offsets.
- std::vector<SectionDimensionsElf> reloc_section_dims_;
- // Headers of executable sections, sorted by file offsets of the data each
- // header points to.
- std::vector<const typename Traits::Elf_Shdr*> exec_headers_;
- // Sorted file offsets of abs32 locations.
- std::deque<offset_t> abs32_locations_;
- };
- // Disassembler for ELF with Intel architectures.
- template <class TRAITS>
- class DisassemblerElfIntel : public DisassemblerElf<TRAITS> {
- public:
- using Traits = TRAITS;
- enum ReferenceType : uint8_t { kReloc, kAbs32, kRel32, kTypeCount };
- DisassemblerElfIntel();
- DisassemblerElfIntel(const DisassemblerElfIntel&) = delete;
- const DisassemblerElfIntel& operator=(const DisassemblerElfIntel&) = delete;
- ~DisassemblerElfIntel() override;
- // Disassembler:
- std::vector<ReferenceGroup> MakeReferenceGroups() const override;
- // DisassemblerElf:
- void ParseExecSection(const typename Traits::Elf_Shdr& section) override;
- void PostProcessRel32() override;
- // Specialized Read/Write functions.
- std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
- std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
- std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lo, offset_t hi);
- std::unique_ptr<ReferenceWriter> MakeWriteRel32(MutableBufferView image);
- private:
- // Sorted file offsets of rel32 locations.
- // Using std::deque to reduce peak memory footprint.
- std::deque<offset_t> rel32_locations_;
- };
- using DisassemblerElfX86 = DisassemblerElfIntel<Elf32IntelTraits>;
- using DisassemblerElfX64 = DisassemblerElfIntel<Elf64IntelTraits>;
- // Disassembler for ELF with ARM architectures.
- template <class TRAITS>
- class DisassemblerElfArm : public DisassemblerElf<TRAITS> {
- public:
- using Traits = TRAITS;
- DisassemblerElfArm();
- DisassemblerElfArm(const DisassemblerElfArm&) = delete;
- const DisassemblerElfArm& operator=(const DisassemblerElfArm&) = delete;
- ~DisassemblerElfArm() override;
- // Determines whether target |offset| is in an executable section.
- bool IsTargetOffsetInExecSection(offset_t offset) const;
- // Creates an architecture-specific Rel32Finder for ParseExecSection.
- virtual std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
- const typename Traits::Elf_Shdr& section) = 0;
- // DisassemblerElf:
- void ParseExecSection(const typename Traits::Elf_Shdr& section) override;
- void PostProcessRel32() override;
- // Specialized Read/Write functions.
- std::unique_ptr<ReferenceReader> MakeReadAbs32(offset_t lo, offset_t hi);
- std::unique_ptr<ReferenceWriter> MakeWriteAbs32(MutableBufferView image);
- // Specialized Read/Write/Mix functions for different rel32 address types.
- template <class ADDR_TRAITS>
- std::unique_ptr<ReferenceReader> MakeReadRel32(offset_t lower,
- offset_t upper);
- template <class ADDR_TRAITS>
- std::unique_ptr<ReferenceWriter> MakeWriteRel32(MutableBufferView image);
- template <class ADDR_TRAITS>
- std::unique_ptr<ReferenceMixer> MakeMixRel32(ConstBufferView old_image,
- ConstBufferView new_image);
- protected:
- // Sorted file offsets of rel32 locations for each rel32 address type.
- std::deque<offset_t>
- rel32_locations_table_[Traits::ArmReferenceType::kTypeCount];
- };
- // Disassembler for ELF with AArch32 (AKA ARM32).
- class DisassemblerElfAArch32 : public DisassemblerElfArm<ElfAArch32Traits> {
- public:
- DisassemblerElfAArch32();
- DisassemblerElfAArch32(const DisassemblerElfAArch32&) = delete;
- const DisassemblerElfAArch32& operator=(const DisassemblerElfAArch32&) =
- delete;
- ~DisassemblerElfAArch32() override;
- // Disassembler:
- std::vector<ReferenceGroup> MakeReferenceGroups() const override;
- // DisassemblerElfArm:
- std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
- const typename Traits::Elf_Shdr& section) override;
- // Under the naive assumption that an executable section is entirely ARM mode
- // or THUMB2 mode, this function implements heuristics to distinguish between
- // the two. Returns true if section is THUMB2 mode; otherwise return false.
- bool IsExecSectionThumb2(const typename Traits::Elf_Shdr& section) const;
- };
- // Disassembler for ELF with AArch64 (AKA ARM64).
- class DisassemblerElfAArch64 : public DisassemblerElfArm<ElfAArch64Traits> {
- public:
- DisassemblerElfAArch64();
- DisassemblerElfAArch64(const DisassemblerElfAArch64&) = delete;
- const DisassemblerElfAArch64& operator=(const DisassemblerElfAArch64&) =
- delete;
- ~DisassemblerElfAArch64() override;
- // Disassembler:
- std::vector<ReferenceGroup> MakeReferenceGroups() const override;
- // DisassemblerElfArm:
- std::unique_ptr<typename Traits::Rel32FinderUse> MakeRel32Finder(
- const typename Traits::Elf_Shdr& section) override;
- };
- } // namespace zucchini
- #endif // COMPONENTS_ZUCCHINI_DISASSEMBLER_ELF_H_
|