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