diff options
Diffstat (limited to 'contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h')
-rw-r--r-- | contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h | 1060 |
1 files changed, 1060 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h new file mode 100644 index 000000000000..f3df93b9662f --- /dev/null +++ b/contrib/llvm-project/llvm/tools/llvm-objcopy/ELF/Object.h @@ -0,0 +1,1060 @@ +//===- Object.h -------------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_OBJCOPY_OBJECT_H +#define LLVM_TOOLS_OBJCOPY_OBJECT_H + +#include "Buffer.h" +#include "CopyConfig.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/Errc.h" +#include "llvm/Support/FileOutputBuffer.h" +#include <cstddef> +#include <cstdint> +#include <functional> +#include <memory> +#include <set> +#include <vector> + +namespace llvm { +enum class DebugCompressionType; +namespace objcopy { +namespace elf { + +class SectionBase; +class Section; +class OwnedDataSection; +class StringTableSection; +class SymbolTableSection; +class RelocationSection; +class DynamicRelocationSection; +class GnuDebugLinkSection; +class GroupSection; +class SectionIndexSection; +class CompressedSection; +class DecompressedSection; +class Segment; +class Object; +struct Symbol; + +class SectionTableRef { + MutableArrayRef<std::unique_ptr<SectionBase>> Sections; + +public: + using iterator = pointee_iterator<std::unique_ptr<SectionBase> *>; + + explicit SectionTableRef(MutableArrayRef<std::unique_ptr<SectionBase>> Secs) + : Sections(Secs) {} + SectionTableRef(const SectionTableRef &) = default; + + iterator begin() { return iterator(Sections.data()); } + iterator end() { return iterator(Sections.data() + Sections.size()); } + size_t size() const { return Sections.size(); } + + SectionBase *getSection(uint32_t Index, Twine ErrMsg); + + template <class T> + T *getSectionOfType(uint32_t Index, Twine IndexErrMsg, Twine TypeErrMsg); +}; + +enum ElfType { ELFT_ELF32LE, ELFT_ELF64LE, ELFT_ELF32BE, ELFT_ELF64BE }; + +class SectionVisitor { +public: + virtual ~SectionVisitor() = default; + + virtual void visit(const Section &Sec) = 0; + virtual void visit(const OwnedDataSection &Sec) = 0; + virtual void visit(const StringTableSection &Sec) = 0; + virtual void visit(const SymbolTableSection &Sec) = 0; + virtual void visit(const RelocationSection &Sec) = 0; + virtual void visit(const DynamicRelocationSection &Sec) = 0; + virtual void visit(const GnuDebugLinkSection &Sec) = 0; + virtual void visit(const GroupSection &Sec) = 0; + virtual void visit(const SectionIndexSection &Sec) = 0; + virtual void visit(const CompressedSection &Sec) = 0; + virtual void visit(const DecompressedSection &Sec) = 0; +}; + +class MutableSectionVisitor { +public: + virtual ~MutableSectionVisitor() = default; + + virtual void visit(Section &Sec) = 0; + virtual void visit(OwnedDataSection &Sec) = 0; + virtual void visit(StringTableSection &Sec) = 0; + virtual void visit(SymbolTableSection &Sec) = 0; + virtual void visit(RelocationSection &Sec) = 0; + virtual void visit(DynamicRelocationSection &Sec) = 0; + virtual void visit(GnuDebugLinkSection &Sec) = 0; + virtual void visit(GroupSection &Sec) = 0; + virtual void visit(SectionIndexSection &Sec) = 0; + virtual void visit(CompressedSection &Sec) = 0; + virtual void visit(DecompressedSection &Sec) = 0; +}; + +class SectionWriter : public SectionVisitor { +protected: + Buffer &Out; + +public: + virtual ~SectionWriter() = default; + + void visit(const Section &Sec) override; + void visit(const OwnedDataSection &Sec) override; + void visit(const StringTableSection &Sec) override; + void visit(const DynamicRelocationSection &Sec) override; + virtual void visit(const SymbolTableSection &Sec) override = 0; + virtual void visit(const RelocationSection &Sec) override = 0; + virtual void visit(const GnuDebugLinkSection &Sec) override = 0; + virtual void visit(const GroupSection &Sec) override = 0; + virtual void visit(const SectionIndexSection &Sec) override = 0; + virtual void visit(const CompressedSection &Sec) override = 0; + virtual void visit(const DecompressedSection &Sec) override = 0; + + explicit SectionWriter(Buffer &Buf) : Out(Buf) {} +}; + +template <class ELFT> class ELFSectionWriter : public SectionWriter { +private: + using Elf_Word = typename ELFT::Word; + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Sym = typename ELFT::Sym; + +public: + virtual ~ELFSectionWriter() {} + void visit(const SymbolTableSection &Sec) override; + void visit(const RelocationSection &Sec) override; + void visit(const GnuDebugLinkSection &Sec) override; + void visit(const GroupSection &Sec) override; + void visit(const SectionIndexSection &Sec) override; + void visit(const CompressedSection &Sec) override; + void visit(const DecompressedSection &Sec) override; + + explicit ELFSectionWriter(Buffer &Buf) : SectionWriter(Buf) {} +}; + +template <class ELFT> class ELFSectionSizer : public MutableSectionVisitor { +private: + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Sym = typename ELFT::Sym; + using Elf_Word = typename ELFT::Word; + using Elf_Xword = typename ELFT::Xword; + +public: + void visit(Section &Sec) override; + void visit(OwnedDataSection &Sec) override; + void visit(StringTableSection &Sec) override; + void visit(DynamicRelocationSection &Sec) override; + void visit(SymbolTableSection &Sec) override; + void visit(RelocationSection &Sec) override; + void visit(GnuDebugLinkSection &Sec) override; + void visit(GroupSection &Sec) override; + void visit(SectionIndexSection &Sec) override; + void visit(CompressedSection &Sec) override; + void visit(DecompressedSection &Sec) override; +}; + +#define MAKE_SEC_WRITER_FRIEND \ + friend class SectionWriter; \ + friend class IHexSectionWriterBase; \ + friend class IHexSectionWriter; \ + template <class ELFT> friend class ELFSectionWriter; \ + template <class ELFT> friend class ELFSectionSizer; + +class BinarySectionWriter : public SectionWriter { +public: + virtual ~BinarySectionWriter() {} + + void visit(const SymbolTableSection &Sec) override; + void visit(const RelocationSection &Sec) override; + void visit(const GnuDebugLinkSection &Sec) override; + void visit(const GroupSection &Sec) override; + void visit(const SectionIndexSection &Sec) override; + void visit(const CompressedSection &Sec) override; + void visit(const DecompressedSection &Sec) override; + + explicit BinarySectionWriter(Buffer &Buf) : SectionWriter(Buf) {} +}; + +using IHexLineData = SmallVector<char, 64>; + +struct IHexRecord { + // Memory address of the record. + uint16_t Addr; + // Record type (see below). + uint16_t Type; + // Record data in hexadecimal form. + StringRef HexData; + + // Helper method to get file length of the record + // including newline character + static size_t getLength(size_t DataSize) { + // :LLAAAATT[DD...DD]CC' + return DataSize * 2 + 11; + } + + // Gets length of line in a file (getLength + CRLF). + static size_t getLineLength(size_t DataSize) { + return getLength(DataSize) + 2; + } + + // Given type, address and data returns line which can + // be written to output file. + static IHexLineData getLine(uint8_t Type, uint16_t Addr, + ArrayRef<uint8_t> Data); + + // Parses the line and returns record if possible. + // Line should be trimmed from whitespace characters. + static Expected<IHexRecord> parse(StringRef Line); + + // Calculates checksum of stringified record representation + // S must NOT contain leading ':' and trailing whitespace + // characters + static uint8_t getChecksum(StringRef S); + + enum Type { + // Contains data and a 16-bit starting address for the data. + // The byte count specifies number of data bytes in the record. + Data = 0, + // Must occur exactly once per file in the last line of the file. + // The data field is empty (thus byte count is 00) and the address + // field is typically 0000. + EndOfFile = 1, + // The data field contains a 16-bit segment base address (thus byte + // count is always 02) compatible with 80x86 real mode addressing. + // The address field (typically 0000) is ignored. The segment address + // from the most recent 02 record is multiplied by 16 and added to each + // subsequent data record address to form the physical starting address + // for the data. This allows addressing up to one megabyte of address + // space. + SegmentAddr = 2, + // or 80x86 processors, specifies the initial content of the CS:IP + // registers. The address field is 0000, the byte count is always 04, + // the first two data bytes are the CS value, the latter two are the + // IP value. + StartAddr80x86 = 3, + // Allows for 32 bit addressing (up to 4GiB). The record's address field + // is ignored (typically 0000) and its byte count is always 02. The two + // data bytes (big endian) specify the upper 16 bits of the 32 bit + // absolute address for all subsequent type 00 records + ExtendedAddr = 4, + // The address field is 0000 (not used) and the byte count is always 04. + // The four data bytes represent a 32-bit address value. In the case of + // 80386 and higher CPUs, this address is loaded into the EIP register. + StartAddr = 5, + // We have no other valid types + InvalidType = 6 + }; +}; + +// Base class for IHexSectionWriter. This class implements writing algorithm, +// but doesn't actually write records. It is used for output buffer size +// calculation in IHexWriter::finalize. +class IHexSectionWriterBase : public BinarySectionWriter { + // 20-bit segment address + uint32_t SegmentAddr = 0; + // Extended linear address + uint32_t BaseAddr = 0; + + // Write segment address corresponding to 'Addr' + uint64_t writeSegmentAddr(uint64_t Addr); + // Write extended linear (base) address corresponding to 'Addr' + uint64_t writeBaseAddr(uint64_t Addr); + +protected: + // Offset in the output buffer + uint64_t Offset = 0; + + void writeSection(const SectionBase *Sec, ArrayRef<uint8_t> Data); + virtual void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data); + +public: + explicit IHexSectionWriterBase(Buffer &Buf) : BinarySectionWriter(Buf) {} + + uint64_t getBufferOffset() const { return Offset; } + void visit(const Section &Sec) final; + void visit(const OwnedDataSection &Sec) final; + void visit(const StringTableSection &Sec) override; + void visit(const DynamicRelocationSection &Sec) final; + using BinarySectionWriter::visit; +}; + +// Real IHEX section writer +class IHexSectionWriter : public IHexSectionWriterBase { +public: + IHexSectionWriter(Buffer &Buf) : IHexSectionWriterBase(Buf) {} + + void writeData(uint8_t Type, uint16_t Addr, ArrayRef<uint8_t> Data) override; + void visit(const StringTableSection &Sec) override; +}; + +class Writer { +protected: + Object &Obj; + Buffer &Buf; + +public: + virtual ~Writer(); + virtual Error finalize() = 0; + virtual Error write() = 0; + + Writer(Object &O, Buffer &B) : Obj(O), Buf(B) {} +}; + +template <class ELFT> class ELFWriter : public Writer { +private: + using Elf_Addr = typename ELFT::Addr; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Phdr = typename ELFT::Phdr; + using Elf_Ehdr = typename ELFT::Ehdr; + + void initEhdrSegment(); + + void writeEhdr(); + void writePhdr(const Segment &Seg); + void writeShdr(const SectionBase &Sec); + + void writePhdrs(); + void writeShdrs(); + void writeSectionData(); + void writeSegmentData(); + + void assignOffsets(); + + std::unique_ptr<ELFSectionWriter<ELFT>> SecWriter; + + size_t totalSize() const; + +public: + virtual ~ELFWriter() {} + bool WriteSectionHeaders; + + Error finalize() override; + Error write() override; + ELFWriter(Object &Obj, Buffer &Buf, bool WSH); +}; + +class BinaryWriter : public Writer { +private: + std::unique_ptr<BinarySectionWriter> SecWriter; + + uint64_t TotalSize; + +public: + ~BinaryWriter() {} + Error finalize() override; + Error write() override; + BinaryWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {} +}; + +class IHexWriter : public Writer { + struct SectionCompare { + bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const; + }; + + std::set<const SectionBase *, SectionCompare> Sections; + size_t TotalSize; + + Error checkSection(const SectionBase &Sec); + uint64_t writeEntryPointRecord(uint8_t *Buf); + uint64_t writeEndOfFileRecord(uint8_t *Buf); + +public: + ~IHexWriter() {} + Error finalize() override; + Error write() override; + IHexWriter(Object &Obj, Buffer &Buf) : Writer(Obj, Buf) {} +}; + +class SectionBase { +public: + std::string Name; + Segment *ParentSegment = nullptr; + uint64_t HeaderOffset; + uint64_t OriginalOffset = std::numeric_limits<uint64_t>::max(); + uint32_t Index; + bool HasSymbol = false; + + uint64_t Addr = 0; + uint64_t Align = 1; + uint32_t EntrySize = 0; + uint64_t Flags = 0; + uint64_t Info = 0; + uint64_t Link = ELF::SHN_UNDEF; + uint64_t NameIndex = 0; + uint64_t Offset = 0; + uint64_t Size = 0; + uint64_t Type = ELF::SHT_NULL; + ArrayRef<uint8_t> OriginalData; + + SectionBase() = default; + SectionBase(const SectionBase &) = default; + + virtual ~SectionBase() = default; + + virtual void initialize(SectionTableRef SecTable); + virtual void finalize(); + // Remove references to these sections. The list of sections must be sorted. + virtual Error + removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove); + virtual Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove); + virtual void accept(SectionVisitor &Visitor) const = 0; + virtual void accept(MutableSectionVisitor &Visitor) = 0; + virtual void markSymbols(); + virtual void + replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &); +}; + +class Segment { +private: + struct SectionCompare { + bool operator()(const SectionBase *Lhs, const SectionBase *Rhs) const { + // Some sections might have the same address if one of them is empty. To + // fix this we can use the lexicographic ordering on ->Addr and the + // address of the actully stored section. + if (Lhs->OriginalOffset == Rhs->OriginalOffset) + return Lhs < Rhs; + return Lhs->OriginalOffset < Rhs->OriginalOffset; + } + }; + + std::set<const SectionBase *, SectionCompare> Sections; + +public: + uint32_t Type; + uint32_t Flags; + uint64_t Offset; + uint64_t VAddr; + uint64_t PAddr; + uint64_t FileSize; + uint64_t MemSize; + uint64_t Align; + + uint32_t Index; + uint64_t OriginalOffset; + Segment *ParentSegment = nullptr; + ArrayRef<uint8_t> Contents; + + explicit Segment(ArrayRef<uint8_t> Data) : Contents(Data) {} + Segment() {} + + const SectionBase *firstSection() const { + if (!Sections.empty()) + return *Sections.begin(); + return nullptr; + } + + void removeSection(const SectionBase *Sec) { Sections.erase(Sec); } + void addSection(const SectionBase *Sec) { Sections.insert(Sec); } + + ArrayRef<uint8_t> getContents() const { return Contents; } +}; + +class Section : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + ArrayRef<uint8_t> Contents; + SectionBase *LinkSection = nullptr; + +public: + explicit Section(ArrayRef<uint8_t> Data) : Contents(Data) {} + + void accept(SectionVisitor &Visitor) const override; + void accept(MutableSectionVisitor &Visitor) override; + Error removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; + void initialize(SectionTableRef SecTable) override; + void finalize() override; +}; + +class OwnedDataSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + std::vector<uint8_t> Data; + +public: + OwnedDataSection(StringRef SecName, ArrayRef<uint8_t> Data) + : Data(std::begin(Data), std::end(Data)) { + Name = SecName.str(); + Type = ELF::SHT_PROGBITS; + Size = Data.size(); + OriginalOffset = std::numeric_limits<uint64_t>::max(); + } + + OwnedDataSection(const Twine &SecName, uint64_t SecAddr, uint64_t SecFlags, + uint64_t SecOff) { + Name = SecName.str(); + Type = ELF::SHT_PROGBITS; + Addr = SecAddr; + Flags = SecFlags; + OriginalOffset = SecOff; + } + + void appendHexData(StringRef HexData); + void accept(SectionVisitor &Sec) const override; + void accept(MutableSectionVisitor &Visitor) override; +}; + +class CompressedSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + DebugCompressionType CompressionType; + uint64_t DecompressedSize; + uint64_t DecompressedAlign; + SmallVector<char, 128> CompressedData; + +public: + CompressedSection(const SectionBase &Sec, + DebugCompressionType CompressionType); + CompressedSection(ArrayRef<uint8_t> CompressedData, uint64_t DecompressedSize, + uint64_t DecompressedAlign); + + uint64_t getDecompressedSize() const { return DecompressedSize; } + uint64_t getDecompressedAlign() const { return DecompressedAlign; } + + void accept(SectionVisitor &Visitor) const override; + void accept(MutableSectionVisitor &Visitor) override; + + static bool classof(const SectionBase *S) { + return (S->Flags & ELF::SHF_COMPRESSED) || + (StringRef(S->Name).startswith(".zdebug")); + } +}; + +class DecompressedSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + +public: + explicit DecompressedSection(const CompressedSection &Sec) + : SectionBase(Sec) { + Size = Sec.getDecompressedSize(); + Align = Sec.getDecompressedAlign(); + Flags = (Flags & ~ELF::SHF_COMPRESSED); + if (StringRef(Name).startswith(".zdebug")) + Name = "." + Name.substr(2); + } + + void accept(SectionVisitor &Visitor) const override; + void accept(MutableSectionVisitor &Visitor) override; +}; + +// There are two types of string tables that can exist, dynamic and not dynamic. +// In the dynamic case the string table is allocated. Changing a dynamic string +// table would mean altering virtual addresses and thus the memory image. So +// dynamic string tables should not have an interface to modify them or +// reconstruct them. This type lets us reconstruct a string table. To avoid +// this class being used for dynamic string tables (which has happened) the +// classof method checks that the particular instance is not allocated. This +// then agrees with the makeSection method used to construct most sections. +class StringTableSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + StringTableBuilder StrTabBuilder; + +public: + StringTableSection() : StrTabBuilder(StringTableBuilder::ELF) { + Type = ELF::SHT_STRTAB; + } + + void addString(StringRef Name); + uint32_t findIndex(StringRef Name) const; + void prepareForLayout(); + void accept(SectionVisitor &Visitor) const override; + void accept(MutableSectionVisitor &Visitor) override; + + static bool classof(const SectionBase *S) { + if (S->Flags & ELF::SHF_ALLOC) + return false; + return S->Type == ELF::SHT_STRTAB; + } +}; + +// Symbols have a st_shndx field that normally stores an index but occasionally +// stores a different special value. This enum keeps track of what the st_shndx +// field means. Most of the values are just copies of the special SHN_* values. +// SYMBOL_SIMPLE_INDEX means that the st_shndx is just an index of a section. +enum SymbolShndxType { + SYMBOL_SIMPLE_INDEX = 0, + SYMBOL_ABS = ELF::SHN_ABS, + SYMBOL_COMMON = ELF::SHN_COMMON, + SYMBOL_LOPROC = ELF::SHN_LOPROC, + SYMBOL_AMDGPU_LDS = ELF::SHN_AMDGPU_LDS, + SYMBOL_HEXAGON_SCOMMON = ELF::SHN_HEXAGON_SCOMMON, + SYMBOL_HEXAGON_SCOMMON_2 = ELF::SHN_HEXAGON_SCOMMON_2, + SYMBOL_HEXAGON_SCOMMON_4 = ELF::SHN_HEXAGON_SCOMMON_4, + SYMBOL_HEXAGON_SCOMMON_8 = ELF::SHN_HEXAGON_SCOMMON_8, + SYMBOL_HIPROC = ELF::SHN_HIPROC, + SYMBOL_LOOS = ELF::SHN_LOOS, + SYMBOL_HIOS = ELF::SHN_HIOS, + SYMBOL_XINDEX = ELF::SHN_XINDEX, +}; + +struct Symbol { + uint8_t Binding; + SectionBase *DefinedIn = nullptr; + SymbolShndxType ShndxType; + uint32_t Index; + std::string Name; + uint32_t NameIndex; + uint64_t Size; + uint8_t Type; + uint64_t Value; + uint8_t Visibility; + bool Referenced = false; + + uint16_t getShndx() const; + bool isCommon() const; +}; + +class SectionIndexSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + +private: + std::vector<uint32_t> Indexes; + SymbolTableSection *Symbols = nullptr; + +public: + virtual ~SectionIndexSection() {} + void addIndex(uint32_t Index) { + assert(Size > 0); + Indexes.push_back(Index); + } + + void reserve(size_t NumSymbols) { + Indexes.reserve(NumSymbols); + Size = NumSymbols * 4; + } + void setSymTab(SymbolTableSection *SymTab) { Symbols = SymTab; } + void initialize(SectionTableRef SecTable) override; + void finalize() override; + void accept(SectionVisitor &Visitor) const override; + void accept(MutableSectionVisitor &Visitor) override; + + SectionIndexSection() { + Name = ".symtab_shndx"; + Align = 4; + EntrySize = 4; + Type = ELF::SHT_SYMTAB_SHNDX; + } +}; + +class SymbolTableSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + + void setStrTab(StringTableSection *StrTab) { SymbolNames = StrTab; } + void assignIndices(); + +protected: + std::vector<std::unique_ptr<Symbol>> Symbols; + StringTableSection *SymbolNames = nullptr; + SectionIndexSection *SectionIndexTable = nullptr; + + using SymPtr = std::unique_ptr<Symbol>; + +public: + SymbolTableSection() { Type = ELF::SHT_SYMTAB; } + + void addSymbol(Twine Name, uint8_t Bind, uint8_t Type, SectionBase *DefinedIn, + uint64_t Value, uint8_t Visibility, uint16_t Shndx, + uint64_t SymbolSize); + void prepareForLayout(); + // An 'empty' symbol table still contains a null symbol. + bool empty() const { return Symbols.size() == 1; } + void setShndxTable(SectionIndexSection *ShndxTable) { + SectionIndexTable = ShndxTable; + } + const SectionIndexSection *getShndxTable() const { return SectionIndexTable; } + void fillShndxTable(); + const SectionBase *getStrTab() const { return SymbolNames; } + const Symbol *getSymbolByIndex(uint32_t Index) const; + Symbol *getSymbolByIndex(uint32_t Index); + void updateSymbols(function_ref<void(Symbol &)> Callable); + + Error removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; + void initialize(SectionTableRef SecTable) override; + void finalize() override; + void accept(SectionVisitor &Visitor) const override; + void accept(MutableSectionVisitor &Visitor) override; + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; + + static bool classof(const SectionBase *S) { + return S->Type == ELF::SHT_SYMTAB; + } +}; + +struct Relocation { + Symbol *RelocSymbol = nullptr; + uint64_t Offset; + uint64_t Addend; + uint32_t Type; +}; + +// All relocation sections denote relocations to apply to another section. +// However, some relocation sections use a dynamic symbol table and others use +// a regular symbol table. Because the types of the two symbol tables differ in +// our system (because they should behave differently) we can't uniformly +// represent all relocations with the same base class if we expose an interface +// that mentions the symbol table type. So we split the two base types into two +// different classes, one which handles the section the relocation is applied to +// and another which handles the symbol table type. The symbol table type is +// taken as a type parameter to the class (see RelocSectionWithSymtabBase). +class RelocationSectionBase : public SectionBase { +protected: + SectionBase *SecToApplyRel = nullptr; + +public: + const SectionBase *getSection() const { return SecToApplyRel; } + void setSection(SectionBase *Sec) { SecToApplyRel = Sec; } + + static bool classof(const SectionBase *S) { + return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; + } +}; + +// Takes the symbol table type to use as a parameter so that we can deduplicate +// that code between the two symbol table types. +template <class SymTabType> +class RelocSectionWithSymtabBase : public RelocationSectionBase { + void setSymTab(SymTabType *SymTab) { Symbols = SymTab; } + +protected: + RelocSectionWithSymtabBase() = default; + + SymTabType *Symbols = nullptr; + +public: + void initialize(SectionTableRef SecTable) override; + void finalize() override; +}; + +class RelocationSection + : public RelocSectionWithSymtabBase<SymbolTableSection> { + MAKE_SEC_WRITER_FRIEND + + std::vector<Relocation> Relocations; + +public: + void addRelocation(Relocation Rel) { Relocations.push_back(Rel); } + void accept(SectionVisitor &Visitor) const override; + void accept(MutableSectionVisitor &Visitor) override; + Error removeSectionReferences(bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + void markSymbols() override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; + + static bool classof(const SectionBase *S) { + if (S->Flags & ELF::SHF_ALLOC) + return false; + return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; + } +}; + +// TODO: The way stripping and groups interact is complicated +// and still needs to be worked on. + +class GroupSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + const SymbolTableSection *SymTab = nullptr; + Symbol *Sym = nullptr; + ELF::Elf32_Word FlagWord; + SmallVector<SectionBase *, 3> GroupMembers; + +public: + // TODO: Contents is present in several classes of the hierarchy. + // This needs to be refactored to avoid duplication. + ArrayRef<uint8_t> Contents; + + explicit GroupSection(ArrayRef<uint8_t> Data) : Contents(Data) {} + + void setSymTab(const SymbolTableSection *SymTabSec) { SymTab = SymTabSec; } + void setSymbol(Symbol *S) { Sym = S; } + void setFlagWord(ELF::Elf32_Word W) { FlagWord = W; } + void addMember(SectionBase *Sec) { GroupMembers.push_back(Sec); } + + void accept(SectionVisitor &) const override; + void accept(MutableSectionVisitor &Visitor) override; + void finalize() override; + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove) override; + void markSymbols() override; + void replaceSectionReferences( + const DenseMap<SectionBase *, SectionBase *> &FromTo) override; + + static bool classof(const SectionBase *S) { + return S->Type == ELF::SHT_GROUP; + } +}; + +class DynamicSymbolTableSection : public Section { +public: + explicit DynamicSymbolTableSection(ArrayRef<uint8_t> Data) : Section(Data) {} + + static bool classof(const SectionBase *S) { + return S->Type == ELF::SHT_DYNSYM; + } +}; + +class DynamicSection : public Section { +public: + explicit DynamicSection(ArrayRef<uint8_t> Data) : Section(Data) {} + + static bool classof(const SectionBase *S) { + return S->Type == ELF::SHT_DYNAMIC; + } +}; + +class DynamicRelocationSection + : public RelocSectionWithSymtabBase<DynamicSymbolTableSection> { + MAKE_SEC_WRITER_FRIEND + +private: + ArrayRef<uint8_t> Contents; + +public: + explicit DynamicRelocationSection(ArrayRef<uint8_t> Data) : Contents(Data) {} + + void accept(SectionVisitor &) const override; + void accept(MutableSectionVisitor &Visitor) override; + Error removeSectionReferences( + bool AllowBrokenLinks, + function_ref<bool(const SectionBase *)> ToRemove) override; + + static bool classof(const SectionBase *S) { + if (!(S->Flags & ELF::SHF_ALLOC)) + return false; + return S->Type == ELF::SHT_REL || S->Type == ELF::SHT_RELA; + } +}; + +class GnuDebugLinkSection : public SectionBase { + MAKE_SEC_WRITER_FRIEND + +private: + StringRef FileName; + uint32_t CRC32; + + void init(StringRef File); + +public: + // If we add this section from an external source we can use this ctor. + explicit GnuDebugLinkSection(StringRef File, uint32_t PrecomputedCRC); + void accept(SectionVisitor &Visitor) const override; + void accept(MutableSectionVisitor &Visitor) override; +}; + +class Reader { +public: + virtual ~Reader(); + virtual std::unique_ptr<Object> create() const = 0; +}; + +using object::Binary; +using object::ELFFile; +using object::ELFObjectFile; +using object::OwningBinary; + +class BasicELFBuilder { +protected: + uint16_t EMachine; + std::unique_ptr<Object> Obj; + + void initFileHeader(); + void initHeaderSegment(); + StringTableSection *addStrTab(); + SymbolTableSection *addSymTab(StringTableSection *StrTab); + void initSections(); + +public: + BasicELFBuilder(uint16_t EM) + : EMachine(EM), Obj(llvm::make_unique<Object>()) {} +}; + +class BinaryELFBuilder : public BasicELFBuilder { + MemoryBuffer *MemBuf; + void addData(SymbolTableSection *SymTab); + +public: + BinaryELFBuilder(uint16_t EM, MemoryBuffer *MB) + : BasicELFBuilder(EM), MemBuf(MB) {} + + std::unique_ptr<Object> build(); +}; + +class IHexELFBuilder : public BasicELFBuilder { + const std::vector<IHexRecord> &Records; + + void addDataSections(); + +public: + IHexELFBuilder(const std::vector<IHexRecord> &Records) + : BasicELFBuilder(ELF::EM_386), Records(Records) {} + + std::unique_ptr<Object> build(); +}; + +template <class ELFT> class ELFBuilder { +private: + using Elf_Addr = typename ELFT::Addr; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Word = typename ELFT::Word; + + const ELFFile<ELFT> &ElfFile; + Object &Obj; + size_t EhdrOffset = 0; + Optional<StringRef> ExtractPartition; + + void setParentSegment(Segment &Child); + void readProgramHeaders(const ELFFile<ELFT> &HeadersFile); + void initGroupSection(GroupSection *GroupSec); + void initSymbolTable(SymbolTableSection *SymTab); + void readSectionHeaders(); + void readSections(); + void findEhdrOffset(); + SectionBase &makeSection(const Elf_Shdr &Shdr); + +public: + ELFBuilder(const ELFObjectFile<ELFT> &ElfObj, Object &Obj, + Optional<StringRef> ExtractPartition) + : ElfFile(*ElfObj.getELFFile()), Obj(Obj), + ExtractPartition(ExtractPartition) {} + + void build(); +}; + +class BinaryReader : public Reader { + const MachineInfo &MInfo; + MemoryBuffer *MemBuf; + +public: + BinaryReader(const MachineInfo &MI, MemoryBuffer *MB) + : MInfo(MI), MemBuf(MB) {} + std::unique_ptr<Object> create() const override; +}; + +class IHexReader : public Reader { + MemoryBuffer *MemBuf; + + Expected<std::vector<IHexRecord>> parse() const; + Error parseError(size_t LineNo, Error E) const { + return LineNo == -1U + ? createFileError(MemBuf->getBufferIdentifier(), std::move(E)) + : createFileError(MemBuf->getBufferIdentifier(), LineNo, + std::move(E)); + } + template <typename... Ts> + Error parseError(size_t LineNo, char const *Fmt, const Ts &... Vals) const { + Error E = createStringError(errc::invalid_argument, Fmt, Vals...); + return parseError(LineNo, std::move(E)); + } + +public: + IHexReader(MemoryBuffer *MB) : MemBuf(MB) {} + + std::unique_ptr<Object> create() const override; +}; + +class ELFReader : public Reader { + Binary *Bin; + Optional<StringRef> ExtractPartition; + +public: + std::unique_ptr<Object> create() const override; + explicit ELFReader(Binary *B, Optional<StringRef> ExtractPartition) + : Bin(B), ExtractPartition(ExtractPartition) {} +}; + +class Object { +private: + using SecPtr = std::unique_ptr<SectionBase>; + using SegPtr = std::unique_ptr<Segment>; + + std::vector<SecPtr> Sections; + std::vector<SegPtr> Segments; + std::vector<SecPtr> RemovedSections; + +public: + template <class T> + using Range = iterator_range< + pointee_iterator<typename std::vector<std::unique_ptr<T>>::iterator>>; + + template <class T> + using ConstRange = iterator_range<pointee_iterator< + typename std::vector<std::unique_ptr<T>>::const_iterator>>; + + // It is often the case that the ELF header and the program header table are + // not present in any segment. This could be a problem during file layout, + // because other segments may get assigned an offset where either of the + // two should reside, which will effectively corrupt the resulting binary. + // Other than that we use these segments to track program header offsets + // when they may not follow the ELF header. + Segment ElfHdrSegment; + Segment ProgramHdrSegment; + + uint8_t OSABI; + uint8_t ABIVersion; + uint64_t Entry; + uint64_t SHOffset; + uint32_t Type; + uint32_t Machine; + uint32_t Version; + uint32_t Flags; + + bool HadShdrs = true; + StringTableSection *SectionNames = nullptr; + SymbolTableSection *SymbolTable = nullptr; + SectionIndexSection *SectionIndexTable = nullptr; + + void sortSections(); + SectionTableRef sections() { return SectionTableRef(Sections); } + ConstRange<SectionBase> sections() const { + return make_pointee_range(Sections); + } + SectionBase *findSection(StringRef Name) { + auto SecIt = + find_if(Sections, [&](const SecPtr &Sec) { return Sec->Name == Name; }); + return SecIt == Sections.end() ? nullptr : SecIt->get(); + } + SectionTableRef removedSections() { return SectionTableRef(RemovedSections); } + + Range<Segment> segments() { return make_pointee_range(Segments); } + ConstRange<Segment> segments() const { return make_pointee_range(Segments); } + + Error removeSections(bool AllowBrokenLinks, + std::function<bool(const SectionBase &)> ToRemove); + Error removeSymbols(function_ref<bool(const Symbol &)> ToRemove); + template <class T, class... Ts> T &addSection(Ts &&... Args) { + auto Sec = llvm::make_unique<T>(std::forward<Ts>(Args)...); + auto Ptr = Sec.get(); + Sections.emplace_back(std::move(Sec)); + Ptr->Index = Sections.size(); + return *Ptr; + } + Segment &addSegment(ArrayRef<uint8_t> Data) { + Segments.emplace_back(llvm::make_unique<Segment>(Data)); + return *Segments.back(); + } +}; + +} // end namespace elf +} // end namespace objcopy +} // end namespace llvm + +#endif // LLVM_TOOLS_OBJCOPY_OBJECT_H |