10b57cec5SDimitry Andric //===- COFFObjectFile.cpp - COFF object file implementation ---------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file declares the COFFObjectFile class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
140b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
155ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h"
160b57cec5SDimitry Andric #include "llvm/ADT/iterator_range.h"
170b57cec5SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
180b57cec5SDimitry Andric #include "llvm/Object/Binary.h"
190b57cec5SDimitry Andric #include "llvm/Object/COFF.h"
200b57cec5SDimitry Andric #include "llvm/Object/Error.h"
210b57cec5SDimitry Andric #include "llvm/Object/ObjectFile.h"
220b57cec5SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
230b57cec5SDimitry Andric #include "llvm/Support/Endian.h"
240b57cec5SDimitry Andric #include "llvm/Support/Error.h"
250b57cec5SDimitry Andric #include "llvm/Support/ErrorHandling.h"
260b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
2781ad6265SDimitry Andric #include "llvm/Support/MemoryBufferRef.h"
2806c3fb27SDimitry Andric #include "llvm/TargetParser/Triple.h"
290b57cec5SDimitry Andric #include <algorithm>
300b57cec5SDimitry Andric #include <cassert>
31e8d8bef9SDimitry Andric #include <cinttypes>
320b57cec5SDimitry Andric #include <cstddef>
330b57cec5SDimitry Andric #include <cstring>
340b57cec5SDimitry Andric #include <limits>
350b57cec5SDimitry Andric #include <memory>
360b57cec5SDimitry Andric #include <system_error>
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric using namespace llvm;
390b57cec5SDimitry Andric using namespace object;
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric using support::ulittle16_t;
420b57cec5SDimitry Andric using support::ulittle32_t;
430b57cec5SDimitry Andric using support::ulittle64_t;
440b57cec5SDimitry Andric using support::little16_t;
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric // Returns false if size is greater than the buffer size. And sets ec.
checkSize(MemoryBufferRef M,std::error_code & EC,uint64_t Size)470b57cec5SDimitry Andric static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) {
480b57cec5SDimitry Andric if (M.getBufferSize() < Size) {
490b57cec5SDimitry Andric EC = object_error::unexpected_eof;
500b57cec5SDimitry Andric return false;
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric return true;
530b57cec5SDimitry Andric }
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
560b57cec5SDimitry Andric // Returns unexpected_eof if error.
570b57cec5SDimitry Andric template <typename T>
getObject(const T * & Obj,MemoryBufferRef M,const void * Ptr,const uint64_t Size=sizeof (T))585ffd83dbSDimitry Andric static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr,
590b57cec5SDimitry Andric const uint64_t Size = sizeof(T)) {
60e8d8bef9SDimitry Andric uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);
615ffd83dbSDimitry Andric if (Error E = Binary::checkOffset(M, Addr, Size))
625ffd83dbSDimitry Andric return E;
630b57cec5SDimitry Andric Obj = reinterpret_cast<const T *>(Addr);
645ffd83dbSDimitry Andric return Error::success();
650b57cec5SDimitry Andric }
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric // Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without
680b57cec5SDimitry Andric // prefixed slashes.
decodeBase64StringEntry(StringRef Str,uint32_t & Result)690b57cec5SDimitry Andric static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {
700b57cec5SDimitry Andric assert(Str.size() <= 6 && "String too long, possible overflow.");
710b57cec5SDimitry Andric if (Str.size() > 6)
720b57cec5SDimitry Andric return true;
730b57cec5SDimitry Andric
740b57cec5SDimitry Andric uint64_t Value = 0;
750b57cec5SDimitry Andric while (!Str.empty()) {
760b57cec5SDimitry Andric unsigned CharVal;
770b57cec5SDimitry Andric if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..25
780b57cec5SDimitry Andric CharVal = Str[0] - 'A';
790b57cec5SDimitry Andric else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..51
800b57cec5SDimitry Andric CharVal = Str[0] - 'a' + 26;
810b57cec5SDimitry Andric else if (Str[0] >= '0' && Str[0] <= '9') // 52..61
820b57cec5SDimitry Andric CharVal = Str[0] - '0' + 52;
830b57cec5SDimitry Andric else if (Str[0] == '+') // 62
840b57cec5SDimitry Andric CharVal = 62;
850b57cec5SDimitry Andric else if (Str[0] == '/') // 63
860b57cec5SDimitry Andric CharVal = 63;
870b57cec5SDimitry Andric else
880b57cec5SDimitry Andric return true;
890b57cec5SDimitry Andric
900b57cec5SDimitry Andric Value = (Value * 64) + CharVal;
910b57cec5SDimitry Andric Str = Str.substr(1);
920b57cec5SDimitry Andric }
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric if (Value > std::numeric_limits<uint32_t>::max())
950b57cec5SDimitry Andric return true;
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric Result = static_cast<uint32_t>(Value);
980b57cec5SDimitry Andric return false;
990b57cec5SDimitry Andric }
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric template <typename coff_symbol_type>
toSymb(DataRefImpl Ref) const1020b57cec5SDimitry Andric const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {
1030b57cec5SDimitry Andric const coff_symbol_type *Addr =
1040b57cec5SDimitry Andric reinterpret_cast<const coff_symbol_type *>(Ref.p);
1050b57cec5SDimitry Andric
106e8d8bef9SDimitry Andric assert(!checkOffset(Data, reinterpret_cast<uintptr_t>(Addr), sizeof(*Addr)));
1070b57cec5SDimitry Andric #ifndef NDEBUG
1080b57cec5SDimitry Andric // Verify that the symbol points to a valid entry in the symbol table.
109e8d8bef9SDimitry Andric uintptr_t Offset =
110e8d8bef9SDimitry Andric reinterpret_cast<uintptr_t>(Addr) - reinterpret_cast<uintptr_t>(base());
1110b57cec5SDimitry Andric
1120b57cec5SDimitry Andric assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&
1130b57cec5SDimitry Andric "Symbol did not point to the beginning of a symbol");
1140b57cec5SDimitry Andric #endif
1150b57cec5SDimitry Andric
1160b57cec5SDimitry Andric return Addr;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric
toSec(DataRefImpl Ref) const1190b57cec5SDimitry Andric const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {
1200b57cec5SDimitry Andric const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p);
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric #ifndef NDEBUG
1230b57cec5SDimitry Andric // Verify that the section points to a valid entry in the section table.
1240b57cec5SDimitry Andric if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))
1250b57cec5SDimitry Andric report_fatal_error("Section was outside of section table.");
1260b57cec5SDimitry Andric
127e8d8bef9SDimitry Andric uintptr_t Offset = reinterpret_cast<uintptr_t>(Addr) -
128e8d8bef9SDimitry Andric reinterpret_cast<uintptr_t>(SectionTable);
1290b57cec5SDimitry Andric assert(Offset % sizeof(coff_section) == 0 &&
1300b57cec5SDimitry Andric "Section did not point to the beginning of a section");
1310b57cec5SDimitry Andric #endif
1320b57cec5SDimitry Andric
1330b57cec5SDimitry Andric return Addr;
1340b57cec5SDimitry Andric }
1350b57cec5SDimitry Andric
moveSymbolNext(DataRefImpl & Ref) const1360b57cec5SDimitry Andric void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {
1370b57cec5SDimitry Andric auto End = reinterpret_cast<uintptr_t>(StringTable);
1380b57cec5SDimitry Andric if (SymbolTable16) {
1390b57cec5SDimitry Andric const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);
1400b57cec5SDimitry Andric Symb += 1 + Symb->NumberOfAuxSymbols;
1410b57cec5SDimitry Andric Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
1420b57cec5SDimitry Andric } else if (SymbolTable32) {
1430b57cec5SDimitry Andric const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);
1440b57cec5SDimitry Andric Symb += 1 + Symb->NumberOfAuxSymbols;
1450b57cec5SDimitry Andric Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
1460b57cec5SDimitry Andric } else {
1470b57cec5SDimitry Andric llvm_unreachable("no symbol table pointer!");
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
getSymbolName(DataRefImpl Ref) const1510b57cec5SDimitry Andric Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {
1525ffd83dbSDimitry Andric return getSymbolName(getCOFFSymbol(Ref));
1530b57cec5SDimitry Andric }
1540b57cec5SDimitry Andric
getSymbolValueImpl(DataRefImpl Ref) const1550b57cec5SDimitry Andric uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {
1560b57cec5SDimitry Andric return getCOFFSymbol(Ref).getValue();
1570b57cec5SDimitry Andric }
1580b57cec5SDimitry Andric
getSymbolAlignment(DataRefImpl Ref) const1590b57cec5SDimitry Andric uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const {
1600b57cec5SDimitry Andric // MSVC/link.exe seems to align symbols to the next-power-of-2
1610b57cec5SDimitry Andric // up to 32 bytes.
1620b57cec5SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
1630b57cec5SDimitry Andric return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
getSymbolAddress(DataRefImpl Ref) const1660b57cec5SDimitry Andric Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {
1675ffd83dbSDimitry Andric uint64_t Result = cantFail(getSymbolValue(Ref));
1680b57cec5SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
1690b57cec5SDimitry Andric int32_t SectionNumber = Symb.getSectionNumber();
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric if (Symb.isAnyUndefined() || Symb.isCommon() ||
1720b57cec5SDimitry Andric COFF::isReservedSectionNumber(SectionNumber))
1730b57cec5SDimitry Andric return Result;
1740b57cec5SDimitry Andric
1755ffd83dbSDimitry Andric Expected<const coff_section *> Section = getSection(SectionNumber);
1765ffd83dbSDimitry Andric if (!Section)
1775ffd83dbSDimitry Andric return Section.takeError();
1785ffd83dbSDimitry Andric Result += (*Section)->VirtualAddress;
1790b57cec5SDimitry Andric
1800b57cec5SDimitry Andric // The section VirtualAddress does not include ImageBase, and we want to
1810b57cec5SDimitry Andric // return virtual addresses.
1820b57cec5SDimitry Andric Result += getImageBase();
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric return Result;
1850b57cec5SDimitry Andric }
1860b57cec5SDimitry Andric
getSymbolType(DataRefImpl Ref) const1870b57cec5SDimitry Andric Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {
1880b57cec5SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
1890b57cec5SDimitry Andric int32_t SectionNumber = Symb.getSectionNumber();
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
1920b57cec5SDimitry Andric return SymbolRef::ST_Function;
1930b57cec5SDimitry Andric if (Symb.isAnyUndefined())
1940b57cec5SDimitry Andric return SymbolRef::ST_Unknown;
1950b57cec5SDimitry Andric if (Symb.isCommon())
1960b57cec5SDimitry Andric return SymbolRef::ST_Data;
1970b57cec5SDimitry Andric if (Symb.isFileRecord())
1980b57cec5SDimitry Andric return SymbolRef::ST_File;
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric // TODO: perhaps we need a new symbol type ST_Section.
2010b57cec5SDimitry Andric if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())
2020b57cec5SDimitry Andric return SymbolRef::ST_Debug;
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric if (!COFF::isReservedSectionNumber(SectionNumber))
2050b57cec5SDimitry Andric return SymbolRef::ST_Data;
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andric return SymbolRef::ST_Other;
2080b57cec5SDimitry Andric }
2090b57cec5SDimitry Andric
getSymbolFlags(DataRefImpl Ref) const2105ffd83dbSDimitry Andric Expected<uint32_t> COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {
2110b57cec5SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
2120b57cec5SDimitry Andric uint32_t Result = SymbolRef::SF_None;
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric if (Symb.isExternal() || Symb.isWeakExternal())
2150b57cec5SDimitry Andric Result |= SymbolRef::SF_Global;
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {
2180b57cec5SDimitry Andric Result |= SymbolRef::SF_Weak;
2190b57cec5SDimitry Andric if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)
2200b57cec5SDimitry Andric Result |= SymbolRef::SF_Undefined;
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric
2230b57cec5SDimitry Andric if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)
2240b57cec5SDimitry Andric Result |= SymbolRef::SF_Absolute;
2250b57cec5SDimitry Andric
2260b57cec5SDimitry Andric if (Symb.isFileRecord())
2270b57cec5SDimitry Andric Result |= SymbolRef::SF_FormatSpecific;
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric if (Symb.isSectionDefinition())
2300b57cec5SDimitry Andric Result |= SymbolRef::SF_FormatSpecific;
2310b57cec5SDimitry Andric
2320b57cec5SDimitry Andric if (Symb.isCommon())
2330b57cec5SDimitry Andric Result |= SymbolRef::SF_Common;
2340b57cec5SDimitry Andric
2350b57cec5SDimitry Andric if (Symb.isUndefined())
2360b57cec5SDimitry Andric Result |= SymbolRef::SF_Undefined;
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric return Result;
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric
getCommonSymbolSizeImpl(DataRefImpl Ref) const2410b57cec5SDimitry Andric uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {
2420b57cec5SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
2430b57cec5SDimitry Andric return Symb.getValue();
2440b57cec5SDimitry Andric }
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric Expected<section_iterator>
getSymbolSection(DataRefImpl Ref) const2470b57cec5SDimitry Andric COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {
2480b57cec5SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
2490b57cec5SDimitry Andric if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))
2500b57cec5SDimitry Andric return section_end();
2515ffd83dbSDimitry Andric Expected<const coff_section *> Sec = getSection(Symb.getSectionNumber());
2525ffd83dbSDimitry Andric if (!Sec)
2535ffd83dbSDimitry Andric return Sec.takeError();
2540b57cec5SDimitry Andric DataRefImpl Ret;
2555ffd83dbSDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(*Sec);
2560b57cec5SDimitry Andric return section_iterator(SectionRef(Ret, this));
2570b57cec5SDimitry Andric }
2580b57cec5SDimitry Andric
getSymbolSectionID(SymbolRef Sym) const2590b57cec5SDimitry Andric unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {
2600b57cec5SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());
2610b57cec5SDimitry Andric return Symb.getSectionNumber();
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric
moveSectionNext(DataRefImpl & Ref) const2640b57cec5SDimitry Andric void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {
2650b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
2660b57cec5SDimitry Andric Sec += 1;
2670b57cec5SDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(Sec);
2680b57cec5SDimitry Andric }
2690b57cec5SDimitry Andric
getSectionName(DataRefImpl Ref) const2700b57cec5SDimitry Andric Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const {
2710b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
2720b57cec5SDimitry Andric return getSectionName(Sec);
2730b57cec5SDimitry Andric }
2740b57cec5SDimitry Andric
getSectionAddress(DataRefImpl Ref) const2750b57cec5SDimitry Andric uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {
2760b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
2770b57cec5SDimitry Andric uint64_t Result = Sec->VirtualAddress;
2780b57cec5SDimitry Andric
2790b57cec5SDimitry Andric // The section VirtualAddress does not include ImageBase, and we want to
2800b57cec5SDimitry Andric // return virtual addresses.
2810b57cec5SDimitry Andric Result += getImageBase();
2820b57cec5SDimitry Andric return Result;
2830b57cec5SDimitry Andric }
2840b57cec5SDimitry Andric
getSectionIndex(DataRefImpl Sec) const2850b57cec5SDimitry Andric uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
2860b57cec5SDimitry Andric return toSec(Sec) - SectionTable;
2870b57cec5SDimitry Andric }
2880b57cec5SDimitry Andric
getSectionSize(DataRefImpl Ref) const2890b57cec5SDimitry Andric uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {
2900b57cec5SDimitry Andric return getSectionSize(toSec(Ref));
2910b57cec5SDimitry Andric }
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Ref) const2940b57cec5SDimitry Andric COFFObjectFile::getSectionContents(DataRefImpl Ref) const {
2950b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
2960b57cec5SDimitry Andric ArrayRef<uint8_t> Res;
2970b57cec5SDimitry Andric if (Error E = getSectionContents(Sec, Res))
2980b57cec5SDimitry Andric return std::move(E);
2990b57cec5SDimitry Andric return Res;
3000b57cec5SDimitry Andric }
3010b57cec5SDimitry Andric
getSectionAlignment(DataRefImpl Ref) const3020b57cec5SDimitry Andric uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {
3030b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
3040b57cec5SDimitry Andric return Sec->getAlignment();
3050b57cec5SDimitry Andric }
3060b57cec5SDimitry Andric
isSectionCompressed(DataRefImpl Sec) const3070b57cec5SDimitry Andric bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
3080b57cec5SDimitry Andric return false;
3090b57cec5SDimitry Andric }
3100b57cec5SDimitry Andric
isSectionText(DataRefImpl Ref) const3110b57cec5SDimitry Andric bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {
3120b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
3130b57cec5SDimitry Andric return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;
3140b57cec5SDimitry Andric }
3150b57cec5SDimitry Andric
isSectionData(DataRefImpl Ref) const3160b57cec5SDimitry Andric bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {
3170b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
3180b57cec5SDimitry Andric return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
3190b57cec5SDimitry Andric }
3200b57cec5SDimitry Andric
isSectionBSS(DataRefImpl Ref) const3210b57cec5SDimitry Andric bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {
3220b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
3230b57cec5SDimitry Andric const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
3240b57cec5SDimitry Andric COFF::IMAGE_SCN_MEM_READ |
3250b57cec5SDimitry Andric COFF::IMAGE_SCN_MEM_WRITE;
3260b57cec5SDimitry Andric return (Sec->Characteristics & BssFlags) == BssFlags;
3270b57cec5SDimitry Andric }
3280b57cec5SDimitry Andric
3295ffd83dbSDimitry Andric // The .debug sections are the only debug sections for COFF
3305ffd83dbSDimitry Andric // (\see MCObjectFileInfo.cpp).
isDebugSection(DataRefImpl Ref) const331fe6060f1SDimitry Andric bool COFFObjectFile::isDebugSection(DataRefImpl Ref) const {
332fe6060f1SDimitry Andric Expected<StringRef> SectionNameOrErr = getSectionName(Ref);
333fe6060f1SDimitry Andric if (!SectionNameOrErr) {
334fe6060f1SDimitry Andric // TODO: Report the error message properly.
335fe6060f1SDimitry Andric consumeError(SectionNameOrErr.takeError());
336fe6060f1SDimitry Andric return false;
337fe6060f1SDimitry Andric }
338fe6060f1SDimitry Andric StringRef SectionName = SectionNameOrErr.get();
3395f757f3fSDimitry Andric return SectionName.starts_with(".debug");
3405ffd83dbSDimitry Andric }
3415ffd83dbSDimitry Andric
getSectionID(SectionRef Sec) const3420b57cec5SDimitry Andric unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {
3430b57cec5SDimitry Andric uintptr_t Offset =
344e8d8bef9SDimitry Andric Sec.getRawDataRefImpl().p - reinterpret_cast<uintptr_t>(SectionTable);
3450b57cec5SDimitry Andric assert((Offset % sizeof(coff_section)) == 0);
3460b57cec5SDimitry Andric return (Offset / sizeof(coff_section)) + 1;
3470b57cec5SDimitry Andric }
3480b57cec5SDimitry Andric
isSectionVirtual(DataRefImpl Ref) const3490b57cec5SDimitry Andric bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {
3500b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
3510b57cec5SDimitry Andric // In COFF, a virtual section won't have any in-file
3520b57cec5SDimitry Andric // content, so the file pointer to the content will be zero.
3530b57cec5SDimitry Andric return Sec->PointerToRawData == 0;
3540b57cec5SDimitry Andric }
3550b57cec5SDimitry Andric
getNumberOfRelocations(const coff_section * Sec,MemoryBufferRef M,const uint8_t * base)3560b57cec5SDimitry Andric static uint32_t getNumberOfRelocations(const coff_section *Sec,
3570b57cec5SDimitry Andric MemoryBufferRef M, const uint8_t *base) {
3580b57cec5SDimitry Andric // The field for the number of relocations in COFF section table is only
3590b57cec5SDimitry Andric // 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to
3600b57cec5SDimitry Andric // NumberOfRelocations field, and the actual relocation count is stored in the
3610b57cec5SDimitry Andric // VirtualAddress field in the first relocation entry.
3620b57cec5SDimitry Andric if (Sec->hasExtendedRelocations()) {
3630b57cec5SDimitry Andric const coff_relocation *FirstReloc;
3645ffd83dbSDimitry Andric if (Error E = getObject(FirstReloc, M,
3655ffd83dbSDimitry Andric reinterpret_cast<const coff_relocation *>(
3665ffd83dbSDimitry Andric base + Sec->PointerToRelocations))) {
3675ffd83dbSDimitry Andric consumeError(std::move(E));
3680b57cec5SDimitry Andric return 0;
3695ffd83dbSDimitry Andric }
3700b57cec5SDimitry Andric // -1 to exclude this first relocation entry.
3710b57cec5SDimitry Andric return FirstReloc->VirtualAddress - 1;
3720b57cec5SDimitry Andric }
3730b57cec5SDimitry Andric return Sec->NumberOfRelocations;
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric
3760b57cec5SDimitry Andric static const coff_relocation *
getFirstReloc(const coff_section * Sec,MemoryBufferRef M,const uint8_t * Base)3770b57cec5SDimitry Andric getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {
3780b57cec5SDimitry Andric uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);
3790b57cec5SDimitry Andric if (!NumRelocs)
3800b57cec5SDimitry Andric return nullptr;
3810b57cec5SDimitry Andric auto begin = reinterpret_cast<const coff_relocation *>(
3820b57cec5SDimitry Andric Base + Sec->PointerToRelocations);
3830b57cec5SDimitry Andric if (Sec->hasExtendedRelocations()) {
3840b57cec5SDimitry Andric // Skip the first relocation entry repurposed to store the number of
3850b57cec5SDimitry Andric // relocations.
3860b57cec5SDimitry Andric begin++;
3870b57cec5SDimitry Andric }
388e8d8bef9SDimitry Andric if (auto E = Binary::checkOffset(M, reinterpret_cast<uintptr_t>(begin),
3895ffd83dbSDimitry Andric sizeof(coff_relocation) * NumRelocs)) {
3905ffd83dbSDimitry Andric consumeError(std::move(E));
3910b57cec5SDimitry Andric return nullptr;
3925ffd83dbSDimitry Andric }
3930b57cec5SDimitry Andric return begin;
3940b57cec5SDimitry Andric }
3950b57cec5SDimitry Andric
section_rel_begin(DataRefImpl Ref) const3960b57cec5SDimitry Andric relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {
3970b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
3980b57cec5SDimitry Andric const coff_relocation *begin = getFirstReloc(Sec, Data, base());
3990b57cec5SDimitry Andric if (begin && Sec->VirtualAddress != 0)
4000b57cec5SDimitry Andric report_fatal_error("Sections with relocations should have an address of 0");
4010b57cec5SDimitry Andric DataRefImpl Ret;
4020b57cec5SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(begin);
4030b57cec5SDimitry Andric return relocation_iterator(RelocationRef(Ret, this));
4040b57cec5SDimitry Andric }
4050b57cec5SDimitry Andric
section_rel_end(DataRefImpl Ref) const4060b57cec5SDimitry Andric relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {
4070b57cec5SDimitry Andric const coff_section *Sec = toSec(Ref);
4080b57cec5SDimitry Andric const coff_relocation *I = getFirstReloc(Sec, Data, base());
4090b57cec5SDimitry Andric if (I)
4100b57cec5SDimitry Andric I += getNumberOfRelocations(Sec, Data, base());
4110b57cec5SDimitry Andric DataRefImpl Ret;
4120b57cec5SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(I);
4130b57cec5SDimitry Andric return relocation_iterator(RelocationRef(Ret, this));
4140b57cec5SDimitry Andric }
4150b57cec5SDimitry Andric
4160b57cec5SDimitry Andric // Initialize the pointer to the symbol table.
initSymbolTablePtr()4175ffd83dbSDimitry Andric Error COFFObjectFile::initSymbolTablePtr() {
4180b57cec5SDimitry Andric if (COFFHeader)
4195ffd83dbSDimitry Andric if (Error E = getObject(
4200b57cec5SDimitry Andric SymbolTable16, Data, base() + getPointerToSymbolTable(),
4210b57cec5SDimitry Andric (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
4225ffd83dbSDimitry Andric return E;
4230b57cec5SDimitry Andric
4240b57cec5SDimitry Andric if (COFFBigObjHeader)
4255ffd83dbSDimitry Andric if (Error E = getObject(
4260b57cec5SDimitry Andric SymbolTable32, Data, base() + getPointerToSymbolTable(),
4270b57cec5SDimitry Andric (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
4285ffd83dbSDimitry Andric return E;
4290b57cec5SDimitry Andric
4300b57cec5SDimitry Andric // Find string table. The first four byte of the string table contains the
4310b57cec5SDimitry Andric // total size of the string table, including the size field itself. If the
4320b57cec5SDimitry Andric // string table is empty, the value of the first four byte would be 4.
4330b57cec5SDimitry Andric uint32_t StringTableOffset = getPointerToSymbolTable() +
4340b57cec5SDimitry Andric getNumberOfSymbols() * getSymbolTableEntrySize();
4350b57cec5SDimitry Andric const uint8_t *StringTableAddr = base() + StringTableOffset;
4360b57cec5SDimitry Andric const ulittle32_t *StringTableSizePtr;
4375ffd83dbSDimitry Andric if (Error E = getObject(StringTableSizePtr, Data, StringTableAddr))
4385ffd83dbSDimitry Andric return E;
4390b57cec5SDimitry Andric StringTableSize = *StringTableSizePtr;
4405ffd83dbSDimitry Andric if (Error E = getObject(StringTable, Data, StringTableAddr, StringTableSize))
4415ffd83dbSDimitry Andric return E;
4420b57cec5SDimitry Andric
4430b57cec5SDimitry Andric // Treat table sizes < 4 as empty because contrary to the PECOFF spec, some
4440b57cec5SDimitry Andric // tools like cvtres write a size of 0 for an empty table instead of 4.
4450b57cec5SDimitry Andric if (StringTableSize < 4)
4460b57cec5SDimitry Andric StringTableSize = 4;
4470b57cec5SDimitry Andric
4480b57cec5SDimitry Andric // Check that the string table is null terminated if has any in it.
4490b57cec5SDimitry Andric if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)
45081ad6265SDimitry Andric return createStringError(object_error::parse_failed,
45181ad6265SDimitry Andric "string table missing null terminator");
4525ffd83dbSDimitry Andric return Error::success();
4530b57cec5SDimitry Andric }
4540b57cec5SDimitry Andric
getImageBase() const4550b57cec5SDimitry Andric uint64_t COFFObjectFile::getImageBase() const {
4560b57cec5SDimitry Andric if (PE32Header)
4570b57cec5SDimitry Andric return PE32Header->ImageBase;
4580b57cec5SDimitry Andric else if (PE32PlusHeader)
4590b57cec5SDimitry Andric return PE32PlusHeader->ImageBase;
4600b57cec5SDimitry Andric // This actually comes up in practice.
4610b57cec5SDimitry Andric return 0;
4620b57cec5SDimitry Andric }
4630b57cec5SDimitry Andric
4640b57cec5SDimitry Andric // Returns the file offset for the given VA.
getVaPtr(uint64_t Addr,uintptr_t & Res) const4655ffd83dbSDimitry Andric Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
4660b57cec5SDimitry Andric uint64_t ImageBase = getImageBase();
4670b57cec5SDimitry Andric uint64_t Rva = Addr - ImageBase;
4680b57cec5SDimitry Andric assert(Rva <= UINT32_MAX);
4690b57cec5SDimitry Andric return getRvaPtr((uint32_t)Rva, Res);
4700b57cec5SDimitry Andric }
4710b57cec5SDimitry Andric
4720b57cec5SDimitry Andric // Returns the file offset for the given RVA.
getRvaPtr(uint32_t Addr,uintptr_t & Res,const char * ErrorContext) const47381ad6265SDimitry Andric Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res,
47481ad6265SDimitry Andric const char *ErrorContext) const {
4750b57cec5SDimitry Andric for (const SectionRef &S : sections()) {
4760b57cec5SDimitry Andric const coff_section *Section = getCOFFSection(S);
4770b57cec5SDimitry Andric uint32_t SectionStart = Section->VirtualAddress;
4780b57cec5SDimitry Andric uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
4790b57cec5SDimitry Andric if (SectionStart <= Addr && Addr < SectionEnd) {
48081ad6265SDimitry Andric // A table/directory entry can be pointing to somewhere in a stripped
48181ad6265SDimitry Andric // section, in an object that went through `objcopy --only-keep-debug`.
48281ad6265SDimitry Andric // In this case we don't want to cause the parsing of the object file to
48381ad6265SDimitry Andric // fail, otherwise it will be impossible to use this object as debug info
48481ad6265SDimitry Andric // in LLDB. Return SectionStrippedError here so that
48581ad6265SDimitry Andric // COFFObjectFile::initialize can ignore the error.
48681ad6265SDimitry Andric // Somewhat common binaries may have RVAs pointing outside of the
48781ad6265SDimitry Andric // provided raw data. Instead of rejecting the binaries, just
48881ad6265SDimitry Andric // treat the section as stripped for these purposes.
48981ad6265SDimitry Andric if (Section->SizeOfRawData < Section->VirtualSize &&
49081ad6265SDimitry Andric Addr >= SectionStart + Section->SizeOfRawData) {
49181ad6265SDimitry Andric return make_error<SectionStrippedError>();
49281ad6265SDimitry Andric }
4930b57cec5SDimitry Andric uint32_t Offset = Addr - SectionStart;
494e8d8bef9SDimitry Andric Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +
495e8d8bef9SDimitry Andric Offset;
4965ffd83dbSDimitry Andric return Error::success();
4970b57cec5SDimitry Andric }
4980b57cec5SDimitry Andric }
49981ad6265SDimitry Andric if (ErrorContext)
50081ad6265SDimitry Andric return createStringError(object_error::parse_failed,
50181ad6265SDimitry Andric "RVA 0x%" PRIx32 " for %s not found", Addr,
50281ad6265SDimitry Andric ErrorContext);
50381ad6265SDimitry Andric return createStringError(object_error::parse_failed,
50481ad6265SDimitry Andric "RVA 0x%" PRIx32 " not found", Addr);
5050b57cec5SDimitry Andric }
5060b57cec5SDimitry Andric
getRvaAndSizeAsBytes(uint32_t RVA,uint32_t Size,ArrayRef<uint8_t> & Contents,const char * ErrorContext) const5075ffd83dbSDimitry Andric Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
50881ad6265SDimitry Andric ArrayRef<uint8_t> &Contents,
50981ad6265SDimitry Andric const char *ErrorContext) const {
5100b57cec5SDimitry Andric for (const SectionRef &S : sections()) {
5110b57cec5SDimitry Andric const coff_section *Section = getCOFFSection(S);
5120b57cec5SDimitry Andric uint32_t SectionStart = Section->VirtualAddress;
5130b57cec5SDimitry Andric // Check if this RVA is within the section bounds. Be careful about integer
5140b57cec5SDimitry Andric // overflow.
5150b57cec5SDimitry Andric uint32_t OffsetIntoSection = RVA - SectionStart;
5160b57cec5SDimitry Andric if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
5170b57cec5SDimitry Andric Size <= Section->VirtualSize - OffsetIntoSection) {
518e8d8bef9SDimitry Andric uintptr_t Begin = reinterpret_cast<uintptr_t>(base()) +
519e8d8bef9SDimitry Andric Section->PointerToRawData + OffsetIntoSection;
5200b57cec5SDimitry Andric Contents =
5210b57cec5SDimitry Andric ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);
5225ffd83dbSDimitry Andric return Error::success();
5230b57cec5SDimitry Andric }
5240b57cec5SDimitry Andric }
52581ad6265SDimitry Andric if (ErrorContext)
52681ad6265SDimitry Andric return createStringError(object_error::parse_failed,
52781ad6265SDimitry Andric "RVA 0x%" PRIx32 " for %s not found", RVA,
52881ad6265SDimitry Andric ErrorContext);
52981ad6265SDimitry Andric return createStringError(object_error::parse_failed,
53081ad6265SDimitry Andric "RVA 0x%" PRIx32 " not found", RVA);
5310b57cec5SDimitry Andric }
5320b57cec5SDimitry Andric
5330b57cec5SDimitry Andric // Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
5340b57cec5SDimitry Andric // table entry.
getHintName(uint32_t Rva,uint16_t & Hint,StringRef & Name) const5355ffd83dbSDimitry Andric Error COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
5360b57cec5SDimitry Andric StringRef &Name) const {
5370b57cec5SDimitry Andric uintptr_t IntPtr = 0;
5385ffd83dbSDimitry Andric if (Error E = getRvaPtr(Rva, IntPtr))
5395ffd83dbSDimitry Andric return E;
5400b57cec5SDimitry Andric const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);
5410b57cec5SDimitry Andric Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);
5420b57cec5SDimitry Andric Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));
5435ffd83dbSDimitry Andric return Error::success();
5440b57cec5SDimitry Andric }
5450b57cec5SDimitry Andric
getDebugPDBInfo(const debug_directory * DebugDir,const codeview::DebugInfo * & PDBInfo,StringRef & PDBFileName) const5465ffd83dbSDimitry Andric Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
5470b57cec5SDimitry Andric const codeview::DebugInfo *&PDBInfo,
5480b57cec5SDimitry Andric StringRef &PDBFileName) const {
5490b57cec5SDimitry Andric ArrayRef<uint8_t> InfoBytes;
55081ad6265SDimitry Andric if (Error E =
55181ad6265SDimitry Andric getRvaAndSizeAsBytes(DebugDir->AddressOfRawData, DebugDir->SizeOfData,
55281ad6265SDimitry Andric InfoBytes, "PDB info"))
5535ffd83dbSDimitry Andric return E;
5540b57cec5SDimitry Andric if (InfoBytes.size() < sizeof(*PDBInfo) + 1)
55581ad6265SDimitry Andric return createStringError(object_error::parse_failed, "PDB info too small");
5560b57cec5SDimitry Andric PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());
5570b57cec5SDimitry Andric InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));
5580b57cec5SDimitry Andric PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
5590b57cec5SDimitry Andric InfoBytes.size());
5600b57cec5SDimitry Andric // Truncate the name at the first null byte. Ignore any padding.
5610b57cec5SDimitry Andric PDBFileName = PDBFileName.split('\0').first;
5625ffd83dbSDimitry Andric return Error::success();
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric
getDebugPDBInfo(const codeview::DebugInfo * & PDBInfo,StringRef & PDBFileName) const5655ffd83dbSDimitry Andric Error COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,
5660b57cec5SDimitry Andric StringRef &PDBFileName) const {
5670b57cec5SDimitry Andric for (const debug_directory &D : debug_directories())
5680b57cec5SDimitry Andric if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
5690b57cec5SDimitry Andric return getDebugPDBInfo(&D, PDBInfo, PDBFileName);
5700b57cec5SDimitry Andric // If we get here, there is no PDB info to return.
5710b57cec5SDimitry Andric PDBInfo = nullptr;
5720b57cec5SDimitry Andric PDBFileName = StringRef();
5735ffd83dbSDimitry Andric return Error::success();
5740b57cec5SDimitry Andric }
5750b57cec5SDimitry Andric
5760b57cec5SDimitry Andric // Find the import table.
initImportTablePtr()5775ffd83dbSDimitry Andric Error COFFObjectFile::initImportTablePtr() {
5780b57cec5SDimitry Andric // First, we get the RVA of the import table. If the file lacks a pointer to
5790b57cec5SDimitry Andric // the import table, do nothing.
5805ffd83dbSDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::IMPORT_TABLE);
5815ffd83dbSDimitry Andric if (!DataEntry)
5825ffd83dbSDimitry Andric return Error::success();
5830b57cec5SDimitry Andric
5840b57cec5SDimitry Andric // Do nothing if the pointer to import table is NULL.
5850b57cec5SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
5865ffd83dbSDimitry Andric return Error::success();
5870b57cec5SDimitry Andric
5880b57cec5SDimitry Andric uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;
5890b57cec5SDimitry Andric
5900b57cec5SDimitry Andric // Find the section that contains the RVA. This is needed because the RVA is
5910b57cec5SDimitry Andric // the import table's memory address which is different from its file offset.
5920b57cec5SDimitry Andric uintptr_t IntPtr = 0;
59381ad6265SDimitry Andric if (Error E = getRvaPtr(ImportTableRva, IntPtr, "import table"))
5945ffd83dbSDimitry Andric return E;
5955ffd83dbSDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
5965ffd83dbSDimitry Andric return E;
5970b57cec5SDimitry Andric ImportDirectory = reinterpret_cast<
5980b57cec5SDimitry Andric const coff_import_directory_table_entry *>(IntPtr);
5995ffd83dbSDimitry Andric return Error::success();
6000b57cec5SDimitry Andric }
6010b57cec5SDimitry Andric
6020b57cec5SDimitry Andric // Initializes DelayImportDirectory and NumberOfDelayImportDirectory.
initDelayImportTablePtr()6035ffd83dbSDimitry Andric Error COFFObjectFile::initDelayImportTablePtr() {
6045ffd83dbSDimitry Andric const data_directory *DataEntry =
6055ffd83dbSDimitry Andric getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR);
6065ffd83dbSDimitry Andric if (!DataEntry)
6075ffd83dbSDimitry Andric return Error::success();
6080b57cec5SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
6095ffd83dbSDimitry Andric return Error::success();
6100b57cec5SDimitry Andric
6110b57cec5SDimitry Andric uint32_t RVA = DataEntry->RelativeVirtualAddress;
6120b57cec5SDimitry Andric NumberOfDelayImportDirectory = DataEntry->Size /
6130b57cec5SDimitry Andric sizeof(delay_import_directory_table_entry) - 1;
6140b57cec5SDimitry Andric
6150b57cec5SDimitry Andric uintptr_t IntPtr = 0;
61681ad6265SDimitry Andric if (Error E = getRvaPtr(RVA, IntPtr, "delay import table"))
6175ffd83dbSDimitry Andric return E;
61881ad6265SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
61981ad6265SDimitry Andric return E;
62081ad6265SDimitry Andric
6210b57cec5SDimitry Andric DelayImportDirectory = reinterpret_cast<
6220b57cec5SDimitry Andric const delay_import_directory_table_entry *>(IntPtr);
6235ffd83dbSDimitry Andric return Error::success();
6240b57cec5SDimitry Andric }
6250b57cec5SDimitry Andric
6260b57cec5SDimitry Andric // Find the export table.
initExportTablePtr()6275ffd83dbSDimitry Andric Error COFFObjectFile::initExportTablePtr() {
6280b57cec5SDimitry Andric // First, we get the RVA of the export table. If the file lacks a pointer to
6290b57cec5SDimitry Andric // the export table, do nothing.
6305ffd83dbSDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::EXPORT_TABLE);
6315ffd83dbSDimitry Andric if (!DataEntry)
6325ffd83dbSDimitry Andric return Error::success();
6330b57cec5SDimitry Andric
6340b57cec5SDimitry Andric // Do nothing if the pointer to export table is NULL.
6350b57cec5SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
6365ffd83dbSDimitry Andric return Error::success();
6370b57cec5SDimitry Andric
6380b57cec5SDimitry Andric uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
6390b57cec5SDimitry Andric uintptr_t IntPtr = 0;
64081ad6265SDimitry Andric if (Error E = getRvaPtr(ExportTableRva, IntPtr, "export table"))
6415ffd83dbSDimitry Andric return E;
64281ad6265SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
64381ad6265SDimitry Andric return E;
64481ad6265SDimitry Andric
6450b57cec5SDimitry Andric ExportDirectory =
6460b57cec5SDimitry Andric reinterpret_cast<const export_directory_table_entry *>(IntPtr);
6475ffd83dbSDimitry Andric return Error::success();
6480b57cec5SDimitry Andric }
6490b57cec5SDimitry Andric
initBaseRelocPtr()6505ffd83dbSDimitry Andric Error COFFObjectFile::initBaseRelocPtr() {
6515ffd83dbSDimitry Andric const data_directory *DataEntry =
6525ffd83dbSDimitry Andric getDataDirectory(COFF::BASE_RELOCATION_TABLE);
6535ffd83dbSDimitry Andric if (!DataEntry)
6545ffd83dbSDimitry Andric return Error::success();
6550b57cec5SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
6565ffd83dbSDimitry Andric return Error::success();
6570b57cec5SDimitry Andric
6580b57cec5SDimitry Andric uintptr_t IntPtr = 0;
65981ad6265SDimitry Andric if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
66081ad6265SDimitry Andric "base reloc table"))
6615ffd83dbSDimitry Andric return E;
66281ad6265SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
66381ad6265SDimitry Andric return E;
66481ad6265SDimitry Andric
6650b57cec5SDimitry Andric BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(
6660b57cec5SDimitry Andric IntPtr);
6670b57cec5SDimitry Andric BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(
6680b57cec5SDimitry Andric IntPtr + DataEntry->Size);
6690b57cec5SDimitry Andric // FIXME: Verify the section containing BaseRelocHeader has at least
6700b57cec5SDimitry Andric // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
6715ffd83dbSDimitry Andric return Error::success();
6720b57cec5SDimitry Andric }
6730b57cec5SDimitry Andric
initDebugDirectoryPtr()6745ffd83dbSDimitry Andric Error COFFObjectFile::initDebugDirectoryPtr() {
6750b57cec5SDimitry Andric // Get the RVA of the debug directory. Do nothing if it does not exist.
6765ffd83dbSDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::DEBUG_DIRECTORY);
6775ffd83dbSDimitry Andric if (!DataEntry)
6785ffd83dbSDimitry Andric return Error::success();
6790b57cec5SDimitry Andric
6800b57cec5SDimitry Andric // Do nothing if the RVA is NULL.
6810b57cec5SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
6825ffd83dbSDimitry Andric return Error::success();
6830b57cec5SDimitry Andric
6840b57cec5SDimitry Andric // Check that the size is a multiple of the entry size.
6850b57cec5SDimitry Andric if (DataEntry->Size % sizeof(debug_directory) != 0)
68681ad6265SDimitry Andric return createStringError(object_error::parse_failed,
68781ad6265SDimitry Andric "debug directory has uneven size");
6880b57cec5SDimitry Andric
6890b57cec5SDimitry Andric uintptr_t IntPtr = 0;
69081ad6265SDimitry Andric if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
69181ad6265SDimitry Andric "debug directory"))
6925ffd83dbSDimitry Andric return E;
69381ad6265SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
69481ad6265SDimitry Andric return E;
69581ad6265SDimitry Andric
6960b57cec5SDimitry Andric DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
6970b57cec5SDimitry Andric DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(
6980b57cec5SDimitry Andric IntPtr + DataEntry->Size);
6990b57cec5SDimitry Andric // FIXME: Verify the section containing DebugDirectoryBegin has at least
7000b57cec5SDimitry Andric // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
7015ffd83dbSDimitry Andric return Error::success();
7020b57cec5SDimitry Andric }
7030b57cec5SDimitry Andric
initTLSDirectoryPtr()704e8d8bef9SDimitry Andric Error COFFObjectFile::initTLSDirectoryPtr() {
705e8d8bef9SDimitry Andric // Get the RVA of the TLS directory. Do nothing if it does not exist.
706e8d8bef9SDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);
707e8d8bef9SDimitry Andric if (!DataEntry)
708e8d8bef9SDimitry Andric return Error::success();
709e8d8bef9SDimitry Andric
710e8d8bef9SDimitry Andric // Do nothing if the RVA is NULL.
711e8d8bef9SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
712e8d8bef9SDimitry Andric return Error::success();
713e8d8bef9SDimitry Andric
714e8d8bef9SDimitry Andric uint64_t DirSize =
715e8d8bef9SDimitry Andric is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32);
716e8d8bef9SDimitry Andric
717e8d8bef9SDimitry Andric // Check that the size is correct.
718e8d8bef9SDimitry Andric if (DataEntry->Size != DirSize)
719e8d8bef9SDimitry Andric return createStringError(
720e8d8bef9SDimitry Andric object_error::parse_failed,
721e8d8bef9SDimitry Andric "TLS Directory size (%u) is not the expected size (%" PRIu64 ").",
722e8d8bef9SDimitry Andric static_cast<uint32_t>(DataEntry->Size), DirSize);
723e8d8bef9SDimitry Andric
724e8d8bef9SDimitry Andric uintptr_t IntPtr = 0;
72581ad6265SDimitry Andric if (Error E =
72681ad6265SDimitry Andric getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory"))
72781ad6265SDimitry Andric return E;
72881ad6265SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
729e8d8bef9SDimitry Andric return E;
730e8d8bef9SDimitry Andric
731e8d8bef9SDimitry Andric if (is64())
732e8d8bef9SDimitry Andric TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
733e8d8bef9SDimitry Andric else
734e8d8bef9SDimitry Andric TLSDirectory32 = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);
735e8d8bef9SDimitry Andric
736e8d8bef9SDimitry Andric return Error::success();
737e8d8bef9SDimitry Andric }
738e8d8bef9SDimitry Andric
initLoadConfigPtr()7395ffd83dbSDimitry Andric Error COFFObjectFile::initLoadConfigPtr() {
7400b57cec5SDimitry Andric // Get the RVA of the debug directory. Do nothing if it does not exist.
7415ffd83dbSDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);
7425ffd83dbSDimitry Andric if (!DataEntry)
7435ffd83dbSDimitry Andric return Error::success();
7440b57cec5SDimitry Andric
7450b57cec5SDimitry Andric // Do nothing if the RVA is NULL.
7460b57cec5SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
7475ffd83dbSDimitry Andric return Error::success();
7480b57cec5SDimitry Andric uintptr_t IntPtr = 0;
74981ad6265SDimitry Andric if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
75081ad6265SDimitry Andric "load config table"))
75181ad6265SDimitry Andric return E;
75281ad6265SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
7535ffd83dbSDimitry Andric return E;
7540b57cec5SDimitry Andric
7550b57cec5SDimitry Andric LoadConfig = (const void *)IntPtr;
75606c3fb27SDimitry Andric
75706c3fb27SDimitry Andric if (is64()) {
75806c3fb27SDimitry Andric auto Config = getLoadConfig64();
75906c3fb27SDimitry Andric if (Config->Size >=
76006c3fb27SDimitry Andric offsetof(coff_load_configuration64, CHPEMetadataPointer) +
76106c3fb27SDimitry Andric sizeof(Config->CHPEMetadataPointer) &&
76206c3fb27SDimitry Andric Config->CHPEMetadataPointer) {
76306c3fb27SDimitry Andric uint64_t ChpeOff = Config->CHPEMetadataPointer;
76406c3fb27SDimitry Andric if (Error E =
76506c3fb27SDimitry Andric getRvaPtr(ChpeOff - getImageBase(), IntPtr, "CHPE metadata"))
76606c3fb27SDimitry Andric return E;
76706c3fb27SDimitry Andric if (Error E = checkOffset(Data, IntPtr, sizeof(CHPEMetadata)))
76806c3fb27SDimitry Andric return E;
76906c3fb27SDimitry Andric
77006c3fb27SDimitry Andric CHPEMetadata = reinterpret_cast<const chpe_metadata *>(IntPtr);
77106c3fb27SDimitry Andric
77206c3fb27SDimitry Andric // Validate CHPE metadata
77306c3fb27SDimitry Andric if (CHPEMetadata->CodeMapCount) {
77406c3fb27SDimitry Andric if (Error E = getRvaPtr(CHPEMetadata->CodeMap, IntPtr, "CHPE code map"))
77506c3fb27SDimitry Andric return E;
77606c3fb27SDimitry Andric if (Error E = checkOffset(Data, IntPtr,
77706c3fb27SDimitry Andric CHPEMetadata->CodeMapCount *
77806c3fb27SDimitry Andric sizeof(chpe_range_entry)))
77906c3fb27SDimitry Andric return E;
78006c3fb27SDimitry Andric }
78106c3fb27SDimitry Andric
78206c3fb27SDimitry Andric if (CHPEMetadata->CodeRangesToEntryPointsCount) {
78306c3fb27SDimitry Andric if (Error E = getRvaPtr(CHPEMetadata->CodeRangesToEntryPoints, IntPtr,
78406c3fb27SDimitry Andric "CHPE entry point ranges"))
78506c3fb27SDimitry Andric return E;
78606c3fb27SDimitry Andric if (Error E = checkOffset(Data, IntPtr,
78706c3fb27SDimitry Andric CHPEMetadata->CodeRangesToEntryPointsCount *
78806c3fb27SDimitry Andric sizeof(chpe_code_range_entry)))
78906c3fb27SDimitry Andric return E;
79006c3fb27SDimitry Andric }
79106c3fb27SDimitry Andric
79206c3fb27SDimitry Andric if (CHPEMetadata->RedirectionMetadataCount) {
79306c3fb27SDimitry Andric if (Error E = getRvaPtr(CHPEMetadata->RedirectionMetadata, IntPtr,
79406c3fb27SDimitry Andric "CHPE redirection metadata"))
79506c3fb27SDimitry Andric return E;
79606c3fb27SDimitry Andric if (Error E = checkOffset(Data, IntPtr,
79706c3fb27SDimitry Andric CHPEMetadata->RedirectionMetadataCount *
79806c3fb27SDimitry Andric sizeof(chpe_redirection_entry)))
79906c3fb27SDimitry Andric return E;
80006c3fb27SDimitry Andric }
80106c3fb27SDimitry Andric }
80206c3fb27SDimitry Andric }
80306c3fb27SDimitry Andric
8045ffd83dbSDimitry Andric return Error::success();
8050b57cec5SDimitry Andric }
8060b57cec5SDimitry Andric
8075ffd83dbSDimitry Andric Expected<std::unique_ptr<COFFObjectFile>>
create(MemoryBufferRef Object)8085ffd83dbSDimitry Andric COFFObjectFile::create(MemoryBufferRef Object) {
8095ffd83dbSDimitry Andric std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object)));
8105ffd83dbSDimitry Andric if (Error E = Obj->initialize())
8115ffd83dbSDimitry Andric return std::move(E);
8125ffd83dbSDimitry Andric return std::move(Obj);
8135ffd83dbSDimitry Andric }
8145ffd83dbSDimitry Andric
COFFObjectFile(MemoryBufferRef Object)8155ffd83dbSDimitry Andric COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)
8160b57cec5SDimitry Andric : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
8170b57cec5SDimitry Andric COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
8180b57cec5SDimitry Andric DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),
8190b57cec5SDimitry Andric SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),
8205ffd83dbSDimitry Andric ImportDirectory(nullptr), DelayImportDirectory(nullptr),
8215ffd83dbSDimitry Andric NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),
8225ffd83dbSDimitry Andric BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
823e8d8bef9SDimitry Andric DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),
824e8d8bef9SDimitry Andric TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}
8255ffd83dbSDimitry Andric
ignoreStrippedErrors(Error E)82681ad6265SDimitry Andric static Error ignoreStrippedErrors(Error E) {
82781ad6265SDimitry Andric if (E.isA<SectionStrippedError>()) {
82881ad6265SDimitry Andric consumeError(std::move(E));
82981ad6265SDimitry Andric return Error::success();
83081ad6265SDimitry Andric }
83181ad6265SDimitry Andric return E;
83281ad6265SDimitry Andric }
83381ad6265SDimitry Andric
initialize()8345ffd83dbSDimitry Andric Error COFFObjectFile::initialize() {
8350b57cec5SDimitry Andric // Check that we at least have enough room for a header.
8365ffd83dbSDimitry Andric std::error_code EC;
8370b57cec5SDimitry Andric if (!checkSize(Data, EC, sizeof(coff_file_header)))
8385ffd83dbSDimitry Andric return errorCodeToError(EC);
8390b57cec5SDimitry Andric
8400b57cec5SDimitry Andric // The current location in the file where we are looking at.
8410b57cec5SDimitry Andric uint64_t CurPtr = 0;
8420b57cec5SDimitry Andric
8430b57cec5SDimitry Andric // PE header is optional and is present only in executables. If it exists,
8440b57cec5SDimitry Andric // it is placed right after COFF header.
8450b57cec5SDimitry Andric bool HasPEHeader = false;
8460b57cec5SDimitry Andric
8470b57cec5SDimitry Andric // Check if this is a PE/COFF file.
8480b57cec5SDimitry Andric if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {
8490b57cec5SDimitry Andric // PE/COFF, seek through MS-DOS compatibility stub and 4-byte
8500b57cec5SDimitry Andric // PE signature to find 'normal' COFF header.
8510b57cec5SDimitry Andric const auto *DH = reinterpret_cast<const dos_header *>(base());
8520b57cec5SDimitry Andric if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {
8530b57cec5SDimitry Andric CurPtr = DH->AddressOfNewExeHeader;
8540b57cec5SDimitry Andric // Check the PE magic bytes. ("PE\0\0")
8550b57cec5SDimitry Andric if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {
85681ad6265SDimitry Andric return createStringError(object_error::parse_failed,
85781ad6265SDimitry Andric "incorrect PE magic");
8580b57cec5SDimitry Andric }
8590b57cec5SDimitry Andric CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.
8600b57cec5SDimitry Andric HasPEHeader = true;
8610b57cec5SDimitry Andric }
8620b57cec5SDimitry Andric }
8630b57cec5SDimitry Andric
8645ffd83dbSDimitry Andric if (Error E = getObject(COFFHeader, Data, base() + CurPtr))
8655ffd83dbSDimitry Andric return E;
8660b57cec5SDimitry Andric
8670b57cec5SDimitry Andric // It might be a bigobj file, let's check. Note that COFF bigobj and COFF
8680b57cec5SDimitry Andric // import libraries share a common prefix but bigobj is more restrictive.
8690b57cec5SDimitry Andric if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
8700b57cec5SDimitry Andric COFFHeader->NumberOfSections == uint16_t(0xffff) &&
8710b57cec5SDimitry Andric checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {
8725ffd83dbSDimitry Andric if (Error E = getObject(COFFBigObjHeader, Data, base() + CurPtr))
8735ffd83dbSDimitry Andric return E;
8740b57cec5SDimitry Andric
8750b57cec5SDimitry Andric // Verify that we are dealing with bigobj.
8760b57cec5SDimitry Andric if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&
8770b57cec5SDimitry Andric std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,
8780b57cec5SDimitry Andric sizeof(COFF::BigObjMagic)) == 0) {
8790b57cec5SDimitry Andric COFFHeader = nullptr;
8800b57cec5SDimitry Andric CurPtr += sizeof(coff_bigobj_file_header);
8810b57cec5SDimitry Andric } else {
8820b57cec5SDimitry Andric // It's not a bigobj.
8830b57cec5SDimitry Andric COFFBigObjHeader = nullptr;
8840b57cec5SDimitry Andric }
8850b57cec5SDimitry Andric }
8860b57cec5SDimitry Andric if (COFFHeader) {
8870b57cec5SDimitry Andric // The prior checkSize call may have failed. This isn't a hard error
8880b57cec5SDimitry Andric // because we were just trying to sniff out bigobj.
8890b57cec5SDimitry Andric EC = std::error_code();
8900b57cec5SDimitry Andric CurPtr += sizeof(coff_file_header);
8910b57cec5SDimitry Andric
8920b57cec5SDimitry Andric if (COFFHeader->isImportLibrary())
8935ffd83dbSDimitry Andric return errorCodeToError(EC);
8940b57cec5SDimitry Andric }
8950b57cec5SDimitry Andric
8960b57cec5SDimitry Andric if (HasPEHeader) {
8970b57cec5SDimitry Andric const pe32_header *Header;
8985ffd83dbSDimitry Andric if (Error E = getObject(Header, Data, base() + CurPtr))
8995ffd83dbSDimitry Andric return E;
9000b57cec5SDimitry Andric
9010b57cec5SDimitry Andric const uint8_t *DataDirAddr;
9020b57cec5SDimitry Andric uint64_t DataDirSize;
9030b57cec5SDimitry Andric if (Header->Magic == COFF::PE32Header::PE32) {
9040b57cec5SDimitry Andric PE32Header = Header;
9050b57cec5SDimitry Andric DataDirAddr = base() + CurPtr + sizeof(pe32_header);
9060b57cec5SDimitry Andric DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;
9070b57cec5SDimitry Andric } else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {
9080b57cec5SDimitry Andric PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);
9090b57cec5SDimitry Andric DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);
9100b57cec5SDimitry Andric DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
9110b57cec5SDimitry Andric } else {
9120b57cec5SDimitry Andric // It's neither PE32 nor PE32+.
91381ad6265SDimitry Andric return createStringError(object_error::parse_failed,
91481ad6265SDimitry Andric "incorrect PE magic");
9150b57cec5SDimitry Andric }
9165ffd83dbSDimitry Andric if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))
9175ffd83dbSDimitry Andric return E;
9180b57cec5SDimitry Andric }
9190b57cec5SDimitry Andric
9200b57cec5SDimitry Andric if (COFFHeader)
9210b57cec5SDimitry Andric CurPtr += COFFHeader->SizeOfOptionalHeader;
9220b57cec5SDimitry Andric
9235ffd83dbSDimitry Andric assert(COFFHeader || COFFBigObjHeader);
9245ffd83dbSDimitry Andric
9255ffd83dbSDimitry Andric if (Error E =
9265ffd83dbSDimitry Andric getObject(SectionTable, Data, base() + CurPtr,
9275ffd83dbSDimitry Andric (uint64_t)getNumberOfSections() * sizeof(coff_section)))
9285ffd83dbSDimitry Andric return E;
9290b57cec5SDimitry Andric
9300b57cec5SDimitry Andric // Initialize the pointer to the symbol table.
9310b57cec5SDimitry Andric if (getPointerToSymbolTable() != 0) {
9325ffd83dbSDimitry Andric if (Error E = initSymbolTablePtr()) {
9335ffd83dbSDimitry Andric // Recover from errors reading the symbol table.
9345ffd83dbSDimitry Andric consumeError(std::move(E));
9350b57cec5SDimitry Andric SymbolTable16 = nullptr;
9360b57cec5SDimitry Andric SymbolTable32 = nullptr;
9370b57cec5SDimitry Andric StringTable = nullptr;
9380b57cec5SDimitry Andric StringTableSize = 0;
9390b57cec5SDimitry Andric }
9400b57cec5SDimitry Andric } else {
9410b57cec5SDimitry Andric // We had better not have any symbols if we don't have a symbol table.
9420b57cec5SDimitry Andric if (getNumberOfSymbols() != 0) {
94381ad6265SDimitry Andric return createStringError(object_error::parse_failed,
94481ad6265SDimitry Andric "symbol table missing");
9450b57cec5SDimitry Andric }
9460b57cec5SDimitry Andric }
9470b57cec5SDimitry Andric
9480b57cec5SDimitry Andric // Initialize the pointer to the beginning of the import table.
94981ad6265SDimitry Andric if (Error E = ignoreStrippedErrors(initImportTablePtr()))
9505ffd83dbSDimitry Andric return E;
95181ad6265SDimitry Andric if (Error E = ignoreStrippedErrors(initDelayImportTablePtr()))
9525ffd83dbSDimitry Andric return E;
9530b57cec5SDimitry Andric
9540b57cec5SDimitry Andric // Initialize the pointer to the export table.
95581ad6265SDimitry Andric if (Error E = ignoreStrippedErrors(initExportTablePtr()))
9565ffd83dbSDimitry Andric return E;
9570b57cec5SDimitry Andric
9580b57cec5SDimitry Andric // Initialize the pointer to the base relocation table.
95981ad6265SDimitry Andric if (Error E = ignoreStrippedErrors(initBaseRelocPtr()))
9605ffd83dbSDimitry Andric return E;
9610b57cec5SDimitry Andric
962e8d8bef9SDimitry Andric // Initialize the pointer to the debug directory.
96381ad6265SDimitry Andric if (Error E = ignoreStrippedErrors(initDebugDirectoryPtr()))
9645ffd83dbSDimitry Andric return E;
9650b57cec5SDimitry Andric
966e8d8bef9SDimitry Andric // Initialize the pointer to the TLS directory.
96781ad6265SDimitry Andric if (Error E = ignoreStrippedErrors(initTLSDirectoryPtr()))
968e8d8bef9SDimitry Andric return E;
969e8d8bef9SDimitry Andric
97081ad6265SDimitry Andric if (Error E = ignoreStrippedErrors(initLoadConfigPtr()))
9715ffd83dbSDimitry Andric return E;
9720b57cec5SDimitry Andric
9735ffd83dbSDimitry Andric return Error::success();
9740b57cec5SDimitry Andric }
9750b57cec5SDimitry Andric
symbol_begin() const9760b57cec5SDimitry Andric basic_symbol_iterator COFFObjectFile::symbol_begin() const {
9770b57cec5SDimitry Andric DataRefImpl Ret;
9780b57cec5SDimitry Andric Ret.p = getSymbolTable();
9790b57cec5SDimitry Andric return basic_symbol_iterator(SymbolRef(Ret, this));
9800b57cec5SDimitry Andric }
9810b57cec5SDimitry Andric
symbol_end() const9820b57cec5SDimitry Andric basic_symbol_iterator COFFObjectFile::symbol_end() const {
9830b57cec5SDimitry Andric // The symbol table ends where the string table begins.
9840b57cec5SDimitry Andric DataRefImpl Ret;
9850b57cec5SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(StringTable);
9860b57cec5SDimitry Andric return basic_symbol_iterator(SymbolRef(Ret, this));
9870b57cec5SDimitry Andric }
9880b57cec5SDimitry Andric
import_directory_begin() const9890b57cec5SDimitry Andric import_directory_iterator COFFObjectFile::import_directory_begin() const {
9900b57cec5SDimitry Andric if (!ImportDirectory)
9910b57cec5SDimitry Andric return import_directory_end();
9920b57cec5SDimitry Andric if (ImportDirectory->isNull())
9930b57cec5SDimitry Andric return import_directory_end();
9940b57cec5SDimitry Andric return import_directory_iterator(
9950b57cec5SDimitry Andric ImportDirectoryEntryRef(ImportDirectory, 0, this));
9960b57cec5SDimitry Andric }
9970b57cec5SDimitry Andric
import_directory_end() const9980b57cec5SDimitry Andric import_directory_iterator COFFObjectFile::import_directory_end() const {
9990b57cec5SDimitry Andric return import_directory_iterator(
10000b57cec5SDimitry Andric ImportDirectoryEntryRef(nullptr, -1, this));
10010b57cec5SDimitry Andric }
10020b57cec5SDimitry Andric
10030b57cec5SDimitry Andric delay_import_directory_iterator
delay_import_directory_begin() const10040b57cec5SDimitry Andric COFFObjectFile::delay_import_directory_begin() const {
10050b57cec5SDimitry Andric return delay_import_directory_iterator(
10060b57cec5SDimitry Andric DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));
10070b57cec5SDimitry Andric }
10080b57cec5SDimitry Andric
10090b57cec5SDimitry Andric delay_import_directory_iterator
delay_import_directory_end() const10100b57cec5SDimitry Andric COFFObjectFile::delay_import_directory_end() const {
10110b57cec5SDimitry Andric return delay_import_directory_iterator(
10120b57cec5SDimitry Andric DelayImportDirectoryEntryRef(
10130b57cec5SDimitry Andric DelayImportDirectory, NumberOfDelayImportDirectory, this));
10140b57cec5SDimitry Andric }
10150b57cec5SDimitry Andric
export_directory_begin() const10160b57cec5SDimitry Andric export_directory_iterator COFFObjectFile::export_directory_begin() const {
10170b57cec5SDimitry Andric return export_directory_iterator(
10180b57cec5SDimitry Andric ExportDirectoryEntryRef(ExportDirectory, 0, this));
10190b57cec5SDimitry Andric }
10200b57cec5SDimitry Andric
export_directory_end() const10210b57cec5SDimitry Andric export_directory_iterator COFFObjectFile::export_directory_end() const {
10220b57cec5SDimitry Andric if (!ExportDirectory)
10230b57cec5SDimitry Andric return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));
10240b57cec5SDimitry Andric ExportDirectoryEntryRef Ref(ExportDirectory,
10250b57cec5SDimitry Andric ExportDirectory->AddressTableEntries, this);
10260b57cec5SDimitry Andric return export_directory_iterator(Ref);
10270b57cec5SDimitry Andric }
10280b57cec5SDimitry Andric
section_begin() const10290b57cec5SDimitry Andric section_iterator COFFObjectFile::section_begin() const {
10300b57cec5SDimitry Andric DataRefImpl Ret;
10310b57cec5SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(SectionTable);
10320b57cec5SDimitry Andric return section_iterator(SectionRef(Ret, this));
10330b57cec5SDimitry Andric }
10340b57cec5SDimitry Andric
section_end() const10350b57cec5SDimitry Andric section_iterator COFFObjectFile::section_end() const {
10360b57cec5SDimitry Andric DataRefImpl Ret;
10370b57cec5SDimitry Andric int NumSections =
10380b57cec5SDimitry Andric COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();
10390b57cec5SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);
10400b57cec5SDimitry Andric return section_iterator(SectionRef(Ret, this));
10410b57cec5SDimitry Andric }
10420b57cec5SDimitry Andric
base_reloc_begin() const10430b57cec5SDimitry Andric base_reloc_iterator COFFObjectFile::base_reloc_begin() const {
10440b57cec5SDimitry Andric return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));
10450b57cec5SDimitry Andric }
10460b57cec5SDimitry Andric
base_reloc_end() const10470b57cec5SDimitry Andric base_reloc_iterator COFFObjectFile::base_reloc_end() const {
10480b57cec5SDimitry Andric return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));
10490b57cec5SDimitry Andric }
10500b57cec5SDimitry Andric
getBytesInAddress() const10510b57cec5SDimitry Andric uint8_t COFFObjectFile::getBytesInAddress() const {
10520b57cec5SDimitry Andric return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;
10530b57cec5SDimitry Andric }
10540b57cec5SDimitry Andric
getFileFormatName() const10550b57cec5SDimitry Andric StringRef COFFObjectFile::getFileFormatName() const {
10560b57cec5SDimitry Andric switch(getMachine()) {
10570b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
10580b57cec5SDimitry Andric return "COFF-i386";
10590b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
10600b57cec5SDimitry Andric return "COFF-x86-64";
10610b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
10620b57cec5SDimitry Andric return "COFF-ARM";
10630b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
10640b57cec5SDimitry Andric return "COFF-ARM64";
1065bdd1243dSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64EC:
1066bdd1243dSDimitry Andric return "COFF-ARM64EC";
106706c3fb27SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64X:
106806c3fb27SDimitry Andric return "COFF-ARM64X";
10690b57cec5SDimitry Andric default:
10700b57cec5SDimitry Andric return "COFF-<unknown arch>";
10710b57cec5SDimitry Andric }
10720b57cec5SDimitry Andric }
10730b57cec5SDimitry Andric
getArch() const10740b57cec5SDimitry Andric Triple::ArchType COFFObjectFile::getArch() const {
10750b57cec5SDimitry Andric switch (getMachine()) {
10760b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
10770b57cec5SDimitry Andric return Triple::x86;
10780b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
10790b57cec5SDimitry Andric return Triple::x86_64;
10800b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
10810b57cec5SDimitry Andric return Triple::thumb;
10820b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
1083bdd1243dSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64EC:
108406c3fb27SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64X:
10850b57cec5SDimitry Andric return Triple::aarch64;
10860b57cec5SDimitry Andric default:
10870b57cec5SDimitry Andric return Triple::UnknownArch;
10880b57cec5SDimitry Andric }
10890b57cec5SDimitry Andric }
10900b57cec5SDimitry Andric
getStartAddress() const10910b57cec5SDimitry Andric Expected<uint64_t> COFFObjectFile::getStartAddress() const {
10920b57cec5SDimitry Andric if (PE32Header)
10930b57cec5SDimitry Andric return PE32Header->AddressOfEntryPoint;
10940b57cec5SDimitry Andric return 0;
10950b57cec5SDimitry Andric }
10960b57cec5SDimitry Andric
10970b57cec5SDimitry Andric iterator_range<import_directory_iterator>
import_directories() const10980b57cec5SDimitry Andric COFFObjectFile::import_directories() const {
10990b57cec5SDimitry Andric return make_range(import_directory_begin(), import_directory_end());
11000b57cec5SDimitry Andric }
11010b57cec5SDimitry Andric
11020b57cec5SDimitry Andric iterator_range<delay_import_directory_iterator>
delay_import_directories() const11030b57cec5SDimitry Andric COFFObjectFile::delay_import_directories() const {
11040b57cec5SDimitry Andric return make_range(delay_import_directory_begin(),
11050b57cec5SDimitry Andric delay_import_directory_end());
11060b57cec5SDimitry Andric }
11070b57cec5SDimitry Andric
11080b57cec5SDimitry Andric iterator_range<export_directory_iterator>
export_directories() const11090b57cec5SDimitry Andric COFFObjectFile::export_directories() const {
11100b57cec5SDimitry Andric return make_range(export_directory_begin(), export_directory_end());
11110b57cec5SDimitry Andric }
11120b57cec5SDimitry Andric
base_relocs() const11130b57cec5SDimitry Andric iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {
11140b57cec5SDimitry Andric return make_range(base_reloc_begin(), base_reloc_end());
11150b57cec5SDimitry Andric }
11160b57cec5SDimitry Andric
getDataDirectory(uint32_t Index) const11175ffd83dbSDimitry Andric const data_directory *COFFObjectFile::getDataDirectory(uint32_t Index) const {
11185ffd83dbSDimitry Andric if (!DataDirectory)
11195ffd83dbSDimitry Andric return nullptr;
11200b57cec5SDimitry Andric assert(PE32Header || PE32PlusHeader);
11210b57cec5SDimitry Andric uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize
11220b57cec5SDimitry Andric : PE32PlusHeader->NumberOfRvaAndSize;
11235ffd83dbSDimitry Andric if (Index >= NumEnt)
11245ffd83dbSDimitry Andric return nullptr;
11255ffd83dbSDimitry Andric return &DataDirectory[Index];
11260b57cec5SDimitry Andric }
11270b57cec5SDimitry Andric
getSection(int32_t Index) const11285ffd83dbSDimitry Andric Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {
11295ffd83dbSDimitry Andric // Perhaps getting the section of a reserved section index should be an error,
11305ffd83dbSDimitry Andric // but callers rely on this to return null.
11310b57cec5SDimitry Andric if (COFF::isReservedSectionNumber(Index))
11325ffd83dbSDimitry Andric return (const coff_section *)nullptr;
11330b57cec5SDimitry Andric if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {
11340b57cec5SDimitry Andric // We already verified the section table data, so no need to check again.
11355ffd83dbSDimitry Andric return SectionTable + (Index - 1);
11360b57cec5SDimitry Andric }
113781ad6265SDimitry Andric return createStringError(object_error::parse_failed,
113881ad6265SDimitry Andric "section index out of bounds");
11390b57cec5SDimitry Andric }
11400b57cec5SDimitry Andric
getString(uint32_t Offset) const11415ffd83dbSDimitry Andric Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {
11420b57cec5SDimitry Andric if (StringTableSize <= 4)
11430b57cec5SDimitry Andric // Tried to get a string from an empty string table.
114481ad6265SDimitry Andric return createStringError(object_error::parse_failed, "string table empty");
11450b57cec5SDimitry Andric if (Offset >= StringTableSize)
11465ffd83dbSDimitry Andric return errorCodeToError(object_error::unexpected_eof);
11475ffd83dbSDimitry Andric return StringRef(StringTable + Offset);
11480b57cec5SDimitry Andric }
11490b57cec5SDimitry Andric
getSymbolName(COFFSymbolRef Symbol) const11505ffd83dbSDimitry Andric Expected<StringRef> COFFObjectFile::getSymbolName(COFFSymbolRef Symbol) const {
11515ffd83dbSDimitry Andric return getSymbolName(Symbol.getGeneric());
11520b57cec5SDimitry Andric }
11530b57cec5SDimitry Andric
11545ffd83dbSDimitry Andric Expected<StringRef>
getSymbolName(const coff_symbol_generic * Symbol) const11555ffd83dbSDimitry Andric COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol) const {
11560b57cec5SDimitry Andric // Check for string table entry. First 4 bytes are 0.
11575ffd83dbSDimitry Andric if (Symbol->Name.Offset.Zeroes == 0)
11585ffd83dbSDimitry Andric return getString(Symbol->Name.Offset.Offset);
11590b57cec5SDimitry Andric
11600b57cec5SDimitry Andric // Null terminated, let ::strlen figure out the length.
11615ffd83dbSDimitry Andric if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)
11625ffd83dbSDimitry Andric return StringRef(Symbol->Name.ShortName);
11635ffd83dbSDimitry Andric
11640b57cec5SDimitry Andric // Not null terminated, use all 8 bytes.
11655ffd83dbSDimitry Andric return StringRef(Symbol->Name.ShortName, COFF::NameSize);
11660b57cec5SDimitry Andric }
11670b57cec5SDimitry Andric
11680b57cec5SDimitry Andric ArrayRef<uint8_t>
getSymbolAuxData(COFFSymbolRef Symbol) const11690b57cec5SDimitry Andric COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {
11700b57cec5SDimitry Andric const uint8_t *Aux = nullptr;
11710b57cec5SDimitry Andric
11720b57cec5SDimitry Andric size_t SymbolSize = getSymbolTableEntrySize();
11730b57cec5SDimitry Andric if (Symbol.getNumberOfAuxSymbols() > 0) {
11740b57cec5SDimitry Andric // AUX data comes immediately after the symbol in COFF
11750b57cec5SDimitry Andric Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;
11760b57cec5SDimitry Andric #ifndef NDEBUG
11770b57cec5SDimitry Andric // Verify that the Aux symbol points to a valid entry in the symbol table.
11780b57cec5SDimitry Andric uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());
11790b57cec5SDimitry Andric if (Offset < getPointerToSymbolTable() ||
11800b57cec5SDimitry Andric Offset >=
11810b57cec5SDimitry Andric getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))
11820b57cec5SDimitry Andric report_fatal_error("Aux Symbol data was outside of symbol table.");
11830b57cec5SDimitry Andric
11840b57cec5SDimitry Andric assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&
11850b57cec5SDimitry Andric "Aux Symbol data did not point to the beginning of a symbol");
11860b57cec5SDimitry Andric #endif
11870b57cec5SDimitry Andric }
1188bdd1243dSDimitry Andric return ArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);
11890b57cec5SDimitry Andric }
11900b57cec5SDimitry Andric
getSymbolIndex(COFFSymbolRef Symbol) const11910b57cec5SDimitry Andric uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {
11920b57cec5SDimitry Andric uintptr_t Offset =
11930b57cec5SDimitry Andric reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();
11940b57cec5SDimitry Andric assert(Offset % getSymbolTableEntrySize() == 0 &&
11950b57cec5SDimitry Andric "Symbol did not point to the beginning of a symbol");
11960b57cec5SDimitry Andric size_t Index = Offset / getSymbolTableEntrySize();
11970b57cec5SDimitry Andric assert(Index < getNumberOfSymbols());
11980b57cec5SDimitry Andric return Index;
11990b57cec5SDimitry Andric }
12000b57cec5SDimitry Andric
12010b57cec5SDimitry Andric Expected<StringRef>
getSectionName(const coff_section * Sec) const12020b57cec5SDimitry Andric COFFObjectFile::getSectionName(const coff_section *Sec) const {
120381ad6265SDimitry Andric StringRef Name = StringRef(Sec->Name, COFF::NameSize).split('\0').first;
12040b57cec5SDimitry Andric
12050b57cec5SDimitry Andric // Check for string table entry. First byte is '/'.
12065f757f3fSDimitry Andric if (Name.starts_with("/")) {
12070b57cec5SDimitry Andric uint32_t Offset;
12085f757f3fSDimitry Andric if (Name.starts_with("//")) {
12090b57cec5SDimitry Andric if (decodeBase64StringEntry(Name.substr(2), Offset))
12100b57cec5SDimitry Andric return createStringError(object_error::parse_failed,
12115ffd83dbSDimitry Andric "invalid section name");
12120b57cec5SDimitry Andric } else {
12130b57cec5SDimitry Andric if (Name.substr(1).getAsInteger(10, Offset))
12140b57cec5SDimitry Andric return createStringError(object_error::parse_failed,
12150b57cec5SDimitry Andric "invalid section name");
12160b57cec5SDimitry Andric }
12175ffd83dbSDimitry Andric return getString(Offset);
12180b57cec5SDimitry Andric }
12190b57cec5SDimitry Andric
12200b57cec5SDimitry Andric return Name;
12210b57cec5SDimitry Andric }
12220b57cec5SDimitry Andric
getSectionSize(const coff_section * Sec) const12230b57cec5SDimitry Andric uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {
12240b57cec5SDimitry Andric // SizeOfRawData and VirtualSize change what they represent depending on
12250b57cec5SDimitry Andric // whether or not we have an executable image.
12260b57cec5SDimitry Andric //
12270b57cec5SDimitry Andric // For object files, SizeOfRawData contains the size of section's data;
12280b57cec5SDimitry Andric // VirtualSize should be zero but isn't due to buggy COFF writers.
12290b57cec5SDimitry Andric //
12300b57cec5SDimitry Andric // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the
12310b57cec5SDimitry Andric // actual section size is in VirtualSize. It is possible for VirtualSize to
12320b57cec5SDimitry Andric // be greater than SizeOfRawData; the contents past that point should be
12330b57cec5SDimitry Andric // considered to be zero.
12340b57cec5SDimitry Andric if (getDOSHeader())
12350b57cec5SDimitry Andric return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
12360b57cec5SDimitry Andric return Sec->SizeOfRawData;
12370b57cec5SDimitry Andric }
12380b57cec5SDimitry Andric
getSectionContents(const coff_section * Sec,ArrayRef<uint8_t> & Res) const12390b57cec5SDimitry Andric Error COFFObjectFile::getSectionContents(const coff_section *Sec,
12400b57cec5SDimitry Andric ArrayRef<uint8_t> &Res) const {
12410b57cec5SDimitry Andric // In COFF, a virtual section won't have any in-file
12420b57cec5SDimitry Andric // content, so the file pointer to the content will be zero.
12430b57cec5SDimitry Andric if (Sec->PointerToRawData == 0)
12440b57cec5SDimitry Andric return Error::success();
12450b57cec5SDimitry Andric // The only thing that we need to verify is that the contents is contained
12460b57cec5SDimitry Andric // within the file bounds. We don't need to make sure it doesn't cover other
12470b57cec5SDimitry Andric // data, as there's nothing that says that is not allowed.
1248e8d8bef9SDimitry Andric uintptr_t ConStart =
1249e8d8bef9SDimitry Andric reinterpret_cast<uintptr_t>(base()) + Sec->PointerToRawData;
12500b57cec5SDimitry Andric uint32_t SectionSize = getSectionSize(Sec);
12515ffd83dbSDimitry Andric if (Error E = checkOffset(Data, ConStart, SectionSize))
12525ffd83dbSDimitry Andric return E;
1253bdd1243dSDimitry Andric Res = ArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);
12540b57cec5SDimitry Andric return Error::success();
12550b57cec5SDimitry Andric }
12560b57cec5SDimitry Andric
toRel(DataRefImpl Rel) const12570b57cec5SDimitry Andric const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {
12580b57cec5SDimitry Andric return reinterpret_cast<const coff_relocation*>(Rel.p);
12590b57cec5SDimitry Andric }
12600b57cec5SDimitry Andric
moveRelocationNext(DataRefImpl & Rel) const12610b57cec5SDimitry Andric void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
12620b57cec5SDimitry Andric Rel.p = reinterpret_cast<uintptr_t>(
12630b57cec5SDimitry Andric reinterpret_cast<const coff_relocation*>(Rel.p) + 1);
12640b57cec5SDimitry Andric }
12650b57cec5SDimitry Andric
getRelocationOffset(DataRefImpl Rel) const12660b57cec5SDimitry Andric uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
12670b57cec5SDimitry Andric const coff_relocation *R = toRel(Rel);
12680b57cec5SDimitry Andric return R->VirtualAddress;
12690b57cec5SDimitry Andric }
12700b57cec5SDimitry Andric
getRelocationSymbol(DataRefImpl Rel) const12710b57cec5SDimitry Andric symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
12720b57cec5SDimitry Andric const coff_relocation *R = toRel(Rel);
12730b57cec5SDimitry Andric DataRefImpl Ref;
12740b57cec5SDimitry Andric if (R->SymbolTableIndex >= getNumberOfSymbols())
12750b57cec5SDimitry Andric return symbol_end();
12760b57cec5SDimitry Andric if (SymbolTable16)
12770b57cec5SDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);
12780b57cec5SDimitry Andric else if (SymbolTable32)
12790b57cec5SDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);
12800b57cec5SDimitry Andric else
12810b57cec5SDimitry Andric llvm_unreachable("no symbol table pointer!");
12820b57cec5SDimitry Andric return symbol_iterator(SymbolRef(Ref, this));
12830b57cec5SDimitry Andric }
12840b57cec5SDimitry Andric
getRelocationType(DataRefImpl Rel) const12850b57cec5SDimitry Andric uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {
12860b57cec5SDimitry Andric const coff_relocation* R = toRel(Rel);
12870b57cec5SDimitry Andric return R->Type;
12880b57cec5SDimitry Andric }
12890b57cec5SDimitry Andric
12900b57cec5SDimitry Andric const coff_section *
getCOFFSection(const SectionRef & Section) const12910b57cec5SDimitry Andric COFFObjectFile::getCOFFSection(const SectionRef &Section) const {
12920b57cec5SDimitry Andric return toSec(Section.getRawDataRefImpl());
12930b57cec5SDimitry Andric }
12940b57cec5SDimitry Andric
getCOFFSymbol(const DataRefImpl & Ref) const12950b57cec5SDimitry Andric COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {
12960b57cec5SDimitry Andric if (SymbolTable16)
12970b57cec5SDimitry Andric return toSymb<coff_symbol16>(Ref);
12980b57cec5SDimitry Andric if (SymbolTable32)
12990b57cec5SDimitry Andric return toSymb<coff_symbol32>(Ref);
13000b57cec5SDimitry Andric llvm_unreachable("no symbol table pointer!");
13010b57cec5SDimitry Andric }
13020b57cec5SDimitry Andric
getCOFFSymbol(const SymbolRef & Symbol) const13030b57cec5SDimitry Andric COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {
13040b57cec5SDimitry Andric return getCOFFSymbol(Symbol.getRawDataRefImpl());
13050b57cec5SDimitry Andric }
13060b57cec5SDimitry Andric
13070b57cec5SDimitry Andric const coff_relocation *
getCOFFRelocation(const RelocationRef & Reloc) const13080b57cec5SDimitry Andric COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {
13090b57cec5SDimitry Andric return toRel(Reloc.getRawDataRefImpl());
13100b57cec5SDimitry Andric }
13110b57cec5SDimitry Andric
13120b57cec5SDimitry Andric ArrayRef<coff_relocation>
getRelocations(const coff_section * Sec) const13130b57cec5SDimitry Andric COFFObjectFile::getRelocations(const coff_section *Sec) const {
13140b57cec5SDimitry Andric return {getFirstReloc(Sec, Data, base()),
13150b57cec5SDimitry Andric getNumberOfRelocations(Sec, Data, base())};
13160b57cec5SDimitry Andric }
13170b57cec5SDimitry Andric
13180b57cec5SDimitry Andric #define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \
13190b57cec5SDimitry Andric case COFF::reloc_type: \
13200b57cec5SDimitry Andric return #reloc_type;
13210b57cec5SDimitry Andric
getRelocationTypeName(uint16_t Type) const13220b57cec5SDimitry Andric StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
13230b57cec5SDimitry Andric switch (getMachine()) {
13240b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
13250b57cec5SDimitry Andric switch (Type) {
13260b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);
13270b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);
13280b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);
13290b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);
13300b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);
13310b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);
13320b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);
13330b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);
13340b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);
13350b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);
13360b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);
13370b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);
13380b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);
13390b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);
13400b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);
13410b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);
13420b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);
13430b57cec5SDimitry Andric default:
13440b57cec5SDimitry Andric return "Unknown";
13450b57cec5SDimitry Andric }
13460b57cec5SDimitry Andric break;
13470b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
13480b57cec5SDimitry Andric switch (Type) {
13490b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);
13500b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);
13510b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);
13520b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);
13530b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);
13540b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);
13550b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);
13560b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);
13570b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32);
13580b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);
13590b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);
13600b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);
13610b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);
13620b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);
13630b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);
13640b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);
13650b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR);
13660b57cec5SDimitry Andric default:
13670b57cec5SDimitry Andric return "Unknown";
13680b57cec5SDimitry Andric }
13690b57cec5SDimitry Andric break;
13700b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
1371bdd1243dSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64EC:
137206c3fb27SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64X:
13730b57cec5SDimitry Andric switch (Type) {
13740b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);
13750b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);
13760b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);
13770b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);
13780b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);
13790b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);
13800b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);
13810b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);
13820b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);
13830b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);
13840b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);
13850b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);
13860b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);
13870b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);
13880b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);
13890b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);
13900b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);
13910b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32);
13920b57cec5SDimitry Andric default:
13930b57cec5SDimitry Andric return "Unknown";
13940b57cec5SDimitry Andric }
13950b57cec5SDimitry Andric break;
13960b57cec5SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
13970b57cec5SDimitry Andric switch (Type) {
13980b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);
13990b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);
14000b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);
14010b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);
14020b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);
14030b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);
14040b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);
14050b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);
14060b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);
14070b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);
14080b57cec5SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);
14090b57cec5SDimitry Andric default:
14100b57cec5SDimitry Andric return "Unknown";
14110b57cec5SDimitry Andric }
14120b57cec5SDimitry Andric break;
14130b57cec5SDimitry Andric default:
14140b57cec5SDimitry Andric return "Unknown";
14150b57cec5SDimitry Andric }
14160b57cec5SDimitry Andric }
14170b57cec5SDimitry Andric
14180b57cec5SDimitry Andric #undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME
14190b57cec5SDimitry Andric
getRelocationTypeName(DataRefImpl Rel,SmallVectorImpl<char> & Result) const14200b57cec5SDimitry Andric void COFFObjectFile::getRelocationTypeName(
14210b57cec5SDimitry Andric DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
14220b57cec5SDimitry Andric const coff_relocation *Reloc = toRel(Rel);
14230b57cec5SDimitry Andric StringRef Res = getRelocationTypeName(Reloc->Type);
14240b57cec5SDimitry Andric Result.append(Res.begin(), Res.end());
14250b57cec5SDimitry Andric }
14260b57cec5SDimitry Andric
isRelocatableObject() const14270b57cec5SDimitry Andric bool COFFObjectFile::isRelocatableObject() const {
14280b57cec5SDimitry Andric return !DataDirectory;
14290b57cec5SDimitry Andric }
14300b57cec5SDimitry Andric
mapDebugSectionName(StringRef Name) const14310b57cec5SDimitry Andric StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {
14320b57cec5SDimitry Andric return StringSwitch<StringRef>(Name)
14330b57cec5SDimitry Andric .Case("eh_fram", "eh_frame")
14340b57cec5SDimitry Andric .Default(Name);
14350b57cec5SDimitry Andric }
14360b57cec5SDimitry Andric
14370b57cec5SDimitry Andric bool ImportDirectoryEntryRef::
operator ==(const ImportDirectoryEntryRef & Other) const14380b57cec5SDimitry Andric operator==(const ImportDirectoryEntryRef &Other) const {
14390b57cec5SDimitry Andric return ImportTable == Other.ImportTable && Index == Other.Index;
14400b57cec5SDimitry Andric }
14410b57cec5SDimitry Andric
moveNext()14420b57cec5SDimitry Andric void ImportDirectoryEntryRef::moveNext() {
14430b57cec5SDimitry Andric ++Index;
14440b57cec5SDimitry Andric if (ImportTable[Index].isNull()) {
14450b57cec5SDimitry Andric Index = -1;
14460b57cec5SDimitry Andric ImportTable = nullptr;
14470b57cec5SDimitry Andric }
14480b57cec5SDimitry Andric }
14490b57cec5SDimitry Andric
getImportTableEntry(const coff_import_directory_table_entry * & Result) const14505ffd83dbSDimitry Andric Error ImportDirectoryEntryRef::getImportTableEntry(
14510b57cec5SDimitry Andric const coff_import_directory_table_entry *&Result) const {
14520b57cec5SDimitry Andric return getObject(Result, OwningObject->Data, ImportTable + Index);
14530b57cec5SDimitry Andric }
14540b57cec5SDimitry Andric
14550b57cec5SDimitry Andric static imported_symbol_iterator
makeImportedSymbolIterator(const COFFObjectFile * Object,uintptr_t Ptr,int Index)14560b57cec5SDimitry Andric makeImportedSymbolIterator(const COFFObjectFile *Object,
14570b57cec5SDimitry Andric uintptr_t Ptr, int Index) {
14580b57cec5SDimitry Andric if (Object->getBytesInAddress() == 4) {
14590b57cec5SDimitry Andric auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);
14600b57cec5SDimitry Andric return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
14610b57cec5SDimitry Andric }
14620b57cec5SDimitry Andric auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);
14630b57cec5SDimitry Andric return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
14640b57cec5SDimitry Andric }
14650b57cec5SDimitry Andric
14660b57cec5SDimitry Andric static imported_symbol_iterator
importedSymbolBegin(uint32_t RVA,const COFFObjectFile * Object)14670b57cec5SDimitry Andric importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {
14680b57cec5SDimitry Andric uintptr_t IntPtr = 0;
14695ffd83dbSDimitry Andric // FIXME: Handle errors.
14705ffd83dbSDimitry Andric cantFail(Object->getRvaPtr(RVA, IntPtr));
14710b57cec5SDimitry Andric return makeImportedSymbolIterator(Object, IntPtr, 0);
14720b57cec5SDimitry Andric }
14730b57cec5SDimitry Andric
14740b57cec5SDimitry Andric static imported_symbol_iterator
importedSymbolEnd(uint32_t RVA,const COFFObjectFile * Object)14750b57cec5SDimitry Andric importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {
14760b57cec5SDimitry Andric uintptr_t IntPtr = 0;
14775ffd83dbSDimitry Andric // FIXME: Handle errors.
14785ffd83dbSDimitry Andric cantFail(Object->getRvaPtr(RVA, IntPtr));
14790b57cec5SDimitry Andric // Forward the pointer to the last entry which is null.
14800b57cec5SDimitry Andric int Index = 0;
14810b57cec5SDimitry Andric if (Object->getBytesInAddress() == 4) {
14820b57cec5SDimitry Andric auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);
14830b57cec5SDimitry Andric while (*Entry++)
14840b57cec5SDimitry Andric ++Index;
14850b57cec5SDimitry Andric } else {
14860b57cec5SDimitry Andric auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);
14870b57cec5SDimitry Andric while (*Entry++)
14880b57cec5SDimitry Andric ++Index;
14890b57cec5SDimitry Andric }
14900b57cec5SDimitry Andric return makeImportedSymbolIterator(Object, IntPtr, Index);
14910b57cec5SDimitry Andric }
14920b57cec5SDimitry Andric
14930b57cec5SDimitry Andric imported_symbol_iterator
imported_symbol_begin() const14940b57cec5SDimitry Andric ImportDirectoryEntryRef::imported_symbol_begin() const {
14950b57cec5SDimitry Andric return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,
14960b57cec5SDimitry Andric OwningObject);
14970b57cec5SDimitry Andric }
14980b57cec5SDimitry Andric
14990b57cec5SDimitry Andric imported_symbol_iterator
imported_symbol_end() const15000b57cec5SDimitry Andric ImportDirectoryEntryRef::imported_symbol_end() const {
15010b57cec5SDimitry Andric return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,
15020b57cec5SDimitry Andric OwningObject);
15030b57cec5SDimitry Andric }
15040b57cec5SDimitry Andric
15050b57cec5SDimitry Andric iterator_range<imported_symbol_iterator>
imported_symbols() const15060b57cec5SDimitry Andric ImportDirectoryEntryRef::imported_symbols() const {
15070b57cec5SDimitry Andric return make_range(imported_symbol_begin(), imported_symbol_end());
15080b57cec5SDimitry Andric }
15090b57cec5SDimitry Andric
lookup_table_begin() const15100b57cec5SDimitry Andric imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {
15110b57cec5SDimitry Andric return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,
15120b57cec5SDimitry Andric OwningObject);
15130b57cec5SDimitry Andric }
15140b57cec5SDimitry Andric
lookup_table_end() const15150b57cec5SDimitry Andric imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {
15160b57cec5SDimitry Andric return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,
15170b57cec5SDimitry Andric OwningObject);
15180b57cec5SDimitry Andric }
15190b57cec5SDimitry Andric
15200b57cec5SDimitry Andric iterator_range<imported_symbol_iterator>
lookup_table_symbols() const15210b57cec5SDimitry Andric ImportDirectoryEntryRef::lookup_table_symbols() const {
15220b57cec5SDimitry Andric return make_range(lookup_table_begin(), lookup_table_end());
15230b57cec5SDimitry Andric }
15240b57cec5SDimitry Andric
getName(StringRef & Result) const15255ffd83dbSDimitry Andric Error ImportDirectoryEntryRef::getName(StringRef &Result) const {
15260b57cec5SDimitry Andric uintptr_t IntPtr = 0;
152781ad6265SDimitry Andric if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr,
152881ad6265SDimitry Andric "import directory name"))
15295ffd83dbSDimitry Andric return E;
15300b57cec5SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
15315ffd83dbSDimitry Andric return Error::success();
15320b57cec5SDimitry Andric }
15330b57cec5SDimitry Andric
15345ffd83dbSDimitry Andric Error
getImportLookupTableRVA(uint32_t & Result) const15350b57cec5SDimitry Andric ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {
15360b57cec5SDimitry Andric Result = ImportTable[Index].ImportLookupTableRVA;
15375ffd83dbSDimitry Andric return Error::success();
15380b57cec5SDimitry Andric }
15390b57cec5SDimitry Andric
getImportAddressTableRVA(uint32_t & Result) const15405ffd83dbSDimitry Andric Error ImportDirectoryEntryRef::getImportAddressTableRVA(
15415ffd83dbSDimitry Andric uint32_t &Result) const {
15420b57cec5SDimitry Andric Result = ImportTable[Index].ImportAddressTableRVA;
15435ffd83dbSDimitry Andric return Error::success();
15440b57cec5SDimitry Andric }
15450b57cec5SDimitry Andric
15460b57cec5SDimitry Andric bool DelayImportDirectoryEntryRef::
operator ==(const DelayImportDirectoryEntryRef & Other) const15470b57cec5SDimitry Andric operator==(const DelayImportDirectoryEntryRef &Other) const {
15480b57cec5SDimitry Andric return Table == Other.Table && Index == Other.Index;
15490b57cec5SDimitry Andric }
15500b57cec5SDimitry Andric
moveNext()15510b57cec5SDimitry Andric void DelayImportDirectoryEntryRef::moveNext() {
15520b57cec5SDimitry Andric ++Index;
15530b57cec5SDimitry Andric }
15540b57cec5SDimitry Andric
15550b57cec5SDimitry Andric imported_symbol_iterator
imported_symbol_begin() const15560b57cec5SDimitry Andric DelayImportDirectoryEntryRef::imported_symbol_begin() const {
15570b57cec5SDimitry Andric return importedSymbolBegin(Table[Index].DelayImportNameTable,
15580b57cec5SDimitry Andric OwningObject);
15590b57cec5SDimitry Andric }
15600b57cec5SDimitry Andric
15610b57cec5SDimitry Andric imported_symbol_iterator
imported_symbol_end() const15620b57cec5SDimitry Andric DelayImportDirectoryEntryRef::imported_symbol_end() const {
15630b57cec5SDimitry Andric return importedSymbolEnd(Table[Index].DelayImportNameTable,
15640b57cec5SDimitry Andric OwningObject);
15650b57cec5SDimitry Andric }
15660b57cec5SDimitry Andric
15670b57cec5SDimitry Andric iterator_range<imported_symbol_iterator>
imported_symbols() const15680b57cec5SDimitry Andric DelayImportDirectoryEntryRef::imported_symbols() const {
15690b57cec5SDimitry Andric return make_range(imported_symbol_begin(), imported_symbol_end());
15700b57cec5SDimitry Andric }
15710b57cec5SDimitry Andric
getName(StringRef & Result) const15725ffd83dbSDimitry Andric Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {
15730b57cec5SDimitry Andric uintptr_t IntPtr = 0;
157481ad6265SDimitry Andric if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr,
157581ad6265SDimitry Andric "delay import directory name"))
15765ffd83dbSDimitry Andric return E;
15770b57cec5SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
15785ffd83dbSDimitry Andric return Error::success();
15790b57cec5SDimitry Andric }
15800b57cec5SDimitry Andric
getDelayImportTable(const delay_import_directory_table_entry * & Result) const15815ffd83dbSDimitry Andric Error DelayImportDirectoryEntryRef::getDelayImportTable(
15825ffd83dbSDimitry Andric const delay_import_directory_table_entry *&Result) const {
15830b57cec5SDimitry Andric Result = &Table[Index];
15845ffd83dbSDimitry Andric return Error::success();
15850b57cec5SDimitry Andric }
15860b57cec5SDimitry Andric
getImportAddress(int AddrIndex,uint64_t & Result) const15875ffd83dbSDimitry Andric Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,
15885ffd83dbSDimitry Andric uint64_t &Result) const {
15890b57cec5SDimitry Andric uint32_t RVA = Table[Index].DelayImportAddressTable +
15900b57cec5SDimitry Andric AddrIndex * (OwningObject->is64() ? 8 : 4);
15910b57cec5SDimitry Andric uintptr_t IntPtr = 0;
159281ad6265SDimitry Andric if (Error E = OwningObject->getRvaPtr(RVA, IntPtr, "import address"))
15935ffd83dbSDimitry Andric return E;
15940b57cec5SDimitry Andric if (OwningObject->is64())
15950b57cec5SDimitry Andric Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);
15960b57cec5SDimitry Andric else
15970b57cec5SDimitry Andric Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);
15985ffd83dbSDimitry Andric return Error::success();
15990b57cec5SDimitry Andric }
16000b57cec5SDimitry Andric
16010b57cec5SDimitry Andric bool ExportDirectoryEntryRef::
operator ==(const ExportDirectoryEntryRef & Other) const16020b57cec5SDimitry Andric operator==(const ExportDirectoryEntryRef &Other) const {
16030b57cec5SDimitry Andric return ExportTable == Other.ExportTable && Index == Other.Index;
16040b57cec5SDimitry Andric }
16050b57cec5SDimitry Andric
moveNext()16060b57cec5SDimitry Andric void ExportDirectoryEntryRef::moveNext() {
16070b57cec5SDimitry Andric ++Index;
16080b57cec5SDimitry Andric }
16090b57cec5SDimitry Andric
16100b57cec5SDimitry Andric // Returns the name of the current export symbol. If the symbol is exported only
16110b57cec5SDimitry Andric // by ordinal, the empty string is set as a result.
getDllName(StringRef & Result) const16125ffd83dbSDimitry Andric Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {
16130b57cec5SDimitry Andric uintptr_t IntPtr = 0;
161481ad6265SDimitry Andric if (Error E =
161581ad6265SDimitry Andric OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr, "dll name"))
16165ffd83dbSDimitry Andric return E;
16170b57cec5SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
16185ffd83dbSDimitry Andric return Error::success();
16190b57cec5SDimitry Andric }
16200b57cec5SDimitry Andric
16210b57cec5SDimitry Andric // Returns the starting ordinal number.
getOrdinalBase(uint32_t & Result) const16225ffd83dbSDimitry Andric Error ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {
16230b57cec5SDimitry Andric Result = ExportTable->OrdinalBase;
16245ffd83dbSDimitry Andric return Error::success();
16250b57cec5SDimitry Andric }
16260b57cec5SDimitry Andric
16270b57cec5SDimitry Andric // Returns the export ordinal of the current export symbol.
getOrdinal(uint32_t & Result) const16285ffd83dbSDimitry Andric Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
16290b57cec5SDimitry Andric Result = ExportTable->OrdinalBase + Index;
16305ffd83dbSDimitry Andric return Error::success();
16310b57cec5SDimitry Andric }
16320b57cec5SDimitry Andric
16330b57cec5SDimitry Andric // Returns the address of the current export symbol.
getExportRVA(uint32_t & Result) const16345ffd83dbSDimitry Andric Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
16350b57cec5SDimitry Andric uintptr_t IntPtr = 0;
163681ad6265SDimitry Andric if (Error EC = OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA,
163781ad6265SDimitry Andric IntPtr, "export address"))
16380b57cec5SDimitry Andric return EC;
16390b57cec5SDimitry Andric const export_address_table_entry *entry =
16400b57cec5SDimitry Andric reinterpret_cast<const export_address_table_entry *>(IntPtr);
16410b57cec5SDimitry Andric Result = entry[Index].ExportRVA;
16425ffd83dbSDimitry Andric return Error::success();
16430b57cec5SDimitry Andric }
16440b57cec5SDimitry Andric
16450b57cec5SDimitry Andric // Returns the name of the current export symbol. If the symbol is exported only
16460b57cec5SDimitry Andric // by ordinal, the empty string is set as a result.
16475ffd83dbSDimitry Andric Error
getSymbolName(StringRef & Result) const16480b57cec5SDimitry Andric ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
16490b57cec5SDimitry Andric uintptr_t IntPtr = 0;
165081ad6265SDimitry Andric if (Error EC = OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr,
165181ad6265SDimitry Andric "export ordinal table"))
16520b57cec5SDimitry Andric return EC;
16530b57cec5SDimitry Andric const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
16540b57cec5SDimitry Andric
16550b57cec5SDimitry Andric uint32_t NumEntries = ExportTable->NumberOfNamePointers;
16560b57cec5SDimitry Andric int Offset = 0;
16570b57cec5SDimitry Andric for (const ulittle16_t *I = Start, *E = Start + NumEntries;
16580b57cec5SDimitry Andric I < E; ++I, ++Offset) {
16590b57cec5SDimitry Andric if (*I != Index)
16600b57cec5SDimitry Andric continue;
166181ad6265SDimitry Andric if (Error EC = OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr,
166281ad6265SDimitry Andric "export table entry"))
16630b57cec5SDimitry Andric return EC;
16640b57cec5SDimitry Andric const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
166581ad6265SDimitry Andric if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr,
166681ad6265SDimitry Andric "export symbol name"))
16670b57cec5SDimitry Andric return EC;
16680b57cec5SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
16695ffd83dbSDimitry Andric return Error::success();
16700b57cec5SDimitry Andric }
16710b57cec5SDimitry Andric Result = "";
16725ffd83dbSDimitry Andric return Error::success();
16730b57cec5SDimitry Andric }
16740b57cec5SDimitry Andric
isForwarder(bool & Result) const16755ffd83dbSDimitry Andric Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {
16765ffd83dbSDimitry Andric const data_directory *DataEntry =
16775ffd83dbSDimitry Andric OwningObject->getDataDirectory(COFF::EXPORT_TABLE);
16785ffd83dbSDimitry Andric if (!DataEntry)
167981ad6265SDimitry Andric return createStringError(object_error::parse_failed,
168081ad6265SDimitry Andric "export table missing");
16810b57cec5SDimitry Andric uint32_t RVA;
16820b57cec5SDimitry Andric if (auto EC = getExportRVA(RVA))
16830b57cec5SDimitry Andric return EC;
16840b57cec5SDimitry Andric uint32_t Begin = DataEntry->RelativeVirtualAddress;
16850b57cec5SDimitry Andric uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;
16860b57cec5SDimitry Andric Result = (Begin <= RVA && RVA < End);
16875ffd83dbSDimitry Andric return Error::success();
16880b57cec5SDimitry Andric }
16890b57cec5SDimitry Andric
getForwardTo(StringRef & Result) const16905ffd83dbSDimitry Andric Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
16910b57cec5SDimitry Andric uint32_t RVA;
16920b57cec5SDimitry Andric if (auto EC = getExportRVA(RVA))
16930b57cec5SDimitry Andric return EC;
16940b57cec5SDimitry Andric uintptr_t IntPtr = 0;
169581ad6265SDimitry Andric if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr, "export forward target"))
16960b57cec5SDimitry Andric return EC;
16970b57cec5SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
16985ffd83dbSDimitry Andric return Error::success();
16990b57cec5SDimitry Andric }
17000b57cec5SDimitry Andric
17010b57cec5SDimitry Andric bool ImportedSymbolRef::
operator ==(const ImportedSymbolRef & Other) const17020b57cec5SDimitry Andric operator==(const ImportedSymbolRef &Other) const {
17030b57cec5SDimitry Andric return Entry32 == Other.Entry32 && Entry64 == Other.Entry64
17040b57cec5SDimitry Andric && Index == Other.Index;
17050b57cec5SDimitry Andric }
17060b57cec5SDimitry Andric
moveNext()17070b57cec5SDimitry Andric void ImportedSymbolRef::moveNext() {
17080b57cec5SDimitry Andric ++Index;
17090b57cec5SDimitry Andric }
17100b57cec5SDimitry Andric
getSymbolName(StringRef & Result) const17115ffd83dbSDimitry Andric Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {
17120b57cec5SDimitry Andric uint32_t RVA;
17130b57cec5SDimitry Andric if (Entry32) {
17140b57cec5SDimitry Andric // If a symbol is imported only by ordinal, it has no name.
17150b57cec5SDimitry Andric if (Entry32[Index].isOrdinal())
17165ffd83dbSDimitry Andric return Error::success();
17170b57cec5SDimitry Andric RVA = Entry32[Index].getHintNameRVA();
17180b57cec5SDimitry Andric } else {
17190b57cec5SDimitry Andric if (Entry64[Index].isOrdinal())
17205ffd83dbSDimitry Andric return Error::success();
17210b57cec5SDimitry Andric RVA = Entry64[Index].getHintNameRVA();
17220b57cec5SDimitry Andric }
17230b57cec5SDimitry Andric uintptr_t IntPtr = 0;
172481ad6265SDimitry Andric if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol name"))
17250b57cec5SDimitry Andric return EC;
17260b57cec5SDimitry Andric // +2 because the first two bytes is hint.
17270b57cec5SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));
17285ffd83dbSDimitry Andric return Error::success();
17290b57cec5SDimitry Andric }
17300b57cec5SDimitry Andric
isOrdinal(bool & Result) const17315ffd83dbSDimitry Andric Error ImportedSymbolRef::isOrdinal(bool &Result) const {
17320b57cec5SDimitry Andric if (Entry32)
17330b57cec5SDimitry Andric Result = Entry32[Index].isOrdinal();
17340b57cec5SDimitry Andric else
17350b57cec5SDimitry Andric Result = Entry64[Index].isOrdinal();
17365ffd83dbSDimitry Andric return Error::success();
17370b57cec5SDimitry Andric }
17380b57cec5SDimitry Andric
getHintNameRVA(uint32_t & Result) const17395ffd83dbSDimitry Andric Error ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {
17400b57cec5SDimitry Andric if (Entry32)
17410b57cec5SDimitry Andric Result = Entry32[Index].getHintNameRVA();
17420b57cec5SDimitry Andric else
17430b57cec5SDimitry Andric Result = Entry64[Index].getHintNameRVA();
17445ffd83dbSDimitry Andric return Error::success();
17450b57cec5SDimitry Andric }
17460b57cec5SDimitry Andric
getOrdinal(uint16_t & Result) const17475ffd83dbSDimitry Andric Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {
17480b57cec5SDimitry Andric uint32_t RVA;
17490b57cec5SDimitry Andric if (Entry32) {
17500b57cec5SDimitry Andric if (Entry32[Index].isOrdinal()) {
17510b57cec5SDimitry Andric Result = Entry32[Index].getOrdinal();
17525ffd83dbSDimitry Andric return Error::success();
17530b57cec5SDimitry Andric }
17540b57cec5SDimitry Andric RVA = Entry32[Index].getHintNameRVA();
17550b57cec5SDimitry Andric } else {
17560b57cec5SDimitry Andric if (Entry64[Index].isOrdinal()) {
17570b57cec5SDimitry Andric Result = Entry64[Index].getOrdinal();
17585ffd83dbSDimitry Andric return Error::success();
17590b57cec5SDimitry Andric }
17600b57cec5SDimitry Andric RVA = Entry64[Index].getHintNameRVA();
17610b57cec5SDimitry Andric }
17620b57cec5SDimitry Andric uintptr_t IntPtr = 0;
176381ad6265SDimitry Andric if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol ordinal"))
17640b57cec5SDimitry Andric return EC;
17650b57cec5SDimitry Andric Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);
17665ffd83dbSDimitry Andric return Error::success();
17670b57cec5SDimitry Andric }
17680b57cec5SDimitry Andric
17690b57cec5SDimitry Andric Expected<std::unique_ptr<COFFObjectFile>>
createCOFFObjectFile(MemoryBufferRef Object)17700b57cec5SDimitry Andric ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {
17715ffd83dbSDimitry Andric return COFFObjectFile::create(Object);
17720b57cec5SDimitry Andric }
17730b57cec5SDimitry Andric
operator ==(const BaseRelocRef & Other) const17740b57cec5SDimitry Andric bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {
17750b57cec5SDimitry Andric return Header == Other.Header && Index == Other.Index;
17760b57cec5SDimitry Andric }
17770b57cec5SDimitry Andric
moveNext()17780b57cec5SDimitry Andric void BaseRelocRef::moveNext() {
17790b57cec5SDimitry Andric // Header->BlockSize is the size of the current block, including the
17800b57cec5SDimitry Andric // size of the header itself.
17810b57cec5SDimitry Andric uint32_t Size = sizeof(*Header) +
17820b57cec5SDimitry Andric sizeof(coff_base_reloc_block_entry) * (Index + 1);
17830b57cec5SDimitry Andric if (Size == Header->BlockSize) {
17840b57cec5SDimitry Andric // .reloc contains a list of base relocation blocks. Each block
17850b57cec5SDimitry Andric // consists of the header followed by entries. The header contains
17860b57cec5SDimitry Andric // how many entories will follow. When we reach the end of the
17870b57cec5SDimitry Andric // current block, proceed to the next block.
17880b57cec5SDimitry Andric Header = reinterpret_cast<const coff_base_reloc_block_header *>(
17890b57cec5SDimitry Andric reinterpret_cast<const uint8_t *>(Header) + Size);
17900b57cec5SDimitry Andric Index = 0;
17910b57cec5SDimitry Andric } else {
17920b57cec5SDimitry Andric ++Index;
17930b57cec5SDimitry Andric }
17940b57cec5SDimitry Andric }
17950b57cec5SDimitry Andric
getType(uint8_t & Type) const17965ffd83dbSDimitry Andric Error BaseRelocRef::getType(uint8_t &Type) const {
17970b57cec5SDimitry Andric auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
17980b57cec5SDimitry Andric Type = Entry[Index].getType();
17995ffd83dbSDimitry Andric return Error::success();
18000b57cec5SDimitry Andric }
18010b57cec5SDimitry Andric
getRVA(uint32_t & Result) const18025ffd83dbSDimitry Andric Error BaseRelocRef::getRVA(uint32_t &Result) const {
18030b57cec5SDimitry Andric auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
18040b57cec5SDimitry Andric Result = Header->PageRVA + Entry[Index].getOffset();
18055ffd83dbSDimitry Andric return Error::success();
18060b57cec5SDimitry Andric }
18070b57cec5SDimitry Andric
18088bcb0991SDimitry Andric #define RETURN_IF_ERROR(Expr) \
18098bcb0991SDimitry Andric do { \
18108bcb0991SDimitry Andric Error E = (Expr); \
18110b57cec5SDimitry Andric if (E) \
18128bcb0991SDimitry Andric return std::move(E); \
18138bcb0991SDimitry Andric } while (0)
18140b57cec5SDimitry Andric
18150b57cec5SDimitry Andric Expected<ArrayRef<UTF16>>
getDirStringAtOffset(uint32_t Offset)18160b57cec5SDimitry Andric ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {
18170b57cec5SDimitry Andric BinaryStreamReader Reader = BinaryStreamReader(BBS);
18180b57cec5SDimitry Andric Reader.setOffset(Offset);
18190b57cec5SDimitry Andric uint16_t Length;
18200b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readInteger(Length));
18210b57cec5SDimitry Andric ArrayRef<UTF16> RawDirString;
18220b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));
18230b57cec5SDimitry Andric return RawDirString;
18240b57cec5SDimitry Andric }
18250b57cec5SDimitry Andric
18260b57cec5SDimitry Andric Expected<ArrayRef<UTF16>>
getEntryNameString(const coff_resource_dir_entry & Entry)18270b57cec5SDimitry Andric ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {
18280b57cec5SDimitry Andric return getDirStringAtOffset(Entry.Identifier.getNameOffset());
18290b57cec5SDimitry Andric }
18300b57cec5SDimitry Andric
18310b57cec5SDimitry Andric Expected<const coff_resource_dir_table &>
getTableAtOffset(uint32_t Offset)18320b57cec5SDimitry Andric ResourceSectionRef::getTableAtOffset(uint32_t Offset) {
18330b57cec5SDimitry Andric const coff_resource_dir_table *Table = nullptr;
18340b57cec5SDimitry Andric
18350b57cec5SDimitry Andric BinaryStreamReader Reader(BBS);
18360b57cec5SDimitry Andric Reader.setOffset(Offset);
18370b57cec5SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Table));
18380b57cec5SDimitry Andric assert(Table != nullptr);
18390b57cec5SDimitry Andric return *Table;
18400b57cec5SDimitry Andric }
18410b57cec5SDimitry Andric
18428bcb0991SDimitry Andric Expected<const coff_resource_dir_entry &>
getTableEntryAtOffset(uint32_t Offset)18438bcb0991SDimitry Andric ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {
18448bcb0991SDimitry Andric const coff_resource_dir_entry *Entry = nullptr;
18458bcb0991SDimitry Andric
18468bcb0991SDimitry Andric BinaryStreamReader Reader(BBS);
18478bcb0991SDimitry Andric Reader.setOffset(Offset);
18488bcb0991SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Entry));
18498bcb0991SDimitry Andric assert(Entry != nullptr);
18508bcb0991SDimitry Andric return *Entry;
18518bcb0991SDimitry Andric }
18528bcb0991SDimitry Andric
18538bcb0991SDimitry Andric Expected<const coff_resource_data_entry &>
getDataEntryAtOffset(uint32_t Offset)18548bcb0991SDimitry Andric ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {
18558bcb0991SDimitry Andric const coff_resource_data_entry *Entry = nullptr;
18568bcb0991SDimitry Andric
18578bcb0991SDimitry Andric BinaryStreamReader Reader(BBS);
18588bcb0991SDimitry Andric Reader.setOffset(Offset);
18598bcb0991SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Entry));
18608bcb0991SDimitry Andric assert(Entry != nullptr);
18618bcb0991SDimitry Andric return *Entry;
18628bcb0991SDimitry Andric }
18638bcb0991SDimitry Andric
18640b57cec5SDimitry Andric Expected<const coff_resource_dir_table &>
getEntrySubDir(const coff_resource_dir_entry & Entry)18650b57cec5SDimitry Andric ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {
18668bcb0991SDimitry Andric assert(Entry.Offset.isSubDir());
18670b57cec5SDimitry Andric return getTableAtOffset(Entry.Offset.value());
18680b57cec5SDimitry Andric }
18690b57cec5SDimitry Andric
18708bcb0991SDimitry Andric Expected<const coff_resource_data_entry &>
getEntryData(const coff_resource_dir_entry & Entry)18718bcb0991SDimitry Andric ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {
18728bcb0991SDimitry Andric assert(!Entry.Offset.isSubDir());
18738bcb0991SDimitry Andric return getDataEntryAtOffset(Entry.Offset.value());
18748bcb0991SDimitry Andric }
18758bcb0991SDimitry Andric
getBaseTable()18760b57cec5SDimitry Andric Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {
18770b57cec5SDimitry Andric return getTableAtOffset(0);
18780b57cec5SDimitry Andric }
18798bcb0991SDimitry Andric
18808bcb0991SDimitry Andric Expected<const coff_resource_dir_entry &>
getTableEntry(const coff_resource_dir_table & Table,uint32_t Index)18818bcb0991SDimitry Andric ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,
18828bcb0991SDimitry Andric uint32_t Index) {
18838bcb0991SDimitry Andric if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))
18848bcb0991SDimitry Andric return createStringError(object_error::parse_failed, "index out of range");
18858bcb0991SDimitry Andric const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);
18868bcb0991SDimitry Andric ptrdiff_t TableOffset = TablePtr - BBS.data().data();
18878bcb0991SDimitry Andric return getTableEntryAtOffset(TableOffset + sizeof(Table) +
18888bcb0991SDimitry Andric Index * sizeof(coff_resource_dir_entry));
18898bcb0991SDimitry Andric }
18908bcb0991SDimitry Andric
load(const COFFObjectFile * O)18918bcb0991SDimitry Andric Error ResourceSectionRef::load(const COFFObjectFile *O) {
18928bcb0991SDimitry Andric for (const SectionRef &S : O->sections()) {
18938bcb0991SDimitry Andric Expected<StringRef> Name = S.getName();
18948bcb0991SDimitry Andric if (!Name)
18958bcb0991SDimitry Andric return Name.takeError();
18968bcb0991SDimitry Andric
18978bcb0991SDimitry Andric if (*Name == ".rsrc" || *Name == ".rsrc$01")
18988bcb0991SDimitry Andric return load(O, S);
18998bcb0991SDimitry Andric }
19008bcb0991SDimitry Andric return createStringError(object_error::parse_failed,
19018bcb0991SDimitry Andric "no resource section found");
19028bcb0991SDimitry Andric }
19038bcb0991SDimitry Andric
load(const COFFObjectFile * O,const SectionRef & S)19048bcb0991SDimitry Andric Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {
19058bcb0991SDimitry Andric Obj = O;
19068bcb0991SDimitry Andric Section = S;
19078bcb0991SDimitry Andric Expected<StringRef> Contents = Section.getContents();
19088bcb0991SDimitry Andric if (!Contents)
19098bcb0991SDimitry Andric return Contents.takeError();
19105f757f3fSDimitry Andric BBS = BinaryByteStream(*Contents, llvm::endianness::little);
19118bcb0991SDimitry Andric const coff_section *COFFSect = Obj->getCOFFSection(Section);
19128bcb0991SDimitry Andric ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);
19138bcb0991SDimitry Andric Relocs.reserve(OrigRelocs.size());
19148bcb0991SDimitry Andric for (const coff_relocation &R : OrigRelocs)
19158bcb0991SDimitry Andric Relocs.push_back(&R);
1916e8d8bef9SDimitry Andric llvm::sort(Relocs, [](const coff_relocation *A, const coff_relocation *B) {
19178bcb0991SDimitry Andric return A->VirtualAddress < B->VirtualAddress;
19188bcb0991SDimitry Andric });
19198bcb0991SDimitry Andric return Error::success();
19208bcb0991SDimitry Andric }
19218bcb0991SDimitry Andric
19228bcb0991SDimitry Andric Expected<StringRef>
getContents(const coff_resource_data_entry & Entry)19238bcb0991SDimitry Andric ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
19248bcb0991SDimitry Andric if (!Obj)
19258bcb0991SDimitry Andric return createStringError(object_error::parse_failed, "no object provided");
19268bcb0991SDimitry Andric
19278bcb0991SDimitry Andric // Find a potential relocation at the DataRVA field (first member of
19288bcb0991SDimitry Andric // the coff_resource_data_entry struct).
19298bcb0991SDimitry Andric const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);
19308bcb0991SDimitry Andric ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();
19318bcb0991SDimitry Andric coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),
19328bcb0991SDimitry Andric ulittle16_t(0)};
19338bcb0991SDimitry Andric auto RelocsForOffset =
19348bcb0991SDimitry Andric std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,
19358bcb0991SDimitry Andric [](const coff_relocation *A, const coff_relocation *B) {
19368bcb0991SDimitry Andric return A->VirtualAddress < B->VirtualAddress;
19378bcb0991SDimitry Andric });
19388bcb0991SDimitry Andric
19398bcb0991SDimitry Andric if (RelocsForOffset.first != RelocsForOffset.second) {
19408bcb0991SDimitry Andric // We found a relocation with the right offset. Check that it does have
19418bcb0991SDimitry Andric // the expected type.
19428bcb0991SDimitry Andric const coff_relocation &R = **RelocsForOffset.first;
19438bcb0991SDimitry Andric uint16_t RVAReloc;
19448bcb0991SDimitry Andric switch (Obj->getMachine()) {
19458bcb0991SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
19468bcb0991SDimitry Andric RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;
19478bcb0991SDimitry Andric break;
19488bcb0991SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
19498bcb0991SDimitry Andric RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;
19508bcb0991SDimitry Andric break;
19518bcb0991SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
19528bcb0991SDimitry Andric RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;
19538bcb0991SDimitry Andric break;
19548bcb0991SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
1955bdd1243dSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64EC:
195606c3fb27SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64X:
19578bcb0991SDimitry Andric RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
19588bcb0991SDimitry Andric break;
19598bcb0991SDimitry Andric default:
19608bcb0991SDimitry Andric return createStringError(object_error::parse_failed,
19618bcb0991SDimitry Andric "unsupported architecture");
19628bcb0991SDimitry Andric }
19638bcb0991SDimitry Andric if (R.Type != RVAReloc)
19648bcb0991SDimitry Andric return createStringError(object_error::parse_failed,
19658bcb0991SDimitry Andric "unexpected relocation type");
19668bcb0991SDimitry Andric // Get the relocation's symbol
19678bcb0991SDimitry Andric Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);
19688bcb0991SDimitry Andric if (!Sym)
19698bcb0991SDimitry Andric return Sym.takeError();
19708bcb0991SDimitry Andric // And the symbol's section
19715ffd83dbSDimitry Andric Expected<const coff_section *> Section =
19725ffd83dbSDimitry Andric Obj->getSection(Sym->getSectionNumber());
19735ffd83dbSDimitry Andric if (!Section)
19745ffd83dbSDimitry Andric return Section.takeError();
19758bcb0991SDimitry Andric // Add the initial value of DataRVA to the symbol's offset to find the
19768bcb0991SDimitry Andric // data it points at.
19778bcb0991SDimitry Andric uint64_t Offset = Entry.DataRVA + Sym->getValue();
19788bcb0991SDimitry Andric ArrayRef<uint8_t> Contents;
19795ffd83dbSDimitry Andric if (Error E = Obj->getSectionContents(*Section, Contents))
19808bcb0991SDimitry Andric return std::move(E);
19818bcb0991SDimitry Andric if (Offset + Entry.DataSize > Contents.size())
19828bcb0991SDimitry Andric return createStringError(object_error::parse_failed,
19838bcb0991SDimitry Andric "data outside of section");
19848bcb0991SDimitry Andric // Return a reference to the data inside the section.
19858bcb0991SDimitry Andric return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,
19868bcb0991SDimitry Andric Entry.DataSize);
19878bcb0991SDimitry Andric } else {
19888bcb0991SDimitry Andric // Relocatable objects need a relocation for the DataRVA field.
19898bcb0991SDimitry Andric if (Obj->isRelocatableObject())
19908bcb0991SDimitry Andric return createStringError(object_error::parse_failed,
19918bcb0991SDimitry Andric "no relocation found for DataRVA");
19928bcb0991SDimitry Andric
19938bcb0991SDimitry Andric // Locate the section that contains the address that DataRVA points at.
19948bcb0991SDimitry Andric uint64_t VA = Entry.DataRVA + Obj->getImageBase();
19958bcb0991SDimitry Andric for (const SectionRef &S : Obj->sections()) {
19968bcb0991SDimitry Andric if (VA >= S.getAddress() &&
19978bcb0991SDimitry Andric VA + Entry.DataSize <= S.getAddress() + S.getSize()) {
19988bcb0991SDimitry Andric uint64_t Offset = VA - S.getAddress();
19998bcb0991SDimitry Andric Expected<StringRef> Contents = S.getContents();
20008bcb0991SDimitry Andric if (!Contents)
20018bcb0991SDimitry Andric return Contents.takeError();
20028bcb0991SDimitry Andric return Contents->slice(Offset, Offset + Entry.DataSize);
20038bcb0991SDimitry Andric }
20048bcb0991SDimitry Andric }
20058bcb0991SDimitry Andric return createStringError(object_error::parse_failed,
20068bcb0991SDimitry Andric "address not found in image");
20078bcb0991SDimitry Andric }
20088bcb0991SDimitry Andric }
2009