Path: blob/main/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp
35232 views
//===- COFFObjectFile.cpp - COFF object file implementation ---------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file declares the COFFObjectFile class.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ADT/ArrayRef.h"13#include "llvm/ADT/StringRef.h"14#include "llvm/ADT/StringSwitch.h"15#include "llvm/ADT/iterator_range.h"16#include "llvm/Object/Binary.h"17#include "llvm/Object/COFF.h"18#include "llvm/Object/Error.h"19#include "llvm/Object/ObjectFile.h"20#include "llvm/Object/WindowsMachineFlag.h"21#include "llvm/Support/BinaryStreamReader.h"22#include "llvm/Support/Endian.h"23#include "llvm/Support/Error.h"24#include "llvm/Support/ErrorHandling.h"25#include "llvm/Support/MathExtras.h"26#include "llvm/Support/MemoryBufferRef.h"27#include <algorithm>28#include <cassert>29#include <cinttypes>30#include <cstddef>31#include <cstring>32#include <limits>33#include <memory>34#include <system_error>3536using namespace llvm;37using namespace object;3839using support::ulittle16_t;40using support::ulittle32_t;41using support::ulittle64_t;42using support::little16_t;4344// Returns false if size is greater than the buffer size. And sets ec.45static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) {46if (M.getBufferSize() < Size) {47EC = object_error::unexpected_eof;48return false;49}50return true;51}5253// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.54// Returns unexpected_eof if error.55template <typename T>56static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr,57const uint64_t Size = sizeof(T)) {58uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);59if (Error E = Binary::checkOffset(M, Addr, Size))60return E;61Obj = reinterpret_cast<const T *>(Addr);62return Error::success();63}6465// Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without66// prefixed slashes.67static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {68assert(Str.size() <= 6 && "String too long, possible overflow.");69if (Str.size() > 6)70return true;7172uint64_t Value = 0;73while (!Str.empty()) {74unsigned CharVal;75if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..2576CharVal = Str[0] - 'A';77else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..5178CharVal = Str[0] - 'a' + 26;79else if (Str[0] >= '0' && Str[0] <= '9') // 52..6180CharVal = Str[0] - '0' + 52;81else if (Str[0] == '+') // 6282CharVal = 62;83else if (Str[0] == '/') // 6384CharVal = 63;85else86return true;8788Value = (Value * 64) + CharVal;89Str = Str.substr(1);90}9192if (Value > std::numeric_limits<uint32_t>::max())93return true;9495Result = static_cast<uint32_t>(Value);96return false;97}9899template <typename coff_symbol_type>100const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {101const coff_symbol_type *Addr =102reinterpret_cast<const coff_symbol_type *>(Ref.p);103104assert(!checkOffset(Data, reinterpret_cast<uintptr_t>(Addr), sizeof(*Addr)));105#ifndef NDEBUG106// Verify that the symbol points to a valid entry in the symbol table.107uintptr_t Offset =108reinterpret_cast<uintptr_t>(Addr) - reinterpret_cast<uintptr_t>(base());109110assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&111"Symbol did not point to the beginning of a symbol");112#endif113114return Addr;115}116117const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {118const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p);119120#ifndef NDEBUG121// Verify that the section points to a valid entry in the section table.122if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))123report_fatal_error("Section was outside of section table.");124125uintptr_t Offset = reinterpret_cast<uintptr_t>(Addr) -126reinterpret_cast<uintptr_t>(SectionTable);127assert(Offset % sizeof(coff_section) == 0 &&128"Section did not point to the beginning of a section");129#endif130131return Addr;132}133134void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {135auto End = reinterpret_cast<uintptr_t>(StringTable);136if (SymbolTable16) {137const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);138Symb += 1 + Symb->NumberOfAuxSymbols;139Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);140} else if (SymbolTable32) {141const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);142Symb += 1 + Symb->NumberOfAuxSymbols;143Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);144} else {145llvm_unreachable("no symbol table pointer!");146}147}148149Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {150return getSymbolName(getCOFFSymbol(Ref));151}152153uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {154return getCOFFSymbol(Ref).getValue();155}156157uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const {158// MSVC/link.exe seems to align symbols to the next-power-of-2159// up to 32 bytes.160COFFSymbolRef Symb = getCOFFSymbol(Ref);161return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));162}163164Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {165uint64_t Result = cantFail(getSymbolValue(Ref));166COFFSymbolRef Symb = getCOFFSymbol(Ref);167int32_t SectionNumber = Symb.getSectionNumber();168169if (Symb.isAnyUndefined() || Symb.isCommon() ||170COFF::isReservedSectionNumber(SectionNumber))171return Result;172173Expected<const coff_section *> Section = getSection(SectionNumber);174if (!Section)175return Section.takeError();176Result += (*Section)->VirtualAddress;177178// The section VirtualAddress does not include ImageBase, and we want to179// return virtual addresses.180Result += getImageBase();181182return Result;183}184185Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {186COFFSymbolRef Symb = getCOFFSymbol(Ref);187int32_t SectionNumber = Symb.getSectionNumber();188189if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)190return SymbolRef::ST_Function;191if (Symb.isAnyUndefined())192return SymbolRef::ST_Unknown;193if (Symb.isCommon())194return SymbolRef::ST_Data;195if (Symb.isFileRecord())196return SymbolRef::ST_File;197198// TODO: perhaps we need a new symbol type ST_Section.199if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())200return SymbolRef::ST_Debug;201202if (!COFF::isReservedSectionNumber(SectionNumber))203return SymbolRef::ST_Data;204205return SymbolRef::ST_Other;206}207208Expected<uint32_t> COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {209COFFSymbolRef Symb = getCOFFSymbol(Ref);210uint32_t Result = SymbolRef::SF_None;211212if (Symb.isExternal() || Symb.isWeakExternal())213Result |= SymbolRef::SF_Global;214215if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {216Result |= SymbolRef::SF_Weak;217if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)218Result |= SymbolRef::SF_Undefined;219}220221if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)222Result |= SymbolRef::SF_Absolute;223224if (Symb.isFileRecord())225Result |= SymbolRef::SF_FormatSpecific;226227if (Symb.isSectionDefinition())228Result |= SymbolRef::SF_FormatSpecific;229230if (Symb.isCommon())231Result |= SymbolRef::SF_Common;232233if (Symb.isUndefined())234Result |= SymbolRef::SF_Undefined;235236return Result;237}238239uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {240COFFSymbolRef Symb = getCOFFSymbol(Ref);241return Symb.getValue();242}243244Expected<section_iterator>245COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {246COFFSymbolRef Symb = getCOFFSymbol(Ref);247if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))248return section_end();249Expected<const coff_section *> Sec = getSection(Symb.getSectionNumber());250if (!Sec)251return Sec.takeError();252DataRefImpl Ret;253Ret.p = reinterpret_cast<uintptr_t>(*Sec);254return section_iterator(SectionRef(Ret, this));255}256257unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {258COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());259return Symb.getSectionNumber();260}261262void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {263const coff_section *Sec = toSec(Ref);264Sec += 1;265Ref.p = reinterpret_cast<uintptr_t>(Sec);266}267268Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const {269const coff_section *Sec = toSec(Ref);270return getSectionName(Sec);271}272273uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {274const coff_section *Sec = toSec(Ref);275uint64_t Result = Sec->VirtualAddress;276277// The section VirtualAddress does not include ImageBase, and we want to278// return virtual addresses.279Result += getImageBase();280return Result;281}282283uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {284return toSec(Sec) - SectionTable;285}286287uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {288return getSectionSize(toSec(Ref));289}290291Expected<ArrayRef<uint8_t>>292COFFObjectFile::getSectionContents(DataRefImpl Ref) const {293const coff_section *Sec = toSec(Ref);294ArrayRef<uint8_t> Res;295if (Error E = getSectionContents(Sec, Res))296return E;297return Res;298}299300uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {301const coff_section *Sec = toSec(Ref);302return Sec->getAlignment();303}304305bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {306return false;307}308309bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {310const coff_section *Sec = toSec(Ref);311return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;312}313314bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {315const coff_section *Sec = toSec(Ref);316return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;317}318319bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {320const coff_section *Sec = toSec(Ref);321const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |322COFF::IMAGE_SCN_MEM_READ |323COFF::IMAGE_SCN_MEM_WRITE;324return (Sec->Characteristics & BssFlags) == BssFlags;325}326327// The .debug sections are the only debug sections for COFF328// (\see MCObjectFileInfo.cpp).329bool COFFObjectFile::isDebugSection(DataRefImpl Ref) const {330Expected<StringRef> SectionNameOrErr = getSectionName(Ref);331if (!SectionNameOrErr) {332// TODO: Report the error message properly.333consumeError(SectionNameOrErr.takeError());334return false;335}336StringRef SectionName = SectionNameOrErr.get();337return SectionName.starts_with(".debug");338}339340unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {341uintptr_t Offset =342Sec.getRawDataRefImpl().p - reinterpret_cast<uintptr_t>(SectionTable);343assert((Offset % sizeof(coff_section)) == 0);344return (Offset / sizeof(coff_section)) + 1;345}346347bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {348const coff_section *Sec = toSec(Ref);349// In COFF, a virtual section won't have any in-file350// content, so the file pointer to the content will be zero.351return Sec->PointerToRawData == 0;352}353354static uint32_t getNumberOfRelocations(const coff_section *Sec,355MemoryBufferRef M, const uint8_t *base) {356// The field for the number of relocations in COFF section table is only357// 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to358// NumberOfRelocations field, and the actual relocation count is stored in the359// VirtualAddress field in the first relocation entry.360if (Sec->hasExtendedRelocations()) {361const coff_relocation *FirstReloc;362if (Error E = getObject(FirstReloc, M,363reinterpret_cast<const coff_relocation *>(364base + Sec->PointerToRelocations))) {365consumeError(std::move(E));366return 0;367}368// -1 to exclude this first relocation entry.369return FirstReloc->VirtualAddress - 1;370}371return Sec->NumberOfRelocations;372}373374static const coff_relocation *375getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {376uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);377if (!NumRelocs)378return nullptr;379auto begin = reinterpret_cast<const coff_relocation *>(380Base + Sec->PointerToRelocations);381if (Sec->hasExtendedRelocations()) {382// Skip the first relocation entry repurposed to store the number of383// relocations.384begin++;385}386if (auto E = Binary::checkOffset(M, reinterpret_cast<uintptr_t>(begin),387sizeof(coff_relocation) * NumRelocs)) {388consumeError(std::move(E));389return nullptr;390}391return begin;392}393394relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {395const coff_section *Sec = toSec(Ref);396const coff_relocation *begin = getFirstReloc(Sec, Data, base());397if (begin && Sec->VirtualAddress != 0)398report_fatal_error("Sections with relocations should have an address of 0");399DataRefImpl Ret;400Ret.p = reinterpret_cast<uintptr_t>(begin);401return relocation_iterator(RelocationRef(Ret, this));402}403404relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {405const coff_section *Sec = toSec(Ref);406const coff_relocation *I = getFirstReloc(Sec, Data, base());407if (I)408I += getNumberOfRelocations(Sec, Data, base());409DataRefImpl Ret;410Ret.p = reinterpret_cast<uintptr_t>(I);411return relocation_iterator(RelocationRef(Ret, this));412}413414// Initialize the pointer to the symbol table.415Error COFFObjectFile::initSymbolTablePtr() {416if (COFFHeader)417if (Error E = getObject(418SymbolTable16, Data, base() + getPointerToSymbolTable(),419(uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))420return E;421422if (COFFBigObjHeader)423if (Error E = getObject(424SymbolTable32, Data, base() + getPointerToSymbolTable(),425(uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))426return E;427428// Find string table. The first four byte of the string table contains the429// total size of the string table, including the size field itself. If the430// string table is empty, the value of the first four byte would be 4.431uint32_t StringTableOffset = getPointerToSymbolTable() +432getNumberOfSymbols() * getSymbolTableEntrySize();433const uint8_t *StringTableAddr = base() + StringTableOffset;434const ulittle32_t *StringTableSizePtr;435if (Error E = getObject(StringTableSizePtr, Data, StringTableAddr))436return E;437StringTableSize = *StringTableSizePtr;438if (Error E = getObject(StringTable, Data, StringTableAddr, StringTableSize))439return E;440441// Treat table sizes < 4 as empty because contrary to the PECOFF spec, some442// tools like cvtres write a size of 0 for an empty table instead of 4.443if (StringTableSize < 4)444StringTableSize = 4;445446// Check that the string table is null terminated if has any in it.447if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)448return createStringError(object_error::parse_failed,449"string table missing null terminator");450return Error::success();451}452453uint64_t COFFObjectFile::getImageBase() const {454if (PE32Header)455return PE32Header->ImageBase;456else if (PE32PlusHeader)457return PE32PlusHeader->ImageBase;458// This actually comes up in practice.459return 0;460}461462// Returns the file offset for the given VA.463Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {464uint64_t ImageBase = getImageBase();465uint64_t Rva = Addr - ImageBase;466assert(Rva <= UINT32_MAX);467return getRvaPtr((uint32_t)Rva, Res);468}469470// Returns the file offset for the given RVA.471Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res,472const char *ErrorContext) const {473for (const SectionRef &S : sections()) {474const coff_section *Section = getCOFFSection(S);475uint32_t SectionStart = Section->VirtualAddress;476uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;477if (SectionStart <= Addr && Addr < SectionEnd) {478// A table/directory entry can be pointing to somewhere in a stripped479// section, in an object that went through `objcopy --only-keep-debug`.480// In this case we don't want to cause the parsing of the object file to481// fail, otherwise it will be impossible to use this object as debug info482// in LLDB. Return SectionStrippedError here so that483// COFFObjectFile::initialize can ignore the error.484// Somewhat common binaries may have RVAs pointing outside of the485// provided raw data. Instead of rejecting the binaries, just486// treat the section as stripped for these purposes.487if (Section->SizeOfRawData < Section->VirtualSize &&488Addr >= SectionStart + Section->SizeOfRawData) {489return make_error<SectionStrippedError>();490}491uint32_t Offset = Addr - SectionStart;492Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +493Offset;494return Error::success();495}496}497if (ErrorContext)498return createStringError(object_error::parse_failed,499"RVA 0x%" PRIx32 " for %s not found", Addr,500ErrorContext);501return createStringError(object_error::parse_failed,502"RVA 0x%" PRIx32 " not found", Addr);503}504505Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,506ArrayRef<uint8_t> &Contents,507const char *ErrorContext) const {508for (const SectionRef &S : sections()) {509const coff_section *Section = getCOFFSection(S);510uint32_t SectionStart = Section->VirtualAddress;511// Check if this RVA is within the section bounds. Be careful about integer512// overflow.513uint32_t OffsetIntoSection = RVA - SectionStart;514if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&515Size <= Section->VirtualSize - OffsetIntoSection) {516uintptr_t Begin = reinterpret_cast<uintptr_t>(base()) +517Section->PointerToRawData + OffsetIntoSection;518Contents =519ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);520return Error::success();521}522}523if (ErrorContext)524return createStringError(object_error::parse_failed,525"RVA 0x%" PRIx32 " for %s not found", RVA,526ErrorContext);527return createStringError(object_error::parse_failed,528"RVA 0x%" PRIx32 " not found", RVA);529}530531// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name532// table entry.533Error COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,534StringRef &Name) const {535uintptr_t IntPtr = 0;536if (Error E = getRvaPtr(Rva, IntPtr))537return E;538const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);539Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);540Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));541return Error::success();542}543544Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,545const codeview::DebugInfo *&PDBInfo,546StringRef &PDBFileName) const {547ArrayRef<uint8_t> InfoBytes;548if (Error E =549getRvaAndSizeAsBytes(DebugDir->AddressOfRawData, DebugDir->SizeOfData,550InfoBytes, "PDB info"))551return E;552if (InfoBytes.size() < sizeof(*PDBInfo) + 1)553return createStringError(object_error::parse_failed, "PDB info too small");554PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());555InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));556PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),557InfoBytes.size());558// Truncate the name at the first null byte. Ignore any padding.559PDBFileName = PDBFileName.split('\0').first;560return Error::success();561}562563Error COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,564StringRef &PDBFileName) const {565for (const debug_directory &D : debug_directories())566if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)567return getDebugPDBInfo(&D, PDBInfo, PDBFileName);568// If we get here, there is no PDB info to return.569PDBInfo = nullptr;570PDBFileName = StringRef();571return Error::success();572}573574// Find the import table.575Error COFFObjectFile::initImportTablePtr() {576// First, we get the RVA of the import table. If the file lacks a pointer to577// the import table, do nothing.578const data_directory *DataEntry = getDataDirectory(COFF::IMPORT_TABLE);579if (!DataEntry)580return Error::success();581582// Do nothing if the pointer to import table is NULL.583if (DataEntry->RelativeVirtualAddress == 0)584return Error::success();585586uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;587588// Find the section that contains the RVA. This is needed because the RVA is589// the import table's memory address which is different from its file offset.590uintptr_t IntPtr = 0;591if (Error E = getRvaPtr(ImportTableRva, IntPtr, "import table"))592return E;593if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))594return E;595ImportDirectory = reinterpret_cast<596const coff_import_directory_table_entry *>(IntPtr);597return Error::success();598}599600// Initializes DelayImportDirectory and NumberOfDelayImportDirectory.601Error COFFObjectFile::initDelayImportTablePtr() {602const data_directory *DataEntry =603getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR);604if (!DataEntry)605return Error::success();606if (DataEntry->RelativeVirtualAddress == 0)607return Error::success();608609uint32_t RVA = DataEntry->RelativeVirtualAddress;610NumberOfDelayImportDirectory = DataEntry->Size /611sizeof(delay_import_directory_table_entry) - 1;612613uintptr_t IntPtr = 0;614if (Error E = getRvaPtr(RVA, IntPtr, "delay import table"))615return E;616if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))617return E;618619DelayImportDirectory = reinterpret_cast<620const delay_import_directory_table_entry *>(IntPtr);621return Error::success();622}623624// Find the export table.625Error COFFObjectFile::initExportTablePtr() {626// First, we get the RVA of the export table. If the file lacks a pointer to627// the export table, do nothing.628const data_directory *DataEntry = getDataDirectory(COFF::EXPORT_TABLE);629if (!DataEntry)630return Error::success();631632// Do nothing if the pointer to export table is NULL.633if (DataEntry->RelativeVirtualAddress == 0)634return Error::success();635636uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;637uintptr_t IntPtr = 0;638if (Error E = getRvaPtr(ExportTableRva, IntPtr, "export table"))639return E;640if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))641return E;642643ExportDirectory =644reinterpret_cast<const export_directory_table_entry *>(IntPtr);645return Error::success();646}647648Error COFFObjectFile::initBaseRelocPtr() {649const data_directory *DataEntry =650getDataDirectory(COFF::BASE_RELOCATION_TABLE);651if (!DataEntry)652return Error::success();653if (DataEntry->RelativeVirtualAddress == 0)654return Error::success();655656uintptr_t IntPtr = 0;657if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,658"base reloc table"))659return E;660if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))661return E;662663BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(664IntPtr);665BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(666IntPtr + DataEntry->Size);667// FIXME: Verify the section containing BaseRelocHeader has at least668// DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.669return Error::success();670}671672Error COFFObjectFile::initDebugDirectoryPtr() {673// Get the RVA of the debug directory. Do nothing if it does not exist.674const data_directory *DataEntry = getDataDirectory(COFF::DEBUG_DIRECTORY);675if (!DataEntry)676return Error::success();677678// Do nothing if the RVA is NULL.679if (DataEntry->RelativeVirtualAddress == 0)680return Error::success();681682// Check that the size is a multiple of the entry size.683if (DataEntry->Size % sizeof(debug_directory) != 0)684return createStringError(object_error::parse_failed,685"debug directory has uneven size");686687uintptr_t IntPtr = 0;688if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,689"debug directory"))690return E;691if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))692return E;693694DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);695DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(696IntPtr + DataEntry->Size);697// FIXME: Verify the section containing DebugDirectoryBegin has at least698// DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.699return Error::success();700}701702Error COFFObjectFile::initTLSDirectoryPtr() {703// Get the RVA of the TLS directory. Do nothing if it does not exist.704const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);705if (!DataEntry)706return Error::success();707708// Do nothing if the RVA is NULL.709if (DataEntry->RelativeVirtualAddress == 0)710return Error::success();711712uint64_t DirSize =713is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32);714715// Check that the size is correct.716if (DataEntry->Size != DirSize)717return createStringError(718object_error::parse_failed,719"TLS Directory size (%u) is not the expected size (%" PRIu64 ").",720static_cast<uint32_t>(DataEntry->Size), DirSize);721722uintptr_t IntPtr = 0;723if (Error E =724getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory"))725return E;726if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))727return E;728729if (is64())730TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);731else732TLSDirectory32 = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);733734return Error::success();735}736737Error COFFObjectFile::initLoadConfigPtr() {738// Get the RVA of the debug directory. Do nothing if it does not exist.739const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);740if (!DataEntry)741return Error::success();742743// Do nothing if the RVA is NULL.744if (DataEntry->RelativeVirtualAddress == 0)745return Error::success();746uintptr_t IntPtr = 0;747if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,748"load config table"))749return E;750if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))751return E;752753LoadConfig = (const void *)IntPtr;754755if (is64()) {756auto Config = getLoadConfig64();757if (Config->Size >=758offsetof(coff_load_configuration64, CHPEMetadataPointer) +759sizeof(Config->CHPEMetadataPointer) &&760Config->CHPEMetadataPointer) {761uint64_t ChpeOff = Config->CHPEMetadataPointer;762if (Error E =763getRvaPtr(ChpeOff - getImageBase(), IntPtr, "CHPE metadata"))764return E;765if (Error E = checkOffset(Data, IntPtr, sizeof(CHPEMetadata)))766return E;767768CHPEMetadata = reinterpret_cast<const chpe_metadata *>(IntPtr);769770// Validate CHPE metadata771if (CHPEMetadata->CodeMapCount) {772if (Error E = getRvaPtr(CHPEMetadata->CodeMap, IntPtr, "CHPE code map"))773return E;774if (Error E = checkOffset(Data, IntPtr,775CHPEMetadata->CodeMapCount *776sizeof(chpe_range_entry)))777return E;778}779780if (CHPEMetadata->CodeRangesToEntryPointsCount) {781if (Error E = getRvaPtr(CHPEMetadata->CodeRangesToEntryPoints, IntPtr,782"CHPE entry point ranges"))783return E;784if (Error E = checkOffset(Data, IntPtr,785CHPEMetadata->CodeRangesToEntryPointsCount *786sizeof(chpe_code_range_entry)))787return E;788}789790if (CHPEMetadata->RedirectionMetadataCount) {791if (Error E = getRvaPtr(CHPEMetadata->RedirectionMetadata, IntPtr,792"CHPE redirection metadata"))793return E;794if (Error E = checkOffset(Data, IntPtr,795CHPEMetadata->RedirectionMetadataCount *796sizeof(chpe_redirection_entry)))797return E;798}799}800}801802return Error::success();803}804805Expected<std::unique_ptr<COFFObjectFile>>806COFFObjectFile::create(MemoryBufferRef Object) {807std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object)));808if (Error E = Obj->initialize())809return E;810return std::move(Obj);811}812813COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)814: ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),815COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),816DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),817SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),818ImportDirectory(nullptr), DelayImportDirectory(nullptr),819NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),820BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),821DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),822TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}823824static Error ignoreStrippedErrors(Error E) {825if (E.isA<SectionStrippedError>()) {826consumeError(std::move(E));827return Error::success();828}829return E;830}831832Error COFFObjectFile::initialize() {833// Check that we at least have enough room for a header.834std::error_code EC;835if (!checkSize(Data, EC, sizeof(coff_file_header)))836return errorCodeToError(EC);837838// The current location in the file where we are looking at.839uint64_t CurPtr = 0;840841// PE header is optional and is present only in executables. If it exists,842// it is placed right after COFF header.843bool HasPEHeader = false;844845// Check if this is a PE/COFF file.846if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {847// PE/COFF, seek through MS-DOS compatibility stub and 4-byte848// PE signature to find 'normal' COFF header.849const auto *DH = reinterpret_cast<const dos_header *>(base());850if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {851CurPtr = DH->AddressOfNewExeHeader;852// Check the PE magic bytes. ("PE\0\0")853if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {854return createStringError(object_error::parse_failed,855"incorrect PE magic");856}857CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.858HasPEHeader = true;859}860}861862if (Error E = getObject(COFFHeader, Data, base() + CurPtr))863return E;864865// It might be a bigobj file, let's check. Note that COFF bigobj and COFF866// import libraries share a common prefix but bigobj is more restrictive.867if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&868COFFHeader->NumberOfSections == uint16_t(0xffff) &&869checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {870if (Error E = getObject(COFFBigObjHeader, Data, base() + CurPtr))871return E;872873// Verify that we are dealing with bigobj.874if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&875std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,876sizeof(COFF::BigObjMagic)) == 0) {877COFFHeader = nullptr;878CurPtr += sizeof(coff_bigobj_file_header);879} else {880// It's not a bigobj.881COFFBigObjHeader = nullptr;882}883}884if (COFFHeader) {885// The prior checkSize call may have failed. This isn't a hard error886// because we were just trying to sniff out bigobj.887EC = std::error_code();888CurPtr += sizeof(coff_file_header);889890if (COFFHeader->isImportLibrary())891return errorCodeToError(EC);892}893894if (HasPEHeader) {895const pe32_header *Header;896if (Error E = getObject(Header, Data, base() + CurPtr))897return E;898899const uint8_t *DataDirAddr;900uint64_t DataDirSize;901if (Header->Magic == COFF::PE32Header::PE32) {902PE32Header = Header;903DataDirAddr = base() + CurPtr + sizeof(pe32_header);904DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;905} else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {906PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);907DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);908DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;909} else {910// It's neither PE32 nor PE32+.911return createStringError(object_error::parse_failed,912"incorrect PE magic");913}914if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))915return E;916}917918if (COFFHeader)919CurPtr += COFFHeader->SizeOfOptionalHeader;920921assert(COFFHeader || COFFBigObjHeader);922923if (Error E =924getObject(SectionTable, Data, base() + CurPtr,925(uint64_t)getNumberOfSections() * sizeof(coff_section)))926return E;927928// Initialize the pointer to the symbol table.929if (getPointerToSymbolTable() != 0) {930if (Error E = initSymbolTablePtr()) {931// Recover from errors reading the symbol table.932consumeError(std::move(E));933SymbolTable16 = nullptr;934SymbolTable32 = nullptr;935StringTable = nullptr;936StringTableSize = 0;937}938} else {939// We had better not have any symbols if we don't have a symbol table.940if (getNumberOfSymbols() != 0) {941return createStringError(object_error::parse_failed,942"symbol table missing");943}944}945946// Initialize the pointer to the beginning of the import table.947if (Error E = ignoreStrippedErrors(initImportTablePtr()))948return E;949if (Error E = ignoreStrippedErrors(initDelayImportTablePtr()))950return E;951952// Initialize the pointer to the export table.953if (Error E = ignoreStrippedErrors(initExportTablePtr()))954return E;955956// Initialize the pointer to the base relocation table.957if (Error E = ignoreStrippedErrors(initBaseRelocPtr()))958return E;959960// Initialize the pointer to the debug directory.961if (Error E = ignoreStrippedErrors(initDebugDirectoryPtr()))962return E;963964// Initialize the pointer to the TLS directory.965if (Error E = ignoreStrippedErrors(initTLSDirectoryPtr()))966return E;967968if (Error E = ignoreStrippedErrors(initLoadConfigPtr()))969return E;970971return Error::success();972}973974basic_symbol_iterator COFFObjectFile::symbol_begin() const {975DataRefImpl Ret;976Ret.p = getSymbolTable();977return basic_symbol_iterator(SymbolRef(Ret, this));978}979980basic_symbol_iterator COFFObjectFile::symbol_end() const {981// The symbol table ends where the string table begins.982DataRefImpl Ret;983Ret.p = reinterpret_cast<uintptr_t>(StringTable);984return basic_symbol_iterator(SymbolRef(Ret, this));985}986987import_directory_iterator COFFObjectFile::import_directory_begin() const {988if (!ImportDirectory)989return import_directory_end();990if (ImportDirectory->isNull())991return import_directory_end();992return import_directory_iterator(993ImportDirectoryEntryRef(ImportDirectory, 0, this));994}995996import_directory_iterator COFFObjectFile::import_directory_end() const {997return import_directory_iterator(998ImportDirectoryEntryRef(nullptr, -1, this));999}10001001delay_import_directory_iterator1002COFFObjectFile::delay_import_directory_begin() const {1003return delay_import_directory_iterator(1004DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));1005}10061007delay_import_directory_iterator1008COFFObjectFile::delay_import_directory_end() const {1009return delay_import_directory_iterator(1010DelayImportDirectoryEntryRef(1011DelayImportDirectory, NumberOfDelayImportDirectory, this));1012}10131014export_directory_iterator COFFObjectFile::export_directory_begin() const {1015return export_directory_iterator(1016ExportDirectoryEntryRef(ExportDirectory, 0, this));1017}10181019export_directory_iterator COFFObjectFile::export_directory_end() const {1020if (!ExportDirectory)1021return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));1022ExportDirectoryEntryRef Ref(ExportDirectory,1023ExportDirectory->AddressTableEntries, this);1024return export_directory_iterator(Ref);1025}10261027section_iterator COFFObjectFile::section_begin() const {1028DataRefImpl Ret;1029Ret.p = reinterpret_cast<uintptr_t>(SectionTable);1030return section_iterator(SectionRef(Ret, this));1031}10321033section_iterator COFFObjectFile::section_end() const {1034DataRefImpl Ret;1035int NumSections =1036COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();1037Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);1038return section_iterator(SectionRef(Ret, this));1039}10401041base_reloc_iterator COFFObjectFile::base_reloc_begin() const {1042return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));1043}10441045base_reloc_iterator COFFObjectFile::base_reloc_end() const {1046return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));1047}10481049uint8_t COFFObjectFile::getBytesInAddress() const {1050return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;1051}10521053StringRef COFFObjectFile::getFileFormatName() const {1054switch(getMachine()) {1055case COFF::IMAGE_FILE_MACHINE_I386:1056return "COFF-i386";1057case COFF::IMAGE_FILE_MACHINE_AMD64:1058return "COFF-x86-64";1059case COFF::IMAGE_FILE_MACHINE_ARMNT:1060return "COFF-ARM";1061case COFF::IMAGE_FILE_MACHINE_ARM64:1062return "COFF-ARM64";1063case COFF::IMAGE_FILE_MACHINE_ARM64EC:1064return "COFF-ARM64EC";1065case COFF::IMAGE_FILE_MACHINE_ARM64X:1066return "COFF-ARM64X";1067default:1068return "COFF-<unknown arch>";1069}1070}10711072Triple::ArchType COFFObjectFile::getArch() const {1073return getMachineArchType(getMachine());1074}10751076Expected<uint64_t> COFFObjectFile::getStartAddress() const {1077if (PE32Header)1078return PE32Header->AddressOfEntryPoint;1079return 0;1080}10811082iterator_range<import_directory_iterator>1083COFFObjectFile::import_directories() const {1084return make_range(import_directory_begin(), import_directory_end());1085}10861087iterator_range<delay_import_directory_iterator>1088COFFObjectFile::delay_import_directories() const {1089return make_range(delay_import_directory_begin(),1090delay_import_directory_end());1091}10921093iterator_range<export_directory_iterator>1094COFFObjectFile::export_directories() const {1095return make_range(export_directory_begin(), export_directory_end());1096}10971098iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {1099return make_range(base_reloc_begin(), base_reloc_end());1100}11011102const data_directory *COFFObjectFile::getDataDirectory(uint32_t Index) const {1103if (!DataDirectory)1104return nullptr;1105assert(PE32Header || PE32PlusHeader);1106uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize1107: PE32PlusHeader->NumberOfRvaAndSize;1108if (Index >= NumEnt)1109return nullptr;1110return &DataDirectory[Index];1111}11121113Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {1114// Perhaps getting the section of a reserved section index should be an error,1115// but callers rely on this to return null.1116if (COFF::isReservedSectionNumber(Index))1117return (const coff_section *)nullptr;1118if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {1119// We already verified the section table data, so no need to check again.1120return SectionTable + (Index - 1);1121}1122return createStringError(object_error::parse_failed,1123"section index out of bounds");1124}11251126Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {1127if (StringTableSize <= 4)1128// Tried to get a string from an empty string table.1129return createStringError(object_error::parse_failed, "string table empty");1130if (Offset >= StringTableSize)1131return errorCodeToError(object_error::unexpected_eof);1132return StringRef(StringTable + Offset);1133}11341135Expected<StringRef> COFFObjectFile::getSymbolName(COFFSymbolRef Symbol) const {1136return getSymbolName(Symbol.getGeneric());1137}11381139Expected<StringRef>1140COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol) const {1141// Check for string table entry. First 4 bytes are 0.1142if (Symbol->Name.Offset.Zeroes == 0)1143return getString(Symbol->Name.Offset.Offset);11441145// Null terminated, let ::strlen figure out the length.1146if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)1147return StringRef(Symbol->Name.ShortName);11481149// Not null terminated, use all 8 bytes.1150return StringRef(Symbol->Name.ShortName, COFF::NameSize);1151}11521153ArrayRef<uint8_t>1154COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {1155const uint8_t *Aux = nullptr;11561157size_t SymbolSize = getSymbolTableEntrySize();1158if (Symbol.getNumberOfAuxSymbols() > 0) {1159// AUX data comes immediately after the symbol in COFF1160Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;1161#ifndef NDEBUG1162// Verify that the Aux symbol points to a valid entry in the symbol table.1163uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());1164if (Offset < getPointerToSymbolTable() ||1165Offset >=1166getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))1167report_fatal_error("Aux Symbol data was outside of symbol table.");11681169assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&1170"Aux Symbol data did not point to the beginning of a symbol");1171#endif1172}1173return ArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);1174}11751176uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {1177uintptr_t Offset =1178reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();1179assert(Offset % getSymbolTableEntrySize() == 0 &&1180"Symbol did not point to the beginning of a symbol");1181size_t Index = Offset / getSymbolTableEntrySize();1182assert(Index < getNumberOfSymbols());1183return Index;1184}11851186Expected<StringRef>1187COFFObjectFile::getSectionName(const coff_section *Sec) const {1188StringRef Name = StringRef(Sec->Name, COFF::NameSize).split('\0').first;11891190// Check for string table entry. First byte is '/'.1191if (Name.starts_with("/")) {1192uint32_t Offset;1193if (Name.starts_with("//")) {1194if (decodeBase64StringEntry(Name.substr(2), Offset))1195return createStringError(object_error::parse_failed,1196"invalid section name");1197} else {1198if (Name.substr(1).getAsInteger(10, Offset))1199return createStringError(object_error::parse_failed,1200"invalid section name");1201}1202return getString(Offset);1203}12041205return Name;1206}12071208uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {1209// SizeOfRawData and VirtualSize change what they represent depending on1210// whether or not we have an executable image.1211//1212// For object files, SizeOfRawData contains the size of section's data;1213// VirtualSize should be zero but isn't due to buggy COFF writers.1214//1215// For executables, SizeOfRawData *must* be a multiple of FileAlignment; the1216// actual section size is in VirtualSize. It is possible for VirtualSize to1217// be greater than SizeOfRawData; the contents past that point should be1218// considered to be zero.1219if (getDOSHeader())1220return std::min(Sec->VirtualSize, Sec->SizeOfRawData);1221return Sec->SizeOfRawData;1222}12231224Error COFFObjectFile::getSectionContents(const coff_section *Sec,1225ArrayRef<uint8_t> &Res) const {1226// In COFF, a virtual section won't have any in-file1227// content, so the file pointer to the content will be zero.1228if (Sec->PointerToRawData == 0)1229return Error::success();1230// The only thing that we need to verify is that the contents is contained1231// within the file bounds. We don't need to make sure it doesn't cover other1232// data, as there's nothing that says that is not allowed.1233uintptr_t ConStart =1234reinterpret_cast<uintptr_t>(base()) + Sec->PointerToRawData;1235uint32_t SectionSize = getSectionSize(Sec);1236if (Error E = checkOffset(Data, ConStart, SectionSize))1237return E;1238Res = ArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);1239return Error::success();1240}12411242const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {1243return reinterpret_cast<const coff_relocation*>(Rel.p);1244}12451246void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {1247Rel.p = reinterpret_cast<uintptr_t>(1248reinterpret_cast<const coff_relocation*>(Rel.p) + 1);1249}12501251uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {1252const coff_relocation *R = toRel(Rel);1253return R->VirtualAddress;1254}12551256symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {1257const coff_relocation *R = toRel(Rel);1258DataRefImpl Ref;1259if (R->SymbolTableIndex >= getNumberOfSymbols())1260return symbol_end();1261if (SymbolTable16)1262Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);1263else if (SymbolTable32)1264Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);1265else1266llvm_unreachable("no symbol table pointer!");1267return symbol_iterator(SymbolRef(Ref, this));1268}12691270uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {1271const coff_relocation* R = toRel(Rel);1272return R->Type;1273}12741275const coff_section *1276COFFObjectFile::getCOFFSection(const SectionRef &Section) const {1277return toSec(Section.getRawDataRefImpl());1278}12791280COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {1281if (SymbolTable16)1282return toSymb<coff_symbol16>(Ref);1283if (SymbolTable32)1284return toSymb<coff_symbol32>(Ref);1285llvm_unreachable("no symbol table pointer!");1286}12871288COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {1289return getCOFFSymbol(Symbol.getRawDataRefImpl());1290}12911292const coff_relocation *1293COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {1294return toRel(Reloc.getRawDataRefImpl());1295}12961297ArrayRef<coff_relocation>1298COFFObjectFile::getRelocations(const coff_section *Sec) const {1299return {getFirstReloc(Sec, Data, base()),1300getNumberOfRelocations(Sec, Data, base())};1301}13021303#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \1304case COFF::reloc_type: \1305return #reloc_type;13061307StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {1308switch (getArch()) {1309case Triple::x86_64:1310switch (Type) {1311LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);1312LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);1313LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);1314LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);1315LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);1316LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);1317LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);1318LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);1319LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);1320LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);1321LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);1322LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);1323LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);1324LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);1325LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);1326LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);1327LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);1328default:1329return "Unknown";1330}1331break;1332case Triple::thumb:1333switch (Type) {1334LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);1335LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);1336LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);1337LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);1338LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);1339LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);1340LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);1341LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);1342LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32);1343LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);1344LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);1345LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);1346LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);1347LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);1348LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);1349LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);1350LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR);1351default:1352return "Unknown";1353}1354break;1355case Triple::aarch64:1356switch (Type) {1357LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);1358LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);1359LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);1360LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);1361LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);1362LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);1363LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);1364LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);1365LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);1366LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);1367LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);1368LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);1369LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);1370LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);1371LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);1372LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);1373LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);1374LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32);1375default:1376return "Unknown";1377}1378break;1379case Triple::x86:1380switch (Type) {1381LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);1382LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);1383LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);1384LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);1385LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);1386LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);1387LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);1388LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);1389LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);1390LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);1391LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);1392default:1393return "Unknown";1394}1395break;1396default:1397return "Unknown";1398}1399}14001401#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME14021403void COFFObjectFile::getRelocationTypeName(1404DataRefImpl Rel, SmallVectorImpl<char> &Result) const {1405const coff_relocation *Reloc = toRel(Rel);1406StringRef Res = getRelocationTypeName(Reloc->Type);1407Result.append(Res.begin(), Res.end());1408}14091410bool COFFObjectFile::isRelocatableObject() const {1411return !DataDirectory;1412}14131414StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {1415return StringSwitch<StringRef>(Name)1416.Case("eh_fram", "eh_frame")1417.Default(Name);1418}14191420bool ImportDirectoryEntryRef::1421operator==(const ImportDirectoryEntryRef &Other) const {1422return ImportTable == Other.ImportTable && Index == Other.Index;1423}14241425void ImportDirectoryEntryRef::moveNext() {1426++Index;1427if (ImportTable[Index].isNull()) {1428Index = -1;1429ImportTable = nullptr;1430}1431}14321433Error ImportDirectoryEntryRef::getImportTableEntry(1434const coff_import_directory_table_entry *&Result) const {1435return getObject(Result, OwningObject->Data, ImportTable + Index);1436}14371438static imported_symbol_iterator1439makeImportedSymbolIterator(const COFFObjectFile *Object,1440uintptr_t Ptr, int Index) {1441if (Object->getBytesInAddress() == 4) {1442auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);1443return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));1444}1445auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);1446return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));1447}14481449static imported_symbol_iterator1450importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {1451uintptr_t IntPtr = 0;1452// FIXME: Handle errors.1453cantFail(Object->getRvaPtr(RVA, IntPtr));1454return makeImportedSymbolIterator(Object, IntPtr, 0);1455}14561457static imported_symbol_iterator1458importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {1459uintptr_t IntPtr = 0;1460// FIXME: Handle errors.1461cantFail(Object->getRvaPtr(RVA, IntPtr));1462// Forward the pointer to the last entry which is null.1463int Index = 0;1464if (Object->getBytesInAddress() == 4) {1465auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);1466while (*Entry++)1467++Index;1468} else {1469auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);1470while (*Entry++)1471++Index;1472}1473return makeImportedSymbolIterator(Object, IntPtr, Index);1474}14751476imported_symbol_iterator1477ImportDirectoryEntryRef::imported_symbol_begin() const {1478return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,1479OwningObject);1480}14811482imported_symbol_iterator1483ImportDirectoryEntryRef::imported_symbol_end() const {1484return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,1485OwningObject);1486}14871488iterator_range<imported_symbol_iterator>1489ImportDirectoryEntryRef::imported_symbols() const {1490return make_range(imported_symbol_begin(), imported_symbol_end());1491}14921493imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {1494return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,1495OwningObject);1496}14971498imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {1499return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,1500OwningObject);1501}15021503iterator_range<imported_symbol_iterator>1504ImportDirectoryEntryRef::lookup_table_symbols() const {1505return make_range(lookup_table_begin(), lookup_table_end());1506}15071508Error ImportDirectoryEntryRef::getName(StringRef &Result) const {1509uintptr_t IntPtr = 0;1510if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr,1511"import directory name"))1512return E;1513Result = StringRef(reinterpret_cast<const char *>(IntPtr));1514return Error::success();1515}15161517Error1518ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {1519Result = ImportTable[Index].ImportLookupTableRVA;1520return Error::success();1521}15221523Error ImportDirectoryEntryRef::getImportAddressTableRVA(1524uint32_t &Result) const {1525Result = ImportTable[Index].ImportAddressTableRVA;1526return Error::success();1527}15281529bool DelayImportDirectoryEntryRef::1530operator==(const DelayImportDirectoryEntryRef &Other) const {1531return Table == Other.Table && Index == Other.Index;1532}15331534void DelayImportDirectoryEntryRef::moveNext() {1535++Index;1536}15371538imported_symbol_iterator1539DelayImportDirectoryEntryRef::imported_symbol_begin() const {1540return importedSymbolBegin(Table[Index].DelayImportNameTable,1541OwningObject);1542}15431544imported_symbol_iterator1545DelayImportDirectoryEntryRef::imported_symbol_end() const {1546return importedSymbolEnd(Table[Index].DelayImportNameTable,1547OwningObject);1548}15491550iterator_range<imported_symbol_iterator>1551DelayImportDirectoryEntryRef::imported_symbols() const {1552return make_range(imported_symbol_begin(), imported_symbol_end());1553}15541555Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {1556uintptr_t IntPtr = 0;1557if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr,1558"delay import directory name"))1559return E;1560Result = StringRef(reinterpret_cast<const char *>(IntPtr));1561return Error::success();1562}15631564Error DelayImportDirectoryEntryRef::getDelayImportTable(1565const delay_import_directory_table_entry *&Result) const {1566Result = &Table[Index];1567return Error::success();1568}15691570Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,1571uint64_t &Result) const {1572uint32_t RVA = Table[Index].DelayImportAddressTable +1573AddrIndex * (OwningObject->is64() ? 8 : 4);1574uintptr_t IntPtr = 0;1575if (Error E = OwningObject->getRvaPtr(RVA, IntPtr, "import address"))1576return E;1577if (OwningObject->is64())1578Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);1579else1580Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);1581return Error::success();1582}15831584bool ExportDirectoryEntryRef::1585operator==(const ExportDirectoryEntryRef &Other) const {1586return ExportTable == Other.ExportTable && Index == Other.Index;1587}15881589void ExportDirectoryEntryRef::moveNext() {1590++Index;1591}15921593// Returns the name of the current export symbol. If the symbol is exported only1594// by ordinal, the empty string is set as a result.1595Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {1596uintptr_t IntPtr = 0;1597if (Error E =1598OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr, "dll name"))1599return E;1600Result = StringRef(reinterpret_cast<const char *>(IntPtr));1601return Error::success();1602}16031604// Returns the starting ordinal number.1605Error ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {1606Result = ExportTable->OrdinalBase;1607return Error::success();1608}16091610// Returns the export ordinal of the current export symbol.1611Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {1612Result = ExportTable->OrdinalBase + Index;1613return Error::success();1614}16151616// Returns the address of the current export symbol.1617Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {1618uintptr_t IntPtr = 0;1619if (Error EC = OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA,1620IntPtr, "export address"))1621return EC;1622const export_address_table_entry *entry =1623reinterpret_cast<const export_address_table_entry *>(IntPtr);1624Result = entry[Index].ExportRVA;1625return Error::success();1626}16271628// Returns the name of the current export symbol. If the symbol is exported only1629// by ordinal, the empty string is set as a result.1630Error1631ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {1632uintptr_t IntPtr = 0;1633if (Error EC = OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr,1634"export ordinal table"))1635return EC;1636const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);16371638uint32_t NumEntries = ExportTable->NumberOfNamePointers;1639int Offset = 0;1640for (const ulittle16_t *I = Start, *E = Start + NumEntries;1641I < E; ++I, ++Offset) {1642if (*I != Index)1643continue;1644if (Error EC = OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr,1645"export table entry"))1646return EC;1647const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);1648if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr,1649"export symbol name"))1650return EC;1651Result = StringRef(reinterpret_cast<const char *>(IntPtr));1652return Error::success();1653}1654Result = "";1655return Error::success();1656}16571658Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {1659const data_directory *DataEntry =1660OwningObject->getDataDirectory(COFF::EXPORT_TABLE);1661if (!DataEntry)1662return createStringError(object_error::parse_failed,1663"export table missing");1664uint32_t RVA;1665if (auto EC = getExportRVA(RVA))1666return EC;1667uint32_t Begin = DataEntry->RelativeVirtualAddress;1668uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;1669Result = (Begin <= RVA && RVA < End);1670return Error::success();1671}16721673Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {1674uint32_t RVA;1675if (auto EC = getExportRVA(RVA))1676return EC;1677uintptr_t IntPtr = 0;1678if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr, "export forward target"))1679return EC;1680Result = StringRef(reinterpret_cast<const char *>(IntPtr));1681return Error::success();1682}16831684bool ImportedSymbolRef::1685operator==(const ImportedSymbolRef &Other) const {1686return Entry32 == Other.Entry32 && Entry64 == Other.Entry641687&& Index == Other.Index;1688}16891690void ImportedSymbolRef::moveNext() {1691++Index;1692}16931694Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {1695uint32_t RVA;1696if (Entry32) {1697// If a symbol is imported only by ordinal, it has no name.1698if (Entry32[Index].isOrdinal())1699return Error::success();1700RVA = Entry32[Index].getHintNameRVA();1701} else {1702if (Entry64[Index].isOrdinal())1703return Error::success();1704RVA = Entry64[Index].getHintNameRVA();1705}1706uintptr_t IntPtr = 0;1707if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol name"))1708return EC;1709// +2 because the first two bytes is hint.1710Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));1711return Error::success();1712}17131714Error ImportedSymbolRef::isOrdinal(bool &Result) const {1715if (Entry32)1716Result = Entry32[Index].isOrdinal();1717else1718Result = Entry64[Index].isOrdinal();1719return Error::success();1720}17211722Error ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {1723if (Entry32)1724Result = Entry32[Index].getHintNameRVA();1725else1726Result = Entry64[Index].getHintNameRVA();1727return Error::success();1728}17291730Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {1731uint32_t RVA;1732if (Entry32) {1733if (Entry32[Index].isOrdinal()) {1734Result = Entry32[Index].getOrdinal();1735return Error::success();1736}1737RVA = Entry32[Index].getHintNameRVA();1738} else {1739if (Entry64[Index].isOrdinal()) {1740Result = Entry64[Index].getOrdinal();1741return Error::success();1742}1743RVA = Entry64[Index].getHintNameRVA();1744}1745uintptr_t IntPtr = 0;1746if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol ordinal"))1747return EC;1748Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);1749return Error::success();1750}17511752Expected<std::unique_ptr<COFFObjectFile>>1753ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {1754return COFFObjectFile::create(Object);1755}17561757bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {1758return Header == Other.Header && Index == Other.Index;1759}17601761void BaseRelocRef::moveNext() {1762// Header->BlockSize is the size of the current block, including the1763// size of the header itself.1764uint32_t Size = sizeof(*Header) +1765sizeof(coff_base_reloc_block_entry) * (Index + 1);1766if (Size == Header->BlockSize) {1767// .reloc contains a list of base relocation blocks. Each block1768// consists of the header followed by entries. The header contains1769// how many entories will follow. When we reach the end of the1770// current block, proceed to the next block.1771Header = reinterpret_cast<const coff_base_reloc_block_header *>(1772reinterpret_cast<const uint8_t *>(Header) + Size);1773Index = 0;1774} else {1775++Index;1776}1777}17781779Error BaseRelocRef::getType(uint8_t &Type) const {1780auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);1781Type = Entry[Index].getType();1782return Error::success();1783}17841785Error BaseRelocRef::getRVA(uint32_t &Result) const {1786auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);1787Result = Header->PageRVA + Entry[Index].getOffset();1788return Error::success();1789}17901791#define RETURN_IF_ERROR(Expr) \1792do { \1793Error E = (Expr); \1794if (E) \1795return std::move(E); \1796} while (0)17971798Expected<ArrayRef<UTF16>>1799ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {1800BinaryStreamReader Reader = BinaryStreamReader(BBS);1801Reader.setOffset(Offset);1802uint16_t Length;1803RETURN_IF_ERROR(Reader.readInteger(Length));1804ArrayRef<UTF16> RawDirString;1805RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));1806return RawDirString;1807}18081809Expected<ArrayRef<UTF16>>1810ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {1811return getDirStringAtOffset(Entry.Identifier.getNameOffset());1812}18131814Expected<const coff_resource_dir_table &>1815ResourceSectionRef::getTableAtOffset(uint32_t Offset) {1816const coff_resource_dir_table *Table = nullptr;18171818BinaryStreamReader Reader(BBS);1819Reader.setOffset(Offset);1820RETURN_IF_ERROR(Reader.readObject(Table));1821assert(Table != nullptr);1822return *Table;1823}18241825Expected<const coff_resource_dir_entry &>1826ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {1827const coff_resource_dir_entry *Entry = nullptr;18281829BinaryStreamReader Reader(BBS);1830Reader.setOffset(Offset);1831RETURN_IF_ERROR(Reader.readObject(Entry));1832assert(Entry != nullptr);1833return *Entry;1834}18351836Expected<const coff_resource_data_entry &>1837ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {1838const coff_resource_data_entry *Entry = nullptr;18391840BinaryStreamReader Reader(BBS);1841Reader.setOffset(Offset);1842RETURN_IF_ERROR(Reader.readObject(Entry));1843assert(Entry != nullptr);1844return *Entry;1845}18461847Expected<const coff_resource_dir_table &>1848ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {1849assert(Entry.Offset.isSubDir());1850return getTableAtOffset(Entry.Offset.value());1851}18521853Expected<const coff_resource_data_entry &>1854ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {1855assert(!Entry.Offset.isSubDir());1856return getDataEntryAtOffset(Entry.Offset.value());1857}18581859Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {1860return getTableAtOffset(0);1861}18621863Expected<const coff_resource_dir_entry &>1864ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,1865uint32_t Index) {1866if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))1867return createStringError(object_error::parse_failed, "index out of range");1868const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);1869ptrdiff_t TableOffset = TablePtr - BBS.data().data();1870return getTableEntryAtOffset(TableOffset + sizeof(Table) +1871Index * sizeof(coff_resource_dir_entry));1872}18731874Error ResourceSectionRef::load(const COFFObjectFile *O) {1875for (const SectionRef &S : O->sections()) {1876Expected<StringRef> Name = S.getName();1877if (!Name)1878return Name.takeError();18791880if (*Name == ".rsrc" || *Name == ".rsrc$01")1881return load(O, S);1882}1883return createStringError(object_error::parse_failed,1884"no resource section found");1885}18861887Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {1888Obj = O;1889Section = S;1890Expected<StringRef> Contents = Section.getContents();1891if (!Contents)1892return Contents.takeError();1893BBS = BinaryByteStream(*Contents, llvm::endianness::little);1894const coff_section *COFFSect = Obj->getCOFFSection(Section);1895ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);1896Relocs.reserve(OrigRelocs.size());1897for (const coff_relocation &R : OrigRelocs)1898Relocs.push_back(&R);1899llvm::sort(Relocs, [](const coff_relocation *A, const coff_relocation *B) {1900return A->VirtualAddress < B->VirtualAddress;1901});1902return Error::success();1903}19041905Expected<StringRef>1906ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {1907if (!Obj)1908return createStringError(object_error::parse_failed, "no object provided");19091910// Find a potential relocation at the DataRVA field (first member of1911// the coff_resource_data_entry struct).1912const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);1913ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();1914coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),1915ulittle16_t(0)};1916auto RelocsForOffset =1917std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,1918[](const coff_relocation *A, const coff_relocation *B) {1919return A->VirtualAddress < B->VirtualAddress;1920});19211922if (RelocsForOffset.first != RelocsForOffset.second) {1923// We found a relocation with the right offset. Check that it does have1924// the expected type.1925const coff_relocation &R = **RelocsForOffset.first;1926uint16_t RVAReloc;1927switch (Obj->getArch()) {1928case Triple::x86:1929RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;1930break;1931case Triple::x86_64:1932RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;1933break;1934case Triple::thumb:1935RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;1936break;1937case Triple::aarch64:1938RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;1939break;1940default:1941return createStringError(object_error::parse_failed,1942"unsupported architecture");1943}1944if (R.Type != RVAReloc)1945return createStringError(object_error::parse_failed,1946"unexpected relocation type");1947// Get the relocation's symbol1948Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);1949if (!Sym)1950return Sym.takeError();1951// And the symbol's section1952Expected<const coff_section *> Section =1953Obj->getSection(Sym->getSectionNumber());1954if (!Section)1955return Section.takeError();1956// Add the initial value of DataRVA to the symbol's offset to find the1957// data it points at.1958uint64_t Offset = Entry.DataRVA + Sym->getValue();1959ArrayRef<uint8_t> Contents;1960if (Error E = Obj->getSectionContents(*Section, Contents))1961return E;1962if (Offset + Entry.DataSize > Contents.size())1963return createStringError(object_error::parse_failed,1964"data outside of section");1965// Return a reference to the data inside the section.1966return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,1967Entry.DataSize);1968} else {1969// Relocatable objects need a relocation for the DataRVA field.1970if (Obj->isRelocatableObject())1971return createStringError(object_error::parse_failed,1972"no relocation found for DataRVA");19731974// Locate the section that contains the address that DataRVA points at.1975uint64_t VA = Entry.DataRVA + Obj->getImageBase();1976for (const SectionRef &S : Obj->sections()) {1977if (VA >= S.getAddress() &&1978VA + Entry.DataSize <= S.getAddress() + S.getSize()) {1979uint64_t Offset = VA - S.getAddress();1980Expected<StringRef> Contents = S.getContents();1981if (!Contents)1982return Contents.takeError();1983return Contents->slice(Offset, Offset + Entry.DataSize);1984}1985}1986return createStringError(object_error::parse_failed,1987"address not found in image");1988}1989}199019911992