llvm-project
1990 строк · 70.1 Кб
1//===- COFFObjectFile.cpp - COFF object file implementation ---------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file declares the COFFObjectFile class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/ADT/ArrayRef.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/ADT/StringSwitch.h"16#include "llvm/ADT/iterator_range.h"17#include "llvm/Object/Binary.h"18#include "llvm/Object/COFF.h"19#include "llvm/Object/Error.h"20#include "llvm/Object/ObjectFile.h"21#include "llvm/Object/WindowsMachineFlag.h"22#include "llvm/Support/BinaryStreamReader.h"23#include "llvm/Support/Endian.h"24#include "llvm/Support/Error.h"25#include "llvm/Support/ErrorHandling.h"26#include "llvm/Support/MathExtras.h"27#include "llvm/Support/MemoryBufferRef.h"28#include <algorithm>29#include <cassert>30#include <cinttypes>31#include <cstddef>32#include <cstring>33#include <limits>34#include <memory>35#include <system_error>36
37using namespace llvm;38using namespace object;39
40using support::ulittle16_t;41using support::ulittle32_t;42using support::ulittle64_t;43using support::little16_t;44
45// Returns false if size is greater than the buffer size. And sets ec.
46static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) {47if (M.getBufferSize() < Size) {48EC = object_error::unexpected_eof;49return false;50}51return true;52}
53
54// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
55// Returns unexpected_eof if error.
56template <typename T>57static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr,58const uint64_t Size = sizeof(T)) {59uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);60if (Error E = Binary::checkOffset(M, Addr, Size))61return E;62Obj = reinterpret_cast<const T *>(Addr);63return Error::success();64}
65
66// Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without
67// prefixed slashes.
68static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {69assert(Str.size() <= 6 && "String too long, possible overflow.");70if (Str.size() > 6)71return true;72
73uint64_t Value = 0;74while (!Str.empty()) {75unsigned CharVal;76if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..2577CharVal = Str[0] - 'A';78else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..5179CharVal = Str[0] - 'a' + 26;80else if (Str[0] >= '0' && Str[0] <= '9') // 52..6181CharVal = Str[0] - '0' + 52;82else if (Str[0] == '+') // 6283CharVal = 62;84else if (Str[0] == '/') // 6385CharVal = 63;86else87return true;88
89Value = (Value * 64) + CharVal;90Str = Str.substr(1);91}92
93if (Value > std::numeric_limits<uint32_t>::max())94return true;95
96Result = static_cast<uint32_t>(Value);97return false;98}
99
100template <typename coff_symbol_type>101const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {102const coff_symbol_type *Addr =103reinterpret_cast<const coff_symbol_type *>(Ref.p);104
105assert(!checkOffset(Data, reinterpret_cast<uintptr_t>(Addr), sizeof(*Addr)));106#ifndef NDEBUG107// Verify that the symbol points to a valid entry in the symbol table.108uintptr_t Offset =109reinterpret_cast<uintptr_t>(Addr) - reinterpret_cast<uintptr_t>(base());110
111assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&112"Symbol did not point to the beginning of a symbol");113#endif114
115return Addr;116}
117
118const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {119const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p);120
121#ifndef NDEBUG122// Verify that the section points to a valid entry in the section table.123if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))124report_fatal_error("Section was outside of section table.");125
126uintptr_t Offset = reinterpret_cast<uintptr_t>(Addr) -127reinterpret_cast<uintptr_t>(SectionTable);128assert(Offset % sizeof(coff_section) == 0 &&129"Section did not point to the beginning of a section");130#endif131
132return Addr;133}
134
135void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {136auto End = reinterpret_cast<uintptr_t>(StringTable);137if (SymbolTable16) {138const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);139Symb += 1 + Symb->NumberOfAuxSymbols;140Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);141} else if (SymbolTable32) {142const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);143Symb += 1 + Symb->NumberOfAuxSymbols;144Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);145} else {146llvm_unreachable("no symbol table pointer!");147}148}
149
150Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {151return getSymbolName(getCOFFSymbol(Ref));152}
153
154uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {155return getCOFFSymbol(Ref).getValue();156}
157
158uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const {159// MSVC/link.exe seems to align symbols to the next-power-of-2160// up to 32 bytes.161COFFSymbolRef Symb = getCOFFSymbol(Ref);162return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));163}
164
165Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {166uint64_t Result = cantFail(getSymbolValue(Ref));167COFFSymbolRef Symb = getCOFFSymbol(Ref);168int32_t SectionNumber = Symb.getSectionNumber();169
170if (Symb.isAnyUndefined() || Symb.isCommon() ||171COFF::isReservedSectionNumber(SectionNumber))172return Result;173
174Expected<const coff_section *> Section = getSection(SectionNumber);175if (!Section)176return Section.takeError();177Result += (*Section)->VirtualAddress;178
179// The section VirtualAddress does not include ImageBase, and we want to180// return virtual addresses.181Result += getImageBase();182
183return Result;184}
185
186Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {187COFFSymbolRef Symb = getCOFFSymbol(Ref);188int32_t SectionNumber = Symb.getSectionNumber();189
190if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)191return SymbolRef::ST_Function;192if (Symb.isAnyUndefined())193return SymbolRef::ST_Unknown;194if (Symb.isCommon())195return SymbolRef::ST_Data;196if (Symb.isFileRecord())197return SymbolRef::ST_File;198
199// TODO: perhaps we need a new symbol type ST_Section.200if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())201return SymbolRef::ST_Debug;202
203if (!COFF::isReservedSectionNumber(SectionNumber))204return SymbolRef::ST_Data;205
206return SymbolRef::ST_Other;207}
208
209Expected<uint32_t> COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {210COFFSymbolRef Symb = getCOFFSymbol(Ref);211uint32_t Result = SymbolRef::SF_None;212
213if (Symb.isExternal() || Symb.isWeakExternal())214Result |= SymbolRef::SF_Global;215
216if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {217Result |= SymbolRef::SF_Weak;218if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)219Result |= SymbolRef::SF_Undefined;220}221
222if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)223Result |= SymbolRef::SF_Absolute;224
225if (Symb.isFileRecord())226Result |= SymbolRef::SF_FormatSpecific;227
228if (Symb.isSectionDefinition())229Result |= SymbolRef::SF_FormatSpecific;230
231if (Symb.isCommon())232Result |= SymbolRef::SF_Common;233
234if (Symb.isUndefined())235Result |= SymbolRef::SF_Undefined;236
237return Result;238}
239
240uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {241COFFSymbolRef Symb = getCOFFSymbol(Ref);242return Symb.getValue();243}
244
245Expected<section_iterator>246COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {247COFFSymbolRef Symb = getCOFFSymbol(Ref);248if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))249return section_end();250Expected<const coff_section *> Sec = getSection(Symb.getSectionNumber());251if (!Sec)252return Sec.takeError();253DataRefImpl Ret;254Ret.p = reinterpret_cast<uintptr_t>(*Sec);255return section_iterator(SectionRef(Ret, this));256}
257
258unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {259COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());260return Symb.getSectionNumber();261}
262
263void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {264const coff_section *Sec = toSec(Ref);265Sec += 1;266Ref.p = reinterpret_cast<uintptr_t>(Sec);267}
268
269Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const {270const coff_section *Sec = toSec(Ref);271return getSectionName(Sec);272}
273
274uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {275const coff_section *Sec = toSec(Ref);276uint64_t Result = Sec->VirtualAddress;277
278// The section VirtualAddress does not include ImageBase, and we want to279// return virtual addresses.280Result += getImageBase();281return Result;282}
283
284uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {285return toSec(Sec) - SectionTable;286}
287
288uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {289return getSectionSize(toSec(Ref));290}
291
292Expected<ArrayRef<uint8_t>>293COFFObjectFile::getSectionContents(DataRefImpl Ref) const {294const coff_section *Sec = toSec(Ref);295ArrayRef<uint8_t> Res;296if (Error E = getSectionContents(Sec, Res))297return E;298return Res;299}
300
301uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {302const coff_section *Sec = toSec(Ref);303return Sec->getAlignment();304}
305
306bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {307return false;308}
309
310bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {311const coff_section *Sec = toSec(Ref);312return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;313}
314
315bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {316const coff_section *Sec = toSec(Ref);317return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;318}
319
320bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {321const coff_section *Sec = toSec(Ref);322const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |323COFF::IMAGE_SCN_MEM_READ |324COFF::IMAGE_SCN_MEM_WRITE;325return (Sec->Characteristics & BssFlags) == BssFlags;326}
327
328// The .debug sections are the only debug sections for COFF
329// (\see MCObjectFileInfo.cpp).
330bool COFFObjectFile::isDebugSection(DataRefImpl Ref) const {331Expected<StringRef> SectionNameOrErr = getSectionName(Ref);332if (!SectionNameOrErr) {333// TODO: Report the error message properly.334consumeError(SectionNameOrErr.takeError());335return false;336}337StringRef SectionName = SectionNameOrErr.get();338return SectionName.starts_with(".debug");339}
340
341unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {342uintptr_t Offset =343Sec.getRawDataRefImpl().p - reinterpret_cast<uintptr_t>(SectionTable);344assert((Offset % sizeof(coff_section)) == 0);345return (Offset / sizeof(coff_section)) + 1;346}
347
348bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {349const coff_section *Sec = toSec(Ref);350// In COFF, a virtual section won't have any in-file351// content, so the file pointer to the content will be zero.352return Sec->PointerToRawData == 0;353}
354
355static uint32_t getNumberOfRelocations(const coff_section *Sec,356MemoryBufferRef M, const uint8_t *base) {357// The field for the number of relocations in COFF section table is only358// 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to359// NumberOfRelocations field, and the actual relocation count is stored in the360// VirtualAddress field in the first relocation entry.361if (Sec->hasExtendedRelocations()) {362const coff_relocation *FirstReloc;363if (Error E = getObject(FirstReloc, M,364reinterpret_cast<const coff_relocation *>(365base + Sec->PointerToRelocations))) {366consumeError(std::move(E));367return 0;368}369// -1 to exclude this first relocation entry.370return FirstReloc->VirtualAddress - 1;371}372return Sec->NumberOfRelocations;373}
374
375static const coff_relocation *376getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {377uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);378if (!NumRelocs)379return nullptr;380auto begin = reinterpret_cast<const coff_relocation *>(381Base + Sec->PointerToRelocations);382if (Sec->hasExtendedRelocations()) {383// Skip the first relocation entry repurposed to store the number of384// relocations.385begin++;386}387if (auto E = Binary::checkOffset(M, reinterpret_cast<uintptr_t>(begin),388sizeof(coff_relocation) * NumRelocs)) {389consumeError(std::move(E));390return nullptr;391}392return begin;393}
394
395relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {396const coff_section *Sec = toSec(Ref);397const coff_relocation *begin = getFirstReloc(Sec, Data, base());398if (begin && Sec->VirtualAddress != 0)399report_fatal_error("Sections with relocations should have an address of 0");400DataRefImpl Ret;401Ret.p = reinterpret_cast<uintptr_t>(begin);402return relocation_iterator(RelocationRef(Ret, this));403}
404
405relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {406const coff_section *Sec = toSec(Ref);407const coff_relocation *I = getFirstReloc(Sec, Data, base());408if (I)409I += getNumberOfRelocations(Sec, Data, base());410DataRefImpl Ret;411Ret.p = reinterpret_cast<uintptr_t>(I);412return relocation_iterator(RelocationRef(Ret, this));413}
414
415// Initialize the pointer to the symbol table.
416Error COFFObjectFile::initSymbolTablePtr() {417if (COFFHeader)418if (Error E = getObject(419SymbolTable16, Data, base() + getPointerToSymbolTable(),420(uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))421return E;422
423if (COFFBigObjHeader)424if (Error E = getObject(425SymbolTable32, Data, base() + getPointerToSymbolTable(),426(uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))427return E;428
429// Find string table. The first four byte of the string table contains the430// total size of the string table, including the size field itself. If the431// string table is empty, the value of the first four byte would be 4.432uint32_t StringTableOffset = getPointerToSymbolTable() +433getNumberOfSymbols() * getSymbolTableEntrySize();434const uint8_t *StringTableAddr = base() + StringTableOffset;435const ulittle32_t *StringTableSizePtr;436if (Error E = getObject(StringTableSizePtr, Data, StringTableAddr))437return E;438StringTableSize = *StringTableSizePtr;439if (Error E = getObject(StringTable, Data, StringTableAddr, StringTableSize))440return E;441
442// Treat table sizes < 4 as empty because contrary to the PECOFF spec, some443// tools like cvtres write a size of 0 for an empty table instead of 4.444if (StringTableSize < 4)445StringTableSize = 4;446
447// Check that the string table is null terminated if has any in it.448if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)449return createStringError(object_error::parse_failed,450"string table missing null terminator");451return Error::success();452}
453
454uint64_t COFFObjectFile::getImageBase() const {455if (PE32Header)456return PE32Header->ImageBase;457else if (PE32PlusHeader)458return PE32PlusHeader->ImageBase;459// This actually comes up in practice.460return 0;461}
462
463// Returns the file offset for the given VA.
464Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {465uint64_t ImageBase = getImageBase();466uint64_t Rva = Addr - ImageBase;467assert(Rva <= UINT32_MAX);468return getRvaPtr((uint32_t)Rva, Res);469}
470
471// Returns the file offset for the given RVA.
472Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res,473const char *ErrorContext) const {474for (const SectionRef &S : sections()) {475const coff_section *Section = getCOFFSection(S);476uint32_t SectionStart = Section->VirtualAddress;477uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;478if (SectionStart <= Addr && Addr < SectionEnd) {479// A table/directory entry can be pointing to somewhere in a stripped480// section, in an object that went through `objcopy --only-keep-debug`.481// In this case we don't want to cause the parsing of the object file to482// fail, otherwise it will be impossible to use this object as debug info483// in LLDB. Return SectionStrippedError here so that484// COFFObjectFile::initialize can ignore the error.485// Somewhat common binaries may have RVAs pointing outside of the486// provided raw data. Instead of rejecting the binaries, just487// treat the section as stripped for these purposes.488if (Section->SizeOfRawData < Section->VirtualSize &&489Addr >= SectionStart + Section->SizeOfRawData) {490return make_error<SectionStrippedError>();491}492uint32_t Offset = Addr - SectionStart;493Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +494Offset;495return Error::success();496}497}498if (ErrorContext)499return createStringError(object_error::parse_failed,500"RVA 0x%" PRIx32 " for %s not found", Addr,501ErrorContext);502return createStringError(object_error::parse_failed,503"RVA 0x%" PRIx32 " not found", Addr);504}
505
506Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,507ArrayRef<uint8_t> &Contents,508const char *ErrorContext) const {509for (const SectionRef &S : sections()) {510const coff_section *Section = getCOFFSection(S);511uint32_t SectionStart = Section->VirtualAddress;512// Check if this RVA is within the section bounds. Be careful about integer513// overflow.514uint32_t OffsetIntoSection = RVA - SectionStart;515if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&516Size <= Section->VirtualSize - OffsetIntoSection) {517uintptr_t Begin = reinterpret_cast<uintptr_t>(base()) +518Section->PointerToRawData + OffsetIntoSection;519Contents =520ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);521return Error::success();522}523}524if (ErrorContext)525return createStringError(object_error::parse_failed,526"RVA 0x%" PRIx32 " for %s not found", RVA,527ErrorContext);528return createStringError(object_error::parse_failed,529"RVA 0x%" PRIx32 " not found", RVA);530}
531
532// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
533// table entry.
534Error COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,535StringRef &Name) const {536uintptr_t IntPtr = 0;537if (Error E = getRvaPtr(Rva, IntPtr))538return E;539const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);540Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);541Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));542return Error::success();543}
544
545Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,546const codeview::DebugInfo *&PDBInfo,547StringRef &PDBFileName) const {548ArrayRef<uint8_t> InfoBytes;549if (Error E =550getRvaAndSizeAsBytes(DebugDir->AddressOfRawData, DebugDir->SizeOfData,551InfoBytes, "PDB info"))552return E;553if (InfoBytes.size() < sizeof(*PDBInfo) + 1)554return createStringError(object_error::parse_failed, "PDB info too small");555PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());556InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));557PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),558InfoBytes.size());559// Truncate the name at the first null byte. Ignore any padding.560PDBFileName = PDBFileName.split('\0').first;561return Error::success();562}
563
564Error COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,565StringRef &PDBFileName) const {566for (const debug_directory &D : debug_directories())567if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)568return getDebugPDBInfo(&D, PDBInfo, PDBFileName);569// If we get here, there is no PDB info to return.570PDBInfo = nullptr;571PDBFileName = StringRef();572return Error::success();573}
574
575// Find the import table.
576Error COFFObjectFile::initImportTablePtr() {577// First, we get the RVA of the import table. If the file lacks a pointer to578// the import table, do nothing.579const data_directory *DataEntry = getDataDirectory(COFF::IMPORT_TABLE);580if (!DataEntry)581return Error::success();582
583// Do nothing if the pointer to import table is NULL.584if (DataEntry->RelativeVirtualAddress == 0)585return Error::success();586
587uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;588
589// Find the section that contains the RVA. This is needed because the RVA is590// the import table's memory address which is different from its file offset.591uintptr_t IntPtr = 0;592if (Error E = getRvaPtr(ImportTableRva, IntPtr, "import table"))593return E;594if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))595return E;596ImportDirectory = reinterpret_cast<597const coff_import_directory_table_entry *>(IntPtr);598return Error::success();599}
600
601// Initializes DelayImportDirectory and NumberOfDelayImportDirectory.
602Error COFFObjectFile::initDelayImportTablePtr() {603const data_directory *DataEntry =604getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR);605if (!DataEntry)606return Error::success();607if (DataEntry->RelativeVirtualAddress == 0)608return Error::success();609
610uint32_t RVA = DataEntry->RelativeVirtualAddress;611NumberOfDelayImportDirectory = DataEntry->Size /612sizeof(delay_import_directory_table_entry) - 1;613
614uintptr_t IntPtr = 0;615if (Error E = getRvaPtr(RVA, IntPtr, "delay import table"))616return E;617if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))618return E;619
620DelayImportDirectory = reinterpret_cast<621const delay_import_directory_table_entry *>(IntPtr);622return Error::success();623}
624
625// Find the export table.
626Error COFFObjectFile::initExportTablePtr() {627// First, we get the RVA of the export table. If the file lacks a pointer to628// the export table, do nothing.629const data_directory *DataEntry = getDataDirectory(COFF::EXPORT_TABLE);630if (!DataEntry)631return Error::success();632
633// Do nothing if the pointer to export table is NULL.634if (DataEntry->RelativeVirtualAddress == 0)635return Error::success();636
637uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;638uintptr_t IntPtr = 0;639if (Error E = getRvaPtr(ExportTableRva, IntPtr, "export table"))640return E;641if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))642return E;643
644ExportDirectory =645reinterpret_cast<const export_directory_table_entry *>(IntPtr);646return Error::success();647}
648
649Error COFFObjectFile::initBaseRelocPtr() {650const data_directory *DataEntry =651getDataDirectory(COFF::BASE_RELOCATION_TABLE);652if (!DataEntry)653return Error::success();654if (DataEntry->RelativeVirtualAddress == 0)655return Error::success();656
657uintptr_t IntPtr = 0;658if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,659"base reloc table"))660return E;661if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))662return E;663
664BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(665IntPtr);666BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(667IntPtr + DataEntry->Size);668// FIXME: Verify the section containing BaseRelocHeader has at least669// DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.670return Error::success();671}
672
673Error COFFObjectFile::initDebugDirectoryPtr() {674// Get the RVA of the debug directory. Do nothing if it does not exist.675const data_directory *DataEntry = getDataDirectory(COFF::DEBUG_DIRECTORY);676if (!DataEntry)677return Error::success();678
679// Do nothing if the RVA is NULL.680if (DataEntry->RelativeVirtualAddress == 0)681return Error::success();682
683// Check that the size is a multiple of the entry size.684if (DataEntry->Size % sizeof(debug_directory) != 0)685return createStringError(object_error::parse_failed,686"debug directory has uneven size");687
688uintptr_t IntPtr = 0;689if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,690"debug directory"))691return E;692if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))693return E;694
695DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);696DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(697IntPtr + DataEntry->Size);698// FIXME: Verify the section containing DebugDirectoryBegin has at least699// DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.700return Error::success();701}
702
703Error COFFObjectFile::initTLSDirectoryPtr() {704// Get the RVA of the TLS directory. Do nothing if it does not exist.705const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);706if (!DataEntry)707return Error::success();708
709// Do nothing if the RVA is NULL.710if (DataEntry->RelativeVirtualAddress == 0)711return Error::success();712
713uint64_t DirSize =714is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32);715
716// Check that the size is correct.717if (DataEntry->Size != DirSize)718return createStringError(719object_error::parse_failed,720"TLS Directory size (%u) is not the expected size (%" PRIu64 ").",721static_cast<uint32_t>(DataEntry->Size), DirSize);722
723uintptr_t IntPtr = 0;724if (Error E =725getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory"))726return E;727if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))728return E;729
730if (is64())731TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);732else733TLSDirectory32 = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);734
735return Error::success();736}
737
738Error COFFObjectFile::initLoadConfigPtr() {739// Get the RVA of the debug directory. Do nothing if it does not exist.740const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);741if (!DataEntry)742return Error::success();743
744// Do nothing if the RVA is NULL.745if (DataEntry->RelativeVirtualAddress == 0)746return Error::success();747uintptr_t IntPtr = 0;748if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,749"load config table"))750return E;751if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))752return E;753
754LoadConfig = (const void *)IntPtr;755
756if (is64()) {757auto Config = getLoadConfig64();758if (Config->Size >=759offsetof(coff_load_configuration64, CHPEMetadataPointer) +760sizeof(Config->CHPEMetadataPointer) &&761Config->CHPEMetadataPointer) {762uint64_t ChpeOff = Config->CHPEMetadataPointer;763if (Error E =764getRvaPtr(ChpeOff - getImageBase(), IntPtr, "CHPE metadata"))765return E;766if (Error E = checkOffset(Data, IntPtr, sizeof(CHPEMetadata)))767return E;768
769CHPEMetadata = reinterpret_cast<const chpe_metadata *>(IntPtr);770
771// Validate CHPE metadata772if (CHPEMetadata->CodeMapCount) {773if (Error E = getRvaPtr(CHPEMetadata->CodeMap, IntPtr, "CHPE code map"))774return E;775if (Error E = checkOffset(Data, IntPtr,776CHPEMetadata->CodeMapCount *777sizeof(chpe_range_entry)))778return E;779}780
781if (CHPEMetadata->CodeRangesToEntryPointsCount) {782if (Error E = getRvaPtr(CHPEMetadata->CodeRangesToEntryPoints, IntPtr,783"CHPE entry point ranges"))784return E;785if (Error E = checkOffset(Data, IntPtr,786CHPEMetadata->CodeRangesToEntryPointsCount *787sizeof(chpe_code_range_entry)))788return E;789}790
791if (CHPEMetadata->RedirectionMetadataCount) {792if (Error E = getRvaPtr(CHPEMetadata->RedirectionMetadata, IntPtr,793"CHPE redirection metadata"))794return E;795if (Error E = checkOffset(Data, IntPtr,796CHPEMetadata->RedirectionMetadataCount *797sizeof(chpe_redirection_entry)))798return E;799}800}801}802
803return Error::success();804}
805
806Expected<std::unique_ptr<COFFObjectFile>>807COFFObjectFile::create(MemoryBufferRef Object) {808std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object)));809if (Error E = Obj->initialize())810return E;811return std::move(Obj);812}
813
814COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)815: ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),816COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),817DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),818SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),819ImportDirectory(nullptr), DelayImportDirectory(nullptr),820NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),821BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),822DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),823TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}824
825static Error ignoreStrippedErrors(Error E) {826if (E.isA<SectionStrippedError>()) {827consumeError(std::move(E));828return Error::success();829}830return E;831}
832
833Error COFFObjectFile::initialize() {834// Check that we at least have enough room for a header.835std::error_code EC;836if (!checkSize(Data, EC, sizeof(coff_file_header)))837return errorCodeToError(EC);838
839// The current location in the file where we are looking at.840uint64_t CurPtr = 0;841
842// PE header is optional and is present only in executables. If it exists,843// it is placed right after COFF header.844bool HasPEHeader = false;845
846// Check if this is a PE/COFF file.847if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {848// PE/COFF, seek through MS-DOS compatibility stub and 4-byte849// PE signature to find 'normal' COFF header.850const auto *DH = reinterpret_cast<const dos_header *>(base());851if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {852CurPtr = DH->AddressOfNewExeHeader;853// Check the PE magic bytes. ("PE\0\0")854if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {855return createStringError(object_error::parse_failed,856"incorrect PE magic");857}858CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.859HasPEHeader = true;860}861}862
863if (Error E = getObject(COFFHeader, Data, base() + CurPtr))864return E;865
866// It might be a bigobj file, let's check. Note that COFF bigobj and COFF867// import libraries share a common prefix but bigobj is more restrictive.868if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&869COFFHeader->NumberOfSections == uint16_t(0xffff) &&870checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {871if (Error E = getObject(COFFBigObjHeader, Data, base() + CurPtr))872return E;873
874// Verify that we are dealing with bigobj.875if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&876std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,877sizeof(COFF::BigObjMagic)) == 0) {878COFFHeader = nullptr;879CurPtr += sizeof(coff_bigobj_file_header);880} else {881// It's not a bigobj.882COFFBigObjHeader = nullptr;883}884}885if (COFFHeader) {886// The prior checkSize call may have failed. This isn't a hard error887// because we were just trying to sniff out bigobj.888EC = std::error_code();889CurPtr += sizeof(coff_file_header);890
891if (COFFHeader->isImportLibrary())892return errorCodeToError(EC);893}894
895if (HasPEHeader) {896const pe32_header *Header;897if (Error E = getObject(Header, Data, base() + CurPtr))898return E;899
900const uint8_t *DataDirAddr;901uint64_t DataDirSize;902if (Header->Magic == COFF::PE32Header::PE32) {903PE32Header = Header;904DataDirAddr = base() + CurPtr + sizeof(pe32_header);905DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;906} else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {907PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);908DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);909DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;910} else {911// It's neither PE32 nor PE32+.912return createStringError(object_error::parse_failed,913"incorrect PE magic");914}915if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))916return E;917}918
919if (COFFHeader)920CurPtr += COFFHeader->SizeOfOptionalHeader;921
922assert(COFFHeader || COFFBigObjHeader);923
924if (Error E =925getObject(SectionTable, Data, base() + CurPtr,926(uint64_t)getNumberOfSections() * sizeof(coff_section)))927return E;928
929// Initialize the pointer to the symbol table.930if (getPointerToSymbolTable() != 0) {931if (Error E = initSymbolTablePtr()) {932// Recover from errors reading the symbol table.933consumeError(std::move(E));934SymbolTable16 = nullptr;935SymbolTable32 = nullptr;936StringTable = nullptr;937StringTableSize = 0;938}939} else {940// We had better not have any symbols if we don't have a symbol table.941if (getNumberOfSymbols() != 0) {942return createStringError(object_error::parse_failed,943"symbol table missing");944}945}946
947// Initialize the pointer to the beginning of the import table.948if (Error E = ignoreStrippedErrors(initImportTablePtr()))949return E;950if (Error E = ignoreStrippedErrors(initDelayImportTablePtr()))951return E;952
953// Initialize the pointer to the export table.954if (Error E = ignoreStrippedErrors(initExportTablePtr()))955return E;956
957// Initialize the pointer to the base relocation table.958if (Error E = ignoreStrippedErrors(initBaseRelocPtr()))959return E;960
961// Initialize the pointer to the debug directory.962if (Error E = ignoreStrippedErrors(initDebugDirectoryPtr()))963return E;964
965// Initialize the pointer to the TLS directory.966if (Error E = ignoreStrippedErrors(initTLSDirectoryPtr()))967return E;968
969if (Error E = ignoreStrippedErrors(initLoadConfigPtr()))970return E;971
972return Error::success();973}
974
975basic_symbol_iterator COFFObjectFile::symbol_begin() const {976DataRefImpl Ret;977Ret.p = getSymbolTable();978return basic_symbol_iterator(SymbolRef(Ret, this));979}
980
981basic_symbol_iterator COFFObjectFile::symbol_end() const {982// The symbol table ends where the string table begins.983DataRefImpl Ret;984Ret.p = reinterpret_cast<uintptr_t>(StringTable);985return basic_symbol_iterator(SymbolRef(Ret, this));986}
987
988import_directory_iterator COFFObjectFile::import_directory_begin() const {989if (!ImportDirectory)990return import_directory_end();991if (ImportDirectory->isNull())992return import_directory_end();993return import_directory_iterator(994ImportDirectoryEntryRef(ImportDirectory, 0, this));995}
996
997import_directory_iterator COFFObjectFile::import_directory_end() const {998return import_directory_iterator(999ImportDirectoryEntryRef(nullptr, -1, this));1000}
1001
1002delay_import_directory_iterator
1003COFFObjectFile::delay_import_directory_begin() const {1004return delay_import_directory_iterator(1005DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));1006}
1007
1008delay_import_directory_iterator
1009COFFObjectFile::delay_import_directory_end() const {1010return delay_import_directory_iterator(1011DelayImportDirectoryEntryRef(1012DelayImportDirectory, NumberOfDelayImportDirectory, this));1013}
1014
1015export_directory_iterator COFFObjectFile::export_directory_begin() const {1016return export_directory_iterator(1017ExportDirectoryEntryRef(ExportDirectory, 0, this));1018}
1019
1020export_directory_iterator COFFObjectFile::export_directory_end() const {1021if (!ExportDirectory)1022return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));1023ExportDirectoryEntryRef Ref(ExportDirectory,1024ExportDirectory->AddressTableEntries, this);1025return export_directory_iterator(Ref);1026}
1027
1028section_iterator COFFObjectFile::section_begin() const {1029DataRefImpl Ret;1030Ret.p = reinterpret_cast<uintptr_t>(SectionTable);1031return section_iterator(SectionRef(Ret, this));1032}
1033
1034section_iterator COFFObjectFile::section_end() const {1035DataRefImpl Ret;1036int NumSections =1037COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();1038Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);1039return section_iterator(SectionRef(Ret, this));1040}
1041
1042base_reloc_iterator COFFObjectFile::base_reloc_begin() const {1043return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));1044}
1045
1046base_reloc_iterator COFFObjectFile::base_reloc_end() const {1047return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));1048}
1049
1050uint8_t COFFObjectFile::getBytesInAddress() const {1051return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;1052}
1053
1054StringRef COFFObjectFile::getFileFormatName() const {1055switch(getMachine()) {1056case COFF::IMAGE_FILE_MACHINE_I386:1057return "COFF-i386";1058case COFF::IMAGE_FILE_MACHINE_AMD64:1059return "COFF-x86-64";1060case COFF::IMAGE_FILE_MACHINE_ARMNT:1061return "COFF-ARM";1062case COFF::IMAGE_FILE_MACHINE_ARM64:1063return "COFF-ARM64";1064case COFF::IMAGE_FILE_MACHINE_ARM64EC:1065return "COFF-ARM64EC";1066case COFF::IMAGE_FILE_MACHINE_ARM64X:1067return "COFF-ARM64X";1068default:1069return "COFF-<unknown arch>";1070}1071}
1072
1073Triple::ArchType COFFObjectFile::getArch() const {1074return getMachineArchType(getMachine());1075}
1076
1077Expected<uint64_t> COFFObjectFile::getStartAddress() const {1078if (PE32Header)1079return PE32Header->AddressOfEntryPoint;1080return 0;1081}
1082
1083iterator_range<import_directory_iterator>1084COFFObjectFile::import_directories() const {1085return make_range(import_directory_begin(), import_directory_end());1086}
1087
1088iterator_range<delay_import_directory_iterator>1089COFFObjectFile::delay_import_directories() const {1090return make_range(delay_import_directory_begin(),1091delay_import_directory_end());1092}
1093
1094iterator_range<export_directory_iterator>1095COFFObjectFile::export_directories() const {1096return make_range(export_directory_begin(), export_directory_end());1097}
1098
1099iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {1100return make_range(base_reloc_begin(), base_reloc_end());1101}
1102
1103const data_directory *COFFObjectFile::getDataDirectory(uint32_t Index) const {1104if (!DataDirectory)1105return nullptr;1106assert(PE32Header || PE32PlusHeader);1107uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize1108: PE32PlusHeader->NumberOfRvaAndSize;1109if (Index >= NumEnt)1110return nullptr;1111return &DataDirectory[Index];1112}
1113
1114Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {1115// Perhaps getting the section of a reserved section index should be an error,1116// but callers rely on this to return null.1117if (COFF::isReservedSectionNumber(Index))1118return (const coff_section *)nullptr;1119if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {1120// We already verified the section table data, so no need to check again.1121return SectionTable + (Index - 1);1122}1123return createStringError(object_error::parse_failed,1124"section index out of bounds");1125}
1126
1127Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {1128if (StringTableSize <= 4)1129// Tried to get a string from an empty string table.1130return createStringError(object_error::parse_failed, "string table empty");1131if (Offset >= StringTableSize)1132return errorCodeToError(object_error::unexpected_eof);1133return StringRef(StringTable + Offset);1134}
1135
1136Expected<StringRef> COFFObjectFile::getSymbolName(COFFSymbolRef Symbol) const {1137return getSymbolName(Symbol.getGeneric());1138}
1139
1140Expected<StringRef>1141COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol) const {1142// Check for string table entry. First 4 bytes are 0.1143if (Symbol->Name.Offset.Zeroes == 0)1144return getString(Symbol->Name.Offset.Offset);1145
1146// Null terminated, let ::strlen figure out the length.1147if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)1148return StringRef(Symbol->Name.ShortName);1149
1150// Not null terminated, use all 8 bytes.1151return StringRef(Symbol->Name.ShortName, COFF::NameSize);1152}
1153
1154ArrayRef<uint8_t>1155COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {1156const uint8_t *Aux = nullptr;1157
1158size_t SymbolSize = getSymbolTableEntrySize();1159if (Symbol.getNumberOfAuxSymbols() > 0) {1160// AUX data comes immediately after the symbol in COFF1161Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;1162#ifndef NDEBUG1163// Verify that the Aux symbol points to a valid entry in the symbol table.1164uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());1165if (Offset < getPointerToSymbolTable() ||1166Offset >=1167getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))1168report_fatal_error("Aux Symbol data was outside of symbol table.");1169
1170assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&1171"Aux Symbol data did not point to the beginning of a symbol");1172#endif1173}1174return ArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);1175}
1176
1177uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {1178uintptr_t Offset =1179reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();1180assert(Offset % getSymbolTableEntrySize() == 0 &&1181"Symbol did not point to the beginning of a symbol");1182size_t Index = Offset / getSymbolTableEntrySize();1183assert(Index < getNumberOfSymbols());1184return Index;1185}
1186
1187Expected<StringRef>1188COFFObjectFile::getSectionName(const coff_section *Sec) const {1189StringRef Name = StringRef(Sec->Name, COFF::NameSize).split('\0').first;1190
1191// Check for string table entry. First byte is '/'.1192if (Name.starts_with("/")) {1193uint32_t Offset;1194if (Name.starts_with("//")) {1195if (decodeBase64StringEntry(Name.substr(2), Offset))1196return createStringError(object_error::parse_failed,1197"invalid section name");1198} else {1199if (Name.substr(1).getAsInteger(10, Offset))1200return createStringError(object_error::parse_failed,1201"invalid section name");1202}1203return getString(Offset);1204}1205
1206return Name;1207}
1208
1209uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {1210// SizeOfRawData and VirtualSize change what they represent depending on1211// whether or not we have an executable image.1212//1213// For object files, SizeOfRawData contains the size of section's data;1214// VirtualSize should be zero but isn't due to buggy COFF writers.1215//1216// For executables, SizeOfRawData *must* be a multiple of FileAlignment; the1217// actual section size is in VirtualSize. It is possible for VirtualSize to1218// be greater than SizeOfRawData; the contents past that point should be1219// considered to be zero.1220if (getDOSHeader())1221return std::min(Sec->VirtualSize, Sec->SizeOfRawData);1222return Sec->SizeOfRawData;1223}
1224
1225Error COFFObjectFile::getSectionContents(const coff_section *Sec,1226ArrayRef<uint8_t> &Res) const {1227// In COFF, a virtual section won't have any in-file1228// content, so the file pointer to the content will be zero.1229if (Sec->PointerToRawData == 0)1230return Error::success();1231// The only thing that we need to verify is that the contents is contained1232// within the file bounds. We don't need to make sure it doesn't cover other1233// data, as there's nothing that says that is not allowed.1234uintptr_t ConStart =1235reinterpret_cast<uintptr_t>(base()) + Sec->PointerToRawData;1236uint32_t SectionSize = getSectionSize(Sec);1237if (Error E = checkOffset(Data, ConStart, SectionSize))1238return E;1239Res = ArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);1240return Error::success();1241}
1242
1243const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {1244return reinterpret_cast<const coff_relocation*>(Rel.p);1245}
1246
1247void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {1248Rel.p = reinterpret_cast<uintptr_t>(1249reinterpret_cast<const coff_relocation*>(Rel.p) + 1);1250}
1251
1252uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {1253const coff_relocation *R = toRel(Rel);1254return R->VirtualAddress;1255}
1256
1257symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {1258const coff_relocation *R = toRel(Rel);1259DataRefImpl Ref;1260if (R->SymbolTableIndex >= getNumberOfSymbols())1261return symbol_end();1262if (SymbolTable16)1263Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);1264else if (SymbolTable32)1265Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);1266else1267llvm_unreachable("no symbol table pointer!");1268return symbol_iterator(SymbolRef(Ref, this));1269}
1270
1271uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {1272const coff_relocation* R = toRel(Rel);1273return R->Type;1274}
1275
1276const coff_section *1277COFFObjectFile::getCOFFSection(const SectionRef &Section) const {1278return toSec(Section.getRawDataRefImpl());1279}
1280
1281COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {1282if (SymbolTable16)1283return toSymb<coff_symbol16>(Ref);1284if (SymbolTable32)1285return toSymb<coff_symbol32>(Ref);1286llvm_unreachable("no symbol table pointer!");1287}
1288
1289COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {1290return getCOFFSymbol(Symbol.getRawDataRefImpl());1291}
1292
1293const coff_relocation *1294COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {1295return toRel(Reloc.getRawDataRefImpl());1296}
1297
1298ArrayRef<coff_relocation>1299COFFObjectFile::getRelocations(const coff_section *Sec) const {1300return {getFirstReloc(Sec, Data, base()),1301getNumberOfRelocations(Sec, Data, base())};1302}
1303
1304#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \1305case COFF::reloc_type: \1306return #reloc_type;1307
1308StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {1309switch (getArch()) {1310case Triple::x86_64:1311switch (Type) {1312LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);1313LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);1314LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);1315LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);1316LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);1317LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);1318LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);1319LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);1320LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);1321LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);1322LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);1323LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);1324LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);1325LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);1326LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);1327LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);1328LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);1329default:1330return "Unknown";1331}1332break;1333case Triple::thumb:1334switch (Type) {1335LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);1336LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);1337LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);1338LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);1339LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);1340LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);1341LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);1342LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);1343LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32);1344LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);1345LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);1346LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);1347LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);1348LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);1349LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);1350LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);1351LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR);1352default:1353return "Unknown";1354}1355break;1356case Triple::aarch64:1357switch (Type) {1358LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);1359LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);1360LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);1361LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);1362LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);1363LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);1364LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);1365LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);1366LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);1367LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);1368LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);1369LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);1370LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);1371LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);1372LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);1373LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);1374LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);1375LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32);1376default:1377return "Unknown";1378}1379break;1380case Triple::x86:1381switch (Type) {1382LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);1383LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);1384LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);1385LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);1386LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);1387LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);1388LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);1389LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);1390LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);1391LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);1392LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);1393default:1394return "Unknown";1395}1396break;1397default:1398return "Unknown";1399}1400}
1401
1402#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME1403
1404void COFFObjectFile::getRelocationTypeName(1405DataRefImpl Rel, SmallVectorImpl<char> &Result) const {1406const coff_relocation *Reloc = toRel(Rel);1407StringRef Res = getRelocationTypeName(Reloc->Type);1408Result.append(Res.begin(), Res.end());1409}
1410
1411bool COFFObjectFile::isRelocatableObject() const {1412return !DataDirectory;1413}
1414
1415StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {1416return StringSwitch<StringRef>(Name)1417.Case("eh_fram", "eh_frame")1418.Default(Name);1419}
1420
1421bool ImportDirectoryEntryRef::1422operator==(const ImportDirectoryEntryRef &Other) const {1423return ImportTable == Other.ImportTable && Index == Other.Index;1424}
1425
1426void ImportDirectoryEntryRef::moveNext() {1427++Index;1428if (ImportTable[Index].isNull()) {1429Index = -1;1430ImportTable = nullptr;1431}1432}
1433
1434Error ImportDirectoryEntryRef::getImportTableEntry(1435const coff_import_directory_table_entry *&Result) const {1436return getObject(Result, OwningObject->Data, ImportTable + Index);1437}
1438
1439static imported_symbol_iterator1440makeImportedSymbolIterator(const COFFObjectFile *Object,1441uintptr_t Ptr, int Index) {1442if (Object->getBytesInAddress() == 4) {1443auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);1444return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));1445}1446auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);1447return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));1448}
1449
1450static imported_symbol_iterator1451importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {1452uintptr_t IntPtr = 0;1453// FIXME: Handle errors.1454cantFail(Object->getRvaPtr(RVA, IntPtr));1455return makeImportedSymbolIterator(Object, IntPtr, 0);1456}
1457
1458static imported_symbol_iterator1459importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {1460uintptr_t IntPtr = 0;1461// FIXME: Handle errors.1462cantFail(Object->getRvaPtr(RVA, IntPtr));1463// Forward the pointer to the last entry which is null.1464int Index = 0;1465if (Object->getBytesInAddress() == 4) {1466auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);1467while (*Entry++)1468++Index;1469} else {1470auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);1471while (*Entry++)1472++Index;1473}1474return makeImportedSymbolIterator(Object, IntPtr, Index);1475}
1476
1477imported_symbol_iterator
1478ImportDirectoryEntryRef::imported_symbol_begin() const {1479return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,1480OwningObject);1481}
1482
1483imported_symbol_iterator
1484ImportDirectoryEntryRef::imported_symbol_end() const {1485return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,1486OwningObject);1487}
1488
1489iterator_range<imported_symbol_iterator>1490ImportDirectoryEntryRef::imported_symbols() const {1491return make_range(imported_symbol_begin(), imported_symbol_end());1492}
1493
1494imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {1495return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,1496OwningObject);1497}
1498
1499imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {1500return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,1501OwningObject);1502}
1503
1504iterator_range<imported_symbol_iterator>1505ImportDirectoryEntryRef::lookup_table_symbols() const {1506return make_range(lookup_table_begin(), lookup_table_end());1507}
1508
1509Error ImportDirectoryEntryRef::getName(StringRef &Result) const {1510uintptr_t IntPtr = 0;1511if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr,1512"import directory name"))1513return E;1514Result = StringRef(reinterpret_cast<const char *>(IntPtr));1515return Error::success();1516}
1517
1518Error
1519ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {1520Result = ImportTable[Index].ImportLookupTableRVA;1521return Error::success();1522}
1523
1524Error ImportDirectoryEntryRef::getImportAddressTableRVA(1525uint32_t &Result) const {1526Result = ImportTable[Index].ImportAddressTableRVA;1527return Error::success();1528}
1529
1530bool DelayImportDirectoryEntryRef::1531operator==(const DelayImportDirectoryEntryRef &Other) const {1532return Table == Other.Table && Index == Other.Index;1533}
1534
1535void DelayImportDirectoryEntryRef::moveNext() {1536++Index;1537}
1538
1539imported_symbol_iterator
1540DelayImportDirectoryEntryRef::imported_symbol_begin() const {1541return importedSymbolBegin(Table[Index].DelayImportNameTable,1542OwningObject);1543}
1544
1545imported_symbol_iterator
1546DelayImportDirectoryEntryRef::imported_symbol_end() const {1547return importedSymbolEnd(Table[Index].DelayImportNameTable,1548OwningObject);1549}
1550
1551iterator_range<imported_symbol_iterator>1552DelayImportDirectoryEntryRef::imported_symbols() const {1553return make_range(imported_symbol_begin(), imported_symbol_end());1554}
1555
1556Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {1557uintptr_t IntPtr = 0;1558if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr,1559"delay import directory name"))1560return E;1561Result = StringRef(reinterpret_cast<const char *>(IntPtr));1562return Error::success();1563}
1564
1565Error DelayImportDirectoryEntryRef::getDelayImportTable(1566const delay_import_directory_table_entry *&Result) const {1567Result = &Table[Index];1568return Error::success();1569}
1570
1571Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,1572uint64_t &Result) const {1573uint32_t RVA = Table[Index].DelayImportAddressTable +1574AddrIndex * (OwningObject->is64() ? 8 : 4);1575uintptr_t IntPtr = 0;1576if (Error E = OwningObject->getRvaPtr(RVA, IntPtr, "import address"))1577return E;1578if (OwningObject->is64())1579Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);1580else1581Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);1582return Error::success();1583}
1584
1585bool ExportDirectoryEntryRef::1586operator==(const ExportDirectoryEntryRef &Other) const {1587return ExportTable == Other.ExportTable && Index == Other.Index;1588}
1589
1590void ExportDirectoryEntryRef::moveNext() {1591++Index;1592}
1593
1594// Returns the name of the current export symbol. If the symbol is exported only
1595// by ordinal, the empty string is set as a result.
1596Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {1597uintptr_t IntPtr = 0;1598if (Error E =1599OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr, "dll name"))1600return E;1601Result = StringRef(reinterpret_cast<const char *>(IntPtr));1602return Error::success();1603}
1604
1605// Returns the starting ordinal number.
1606Error ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {1607Result = ExportTable->OrdinalBase;1608return Error::success();1609}
1610
1611// Returns the export ordinal of the current export symbol.
1612Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {1613Result = ExportTable->OrdinalBase + Index;1614return Error::success();1615}
1616
1617// Returns the address of the current export symbol.
1618Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {1619uintptr_t IntPtr = 0;1620if (Error EC = OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA,1621IntPtr, "export address"))1622return EC;1623const export_address_table_entry *entry =1624reinterpret_cast<const export_address_table_entry *>(IntPtr);1625Result = entry[Index].ExportRVA;1626return Error::success();1627}
1628
1629// Returns the name of the current export symbol. If the symbol is exported only
1630// by ordinal, the empty string is set as a result.
1631Error
1632ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {1633uintptr_t IntPtr = 0;1634if (Error EC = OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr,1635"export ordinal table"))1636return EC;1637const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);1638
1639uint32_t NumEntries = ExportTable->NumberOfNamePointers;1640int Offset = 0;1641for (const ulittle16_t *I = Start, *E = Start + NumEntries;1642I < E; ++I, ++Offset) {1643if (*I != Index)1644continue;1645if (Error EC = OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr,1646"export table entry"))1647return EC;1648const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);1649if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr,1650"export symbol name"))1651return EC;1652Result = StringRef(reinterpret_cast<const char *>(IntPtr));1653return Error::success();1654}1655Result = "";1656return Error::success();1657}
1658
1659Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {1660const data_directory *DataEntry =1661OwningObject->getDataDirectory(COFF::EXPORT_TABLE);1662if (!DataEntry)1663return createStringError(object_error::parse_failed,1664"export table missing");1665uint32_t RVA;1666if (auto EC = getExportRVA(RVA))1667return EC;1668uint32_t Begin = DataEntry->RelativeVirtualAddress;1669uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;1670Result = (Begin <= RVA && RVA < End);1671return Error::success();1672}
1673
1674Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {1675uint32_t RVA;1676if (auto EC = getExportRVA(RVA))1677return EC;1678uintptr_t IntPtr = 0;1679if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr, "export forward target"))1680return EC;1681Result = StringRef(reinterpret_cast<const char *>(IntPtr));1682return Error::success();1683}
1684
1685bool ImportedSymbolRef::1686operator==(const ImportedSymbolRef &Other) const {1687return Entry32 == Other.Entry32 && Entry64 == Other.Entry641688&& Index == Other.Index;1689}
1690
1691void ImportedSymbolRef::moveNext() {1692++Index;1693}
1694
1695Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {1696uint32_t RVA;1697if (Entry32) {1698// If a symbol is imported only by ordinal, it has no name.1699if (Entry32[Index].isOrdinal())1700return Error::success();1701RVA = Entry32[Index].getHintNameRVA();1702} else {1703if (Entry64[Index].isOrdinal())1704return Error::success();1705RVA = Entry64[Index].getHintNameRVA();1706}1707uintptr_t IntPtr = 0;1708if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol name"))1709return EC;1710// +2 because the first two bytes is hint.1711Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));1712return Error::success();1713}
1714
1715Error ImportedSymbolRef::isOrdinal(bool &Result) const {1716if (Entry32)1717Result = Entry32[Index].isOrdinal();1718else1719Result = Entry64[Index].isOrdinal();1720return Error::success();1721}
1722
1723Error ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {1724if (Entry32)1725Result = Entry32[Index].getHintNameRVA();1726else1727Result = Entry64[Index].getHintNameRVA();1728return Error::success();1729}
1730
1731Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {1732uint32_t RVA;1733if (Entry32) {1734if (Entry32[Index].isOrdinal()) {1735Result = Entry32[Index].getOrdinal();1736return Error::success();1737}1738RVA = Entry32[Index].getHintNameRVA();1739} else {1740if (Entry64[Index].isOrdinal()) {1741Result = Entry64[Index].getOrdinal();1742return Error::success();1743}1744RVA = Entry64[Index].getHintNameRVA();1745}1746uintptr_t IntPtr = 0;1747if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol ordinal"))1748return EC;1749Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);1750return Error::success();1751}
1752
1753Expected<std::unique_ptr<COFFObjectFile>>1754ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {1755return COFFObjectFile::create(Object);1756}
1757
1758bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {1759return Header == Other.Header && Index == Other.Index;1760}
1761
1762void BaseRelocRef::moveNext() {1763// Header->BlockSize is the size of the current block, including the1764// size of the header itself.1765uint32_t Size = sizeof(*Header) +1766sizeof(coff_base_reloc_block_entry) * (Index + 1);1767if (Size == Header->BlockSize) {1768// .reloc contains a list of base relocation blocks. Each block1769// consists of the header followed by entries. The header contains1770// how many entories will follow. When we reach the end of the1771// current block, proceed to the next block.1772Header = reinterpret_cast<const coff_base_reloc_block_header *>(1773reinterpret_cast<const uint8_t *>(Header) + Size);1774Index = 0;1775} else {1776++Index;1777}1778}
1779
1780Error BaseRelocRef::getType(uint8_t &Type) const {1781auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);1782Type = Entry[Index].getType();1783return Error::success();1784}
1785
1786Error BaseRelocRef::getRVA(uint32_t &Result) const {1787auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);1788Result = Header->PageRVA + Entry[Index].getOffset();1789return Error::success();1790}
1791
1792#define RETURN_IF_ERROR(Expr) \1793do { \1794Error E = (Expr); \1795if (E) \1796return std::move(E); \1797} while (0)1798
1799Expected<ArrayRef<UTF16>>1800ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {1801BinaryStreamReader Reader = BinaryStreamReader(BBS);1802Reader.setOffset(Offset);1803uint16_t Length;1804RETURN_IF_ERROR(Reader.readInteger(Length));1805ArrayRef<UTF16> RawDirString;1806RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));1807return RawDirString;1808}
1809
1810Expected<ArrayRef<UTF16>>1811ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {1812return getDirStringAtOffset(Entry.Identifier.getNameOffset());1813}
1814
1815Expected<const coff_resource_dir_table &>1816ResourceSectionRef::getTableAtOffset(uint32_t Offset) {1817const coff_resource_dir_table *Table = nullptr;1818
1819BinaryStreamReader Reader(BBS);1820Reader.setOffset(Offset);1821RETURN_IF_ERROR(Reader.readObject(Table));1822assert(Table != nullptr);1823return *Table;1824}
1825
1826Expected<const coff_resource_dir_entry &>1827ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {1828const coff_resource_dir_entry *Entry = nullptr;1829
1830BinaryStreamReader Reader(BBS);1831Reader.setOffset(Offset);1832RETURN_IF_ERROR(Reader.readObject(Entry));1833assert(Entry != nullptr);1834return *Entry;1835}
1836
1837Expected<const coff_resource_data_entry &>1838ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {1839const coff_resource_data_entry *Entry = nullptr;1840
1841BinaryStreamReader Reader(BBS);1842Reader.setOffset(Offset);1843RETURN_IF_ERROR(Reader.readObject(Entry));1844assert(Entry != nullptr);1845return *Entry;1846}
1847
1848Expected<const coff_resource_dir_table &>1849ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {1850assert(Entry.Offset.isSubDir());1851return getTableAtOffset(Entry.Offset.value());1852}
1853
1854Expected<const coff_resource_data_entry &>1855ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {1856assert(!Entry.Offset.isSubDir());1857return getDataEntryAtOffset(Entry.Offset.value());1858}
1859
1860Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {1861return getTableAtOffset(0);1862}
1863
1864Expected<const coff_resource_dir_entry &>1865ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,1866uint32_t Index) {1867if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))1868return createStringError(object_error::parse_failed, "index out of range");1869const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);1870ptrdiff_t TableOffset = TablePtr - BBS.data().data();1871return getTableEntryAtOffset(TableOffset + sizeof(Table) +1872Index * sizeof(coff_resource_dir_entry));1873}
1874
1875Error ResourceSectionRef::load(const COFFObjectFile *O) {1876for (const SectionRef &S : O->sections()) {1877Expected<StringRef> Name = S.getName();1878if (!Name)1879return Name.takeError();1880
1881if (*Name == ".rsrc" || *Name == ".rsrc$01")1882return load(O, S);1883}1884return createStringError(object_error::parse_failed,1885"no resource section found");1886}
1887
1888Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {1889Obj = O;1890Section = S;1891Expected<StringRef> Contents = Section.getContents();1892if (!Contents)1893return Contents.takeError();1894BBS = BinaryByteStream(*Contents, llvm::endianness::little);1895const coff_section *COFFSect = Obj->getCOFFSection(Section);1896ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);1897Relocs.reserve(OrigRelocs.size());1898for (const coff_relocation &R : OrigRelocs)1899Relocs.push_back(&R);1900llvm::sort(Relocs, [](const coff_relocation *A, const coff_relocation *B) {1901return A->VirtualAddress < B->VirtualAddress;1902});1903return Error::success();1904}
1905
1906Expected<StringRef>1907ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {1908if (!Obj)1909return createStringError(object_error::parse_failed, "no object provided");1910
1911// Find a potential relocation at the DataRVA field (first member of1912// the coff_resource_data_entry struct).1913const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);1914ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();1915coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),1916ulittle16_t(0)};1917auto RelocsForOffset =1918std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,1919[](const coff_relocation *A, const coff_relocation *B) {1920return A->VirtualAddress < B->VirtualAddress;1921});1922
1923if (RelocsForOffset.first != RelocsForOffset.second) {1924// We found a relocation with the right offset. Check that it does have1925// the expected type.1926const coff_relocation &R = **RelocsForOffset.first;1927uint16_t RVAReloc;1928switch (Obj->getArch()) {1929case Triple::x86:1930RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;1931break;1932case Triple::x86_64:1933RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;1934break;1935case Triple::thumb:1936RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;1937break;1938case Triple::aarch64:1939RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;1940break;1941default:1942return createStringError(object_error::parse_failed,1943"unsupported architecture");1944}1945if (R.Type != RVAReloc)1946return createStringError(object_error::parse_failed,1947"unexpected relocation type");1948// Get the relocation's symbol1949Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);1950if (!Sym)1951return Sym.takeError();1952// And the symbol's section1953Expected<const coff_section *> Section =1954Obj->getSection(Sym->getSectionNumber());1955if (!Section)1956return Section.takeError();1957// Add the initial value of DataRVA to the symbol's offset to find the1958// data it points at.1959uint64_t Offset = Entry.DataRVA + Sym->getValue();1960ArrayRef<uint8_t> Contents;1961if (Error E = Obj->getSectionContents(*Section, Contents))1962return E;1963if (Offset + Entry.DataSize > Contents.size())1964return createStringError(object_error::parse_failed,1965"data outside of section");1966// Return a reference to the data inside the section.1967return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,1968Entry.DataSize);1969} else {1970// Relocatable objects need a relocation for the DataRVA field.1971if (Obj->isRelocatableObject())1972return createStringError(object_error::parse_failed,1973"no relocation found for DataRVA");1974
1975// Locate the section that contains the address that DataRVA points at.1976uint64_t VA = Entry.DataRVA + Obj->getImageBase();1977for (const SectionRef &S : Obj->sections()) {1978if (VA >= S.getAddress() &&1979VA + Entry.DataSize <= S.getAddress() + S.getSize()) {1980uint64_t Offset = VA - S.getAddress();1981Expected<StringRef> Contents = S.getContents();1982if (!Contents)1983return Contents.takeError();1984return Contents->slice(Offset, Offset + Entry.DataSize);1985}1986}1987return createStringError(object_error::parse_failed,1988"address not found in image");1989}1990}
1991