2402 lines · cpp
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-exception6//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) {47 if (M.getBufferSize() < Size) {48 EC = object_error::unexpected_eof;49 return false;50 }51 return 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,58 const uint64_t Size = sizeof(T)) {59 uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);60 if (Error E = Binary::checkOffset(M, Addr, Size))61 return E;62 Obj = reinterpret_cast<const T *>(Addr);63 return Error::success();64}65 66// Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without67// prefixed slashes.68static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {69 assert(Str.size() <= 6 && "String too long, possible overflow.");70 if (Str.size() > 6)71 return true;72 73 uint64_t Value = 0;74 while (!Str.empty()) {75 unsigned CharVal;76 if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..2577 CharVal = Str[0] - 'A';78 else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..5179 CharVal = Str[0] - 'a' + 26;80 else if (Str[0] >= '0' && Str[0] <= '9') // 52..6181 CharVal = Str[0] - '0' + 52;82 else if (Str[0] == '+') // 6283 CharVal = 62;84 else if (Str[0] == '/') // 6385 CharVal = 63;86 else87 return true;88 89 Value = (Value * 64) + CharVal;90 Str = Str.substr(1);91 }92 93 if (Value > std::numeric_limits<uint32_t>::max())94 return true;95 96 Result = static_cast<uint32_t>(Value);97 return false;98}99 100template <typename coff_symbol_type>101const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {102 const coff_symbol_type *Addr =103 reinterpret_cast<const coff_symbol_type *>(Ref.p);104 105 assert(!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.108 uintptr_t Offset =109 reinterpret_cast<uintptr_t>(Addr) - reinterpret_cast<uintptr_t>(base());110 111 assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&112 "Symbol did not point to the beginning of a symbol");113#endif114 115 return Addr;116}117 118const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {119 const 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.123 if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))124 report_fatal_error("Section was outside of section table.");125 126 uintptr_t Offset = reinterpret_cast<uintptr_t>(Addr) -127 reinterpret_cast<uintptr_t>(SectionTable);128 assert(Offset % sizeof(coff_section) == 0 &&129 "Section did not point to the beginning of a section");130#endif131 132 return Addr;133}134 135void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {136 auto End = reinterpret_cast<uintptr_t>(StringTable);137 if (SymbolTable16) {138 const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);139 Symb += 1 + Symb->NumberOfAuxSymbols;140 Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);141 } else if (SymbolTable32) {142 const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);143 Symb += 1 + Symb->NumberOfAuxSymbols;144 Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);145 } else {146 llvm_unreachable("no symbol table pointer!");147 }148}149 150Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {151 return getSymbolName(getCOFFSymbol(Ref));152}153 154uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {155 return 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.161 COFFSymbolRef Symb = getCOFFSymbol(Ref);162 return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));163}164 165Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {166 uint64_t Result = cantFail(getSymbolValue(Ref));167 COFFSymbolRef Symb = getCOFFSymbol(Ref);168 int32_t SectionNumber = Symb.getSectionNumber();169 170 if (Symb.isAnyUndefined() || Symb.isCommon() ||171 COFF::isReservedSectionNumber(SectionNumber))172 return Result;173 174 Expected<const coff_section *> Section = getSection(SectionNumber);175 if (!Section)176 return Section.takeError();177 Result += (*Section)->VirtualAddress;178 179 // The section VirtualAddress does not include ImageBase, and we want to180 // return virtual addresses.181 Result += getImageBase();182 183 return Result;184}185 186Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {187 COFFSymbolRef Symb = getCOFFSymbol(Ref);188 int32_t SectionNumber = Symb.getSectionNumber();189 190 if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)191 return SymbolRef::ST_Function;192 if (Symb.isAnyUndefined())193 return SymbolRef::ST_Unknown;194 if (Symb.isCommon())195 return SymbolRef::ST_Data;196 if (Symb.isFileRecord())197 return SymbolRef::ST_File;198 199 // TODO: perhaps we need a new symbol type ST_Section.200 if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())201 return SymbolRef::ST_Debug;202 203 if (!COFF::isReservedSectionNumber(SectionNumber))204 return SymbolRef::ST_Data;205 206 return SymbolRef::ST_Other;207}208 209Expected<uint32_t> COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {210 COFFSymbolRef Symb = getCOFFSymbol(Ref);211 uint32_t Result = SymbolRef::SF_None;212 213 if (Symb.isExternal() || Symb.isWeakExternal())214 Result |= SymbolRef::SF_Global;215 216 if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {217 Result |= SymbolRef::SF_Weak;218 if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)219 Result |= SymbolRef::SF_Undefined;220 }221 222 if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)223 Result |= SymbolRef::SF_Absolute;224 225 if (Symb.isFileRecord())226 Result |= SymbolRef::SF_FormatSpecific;227 228 if (Symb.isSectionDefinition())229 Result |= SymbolRef::SF_FormatSpecific;230 231 if (Symb.isCommon())232 Result |= SymbolRef::SF_Common;233 234 if (Symb.isUndefined())235 Result |= SymbolRef::SF_Undefined;236 237 return Result;238}239 240uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {241 COFFSymbolRef Symb = getCOFFSymbol(Ref);242 return Symb.getValue();243}244 245Expected<section_iterator>246COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {247 COFFSymbolRef Symb = getCOFFSymbol(Ref);248 if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))249 return section_end();250 Expected<const coff_section *> Sec = getSection(Symb.getSectionNumber());251 if (!Sec)252 return Sec.takeError();253 DataRefImpl Ret;254 Ret.p = reinterpret_cast<uintptr_t>(*Sec);255 return section_iterator(SectionRef(Ret, this));256}257 258unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {259 COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());260 return Symb.getSectionNumber();261}262 263void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {264 const coff_section *Sec = toSec(Ref);265 Sec += 1;266 Ref.p = reinterpret_cast<uintptr_t>(Sec);267}268 269Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const {270 const coff_section *Sec = toSec(Ref);271 return getSectionName(Sec);272}273 274uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {275 const coff_section *Sec = toSec(Ref);276 uint64_t Result = Sec->VirtualAddress;277 278 // The section VirtualAddress does not include ImageBase, and we want to279 // return virtual addresses.280 Result += getImageBase();281 return Result;282}283 284uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {285 return toSec(Sec) - SectionTable;286}287 288uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {289 return getSectionSize(toSec(Ref));290}291 292Expected<ArrayRef<uint8_t>>293COFFObjectFile::getSectionContents(DataRefImpl Ref) const {294 const coff_section *Sec = toSec(Ref);295 ArrayRef<uint8_t> Res;296 if (Error E = getSectionContents(Sec, Res))297 return E;298 return Res;299}300 301uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {302 const coff_section *Sec = toSec(Ref);303 return Sec->getAlignment();304}305 306bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {307 return false;308}309 310bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {311 const coff_section *Sec = toSec(Ref);312 return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;313}314 315bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {316 const coff_section *Sec = toSec(Ref);317 return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;318}319 320bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {321 const coff_section *Sec = toSec(Ref);322 const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |323 COFF::IMAGE_SCN_MEM_READ |324 COFF::IMAGE_SCN_MEM_WRITE;325 return (Sec->Characteristics & BssFlags) == BssFlags;326}327 328// The .debug sections are the only debug sections for COFF329// (\see MCObjectFileInfo.cpp).330bool COFFObjectFile::isDebugSection(DataRefImpl Ref) const {331 Expected<StringRef> SectionNameOrErr = getSectionName(Ref);332 if (!SectionNameOrErr) {333 // TODO: Report the error message properly.334 consumeError(SectionNameOrErr.takeError());335 return false;336 }337 StringRef SectionName = SectionNameOrErr.get();338 return SectionName.starts_with(".debug");339}340 341unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {342 uintptr_t Offset =343 Sec.getRawDataRefImpl().p - reinterpret_cast<uintptr_t>(SectionTable);344 assert((Offset % sizeof(coff_section)) == 0);345 return (Offset / sizeof(coff_section)) + 1;346}347 348bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {349 const 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.352 return Sec->PointerToRawData == 0;353}354 355static uint32_t getNumberOfRelocations(const coff_section *Sec,356 MemoryBufferRef 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.361 if (Sec->hasExtendedRelocations()) {362 const coff_relocation *FirstReloc;363 if (Error E = getObject(FirstReloc, M,364 reinterpret_cast<const coff_relocation *>(365 base + Sec->PointerToRelocations))) {366 consumeError(std::move(E));367 return 0;368 }369 // -1 to exclude this first relocation entry.370 return FirstReloc->VirtualAddress - 1;371 }372 return Sec->NumberOfRelocations;373}374 375static const coff_relocation *376getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {377 uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);378 if (!NumRelocs)379 return nullptr;380 auto begin = reinterpret_cast<const coff_relocation *>(381 Base + Sec->PointerToRelocations);382 if (Sec->hasExtendedRelocations()) {383 // Skip the first relocation entry repurposed to store the number of384 // relocations.385 begin++;386 }387 if (auto E = Binary::checkOffset(M, reinterpret_cast<uintptr_t>(begin),388 sizeof(coff_relocation) * NumRelocs)) {389 consumeError(std::move(E));390 return nullptr;391 }392 return begin;393}394 395relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {396 const coff_section *Sec = toSec(Ref);397 const coff_relocation *begin = getFirstReloc(Sec, Data, base());398 if (begin && Sec->VirtualAddress != 0)399 report_fatal_error("Sections with relocations should have an address of 0");400 DataRefImpl Ret;401 Ret.p = reinterpret_cast<uintptr_t>(begin);402 return relocation_iterator(RelocationRef(Ret, this));403}404 405relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {406 const coff_section *Sec = toSec(Ref);407 const coff_relocation *I = getFirstReloc(Sec, Data, base());408 if (I)409 I += getNumberOfRelocations(Sec, Data, base());410 DataRefImpl Ret;411 Ret.p = reinterpret_cast<uintptr_t>(I);412 return relocation_iterator(RelocationRef(Ret, this));413}414 415// Initialize the pointer to the symbol table.416Error COFFObjectFile::initSymbolTablePtr() {417 if (COFFHeader)418 if (Error E = getObject(419 SymbolTable16, Data, base() + getPointerToSymbolTable(),420 (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))421 return E;422 423 if (COFFBigObjHeader)424 if (Error E = getObject(425 SymbolTable32, Data, base() + getPointerToSymbolTable(),426 (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))427 return 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.432 uint32_t StringTableOffset = getPointerToSymbolTable() +433 getNumberOfSymbols() * getSymbolTableEntrySize();434 const uint8_t *StringTableAddr = base() + StringTableOffset;435 const ulittle32_t *StringTableSizePtr;436 if (Error E = getObject(StringTableSizePtr, Data, StringTableAddr))437 return E;438 StringTableSize = *StringTableSizePtr;439 if (Error E = getObject(StringTable, Data, StringTableAddr, StringTableSize))440 return 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.444 if (StringTableSize < 4)445 StringTableSize = 4;446 447 // Check that the string table is null terminated if has any in it.448 if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)449 return createStringError(object_error::parse_failed,450 "string table missing null terminator");451 return Error::success();452}453 454uint64_t COFFObjectFile::getImageBase() const {455 if (PE32Header)456 return PE32Header->ImageBase;457 else if (PE32PlusHeader)458 return PE32PlusHeader->ImageBase;459 // This actually comes up in practice.460 return 0;461}462 463// Returns the file offset for the given VA.464Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {465 uint64_t ImageBase = getImageBase();466 uint64_t Rva = Addr - ImageBase;467 assert(Rva <= UINT32_MAX);468 return 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,473 const char *ErrorContext) const {474 for (const SectionRef &S : sections()) {475 const coff_section *Section = getCOFFSection(S);476 uint32_t SectionStart = Section->VirtualAddress;477 uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;478 if (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.488 if (Section->SizeOfRawData < Section->VirtualSize &&489 Addr >= SectionStart + Section->SizeOfRawData) {490 return make_error<SectionStrippedError>();491 }492 uint32_t Offset = Addr - SectionStart;493 Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +494 Offset;495 return Error::success();496 }497 }498 if (ErrorContext)499 return createStringError(object_error::parse_failed,500 "RVA 0x%" PRIx32 " for %s not found", Addr,501 ErrorContext);502 return createStringError(object_error::parse_failed,503 "RVA 0x%" PRIx32 " not found", Addr);504}505 506Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,507 ArrayRef<uint8_t> &Contents,508 const char *ErrorContext) const {509 for (const SectionRef &S : sections()) {510 const coff_section *Section = getCOFFSection(S);511 uint32_t SectionStart = Section->VirtualAddress;512 // Check if this RVA is within the section bounds. Be careful about integer513 // overflow.514 uint32_t OffsetIntoSection = RVA - SectionStart;515 if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&516 Size <= Section->VirtualSize - OffsetIntoSection) {517 uintptr_t Begin = reinterpret_cast<uintptr_t>(base()) +518 Section->PointerToRawData + OffsetIntoSection;519 Contents =520 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);521 return Error::success();522 }523 }524 if (ErrorContext)525 return createStringError(object_error::parse_failed,526 "RVA 0x%" PRIx32 " for %s not found", RVA,527 ErrorContext);528 return 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/Name533// table entry.534Error COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,535 StringRef &Name) const {536 uintptr_t IntPtr = 0;537 if (Error E = getRvaPtr(Rva, IntPtr))538 return E;539 const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);540 Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);541 Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));542 return Error::success();543}544 545Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,546 const codeview::DebugInfo *&PDBInfo,547 StringRef &PDBFileName) const {548 ArrayRef<uint8_t> InfoBytes;549 if (Error E =550 getRvaAndSizeAsBytes(DebugDir->AddressOfRawData, DebugDir->SizeOfData,551 InfoBytes, "PDB info"))552 return E;553 if (InfoBytes.size() < sizeof(*PDBInfo) + 1)554 return createStringError(object_error::parse_failed, "PDB info too small");555 PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());556 InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));557 PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),558 InfoBytes.size());559 // Truncate the name at the first null byte. Ignore any padding.560 PDBFileName = PDBFileName.split('\0').first;561 return Error::success();562}563 564Error COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,565 StringRef &PDBFileName) const {566 for (const debug_directory &D : debug_directories())567 if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)568 return getDebugPDBInfo(&D, PDBInfo, PDBFileName);569 // If we get here, there is no PDB info to return.570 PDBInfo = nullptr;571 PDBFileName = StringRef();572 return 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.579 const data_directory *DataEntry = getDataDirectory(COFF::IMPORT_TABLE);580 if (!DataEntry)581 return Error::success();582 583 // Do nothing if the pointer to import table is NULL.584 if (DataEntry->RelativeVirtualAddress == 0)585 return Error::success();586 587 uint32_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.591 uintptr_t IntPtr = 0;592 if (Error E = getRvaPtr(ImportTableRva, IntPtr, "import table"))593 return E;594 if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))595 return E;596 ImportDirectory = reinterpret_cast<597 const coff_import_directory_table_entry *>(IntPtr);598 return Error::success();599}600 601// Initializes DelayImportDirectory and NumberOfDelayImportDirectory.602Error COFFObjectFile::initDelayImportTablePtr() {603 const data_directory *DataEntry =604 getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR);605 if (!DataEntry)606 return Error::success();607 if (DataEntry->RelativeVirtualAddress == 0)608 return Error::success();609 610 uint32_t RVA = DataEntry->RelativeVirtualAddress;611 NumberOfDelayImportDirectory = DataEntry->Size /612 sizeof(delay_import_directory_table_entry) - 1;613 614 uintptr_t IntPtr = 0;615 if (Error E = getRvaPtr(RVA, IntPtr, "delay import table"))616 return E;617 if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))618 return E;619 620 DelayImportDirectory = reinterpret_cast<621 const delay_import_directory_table_entry *>(IntPtr);622 return 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.629 const data_directory *DataEntry = getDataDirectory(COFF::EXPORT_TABLE);630 if (!DataEntry)631 return Error::success();632 633 // Do nothing if the pointer to export table is NULL.634 if (DataEntry->RelativeVirtualAddress == 0)635 return Error::success();636 637 uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;638 uintptr_t IntPtr = 0;639 if (Error E = getRvaPtr(ExportTableRva, IntPtr, "export table"))640 return E;641 if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))642 return E;643 644 ExportDirectory =645 reinterpret_cast<const export_directory_table_entry *>(IntPtr);646 return Error::success();647}648 649Error COFFObjectFile::initBaseRelocPtr() {650 const data_directory *DataEntry =651 getDataDirectory(COFF::BASE_RELOCATION_TABLE);652 if (!DataEntry)653 return Error::success();654 if (DataEntry->RelativeVirtualAddress == 0)655 return Error::success();656 657 uintptr_t IntPtr = 0;658 if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,659 "base reloc table"))660 return E;661 if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))662 return E;663 664 BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(665 IntPtr);666 BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(667 IntPtr + DataEntry->Size);668 // FIXME: Verify the section containing BaseRelocHeader has at least669 // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.670 return Error::success();671}672 673Error COFFObjectFile::initDebugDirectoryPtr() {674 // Get the RVA of the debug directory. Do nothing if it does not exist.675 const data_directory *DataEntry = getDataDirectory(COFF::DEBUG_DIRECTORY);676 if (!DataEntry)677 return Error::success();678 679 // Do nothing if the RVA is NULL.680 if (DataEntry->RelativeVirtualAddress == 0)681 return Error::success();682 683 // Check that the size is a multiple of the entry size.684 if (DataEntry->Size % sizeof(debug_directory) != 0)685 return createStringError(object_error::parse_failed,686 "debug directory has uneven size");687 688 uintptr_t IntPtr = 0;689 if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,690 "debug directory"))691 return E;692 if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))693 return E;694 695 DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);696 DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(697 IntPtr + DataEntry->Size);698 // FIXME: Verify the section containing DebugDirectoryBegin has at least699 // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.700 return Error::success();701}702 703Error COFFObjectFile::initTLSDirectoryPtr() {704 // Get the RVA of the TLS directory. Do nothing if it does not exist.705 const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);706 if (!DataEntry)707 return Error::success();708 709 // Do nothing if the RVA is NULL.710 if (DataEntry->RelativeVirtualAddress == 0)711 return Error::success();712 713 uint64_t DirSize =714 is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32);715 716 // Check that the size is correct.717 if (DataEntry->Size != DirSize)718 return createStringError(719 object_error::parse_failed,720 "TLS Directory size (%u) is not the expected size (%" PRIu64 ").",721 static_cast<uint32_t>(DataEntry->Size), DirSize);722 723 uintptr_t IntPtr = 0;724 if (Error E =725 getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory"))726 return E;727 if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))728 return E;729 730 if (is64())731 TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);732 else733 TLSDirectory32 = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);734 735 return Error::success();736}737 738Error COFFObjectFile::initLoadConfigPtr() {739 // Get the RVA of the debug directory. Do nothing if it does not exist.740 const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);741 if (!DataEntry)742 return Error::success();743 744 // Do nothing if the RVA is NULL.745 if (DataEntry->RelativeVirtualAddress == 0)746 return Error::success();747 uintptr_t IntPtr = 0;748 if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,749 "load config table"))750 return E;751 if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))752 return E;753 754 LoadConfig = (const void *)IntPtr;755 756 if (is64()) {757 auto Config = getLoadConfig64();758 if (Config->Size >=759 offsetof(coff_load_configuration64, CHPEMetadataPointer) +760 sizeof(Config->CHPEMetadataPointer) &&761 Config->CHPEMetadataPointer) {762 uint64_t ChpeOff = Config->CHPEMetadataPointer;763 if (Error E =764 getRvaPtr(ChpeOff - getImageBase(), IntPtr, "CHPE metadata"))765 return E;766 if (Error E = checkOffset(Data, IntPtr, sizeof(*CHPEMetadata)))767 return E;768 769 CHPEMetadata = reinterpret_cast<const chpe_metadata *>(IntPtr);770 771 // Validate CHPE metadata772 if (CHPEMetadata->CodeMapCount) {773 if (Error E = getRvaPtr(CHPEMetadata->CodeMap, IntPtr, "CHPE code map"))774 return E;775 if (Error E = checkOffset(Data, IntPtr,776 CHPEMetadata->CodeMapCount *777 sizeof(chpe_range_entry)))778 return E;779 }780 781 if (CHPEMetadata->CodeRangesToEntryPointsCount) {782 if (Error E = getRvaPtr(CHPEMetadata->CodeRangesToEntryPoints, IntPtr,783 "CHPE entry point ranges"))784 return E;785 if (Error E = checkOffset(Data, IntPtr,786 CHPEMetadata->CodeRangesToEntryPointsCount *787 sizeof(chpe_code_range_entry)))788 return E;789 }790 791 if (CHPEMetadata->RedirectionMetadataCount) {792 if (Error E = getRvaPtr(CHPEMetadata->RedirectionMetadata, IntPtr,793 "CHPE redirection metadata"))794 return E;795 if (Error E = checkOffset(Data, IntPtr,796 CHPEMetadata->RedirectionMetadataCount *797 sizeof(chpe_redirection_entry)))798 return E;799 }800 }801 802 if (Config->Size >=803 offsetof(coff_load_configuration64, DynamicValueRelocTableSection) +804 sizeof(Config->DynamicValueRelocTableSection))805 if (Error E = initDynamicRelocPtr(Config->DynamicValueRelocTableSection,806 Config->DynamicValueRelocTableOffset))807 return E;808 } else {809 auto Config = getLoadConfig32();810 if (Config->Size >=811 offsetof(coff_load_configuration32, DynamicValueRelocTableSection) +812 sizeof(Config->DynamicValueRelocTableSection)) {813 if (Error E = initDynamicRelocPtr(Config->DynamicValueRelocTableSection,814 Config->DynamicValueRelocTableOffset))815 return E;816 }817 }818 return Error::success();819}820 821Error COFFObjectFile::initDynamicRelocPtr(uint32_t SectionIndex,822 uint32_t SectionOffset) {823 Expected<const coff_section *> Section = getSection(SectionIndex);824 if (!Section)825 return Section.takeError();826 if (!*Section)827 return Error::success();828 829 // Interpret and validate dynamic relocations.830 ArrayRef<uint8_t> Contents;831 if (Error E = getSectionContents(*Section, Contents))832 return E;833 834 Contents = Contents.drop_front(SectionOffset);835 if (Contents.size() < sizeof(coff_dynamic_reloc_table))836 return createStringError(object_error::parse_failed,837 "Too large DynamicValueRelocTableOffset (" +838 Twine(SectionOffset) + ")");839 840 DynamicRelocTable =841 reinterpret_cast<const coff_dynamic_reloc_table *>(Contents.data());842 843 if (DynamicRelocTable->Version != 1 && DynamicRelocTable->Version != 2)844 return createStringError(object_error::parse_failed,845 "Unsupported dynamic relocations table version (" +846 Twine(DynamicRelocTable->Version) + ")");847 if (DynamicRelocTable->Size > Contents.size() - sizeof(*DynamicRelocTable))848 return createStringError(object_error::parse_failed,849 "Indvalid dynamic relocations directory size (" +850 Twine(DynamicRelocTable->Size) + ")");851 852 for (auto DynReloc : dynamic_relocs()) {853 if (Error e = DynReloc.validate())854 return e;855 }856 857 return Error::success();858}859 860Expected<std::unique_ptr<COFFObjectFile>>861COFFObjectFile::create(MemoryBufferRef Object) {862 std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object)));863 if (Error E = Obj->initialize())864 return E;865 return std::move(Obj);866}867 868COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)869 : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),870 COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),871 DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),872 SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),873 ImportDirectory(nullptr), DelayImportDirectory(nullptr),874 NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),875 BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),876 DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),877 TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}878 879static Error ignoreStrippedErrors(Error E) {880 if (E.isA<SectionStrippedError>()) {881 consumeError(std::move(E));882 return Error::success();883 }884 return E;885}886 887Error COFFObjectFile::initialize() {888 // Check that we at least have enough room for a header.889 std::error_code EC;890 if (!checkSize(Data, EC, sizeof(coff_file_header)))891 return errorCodeToError(EC);892 893 // The current location in the file where we are looking at.894 uint64_t CurPtr = 0;895 896 // PE header is optional and is present only in executables. If it exists,897 // it is placed right after COFF header.898 bool HasPEHeader = false;899 900 // Check if this is a PE/COFF file.901 if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {902 // PE/COFF, seek through MS-DOS compatibility stub and 4-byte903 // PE signature to find 'normal' COFF header.904 const auto *DH = reinterpret_cast<const dos_header *>(base());905 if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {906 CurPtr = DH->AddressOfNewExeHeader;907 // Check the PE magic bytes. ("PE\0\0")908 if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {909 return createStringError(object_error::parse_failed,910 "incorrect PE magic");911 }912 CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.913 HasPEHeader = true;914 }915 }916 917 if (Error E = getObject(COFFHeader, Data, base() + CurPtr))918 return E;919 920 // It might be a bigobj file, let's check. Note that COFF bigobj and COFF921 // import libraries share a common prefix but bigobj is more restrictive.922 if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&923 COFFHeader->NumberOfSections == uint16_t(0xffff) &&924 checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {925 if (Error E = getObject(COFFBigObjHeader, Data, base() + CurPtr))926 return E;927 928 // Verify that we are dealing with bigobj.929 if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&930 std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,931 sizeof(COFF::BigObjMagic)) == 0) {932 COFFHeader = nullptr;933 CurPtr += sizeof(coff_bigobj_file_header);934 } else {935 // It's not a bigobj.936 COFFBigObjHeader = nullptr;937 }938 }939 if (COFFHeader) {940 // The prior checkSize call may have failed. This isn't a hard error941 // because we were just trying to sniff out bigobj.942 EC = std::error_code();943 CurPtr += sizeof(coff_file_header);944 945 if (COFFHeader->isImportLibrary())946 return errorCodeToError(EC);947 }948 949 if (HasPEHeader) {950 const pe32_header *Header;951 if (Error E = getObject(Header, Data, base() + CurPtr))952 return E;953 954 const uint8_t *DataDirAddr;955 uint64_t DataDirSize;956 if (Header->Magic == COFF::PE32Header::PE32) {957 PE32Header = Header;958 DataDirAddr = base() + CurPtr + sizeof(pe32_header);959 DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;960 } else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {961 PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);962 DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);963 DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;964 } else {965 // It's neither PE32 nor PE32+.966 return createStringError(object_error::parse_failed,967 "incorrect PE magic");968 }969 if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))970 return E;971 }972 973 if (COFFHeader)974 CurPtr += COFFHeader->SizeOfOptionalHeader;975 976 assert(COFFHeader || COFFBigObjHeader);977 978 if (Error E =979 getObject(SectionTable, Data, base() + CurPtr,980 (uint64_t)getNumberOfSections() * sizeof(coff_section)))981 return E;982 983 // Initialize the pointer to the symbol table.984 if (getPointerToSymbolTable() != 0) {985 if (Error E = initSymbolTablePtr()) {986 // Recover from errors reading the symbol table.987 consumeError(std::move(E));988 SymbolTable16 = nullptr;989 SymbolTable32 = nullptr;990 StringTable = nullptr;991 StringTableSize = 0;992 }993 } else {994 // We had better not have any symbols if we don't have a symbol table.995 if (getNumberOfSymbols() != 0) {996 return createStringError(object_error::parse_failed,997 "symbol table missing");998 }999 }1000 1001 // Initialize the pointer to the beginning of the import table.1002 if (Error E = ignoreStrippedErrors(initImportTablePtr()))1003 return E;1004 if (Error E = ignoreStrippedErrors(initDelayImportTablePtr()))1005 return E;1006 1007 // Initialize the pointer to the export table.1008 if (Error E = ignoreStrippedErrors(initExportTablePtr()))1009 return E;1010 1011 // Initialize the pointer to the base relocation table.1012 if (Error E = ignoreStrippedErrors(initBaseRelocPtr()))1013 return E;1014 1015 // Initialize the pointer to the debug directory.1016 if (Error E = ignoreStrippedErrors(initDebugDirectoryPtr()))1017 return E;1018 1019 // Initialize the pointer to the TLS directory.1020 if (Error E = ignoreStrippedErrors(initTLSDirectoryPtr()))1021 return E;1022 1023 if (Error E = ignoreStrippedErrors(initLoadConfigPtr()))1024 return E;1025 1026 return Error::success();1027}1028 1029basic_symbol_iterator COFFObjectFile::symbol_begin() const {1030 DataRefImpl Ret;1031 Ret.p = getSymbolTable();1032 return basic_symbol_iterator(SymbolRef(Ret, this));1033}1034 1035basic_symbol_iterator COFFObjectFile::symbol_end() const {1036 // The symbol table ends where the string table begins.1037 DataRefImpl Ret;1038 Ret.p = reinterpret_cast<uintptr_t>(StringTable);1039 return basic_symbol_iterator(SymbolRef(Ret, this));1040}1041 1042import_directory_iterator COFFObjectFile::import_directory_begin() const {1043 if (!ImportDirectory)1044 return import_directory_end();1045 if (ImportDirectory->isNull())1046 return import_directory_end();1047 return import_directory_iterator(1048 ImportDirectoryEntryRef(ImportDirectory, 0, this));1049}1050 1051import_directory_iterator COFFObjectFile::import_directory_end() const {1052 return import_directory_iterator(1053 ImportDirectoryEntryRef(nullptr, -1, this));1054}1055 1056delay_import_directory_iterator1057COFFObjectFile::delay_import_directory_begin() const {1058 return delay_import_directory_iterator(1059 DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));1060}1061 1062delay_import_directory_iterator1063COFFObjectFile::delay_import_directory_end() const {1064 return delay_import_directory_iterator(1065 DelayImportDirectoryEntryRef(1066 DelayImportDirectory, NumberOfDelayImportDirectory, this));1067}1068 1069export_directory_iterator COFFObjectFile::export_directory_begin() const {1070 return export_directory_iterator(1071 ExportDirectoryEntryRef(ExportDirectory, 0, this));1072}1073 1074export_directory_iterator COFFObjectFile::export_directory_end() const {1075 if (!ExportDirectory)1076 return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));1077 ExportDirectoryEntryRef Ref(ExportDirectory,1078 ExportDirectory->AddressTableEntries, this);1079 return export_directory_iterator(Ref);1080}1081 1082section_iterator COFFObjectFile::section_begin() const {1083 DataRefImpl Ret;1084 Ret.p = reinterpret_cast<uintptr_t>(SectionTable);1085 return section_iterator(SectionRef(Ret, this));1086}1087 1088section_iterator COFFObjectFile::section_end() const {1089 DataRefImpl Ret;1090 int NumSections =1091 COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();1092 Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);1093 return section_iterator(SectionRef(Ret, this));1094}1095 1096base_reloc_iterator COFFObjectFile::base_reloc_begin() const {1097 return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));1098}1099 1100base_reloc_iterator COFFObjectFile::base_reloc_end() const {1101 return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));1102}1103 1104dynamic_reloc_iterator COFFObjectFile::dynamic_reloc_begin() const {1105 const void *Header = DynamicRelocTable ? DynamicRelocTable + 1 : nullptr;1106 return dynamic_reloc_iterator(DynamicRelocRef(Header, this));1107}1108 1109dynamic_reloc_iterator COFFObjectFile::dynamic_reloc_end() const {1110 const void *Header = nullptr;1111 if (DynamicRelocTable)1112 Header = reinterpret_cast<const uint8_t *>(DynamicRelocTable + 1) +1113 DynamicRelocTable->Size;1114 return dynamic_reloc_iterator(DynamicRelocRef(Header, this));1115}1116 1117uint8_t COFFObjectFile::getBytesInAddress() const {1118 return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;1119}1120 1121StringRef COFFObjectFile::getFileFormatName() const {1122 switch(getMachine()) {1123 case COFF::IMAGE_FILE_MACHINE_I386:1124 return "COFF-i386";1125 case COFF::IMAGE_FILE_MACHINE_AMD64:1126 return "COFF-x86-64";1127 case COFF::IMAGE_FILE_MACHINE_ARMNT:1128 return "COFF-ARM";1129 case COFF::IMAGE_FILE_MACHINE_ARM64:1130 return "COFF-ARM64";1131 case COFF::IMAGE_FILE_MACHINE_ARM64EC:1132 return "COFF-ARM64EC";1133 case COFF::IMAGE_FILE_MACHINE_ARM64X:1134 return "COFF-ARM64X";1135 case COFF::IMAGE_FILE_MACHINE_R4000:1136 return "COFF-MIPS";1137 default:1138 return "COFF-<unknown arch>";1139 }1140}1141 1142Triple::ArchType COFFObjectFile::getArch() const {1143 return getMachineArchType(getMachine());1144}1145 1146Expected<uint64_t> COFFObjectFile::getStartAddress() const {1147 if (PE32Header)1148 return PE32Header->AddressOfEntryPoint;1149 return 0;1150}1151 1152iterator_range<import_directory_iterator>1153COFFObjectFile::import_directories() const {1154 return make_range(import_directory_begin(), import_directory_end());1155}1156 1157iterator_range<delay_import_directory_iterator>1158COFFObjectFile::delay_import_directories() const {1159 return make_range(delay_import_directory_begin(),1160 delay_import_directory_end());1161}1162 1163iterator_range<export_directory_iterator>1164COFFObjectFile::export_directories() const {1165 return make_range(export_directory_begin(), export_directory_end());1166}1167 1168iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {1169 return make_range(base_reloc_begin(), base_reloc_end());1170}1171 1172iterator_range<dynamic_reloc_iterator> COFFObjectFile::dynamic_relocs() const {1173 return make_range(dynamic_reloc_begin(), dynamic_reloc_end());1174}1175 1176const data_directory *COFFObjectFile::getDataDirectory(uint32_t Index) const {1177 if (!DataDirectory)1178 return nullptr;1179 assert(PE32Header || PE32PlusHeader);1180 uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize1181 : PE32PlusHeader->NumberOfRvaAndSize;1182 if (Index >= NumEnt)1183 return nullptr;1184 return &DataDirectory[Index];1185}1186 1187Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {1188 // Perhaps getting the section of a reserved section index should be an error,1189 // but callers rely on this to return null.1190 if (COFF::isReservedSectionNumber(Index))1191 return (const coff_section *)nullptr;1192 if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {1193 // We already verified the section table data, so no need to check again.1194 return SectionTable + (Index - 1);1195 }1196 return createStringError(object_error::parse_failed,1197 "section index out of bounds");1198}1199 1200Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {1201 if (StringTableSize <= 4)1202 // Tried to get a string from an empty string table.1203 return createStringError(object_error::parse_failed, "string table empty");1204 if (Offset >= StringTableSize)1205 return errorCodeToError(object_error::unexpected_eof);1206 return StringRef(StringTable + Offset);1207}1208 1209Expected<StringRef> COFFObjectFile::getSymbolName(COFFSymbolRef Symbol) const {1210 return getSymbolName(Symbol.getGeneric());1211}1212 1213Expected<StringRef>1214COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol) const {1215 // Check for string table entry. First 4 bytes are 0.1216 if (Symbol->Name.Offset.Zeroes == 0)1217 return getString(Symbol->Name.Offset.Offset);1218 1219 // Null terminated, let ::strlen figure out the length.1220 if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)1221 return StringRef(Symbol->Name.ShortName);1222 1223 // Not null terminated, use all 8 bytes.1224 return StringRef(Symbol->Name.ShortName, COFF::NameSize);1225}1226 1227ArrayRef<uint8_t>1228COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {1229 const uint8_t *Aux = nullptr;1230 1231 size_t SymbolSize = getSymbolTableEntrySize();1232 if (Symbol.getNumberOfAuxSymbols() > 0) {1233 // AUX data comes immediately after the symbol in COFF1234 Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;1235#ifndef NDEBUG1236 // Verify that the Aux symbol points to a valid entry in the symbol table.1237 uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());1238 if (Offset < getPointerToSymbolTable() ||1239 Offset >=1240 getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))1241 report_fatal_error("Aux Symbol data was outside of symbol table.");1242 1243 assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&1244 "Aux Symbol data did not point to the beginning of a symbol");1245#endif1246 }1247 return ArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);1248}1249 1250uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {1251 uintptr_t Offset =1252 reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();1253 assert(Offset % getSymbolTableEntrySize() == 0 &&1254 "Symbol did not point to the beginning of a symbol");1255 size_t Index = Offset / getSymbolTableEntrySize();1256 assert(Index < getNumberOfSymbols());1257 return Index;1258}1259 1260Expected<StringRef>1261COFFObjectFile::getSectionName(const coff_section *Sec) const {1262 StringRef Name = StringRef(Sec->Name, COFF::NameSize).split('\0').first;1263 1264 // Check for string table entry. First byte is '/'.1265 if (Name.starts_with("/")) {1266 uint32_t Offset;1267 if (Name.starts_with("//")) {1268 if (decodeBase64StringEntry(Name.substr(2), Offset))1269 return createStringError(object_error::parse_failed,1270 "invalid section name");1271 } else {1272 if (Name.substr(1).getAsInteger(10, Offset))1273 return createStringError(object_error::parse_failed,1274 "invalid section name");1275 }1276 return getString(Offset);1277 }1278 1279 return Name;1280}1281 1282uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {1283 // SizeOfRawData and VirtualSize change what they represent depending on1284 // whether or not we have an executable image.1285 //1286 // For object files, SizeOfRawData contains the size of section's data;1287 // VirtualSize should be zero but isn't due to buggy COFF writers.1288 //1289 // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the1290 // actual section size is in VirtualSize. It is possible for VirtualSize to1291 // be greater than SizeOfRawData; the contents past that point should be1292 // considered to be zero.1293 if (getDOSHeader())1294 return std::min(Sec->VirtualSize, Sec->SizeOfRawData);1295 return Sec->SizeOfRawData;1296}1297 1298Error COFFObjectFile::getSectionContents(const coff_section *Sec,1299 ArrayRef<uint8_t> &Res) const {1300 // In COFF, a virtual section won't have any in-file1301 // content, so the file pointer to the content will be zero.1302 if (Sec->PointerToRawData == 0)1303 return Error::success();1304 // The only thing that we need to verify is that the contents is contained1305 // within the file bounds. We don't need to make sure it doesn't cover other1306 // data, as there's nothing that says that is not allowed.1307 uintptr_t ConStart =1308 reinterpret_cast<uintptr_t>(base()) + Sec->PointerToRawData;1309 uint32_t SectionSize = getSectionSize(Sec);1310 if (Error E = checkOffset(Data, ConStart, SectionSize))1311 return E;1312 Res = ArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);1313 return Error::success();1314}1315 1316const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {1317 return reinterpret_cast<const coff_relocation*>(Rel.p);1318}1319 1320void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {1321 Rel.p = reinterpret_cast<uintptr_t>(1322 reinterpret_cast<const coff_relocation*>(Rel.p) + 1);1323}1324 1325uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {1326 const coff_relocation *R = toRel(Rel);1327 return R->VirtualAddress;1328}1329 1330symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {1331 const coff_relocation *R = toRel(Rel);1332 DataRefImpl Ref;1333 if (R->SymbolTableIndex >= getNumberOfSymbols())1334 return symbol_end();1335 if (SymbolTable16)1336 Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);1337 else if (SymbolTable32)1338 Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);1339 else1340 llvm_unreachable("no symbol table pointer!");1341 return symbol_iterator(SymbolRef(Ref, this));1342}1343 1344uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {1345 const coff_relocation* R = toRel(Rel);1346 return R->Type;1347}1348 1349const coff_section *1350COFFObjectFile::getCOFFSection(const SectionRef &Section) const {1351 return toSec(Section.getRawDataRefImpl());1352}1353 1354COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {1355 if (SymbolTable16)1356 return toSymb<coff_symbol16>(Ref);1357 if (SymbolTable32)1358 return toSymb<coff_symbol32>(Ref);1359 llvm_unreachable("no symbol table pointer!");1360}1361 1362COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {1363 return getCOFFSymbol(Symbol.getRawDataRefImpl());1364}1365 1366const coff_relocation *1367COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {1368 return toRel(Reloc.getRawDataRefImpl());1369}1370 1371ArrayRef<coff_relocation>1372COFFObjectFile::getRelocations(const coff_section *Sec) const {1373 return {getFirstReloc(Sec, Data, base()),1374 getNumberOfRelocations(Sec, Data, base())};1375}1376 1377#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \1378 case COFF::reloc_type: \1379 return #reloc_type;1380 1381StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {1382 switch (getArch()) {1383 case Triple::x86_64:1384 switch (Type) {1385 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);1386 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);1387 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);1388 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);1389 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);1390 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);1391 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);1392 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);1393 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);1394 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);1395 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);1396 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);1397 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);1398 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);1399 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);1400 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);1401 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);1402 default:1403 return "Unknown";1404 }1405 break;1406 case Triple::thumb:1407 switch (Type) {1408 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);1409 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);1410 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);1411 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);1412 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);1413 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);1414 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);1415 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);1416 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32);1417 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);1418 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);1419 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);1420 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);1421 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);1422 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);1423 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);1424 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR);1425 default:1426 return "Unknown";1427 }1428 break;1429 case Triple::aarch64:1430 switch (Type) {1431 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);1432 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);1433 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);1434 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);1435 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);1436 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);1437 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);1438 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);1439 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);1440 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);1441 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);1442 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);1443 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);1444 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);1445 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);1446 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);1447 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);1448 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32);1449 default:1450 return "Unknown";1451 }1452 break;1453 case Triple::x86:1454 switch (Type) {1455 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);1456 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);1457 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);1458 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);1459 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);1460 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);1461 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);1462 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);1463 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);1464 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);1465 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);1466 default:1467 return "Unknown";1468 }1469 break;1470 case Triple::mipsel:1471 switch (Type) {1472 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_ABSOLUTE);1473 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHALF);1474 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORD);1475 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR);1476 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFHI);1477 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFLO);1478 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_GPREL);1479 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_LITERAL);1480 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECTION);1481 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECREL);1482 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELLO);1483 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_SECRELHI);1484 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_JMPADDR16);1485 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_REFWORDNB);1486 LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_MIPS_PAIR);1487 default:1488 return "Unknown";1489 }1490 break;1491 default:1492 return "Unknown";1493 }1494}1495 1496#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME1497 1498void COFFObjectFile::getRelocationTypeName(1499 DataRefImpl Rel, SmallVectorImpl<char> &Result) const {1500 const coff_relocation *Reloc = toRel(Rel);1501 StringRef Res = getRelocationTypeName(Reloc->Type);1502 Result.append(Res.begin(), Res.end());1503}1504 1505bool COFFObjectFile::isRelocatableObject() const {1506 return !DataDirectory;1507}1508 1509StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {1510 return StringSwitch<StringRef>(Name)1511 .Case("eh_fram", "eh_frame")1512 .Default(Name);1513}1514 1515std::unique_ptr<MemoryBuffer> COFFObjectFile::getHybridObjectView() const {1516 if (getMachine() != COFF::IMAGE_FILE_MACHINE_ARM64X)1517 return nullptr;1518 1519 std::unique_ptr<WritableMemoryBuffer> HybridView;1520 1521 for (auto DynReloc : dynamic_relocs()) {1522 if (DynReloc.getType() != COFF::IMAGE_DYNAMIC_RELOCATION_ARM64X)1523 continue;1524 1525 for (auto reloc : DynReloc.arm64x_relocs()) {1526 if (!HybridView) {1527 HybridView =1528 WritableMemoryBuffer::getNewUninitMemBuffer(Data.getBufferSize());1529 memcpy(HybridView->getBufferStart(), Data.getBufferStart(),1530 Data.getBufferSize());1531 }1532 1533 uint32_t RVA = reloc.getRVA();1534 void *Ptr;1535 uintptr_t IntPtr;1536 if (RVA & ~0xfff) {1537 cantFail(getRvaPtr(RVA, IntPtr));1538 Ptr = HybridView->getBufferStart() + IntPtr -1539 reinterpret_cast<uintptr_t>(base());1540 } else {1541 // PE header relocation.1542 Ptr = HybridView->getBufferStart() + RVA;1543 }1544 1545 switch (reloc.getType()) {1546 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:1547 memset(Ptr, 0, reloc.getSize());1548 break;1549 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE: {1550 auto Value = static_cast<ulittle64_t>(reloc.getValue());1551 memcpy(Ptr, &Value, reloc.getSize());1552 break;1553 }1554 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:1555 *reinterpret_cast<ulittle32_t *>(Ptr) += reloc.getValue();1556 break;1557 }1558 }1559 }1560 return HybridView;1561}1562 1563bool ImportDirectoryEntryRef::1564operator==(const ImportDirectoryEntryRef &Other) const {1565 return ImportTable == Other.ImportTable && Index == Other.Index;1566}1567 1568void ImportDirectoryEntryRef::moveNext() {1569 ++Index;1570 if (ImportTable[Index].isNull()) {1571 Index = -1;1572 ImportTable = nullptr;1573 }1574}1575 1576Error ImportDirectoryEntryRef::getImportTableEntry(1577 const coff_import_directory_table_entry *&Result) const {1578 return getObject(Result, OwningObject->Data, ImportTable + Index);1579}1580 1581static imported_symbol_iterator1582makeImportedSymbolIterator(const COFFObjectFile *Object,1583 uintptr_t Ptr, int Index) {1584 if (Object->getBytesInAddress() == 4) {1585 auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);1586 return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));1587 }1588 auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);1589 return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));1590}1591 1592static imported_symbol_iterator1593importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {1594 uintptr_t IntPtr = 0;1595 // FIXME: Handle errors.1596 cantFail(Object->getRvaPtr(RVA, IntPtr));1597 return makeImportedSymbolIterator(Object, IntPtr, 0);1598}1599 1600static imported_symbol_iterator1601importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {1602 uintptr_t IntPtr = 0;1603 // FIXME: Handle errors.1604 cantFail(Object->getRvaPtr(RVA, IntPtr));1605 // Forward the pointer to the last entry which is null.1606 int Index = 0;1607 if (Object->getBytesInAddress() == 4) {1608 auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);1609 while (*Entry++)1610 ++Index;1611 } else {1612 auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);1613 while (*Entry++)1614 ++Index;1615 }1616 return makeImportedSymbolIterator(Object, IntPtr, Index);1617}1618 1619imported_symbol_iterator1620ImportDirectoryEntryRef::imported_symbol_begin() const {1621 return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,1622 OwningObject);1623}1624 1625imported_symbol_iterator1626ImportDirectoryEntryRef::imported_symbol_end() const {1627 return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,1628 OwningObject);1629}1630 1631iterator_range<imported_symbol_iterator>1632ImportDirectoryEntryRef::imported_symbols() const {1633 return make_range(imported_symbol_begin(), imported_symbol_end());1634}1635 1636imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {1637 return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,1638 OwningObject);1639}1640 1641imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {1642 return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,1643 OwningObject);1644}1645 1646iterator_range<imported_symbol_iterator>1647ImportDirectoryEntryRef::lookup_table_symbols() const {1648 return make_range(lookup_table_begin(), lookup_table_end());1649}1650 1651Error ImportDirectoryEntryRef::getName(StringRef &Result) const {1652 uintptr_t IntPtr = 0;1653 if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr,1654 "import directory name"))1655 return E;1656 Result = StringRef(reinterpret_cast<const char *>(IntPtr));1657 return Error::success();1658}1659 1660Error1661ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {1662 Result = ImportTable[Index].ImportLookupTableRVA;1663 return Error::success();1664}1665 1666Error ImportDirectoryEntryRef::getImportAddressTableRVA(1667 uint32_t &Result) const {1668 Result = ImportTable[Index].ImportAddressTableRVA;1669 return Error::success();1670}1671 1672bool DelayImportDirectoryEntryRef::1673operator==(const DelayImportDirectoryEntryRef &Other) const {1674 return Table == Other.Table && Index == Other.Index;1675}1676 1677void DelayImportDirectoryEntryRef::moveNext() {1678 ++Index;1679}1680 1681imported_symbol_iterator1682DelayImportDirectoryEntryRef::imported_symbol_begin() const {1683 return importedSymbolBegin(Table[Index].DelayImportNameTable,1684 OwningObject);1685}1686 1687imported_symbol_iterator1688DelayImportDirectoryEntryRef::imported_symbol_end() const {1689 return importedSymbolEnd(Table[Index].DelayImportNameTable,1690 OwningObject);1691}1692 1693iterator_range<imported_symbol_iterator>1694DelayImportDirectoryEntryRef::imported_symbols() const {1695 return make_range(imported_symbol_begin(), imported_symbol_end());1696}1697 1698Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {1699 uintptr_t IntPtr = 0;1700 if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr,1701 "delay import directory name"))1702 return E;1703 Result = StringRef(reinterpret_cast<const char *>(IntPtr));1704 return Error::success();1705}1706 1707Error DelayImportDirectoryEntryRef::getDelayImportTable(1708 const delay_import_directory_table_entry *&Result) const {1709 Result = &Table[Index];1710 return Error::success();1711}1712 1713Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,1714 uint64_t &Result) const {1715 uint32_t RVA = Table[Index].DelayImportAddressTable +1716 AddrIndex * (OwningObject->is64() ? 8 : 4);1717 uintptr_t IntPtr = 0;1718 if (Error E = OwningObject->getRvaPtr(RVA, IntPtr, "import address"))1719 return E;1720 if (OwningObject->is64())1721 Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);1722 else1723 Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);1724 return Error::success();1725}1726 1727bool ExportDirectoryEntryRef::1728operator==(const ExportDirectoryEntryRef &Other) const {1729 return ExportTable == Other.ExportTable && Index == Other.Index;1730}1731 1732void ExportDirectoryEntryRef::moveNext() {1733 ++Index;1734}1735 1736// Returns the name of the current export symbol. If the symbol is exported only1737// by ordinal, the empty string is set as a result.1738Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {1739 uintptr_t IntPtr = 0;1740 if (Error E =1741 OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr, "dll name"))1742 return E;1743 Result = StringRef(reinterpret_cast<const char *>(IntPtr));1744 return Error::success();1745}1746 1747// Returns the starting ordinal number.1748Error ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {1749 Result = ExportTable->OrdinalBase;1750 return Error::success();1751}1752 1753// Returns the export ordinal of the current export symbol.1754Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {1755 Result = ExportTable->OrdinalBase + Index;1756 return Error::success();1757}1758 1759// Returns the address of the current export symbol.1760Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {1761 uintptr_t IntPtr = 0;1762 if (Error EC = OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA,1763 IntPtr, "export address"))1764 return EC;1765 const export_address_table_entry *entry =1766 reinterpret_cast<const export_address_table_entry *>(IntPtr);1767 Result = entry[Index].ExportRVA;1768 return Error::success();1769}1770 1771// Returns the name of the current export symbol. If the symbol is exported only1772// by ordinal, the empty string is set as a result.1773Error1774ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {1775 uintptr_t IntPtr = 0;1776 if (Error EC = OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr,1777 "export ordinal table"))1778 return EC;1779 const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);1780 1781 uint32_t NumEntries = ExportTable->NumberOfNamePointers;1782 int Offset = 0;1783 for (const ulittle16_t *I = Start, *E = Start + NumEntries;1784 I < E; ++I, ++Offset) {1785 if (*I != Index)1786 continue;1787 if (Error EC = OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr,1788 "export table entry"))1789 return EC;1790 const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);1791 if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr,1792 "export symbol name"))1793 return EC;1794 Result = StringRef(reinterpret_cast<const char *>(IntPtr));1795 return Error::success();1796 }1797 Result = "";1798 return Error::success();1799}1800 1801Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {1802 const data_directory *DataEntry =1803 OwningObject->getDataDirectory(COFF::EXPORT_TABLE);1804 if (!DataEntry)1805 return createStringError(object_error::parse_failed,1806 "export table missing");1807 uint32_t RVA;1808 if (auto EC = getExportRVA(RVA))1809 return EC;1810 uint32_t Begin = DataEntry->RelativeVirtualAddress;1811 uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;1812 Result = (Begin <= RVA && RVA < End);1813 return Error::success();1814}1815 1816Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {1817 uint32_t RVA;1818 if (auto EC = getExportRVA(RVA))1819 return EC;1820 uintptr_t IntPtr = 0;1821 if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr, "export forward target"))1822 return EC;1823 Result = StringRef(reinterpret_cast<const char *>(IntPtr));1824 return Error::success();1825}1826 1827bool ImportedSymbolRef::1828operator==(const ImportedSymbolRef &Other) const {1829 return Entry32 == Other.Entry32 && Entry64 == Other.Entry641830 && Index == Other.Index;1831}1832 1833void ImportedSymbolRef::moveNext() {1834 ++Index;1835}1836 1837Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {1838 uint32_t RVA;1839 if (Entry32) {1840 // If a symbol is imported only by ordinal, it has no name.1841 if (Entry32[Index].isOrdinal())1842 return Error::success();1843 RVA = Entry32[Index].getHintNameRVA();1844 } else {1845 if (Entry64[Index].isOrdinal())1846 return Error::success();1847 RVA = Entry64[Index].getHintNameRVA();1848 }1849 uintptr_t IntPtr = 0;1850 if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol name"))1851 return EC;1852 // +2 because the first two bytes is hint.1853 Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));1854 return Error::success();1855}1856 1857Error ImportedSymbolRef::isOrdinal(bool &Result) const {1858 if (Entry32)1859 Result = Entry32[Index].isOrdinal();1860 else1861 Result = Entry64[Index].isOrdinal();1862 return Error::success();1863}1864 1865Error ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {1866 if (Entry32)1867 Result = Entry32[Index].getHintNameRVA();1868 else1869 Result = Entry64[Index].getHintNameRVA();1870 return Error::success();1871}1872 1873Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {1874 uint32_t RVA;1875 if (Entry32) {1876 if (Entry32[Index].isOrdinal()) {1877 Result = Entry32[Index].getOrdinal();1878 return Error::success();1879 }1880 RVA = Entry32[Index].getHintNameRVA();1881 } else {1882 if (Entry64[Index].isOrdinal()) {1883 Result = Entry64[Index].getOrdinal();1884 return Error::success();1885 }1886 RVA = Entry64[Index].getHintNameRVA();1887 }1888 uintptr_t IntPtr = 0;1889 if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol ordinal"))1890 return EC;1891 Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);1892 return Error::success();1893}1894 1895Expected<std::unique_ptr<COFFObjectFile>>1896ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {1897 return COFFObjectFile::create(Object);1898}1899 1900bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {1901 return Header == Other.Header && Index == Other.Index;1902}1903 1904void BaseRelocRef::moveNext() {1905 // Header->BlockSize is the size of the current block, including the1906 // size of the header itself.1907 uint32_t Size = sizeof(*Header) +1908 sizeof(coff_base_reloc_block_entry) * (Index + 1);1909 if (Size == Header->BlockSize) {1910 // .reloc contains a list of base relocation blocks. Each block1911 // consists of the header followed by entries. The header contains1912 // how many entories will follow. When we reach the end of the1913 // current block, proceed to the next block.1914 Header = reinterpret_cast<const coff_base_reloc_block_header *>(1915 reinterpret_cast<const uint8_t *>(Header) + Size);1916 Index = 0;1917 } else {1918 ++Index;1919 }1920}1921 1922Error BaseRelocRef::getType(uint8_t &Type) const {1923 auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);1924 Type = Entry[Index].getType();1925 return Error::success();1926}1927 1928Error BaseRelocRef::getRVA(uint32_t &Result) const {1929 auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);1930 Result = Header->PageRVA + Entry[Index].getOffset();1931 return Error::success();1932}1933 1934bool DynamicRelocRef::operator==(const DynamicRelocRef &Other) const {1935 return Header == Other.Header;1936}1937 1938void DynamicRelocRef::moveNext() {1939 switch (Obj->getDynamicRelocTable()->Version) {1940 case 1:1941 if (Obj->is64()) {1942 auto H = reinterpret_cast<const coff_dynamic_relocation64 *>(Header);1943 Header += sizeof(*H) + H->BaseRelocSize;1944 } else {1945 auto H = reinterpret_cast<const coff_dynamic_relocation32 *>(Header);1946 Header += sizeof(*H) + H->BaseRelocSize;1947 }1948 break;1949 case 2:1950 if (Obj->is64()) {1951 auto H = reinterpret_cast<const coff_dynamic_relocation64_v2 *>(Header);1952 Header += H->HeaderSize + H->FixupInfoSize;1953 } else {1954 auto H = reinterpret_cast<const coff_dynamic_relocation32_v2 *>(Header);1955 Header += H->HeaderSize + H->FixupInfoSize;1956 }1957 break;1958 }1959}1960 1961uint32_t DynamicRelocRef::getType() const {1962 switch (Obj->getDynamicRelocTable()->Version) {1963 case 1:1964 if (Obj->is64()) {1965 auto H = reinterpret_cast<const coff_dynamic_relocation64 *>(Header);1966 return H->Symbol;1967 } else {1968 auto H = reinterpret_cast<const coff_dynamic_relocation32 *>(Header);1969 return H->Symbol;1970 }1971 break;1972 case 2:1973 if (Obj->is64()) {1974 auto H = reinterpret_cast<const coff_dynamic_relocation64_v2 *>(Header);1975 return H->Symbol;1976 } else {1977 auto H = reinterpret_cast<const coff_dynamic_relocation32_v2 *>(Header);1978 return H->Symbol;1979 }1980 break;1981 default:1982 llvm_unreachable("invalid version");1983 }1984}1985 1986void DynamicRelocRef::getContents(ArrayRef<uint8_t> &Ref) const {1987 switch (Obj->getDynamicRelocTable()->Version) {1988 case 1:1989 if (Obj->is64()) {1990 auto H = reinterpret_cast<const coff_dynamic_relocation64 *>(Header);1991 Ref = ArrayRef(Header + sizeof(*H), H->BaseRelocSize);1992 } else {1993 auto H = reinterpret_cast<const coff_dynamic_relocation32 *>(Header);1994 Ref = ArrayRef(Header + sizeof(*H), H->BaseRelocSize);1995 }1996 break;1997 case 2:1998 if (Obj->is64()) {1999 auto H = reinterpret_cast<const coff_dynamic_relocation64_v2 *>(Header);2000 Ref = ArrayRef(Header + H->HeaderSize, H->FixupInfoSize);2001 } else {2002 auto H = reinterpret_cast<const coff_dynamic_relocation32_v2 *>(Header);2003 Ref = ArrayRef(Header + H->HeaderSize, H->FixupInfoSize);2004 }2005 break;2006 }2007}2008 2009Error DynamicRelocRef::validate() const {2010 const coff_dynamic_reloc_table *Table = Obj->getDynamicRelocTable();2011 size_t ContentsSize =2012 reinterpret_cast<const uint8_t *>(Table + 1) + Table->Size - Header;2013 size_t HeaderSize;2014 if (Table->Version == 1)2015 HeaderSize = Obj->is64() ? sizeof(coff_dynamic_relocation64)2016 : sizeof(coff_dynamic_relocation32);2017 else2018 HeaderSize = Obj->is64() ? sizeof(coff_dynamic_relocation64_v2)2019 : sizeof(coff_dynamic_relocation32_v2);2020 if (HeaderSize > ContentsSize)2021 return createStringError(object_error::parse_failed,2022 "Unexpected end of dynamic relocations data");2023 2024 if (Table->Version == 2) {2025 size_t Size =2026 Obj->is64()2027 ? reinterpret_cast<const coff_dynamic_relocation64_v2 *>(Header)2028 ->HeaderSize2029 : reinterpret_cast<const coff_dynamic_relocation32_v2 *>(Header)2030 ->HeaderSize;2031 if (Size < HeaderSize || Size > ContentsSize)2032 return createStringError(object_error::parse_failed,2033 "Invalid dynamic relocation header size (" +2034 Twine(Size) + ")");2035 HeaderSize = Size;2036 }2037 2038 ArrayRef<uint8_t> Contents;2039 getContents(Contents);2040 if (Contents.size() > ContentsSize - HeaderSize)2041 return createStringError(object_error::parse_failed,2042 "Too large dynamic relocation size (" +2043 Twine(Contents.size()) + ")");2044 2045 switch (getType()) {2046 case COFF::IMAGE_DYNAMIC_RELOCATION_ARM64X:2047 for (auto Reloc : arm64x_relocs()) {2048 if (Error E = Reloc.validate(Obj))2049 return E;2050 }2051 break;2052 }2053 2054 return Error::success();2055}2056 2057arm64x_reloc_iterator DynamicRelocRef::arm64x_reloc_begin() const {2058 assert(getType() == COFF::IMAGE_DYNAMIC_RELOCATION_ARM64X);2059 ArrayRef<uint8_t> Content;2060 getContents(Content);2061 auto Header =2062 reinterpret_cast<const coff_base_reloc_block_header *>(Content.begin());2063 return arm64x_reloc_iterator(Arm64XRelocRef(Header));2064}2065 2066arm64x_reloc_iterator DynamicRelocRef::arm64x_reloc_end() const {2067 assert(getType() == COFF::IMAGE_DYNAMIC_RELOCATION_ARM64X);2068 ArrayRef<uint8_t> Content;2069 getContents(Content);2070 auto Header =2071 reinterpret_cast<const coff_base_reloc_block_header *>(Content.end());2072 return arm64x_reloc_iterator(Arm64XRelocRef(Header, 0));2073}2074 2075iterator_range<arm64x_reloc_iterator> DynamicRelocRef::arm64x_relocs() const {2076 return make_range(arm64x_reloc_begin(), arm64x_reloc_end());2077}2078 2079bool Arm64XRelocRef::operator==(const Arm64XRelocRef &Other) const {2080 return Header == Other.Header && Index == Other.Index;2081}2082 2083uint8_t Arm64XRelocRef::getEntrySize() const {2084 switch (getType()) {2085 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE:2086 return (1ull << getArg()) / sizeof(uint16_t) + 1;2087 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:2088 return 2;2089 default:2090 return 1;2091 }2092}2093 2094void Arm64XRelocRef::moveNext() {2095 Index += getEntrySize();2096 if (sizeof(*Header) + Index * sizeof(uint16_t) < Header->BlockSize &&2097 !getReloc())2098 ++Index; // Skip padding2099 if (sizeof(*Header) + Index * sizeof(uint16_t) == Header->BlockSize) {2100 // The end of the block, move to the next one.2101 Header =2102 reinterpret_cast<const coff_base_reloc_block_header *>(&getReloc());2103 Index = 0;2104 }2105}2106 2107uint8_t Arm64XRelocRef::getSize() const {2108 switch (getType()) {2109 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:2110 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE:2111 return 1 << getArg();2112 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:2113 return sizeof(uint32_t);2114 }2115 llvm_unreachable("Unknown Arm64XFixupType enum");2116}2117 2118uint64_t Arm64XRelocRef::getValue() const {2119 auto Ptr = reinterpret_cast<const ulittle16_t *>(Header + 1) + Index + 1;2120 2121 switch (getType()) {2122 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE: {2123 ulittle64_t Value(0);2124 memcpy(&Value, Ptr, getSize());2125 return Value;2126 }2127 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA: {2128 uint16_t arg = getArg();2129 int delta = *Ptr;2130 2131 if (arg & 1)2132 delta = -delta;2133 delta *= (arg & 2) ? 8 : 4;2134 return delta;2135 }2136 default:2137 return 0;2138 }2139}2140 2141Error Arm64XRelocRef::validate(const COFFObjectFile *Obj) const {2142 if (!Index) {2143 const coff_dynamic_reloc_table *Table = Obj->getDynamicRelocTable();2144 size_t ContentsSize = reinterpret_cast<const uint8_t *>(Table + 1) +2145 Table->Size -2146 reinterpret_cast<const uint8_t *>(Header);2147 if (ContentsSize < sizeof(coff_base_reloc_block_header))2148 return createStringError(object_error::parse_failed,2149 "Unexpected end of ARM64X relocations data");2150 if (Header->BlockSize <= sizeof(*Header))2151 return createStringError(object_error::parse_failed,2152 "ARM64X relocations block size (" +2153 Twine(Header->BlockSize) + ") is too small");2154 if (Header->BlockSize % sizeof(uint32_t))2155 return createStringError(object_error::parse_failed,2156 "Unaligned ARM64X relocations block size (" +2157 Twine(Header->BlockSize) + ")");2158 if (Header->BlockSize > ContentsSize)2159 return createStringError(object_error::parse_failed,2160 "ARM64X relocations block size (" +2161 Twine(Header->BlockSize) + ") is too large");2162 if (Header->PageRVA & 0xfff)2163 return createStringError(object_error::parse_failed,2164 "Unaligned ARM64X relocations page RVA (" +2165 Twine(Header->PageRVA) + ")");2166 }2167 2168 switch ((getReloc() >> 12) & 3) {2169 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL:2170 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA:2171 break;2172 case COFF::IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE:2173 if (!getArg())2174 return createStringError(object_error::parse_failed,2175 "Invalid ARM64X relocation value size (0)");2176 break;2177 default:2178 return createStringError(object_error::parse_failed,2179 "Invalid relocation type");2180 }2181 2182 uint32_t RelocsSize =2183 (Header->BlockSize - sizeof(*Header)) / sizeof(uint16_t);2184 uint16_t EntrySize = getEntrySize();2185 if (!getReloc() ||2186 (Index + EntrySize + 1 < RelocsSize && !getReloc(EntrySize)))2187 return createStringError(object_error::parse_failed,2188 "Unexpected ARM64X relocations terminator");2189 if (Index + EntrySize > RelocsSize)2190 return createStringError(object_error::parse_failed,2191 "Unexpected end of ARM64X relocations");2192 if (getRVA() % getSize())2193 return createStringError(object_error::parse_failed,2194 "Unaligned ARM64X relocation RVA (" +2195 Twine(getRVA()) + ")");2196 if (Header->PageRVA) {2197 uintptr_t IntPtr;2198 return Obj->getRvaPtr(getRVA() + getSize(), IntPtr, "ARM64X reloc");2199 }2200 return Error::success();2201}2202 2203#define RETURN_IF_ERROR(Expr) \2204 do { \2205 Error E = (Expr); \2206 if (E) \2207 return std::move(E); \2208 } while (0)2209 2210Expected<ArrayRef<UTF16>>2211ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {2212 BinaryStreamReader Reader = BinaryStreamReader(BBS);2213 Reader.setOffset(Offset);2214 uint16_t Length;2215 RETURN_IF_ERROR(Reader.readInteger(Length));2216 ArrayRef<UTF16> RawDirString;2217 RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));2218 return RawDirString;2219}2220 2221Expected<ArrayRef<UTF16>>2222ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {2223 return getDirStringAtOffset(Entry.Identifier.getNameOffset());2224}2225 2226Expected<const coff_resource_dir_table &>2227ResourceSectionRef::getTableAtOffset(uint32_t Offset) {2228 const coff_resource_dir_table *Table = nullptr;2229 2230 BinaryStreamReader Reader(BBS);2231 Reader.setOffset(Offset);2232 RETURN_IF_ERROR(Reader.readObject(Table));2233 assert(Table != nullptr);2234 return *Table;2235}2236 2237Expected<const coff_resource_dir_entry &>2238ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {2239 const coff_resource_dir_entry *Entry = nullptr;2240 2241 BinaryStreamReader Reader(BBS);2242 Reader.setOffset(Offset);2243 RETURN_IF_ERROR(Reader.readObject(Entry));2244 assert(Entry != nullptr);2245 return *Entry;2246}2247 2248Expected<const coff_resource_data_entry &>2249ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {2250 const coff_resource_data_entry *Entry = nullptr;2251 2252 BinaryStreamReader Reader(BBS);2253 Reader.setOffset(Offset);2254 RETURN_IF_ERROR(Reader.readObject(Entry));2255 assert(Entry != nullptr);2256 return *Entry;2257}2258 2259Expected<const coff_resource_dir_table &>2260ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {2261 assert(Entry.Offset.isSubDir());2262 return getTableAtOffset(Entry.Offset.value());2263}2264 2265Expected<const coff_resource_data_entry &>2266ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {2267 assert(!Entry.Offset.isSubDir());2268 return getDataEntryAtOffset(Entry.Offset.value());2269}2270 2271Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {2272 return getTableAtOffset(0);2273}2274 2275Expected<const coff_resource_dir_entry &>2276ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,2277 uint32_t Index) {2278 if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))2279 return createStringError(object_error::parse_failed, "index out of range");2280 const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);2281 ptrdiff_t TableOffset = TablePtr - BBS.data().data();2282 return getTableEntryAtOffset(TableOffset + sizeof(Table) +2283 Index * sizeof(coff_resource_dir_entry));2284}2285 2286Error ResourceSectionRef::load(const COFFObjectFile *O) {2287 for (const SectionRef &S : O->sections()) {2288 Expected<StringRef> Name = S.getName();2289 if (!Name)2290 return Name.takeError();2291 2292 if (*Name == ".rsrc" || *Name == ".rsrc$01")2293 return load(O, S);2294 }2295 return createStringError(object_error::parse_failed,2296 "no resource section found");2297}2298 2299Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {2300 Obj = O;2301 Section = S;2302 Expected<StringRef> Contents = Section.getContents();2303 if (!Contents)2304 return Contents.takeError();2305 BBS = BinaryByteStream(*Contents, llvm::endianness::little);2306 const coff_section *COFFSect = Obj->getCOFFSection(Section);2307 ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);2308 Relocs.reserve(OrigRelocs.size());2309 for (const coff_relocation &R : OrigRelocs)2310 Relocs.push_back(&R);2311 llvm::sort(Relocs, [](const coff_relocation *A, const coff_relocation *B) {2312 return A->VirtualAddress < B->VirtualAddress;2313 });2314 return Error::success();2315}2316 2317Expected<StringRef>2318ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {2319 if (!Obj)2320 return createStringError(object_error::parse_failed, "no object provided");2321 2322 // Find a potential relocation at the DataRVA field (first member of2323 // the coff_resource_data_entry struct).2324 const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);2325 ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();2326 coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),2327 ulittle16_t(0)};2328 auto RelocsForOffset =2329 std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,2330 [](const coff_relocation *A, const coff_relocation *B) {2331 return A->VirtualAddress < B->VirtualAddress;2332 });2333 2334 if (RelocsForOffset.first != RelocsForOffset.second) {2335 // We found a relocation with the right offset. Check that it does have2336 // the expected type.2337 const coff_relocation &R = **RelocsForOffset.first;2338 uint16_t RVAReloc;2339 switch (Obj->getArch()) {2340 case Triple::x86:2341 RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;2342 break;2343 case Triple::x86_64:2344 RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;2345 break;2346 case Triple::thumb:2347 RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;2348 break;2349 case Triple::aarch64:2350 RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;2351 break;2352 default:2353 return createStringError(object_error::parse_failed,2354 "unsupported architecture");2355 }2356 if (R.Type != RVAReloc)2357 return createStringError(object_error::parse_failed,2358 "unexpected relocation type");2359 // Get the relocation's symbol2360 Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);2361 if (!Sym)2362 return Sym.takeError();2363 // And the symbol's section2364 Expected<const coff_section *> Section =2365 Obj->getSection(Sym->getSectionNumber());2366 if (!Section)2367 return Section.takeError();2368 // Add the initial value of DataRVA to the symbol's offset to find the2369 // data it points at.2370 uint64_t Offset = Entry.DataRVA + Sym->getValue();2371 ArrayRef<uint8_t> Contents;2372 if (Error E = Obj->getSectionContents(*Section, Contents))2373 return E;2374 if (Offset + Entry.DataSize > Contents.size())2375 return createStringError(object_error::parse_failed,2376 "data outside of section");2377 // Return a reference to the data inside the section.2378 return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,2379 Entry.DataSize);2380 } else {2381 // Relocatable objects need a relocation for the DataRVA field.2382 if (Obj->isRelocatableObject())2383 return createStringError(object_error::parse_failed,2384 "no relocation found for DataRVA");2385 2386 // Locate the section that contains the address that DataRVA points at.2387 uint64_t VA = Entry.DataRVA + Obj->getImageBase();2388 for (const SectionRef &S : Obj->sections()) {2389 if (VA >= S.getAddress() &&2390 VA + Entry.DataSize <= S.getAddress() + S.getSize()) {2391 uint64_t Offset = VA - S.getAddress();2392 Expected<StringRef> Contents = S.getContents();2393 if (!Contents)2394 return Contents.takeError();2395 return Contents->substr(Offset, Entry.DataSize);2396 }2397 }2398 return createStringError(object_error::parse_failed,2399 "address not found in image");2400 }2401}2402