16bc11b14SDimitry Andric //===- COFFObjectFile.cpp - COFF object file implementation ---------------===//
22754fe60SDimitry Andric //
32754fe60SDimitry Andric // The LLVM Compiler Infrastructure
42754fe60SDimitry Andric //
52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source
62754fe60SDimitry Andric // License. See LICENSE.TXT for details.
72754fe60SDimitry Andric //
82754fe60SDimitry Andric //===----------------------------------------------------------------------===//
92754fe60SDimitry Andric //
102754fe60SDimitry Andric // This file declares the COFFObjectFile class.
112754fe60SDimitry Andric //
122754fe60SDimitry Andric //===----------------------------------------------------------------------===//
132754fe60SDimitry Andric
14dff0c46cSDimitry Andric #include "llvm/ADT/ArrayRef.h"
156bc11b14SDimitry Andric #include "llvm/ADT/StringRef.h"
162754fe60SDimitry Andric #include "llvm/ADT/Triple.h"
173dac3a9bSDimitry Andric #include "llvm/ADT/iterator_range.h"
18db17bf38SDimitry Andric #include "llvm/BinaryFormat/COFF.h"
196bc11b14SDimitry Andric #include "llvm/Object/Binary.h"
206bc11b14SDimitry Andric #include "llvm/Object/COFF.h"
216bc11b14SDimitry Andric #include "llvm/Object/Error.h"
226bc11b14SDimitry Andric #include "llvm/Object/ObjectFile.h"
230f5676f4SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
246bc11b14SDimitry Andric #include "llvm/Support/Endian.h"
256bc11b14SDimitry Andric #include "llvm/Support/Error.h"
266bc11b14SDimitry Andric #include "llvm/Support/ErrorHandling.h"
276bc11b14SDimitry Andric #include "llvm/Support/MathExtras.h"
286bc11b14SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
296bc11b14SDimitry Andric #include <algorithm>
306bc11b14SDimitry Andric #include <cassert>
316bc11b14SDimitry Andric #include <cstddef>
326bc11b14SDimitry Andric #include <cstdint>
336bc11b14SDimitry Andric #include <cstring>
3491bc56edSDimitry Andric #include <limits>
356bc11b14SDimitry Andric #include <memory>
366bc11b14SDimitry Andric #include <system_error>
372754fe60SDimitry Andric
382754fe60SDimitry Andric using namespace llvm;
392754fe60SDimitry Andric using namespace object;
402754fe60SDimitry Andric
412754fe60SDimitry Andric using support::ulittle16_t;
422754fe60SDimitry Andric using support::ulittle32_t;
4339d628a0SDimitry Andric using support::ulittle64_t;
442754fe60SDimitry Andric using support::little16_t;
452754fe60SDimitry Andric
4617a519f9SDimitry Andric // Returns false if size is greater than the buffer size. And sets ec.
checkSize(MemoryBufferRef M,std::error_code & EC,uint64_t Size)4739d628a0SDimitry Andric static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) {
4891bc56edSDimitry Andric if (M.getBufferSize() < Size) {
4991bc56edSDimitry Andric EC = object_error::unexpected_eof;
5017a519f9SDimitry Andric return false;
5117a519f9SDimitry Andric }
5217a519f9SDimitry Andric return true;
532754fe60SDimitry Andric }
542754fe60SDimitry Andric
55f785676fSDimitry Andric // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
56f785676fSDimitry Andric // Returns unexpected_eof if error.
57f785676fSDimitry Andric template <typename T>
getObject(const T * & Obj,MemoryBufferRef M,const void * Ptr,const uint64_t Size=sizeof (T))5839d628a0SDimitry Andric static std::error_code getObject(const T *&Obj, MemoryBufferRef M,
5939d628a0SDimitry Andric const void *Ptr,
6039d628a0SDimitry Andric const uint64_t Size = sizeof(T)) {
61f785676fSDimitry Andric uintptr_t Addr = uintptr_t(Ptr);
622cab237bSDimitry Andric if (std::error_code EC = Binary::checkOffset(M, Addr, Size))
6339d628a0SDimitry Andric return EC;
64f785676fSDimitry Andric Obj = reinterpret_cast<const T *>(Addr);
6597bc6c73SDimitry Andric return std::error_code();
6617a519f9SDimitry Andric }
6791bc56edSDimitry Andric
6891bc56edSDimitry Andric // Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without
6991bc56edSDimitry Andric // prefixed slashes.
decodeBase64StringEntry(StringRef Str,uint32_t & Result)7091bc56edSDimitry Andric static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {
7191bc56edSDimitry Andric assert(Str.size() <= 6 && "String too long, possible overflow.");
7291bc56edSDimitry Andric if (Str.size() > 6)
7391bc56edSDimitry Andric return true;
7491bc56edSDimitry Andric
7591bc56edSDimitry Andric uint64_t Value = 0;
7691bc56edSDimitry Andric while (!Str.empty()) {
7791bc56edSDimitry Andric unsigned CharVal;
7891bc56edSDimitry Andric if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..25
7991bc56edSDimitry Andric CharVal = Str[0] - 'A';
8091bc56edSDimitry Andric else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..51
8191bc56edSDimitry Andric CharVal = Str[0] - 'a' + 26;
8291bc56edSDimitry Andric else if (Str[0] >= '0' && Str[0] <= '9') // 52..61
8391bc56edSDimitry Andric CharVal = Str[0] - '0' + 52;
8491bc56edSDimitry Andric else if (Str[0] == '+') // 62
8591bc56edSDimitry Andric CharVal = 62;
8691bc56edSDimitry Andric else if (Str[0] == '/') // 63
8791bc56edSDimitry Andric CharVal = 63;
8891bc56edSDimitry Andric else
8991bc56edSDimitry Andric return true;
9091bc56edSDimitry Andric
9191bc56edSDimitry Andric Value = (Value * 64) + CharVal;
9291bc56edSDimitry Andric Str = Str.substr(1);
932754fe60SDimitry Andric }
942754fe60SDimitry Andric
9591bc56edSDimitry Andric if (Value > std::numeric_limits<uint32_t>::max())
9691bc56edSDimitry Andric return true;
9791bc56edSDimitry Andric
9891bc56edSDimitry Andric Result = static_cast<uint32_t>(Value);
9991bc56edSDimitry Andric return false;
10091bc56edSDimitry Andric }
10191bc56edSDimitry Andric
10239d628a0SDimitry Andric template <typename coff_symbol_type>
toSymb(DataRefImpl Ref) const10339d628a0SDimitry Andric const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {
10439d628a0SDimitry Andric const coff_symbol_type *Addr =
10539d628a0SDimitry Andric reinterpret_cast<const coff_symbol_type *>(Ref.p);
1062754fe60SDimitry Andric
10739d628a0SDimitry Andric assert(!checkOffset(Data, uintptr_t(Addr), sizeof(*Addr)));
10817a519f9SDimitry Andric #ifndef NDEBUG
10917a519f9SDimitry Andric // Verify that the symbol points to a valid entry in the symbol table.
11091bc56edSDimitry Andric uintptr_t Offset = uintptr_t(Addr) - uintptr_t(base());
11117a519f9SDimitry Andric
11239d628a0SDimitry Andric assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&
11339d628a0SDimitry Andric "Symbol did not point to the beginning of a symbol");
11417a519f9SDimitry Andric #endif
11517a519f9SDimitry Andric
11691bc56edSDimitry Andric return Addr;
1172754fe60SDimitry Andric }
1182754fe60SDimitry Andric
toSec(DataRefImpl Ref) const11991bc56edSDimitry Andric const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {
12091bc56edSDimitry Andric const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p);
1212754fe60SDimitry Andric
12217a519f9SDimitry Andric #ifndef NDEBUG
12317a519f9SDimitry Andric // Verify that the section points to a valid entry in the section table.
12439d628a0SDimitry Andric if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))
12517a519f9SDimitry Andric report_fatal_error("Section was outside of section table.");
1262754fe60SDimitry Andric
12791bc56edSDimitry Andric uintptr_t Offset = uintptr_t(Addr) - uintptr_t(SectionTable);
12891bc56edSDimitry Andric assert(Offset % sizeof(coff_section) == 0 &&
12917a519f9SDimitry Andric "Section did not point to the beginning of a section");
13017a519f9SDimitry Andric #endif
1312754fe60SDimitry Andric
13291bc56edSDimitry Andric return Addr;
13317a519f9SDimitry Andric }
1342754fe60SDimitry Andric
moveSymbolNext(DataRefImpl & Ref) const13591bc56edSDimitry Andric void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {
13639d628a0SDimitry Andric auto End = reinterpret_cast<uintptr_t>(StringTable);
13739d628a0SDimitry Andric if (SymbolTable16) {
13839d628a0SDimitry Andric const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);
13991bc56edSDimitry Andric Symb += 1 + Symb->NumberOfAuxSymbols;
14039d628a0SDimitry Andric Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
14139d628a0SDimitry Andric } else if (SymbolTable32) {
14239d628a0SDimitry Andric const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);
14339d628a0SDimitry Andric Symb += 1 + Symb->NumberOfAuxSymbols;
14439d628a0SDimitry Andric Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
14539d628a0SDimitry Andric } else {
14639d628a0SDimitry Andric llvm_unreachable("no symbol table pointer!");
14739d628a0SDimitry Andric }
1482754fe60SDimitry Andric }
1492754fe60SDimitry Andric
getSymbolName(DataRefImpl Ref) const1503ca95b02SDimitry Andric Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {
15139d628a0SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
1523dac3a9bSDimitry Andric StringRef Result;
1530f5676f4SDimitry Andric if (std::error_code EC = getSymbolName(Symb, Result))
1543ca95b02SDimitry Andric return errorCodeToError(EC);
1553dac3a9bSDimitry Andric return Result;
1563dac3a9bSDimitry Andric }
1573dac3a9bSDimitry Andric
getSymbolValueImpl(DataRefImpl Ref) const158875ed548SDimitry Andric uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {
159875ed548SDimitry Andric return getCOFFSymbol(Ref).getValue();
1602754fe60SDimitry Andric }
1612754fe60SDimitry Andric
getSymbolAlignment(DataRefImpl Ref) const162d88c1a5aSDimitry Andric uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const {
163d88c1a5aSDimitry Andric // MSVC/link.exe seems to align symbols to the next-power-of-2
164d88c1a5aSDimitry Andric // up to 32 bytes.
165d88c1a5aSDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
166d88c1a5aSDimitry Andric return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));
167d88c1a5aSDimitry Andric }
168d88c1a5aSDimitry Andric
getSymbolAddress(DataRefImpl Ref) const1693ca95b02SDimitry Andric Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {
170875ed548SDimitry Andric uint64_t Result = getSymbolValue(Ref);
17139d628a0SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
17239d628a0SDimitry Andric int32_t SectionNumber = Symb.getSectionNumber();
1733dac3a9bSDimitry Andric
1743dac3a9bSDimitry Andric if (Symb.isAnyUndefined() || Symb.isCommon() ||
1753dac3a9bSDimitry Andric COFF::isReservedSectionNumber(SectionNumber))
176875ed548SDimitry Andric return Result;
1773dac3a9bSDimitry Andric
17891bc56edSDimitry Andric const coff_section *Section = nullptr;
17939d628a0SDimitry Andric if (std::error_code EC = getSection(SectionNumber, Section))
1803ca95b02SDimitry Andric return errorCodeToError(EC);
1813dac3a9bSDimitry Andric Result += Section->VirtualAddress;
1827d523365SDimitry Andric
1837d523365SDimitry Andric // The section VirtualAddress does not include ImageBase, and we want to
1847d523365SDimitry Andric // return virtual addresses.
1857d523365SDimitry Andric Result += getImageBase();
1867d523365SDimitry Andric
187875ed548SDimitry Andric return Result;
18839d628a0SDimitry Andric }
18939d628a0SDimitry Andric
getSymbolType(DataRefImpl Ref) const1903ca95b02SDimitry Andric Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {
19139d628a0SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
19239d628a0SDimitry Andric int32_t SectionNumber = Symb.getSectionNumber();
19339d628a0SDimitry Andric
1947d523365SDimitry Andric if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
1957d523365SDimitry Andric return SymbolRef::ST_Function;
1963dac3a9bSDimitry Andric if (Symb.isAnyUndefined())
1973dac3a9bSDimitry Andric return SymbolRef::ST_Unknown;
1983dac3a9bSDimitry Andric if (Symb.isCommon())
1993dac3a9bSDimitry Andric return SymbolRef::ST_Data;
2003dac3a9bSDimitry Andric if (Symb.isFileRecord())
2013dac3a9bSDimitry Andric return SymbolRef::ST_File;
2023dac3a9bSDimitry Andric
203ff0cc061SDimitry Andric // TODO: perhaps we need a new symbol type ST_Section.
2043dac3a9bSDimitry Andric if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())
2053dac3a9bSDimitry Andric return SymbolRef::ST_Debug;
2063dac3a9bSDimitry Andric
2073dac3a9bSDimitry Andric if (!COFF::isReservedSectionNumber(SectionNumber))
2083dac3a9bSDimitry Andric return SymbolRef::ST_Data;
2093dac3a9bSDimitry Andric
2103dac3a9bSDimitry Andric return SymbolRef::ST_Other;
2116122f3e6SDimitry Andric }
2126122f3e6SDimitry Andric
getSymbolFlags(DataRefImpl Ref) const21391bc56edSDimitry Andric uint32_t COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {
21439d628a0SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
21591bc56edSDimitry Andric uint32_t Result = SymbolRef::SF_None;
216dff0c46cSDimitry Andric
21739d628a0SDimitry Andric if (Symb.isExternal() || Symb.isWeakExternal())
218dff0c46cSDimitry Andric Result |= SymbolRef::SF_Global;
219dff0c46cSDimitry Andric
2204ba319b5SDimitry Andric if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {
221dff0c46cSDimitry Andric Result |= SymbolRef::SF_Weak;
2224ba319b5SDimitry Andric if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)
2234ba319b5SDimitry Andric Result |= SymbolRef::SF_Undefined;
224b40b48b8SDimitry Andric }
225dff0c46cSDimitry Andric
22639d628a0SDimitry Andric if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)
227dff0c46cSDimitry Andric Result |= SymbolRef::SF_Absolute;
228dff0c46cSDimitry Andric
22939d628a0SDimitry Andric if (Symb.isFileRecord())
23039d628a0SDimitry Andric Result |= SymbolRef::SF_FormatSpecific;
23139d628a0SDimitry Andric
23239d628a0SDimitry Andric if (Symb.isSectionDefinition())
23339d628a0SDimitry Andric Result |= SymbolRef::SF_FormatSpecific;
23439d628a0SDimitry Andric
23539d628a0SDimitry Andric if (Symb.isCommon())
23639d628a0SDimitry Andric Result |= SymbolRef::SF_Common;
23739d628a0SDimitry Andric
2384ba319b5SDimitry Andric if (Symb.isUndefined())
23939d628a0SDimitry Andric Result |= SymbolRef::SF_Undefined;
24039d628a0SDimitry Andric
24191bc56edSDimitry Andric return Result;
2426122f3e6SDimitry Andric }
2436122f3e6SDimitry Andric
getCommonSymbolSizeImpl(DataRefImpl Ref) const2443dac3a9bSDimitry Andric uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {
24539d628a0SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
24697bc6c73SDimitry Andric return Symb.getValue();
24739d628a0SDimitry Andric }
2482754fe60SDimitry Andric
2493ca95b02SDimitry Andric Expected<section_iterator>
getSymbolSection(DataRefImpl Ref) const2507d523365SDimitry Andric COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {
25139d628a0SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
2527d523365SDimitry Andric if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))
2537d523365SDimitry Andric return section_end();
25491bc56edSDimitry Andric const coff_section *Sec = nullptr;
25539d628a0SDimitry Andric if (std::error_code EC = getSection(Symb.getSectionNumber(), Sec))
2563ca95b02SDimitry Andric return errorCodeToError(EC);
2577d523365SDimitry Andric DataRefImpl Ret;
2587d523365SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(Sec);
2597d523365SDimitry Andric return section_iterator(SectionRef(Ret, this));
2602754fe60SDimitry Andric }
2612754fe60SDimitry Andric
getSymbolSectionID(SymbolRef Sym) const2623dac3a9bSDimitry Andric unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {
2633dac3a9bSDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());
2643dac3a9bSDimitry Andric return Symb.getSectionNumber();
2653dac3a9bSDimitry Andric }
2663dac3a9bSDimitry Andric
moveSectionNext(DataRefImpl & Ref) const26791bc56edSDimitry Andric void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {
26891bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
26991bc56edSDimitry Andric Sec += 1;
27091bc56edSDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(Sec);
2713861d79fSDimitry Andric }
2723861d79fSDimitry Andric
getSectionName(DataRefImpl Ref,StringRef & Result) const27391bc56edSDimitry Andric std::error_code COFFObjectFile::getSectionName(DataRefImpl Ref,
27417a519f9SDimitry Andric StringRef &Result) const {
27591bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
27691bc56edSDimitry Andric return getSectionName(Sec, Result);
2772754fe60SDimitry Andric }
2782754fe60SDimitry Andric
getSectionAddress(DataRefImpl Ref) const27939d628a0SDimitry Andric uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {
28091bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
2817d523365SDimitry Andric uint64_t Result = Sec->VirtualAddress;
2827d523365SDimitry Andric
2837d523365SDimitry Andric // The section VirtualAddress does not include ImageBase, and we want to
2847d523365SDimitry Andric // return virtual addresses.
2857d523365SDimitry Andric Result += getImageBase();
2867d523365SDimitry Andric return Result;
2872754fe60SDimitry Andric }
2882754fe60SDimitry Andric
getSectionIndex(DataRefImpl Sec) const289302affcbSDimitry Andric uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
290302affcbSDimitry Andric return toSec(Sec) - SectionTable;
291302affcbSDimitry Andric }
292302affcbSDimitry Andric
getSectionSize(DataRefImpl Ref) const29339d628a0SDimitry Andric uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {
29439d628a0SDimitry Andric return getSectionSize(toSec(Ref));
2952754fe60SDimitry Andric }
2962754fe60SDimitry Andric
getSectionContents(DataRefImpl Ref,StringRef & Result) const29791bc56edSDimitry Andric std::error_code COFFObjectFile::getSectionContents(DataRefImpl Ref,
29817a519f9SDimitry Andric StringRef &Result) const {
29991bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
300dff0c46cSDimitry Andric ArrayRef<uint8_t> Res;
30191bc56edSDimitry Andric std::error_code EC = getSectionContents(Sec, Res);
302dff0c46cSDimitry Andric Result = StringRef(reinterpret_cast<const char*>(Res.data()), Res.size());
303dff0c46cSDimitry Andric return EC;
3042754fe60SDimitry Andric }
3052754fe60SDimitry Andric
getSectionAlignment(DataRefImpl Ref) const30639d628a0SDimitry Andric uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {
30791bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
3083ca95b02SDimitry Andric return Sec->getAlignment();
3093ca95b02SDimitry Andric }
3103ca95b02SDimitry Andric
isSectionCompressed(DataRefImpl Sec) const3113ca95b02SDimitry Andric bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
3123ca95b02SDimitry Andric return false;
3136122f3e6SDimitry Andric }
3146122f3e6SDimitry Andric
isSectionText(DataRefImpl Ref) const31539d628a0SDimitry Andric bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {
31691bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
31739d628a0SDimitry Andric return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;
3182754fe60SDimitry Andric }
3192754fe60SDimitry Andric
isSectionData(DataRefImpl Ref) const32039d628a0SDimitry Andric bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {
32191bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
32239d628a0SDimitry Andric return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
3236122f3e6SDimitry Andric }
3246122f3e6SDimitry Andric
isSectionBSS(DataRefImpl Ref) const32539d628a0SDimitry Andric bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {
32691bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
327ff0cc061SDimitry Andric const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
328ff0cc061SDimitry Andric COFF::IMAGE_SCN_MEM_READ |
329ff0cc061SDimitry Andric COFF::IMAGE_SCN_MEM_WRITE;
330ff0cc061SDimitry Andric return (Sec->Characteristics & BssFlags) == BssFlags;
3316122f3e6SDimitry Andric }
3326122f3e6SDimitry Andric
getSectionID(SectionRef Sec) const3333dac3a9bSDimitry Andric unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {
3343dac3a9bSDimitry Andric uintptr_t Offset =
3353dac3a9bSDimitry Andric uintptr_t(Sec.getRawDataRefImpl().p) - uintptr_t(SectionTable);
3363dac3a9bSDimitry Andric assert((Offset % sizeof(coff_section)) == 0);
3373dac3a9bSDimitry Andric return (Offset / sizeof(coff_section)) + 1;
3383dac3a9bSDimitry Andric }
3393dac3a9bSDimitry Andric
isSectionVirtual(DataRefImpl Ref) const34039d628a0SDimitry Andric bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {
34191bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
342ff0cc061SDimitry Andric // In COFF, a virtual section won't have any in-file
343ff0cc061SDimitry Andric // content, so the file pointer to the content will be zero.
344ff0cc061SDimitry Andric return Sec->PointerToRawData == 0;
345dff0c46cSDimitry Andric }
346dff0c46cSDimitry Andric
getNumberOfRelocations(const coff_section * Sec,MemoryBufferRef M,const uint8_t * base)34791bc56edSDimitry Andric static uint32_t getNumberOfRelocations(const coff_section *Sec,
34839d628a0SDimitry Andric MemoryBufferRef M, const uint8_t *base) {
34991bc56edSDimitry Andric // The field for the number of relocations in COFF section table is only
35091bc56edSDimitry Andric // 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to
35191bc56edSDimitry Andric // NumberOfRelocations field, and the actual relocation count is stored in the
35291bc56edSDimitry Andric // VirtualAddress field in the first relocation entry.
35391bc56edSDimitry Andric if (Sec->hasExtendedRelocations()) {
35439d628a0SDimitry Andric const coff_relocation *FirstReloc;
35539d628a0SDimitry Andric if (getObject(FirstReloc, M, reinterpret_cast<const coff_relocation*>(
35639d628a0SDimitry Andric base + Sec->PointerToRelocations)))
35739d628a0SDimitry Andric return 0;
35839d628a0SDimitry Andric // -1 to exclude this first relocation entry.
35939d628a0SDimitry Andric return FirstReloc->VirtualAddress - 1;
36091bc56edSDimitry Andric }
36191bc56edSDimitry Andric return Sec->NumberOfRelocations;
36291bc56edSDimitry Andric }
3636122f3e6SDimitry Andric
36439d628a0SDimitry Andric static const coff_relocation *
getFirstReloc(const coff_section * Sec,MemoryBufferRef M,const uint8_t * Base)36539d628a0SDimitry Andric getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {
36639d628a0SDimitry Andric uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);
36739d628a0SDimitry Andric if (!NumRelocs)
36839d628a0SDimitry Andric return nullptr;
36939d628a0SDimitry Andric auto begin = reinterpret_cast<const coff_relocation *>(
37039d628a0SDimitry Andric Base + Sec->PointerToRelocations);
37139d628a0SDimitry Andric if (Sec->hasExtendedRelocations()) {
37239d628a0SDimitry Andric // Skip the first relocation entry repurposed to store the number of
37339d628a0SDimitry Andric // relocations.
37439d628a0SDimitry Andric begin++;
37539d628a0SDimitry Andric }
3762cab237bSDimitry Andric if (Binary::checkOffset(M, uintptr_t(begin),
3772cab237bSDimitry Andric sizeof(coff_relocation) * NumRelocs))
37839d628a0SDimitry Andric return nullptr;
37939d628a0SDimitry Andric return begin;
38039d628a0SDimitry Andric }
38139d628a0SDimitry Andric
section_rel_begin(DataRefImpl Ref) const38239d628a0SDimitry Andric relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {
38339d628a0SDimitry Andric const coff_section *Sec = toSec(Ref);
38439d628a0SDimitry Andric const coff_relocation *begin = getFirstReloc(Sec, Data, base());
385875ed548SDimitry Andric if (begin && Sec->VirtualAddress != 0)
386875ed548SDimitry Andric report_fatal_error("Sections with relocations should have an address of 0");
38739d628a0SDimitry Andric DataRefImpl Ret;
38839d628a0SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(begin);
38939d628a0SDimitry Andric return relocation_iterator(RelocationRef(Ret, this));
39039d628a0SDimitry Andric }
39139d628a0SDimitry Andric
section_rel_end(DataRefImpl Ref) const39291bc56edSDimitry Andric relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {
39391bc56edSDimitry Andric const coff_section *Sec = toSec(Ref);
39439d628a0SDimitry Andric const coff_relocation *I = getFirstReloc(Sec, Data, base());
39539d628a0SDimitry Andric if (I)
39639d628a0SDimitry Andric I += getNumberOfRelocations(Sec, Data, base());
39791bc56edSDimitry Andric DataRefImpl Ret;
39839d628a0SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(I);
39991bc56edSDimitry Andric return relocation_iterator(RelocationRef(Ret, this));
4006122f3e6SDimitry Andric }
4016122f3e6SDimitry Andric
402f785676fSDimitry Andric // Initialize the pointer to the symbol table.
initSymbolTablePtr()40391bc56edSDimitry Andric std::error_code COFFObjectFile::initSymbolTablePtr() {
40439d628a0SDimitry Andric if (COFFHeader)
40591bc56edSDimitry Andric if (std::error_code EC = getObject(
40639d628a0SDimitry Andric SymbolTable16, Data, base() + getPointerToSymbolTable(),
40739d628a0SDimitry Andric (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
40839d628a0SDimitry Andric return EC;
40939d628a0SDimitry Andric
41039d628a0SDimitry Andric if (COFFBigObjHeader)
41139d628a0SDimitry Andric if (std::error_code EC = getObject(
41239d628a0SDimitry Andric SymbolTable32, Data, base() + getPointerToSymbolTable(),
41339d628a0SDimitry Andric (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
41491bc56edSDimitry Andric return EC;
415f785676fSDimitry Andric
416f785676fSDimitry Andric // Find string table. The first four byte of the string table contains the
417f785676fSDimitry Andric // total size of the string table, including the size field itself. If the
418f785676fSDimitry Andric // string table is empty, the value of the first four byte would be 4.
41939d628a0SDimitry Andric uint32_t StringTableOffset = getPointerToSymbolTable() +
42039d628a0SDimitry Andric getNumberOfSymbols() * getSymbolTableEntrySize();
42139d628a0SDimitry Andric const uint8_t *StringTableAddr = base() + StringTableOffset;
422f785676fSDimitry Andric const ulittle32_t *StringTableSizePtr;
42339d628a0SDimitry Andric if (std::error_code EC = getObject(StringTableSizePtr, Data, StringTableAddr))
42491bc56edSDimitry Andric return EC;
425f785676fSDimitry Andric StringTableSize = *StringTableSizePtr;
42691bc56edSDimitry Andric if (std::error_code EC =
42739d628a0SDimitry Andric getObject(StringTable, Data, StringTableAddr, StringTableSize))
42891bc56edSDimitry Andric return EC;
42991bc56edSDimitry Andric
43091bc56edSDimitry Andric // Treat table sizes < 4 as empty because contrary to the PECOFF spec, some
43191bc56edSDimitry Andric // tools like cvtres write a size of 0 for an empty table instead of 4.
43291bc56edSDimitry Andric if (StringTableSize < 4)
43391bc56edSDimitry Andric StringTableSize = 4;
434f785676fSDimitry Andric
435f785676fSDimitry Andric // Check that the string table is null terminated if has any in it.
43691bc56edSDimitry Andric if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)
437f785676fSDimitry Andric return object_error::parse_failed;
43897bc6c73SDimitry Andric return std::error_code();
439f785676fSDimitry Andric }
440f785676fSDimitry Andric
getImageBase() const4417d523365SDimitry Andric uint64_t COFFObjectFile::getImageBase() const {
4427d523365SDimitry Andric if (PE32Header)
4437d523365SDimitry Andric return PE32Header->ImageBase;
4447d523365SDimitry Andric else if (PE32PlusHeader)
4457d523365SDimitry Andric return PE32PlusHeader->ImageBase;
4467d523365SDimitry Andric // This actually comes up in practice.
4477d523365SDimitry Andric return 0;
4487d523365SDimitry Andric }
4497d523365SDimitry Andric
45091bc56edSDimitry Andric // Returns the file offset for the given VA.
getVaPtr(uint64_t Addr,uintptr_t & Res) const45191bc56edSDimitry Andric std::error_code COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
4527d523365SDimitry Andric uint64_t ImageBase = getImageBase();
45391bc56edSDimitry Andric uint64_t Rva = Addr - ImageBase;
45491bc56edSDimitry Andric assert(Rva <= UINT32_MAX);
45591bc56edSDimitry Andric return getRvaPtr((uint32_t)Rva, Res);
45691bc56edSDimitry Andric }
45791bc56edSDimitry Andric
458f785676fSDimitry Andric // Returns the file offset for the given RVA.
getRvaPtr(uint32_t Addr,uintptr_t & Res) const45991bc56edSDimitry Andric std::error_code COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const {
46091bc56edSDimitry Andric for (const SectionRef &S : sections()) {
46191bc56edSDimitry Andric const coff_section *Section = getCOFFSection(S);
462f785676fSDimitry Andric uint32_t SectionStart = Section->VirtualAddress;
463f785676fSDimitry Andric uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
46491bc56edSDimitry Andric if (SectionStart <= Addr && Addr < SectionEnd) {
46591bc56edSDimitry Andric uint32_t Offset = Addr - SectionStart;
466f785676fSDimitry Andric Res = uintptr_t(base()) + Section->PointerToRawData + Offset;
46797bc6c73SDimitry Andric return std::error_code();
468f785676fSDimitry Andric }
469f785676fSDimitry Andric }
470f785676fSDimitry Andric return object_error::parse_failed;
471f785676fSDimitry Andric }
472f785676fSDimitry Andric
4733ca95b02SDimitry Andric std::error_code
getRvaAndSizeAsBytes(uint32_t RVA,uint32_t Size,ArrayRef<uint8_t> & Contents) const4743ca95b02SDimitry Andric COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
4753ca95b02SDimitry Andric ArrayRef<uint8_t> &Contents) const {
4763ca95b02SDimitry Andric for (const SectionRef &S : sections()) {
4773ca95b02SDimitry Andric const coff_section *Section = getCOFFSection(S);
4783ca95b02SDimitry Andric uint32_t SectionStart = Section->VirtualAddress;
4793ca95b02SDimitry Andric // Check if this RVA is within the section bounds. Be careful about integer
4803ca95b02SDimitry Andric // overflow.
4813ca95b02SDimitry Andric uint32_t OffsetIntoSection = RVA - SectionStart;
4823ca95b02SDimitry Andric if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
4833ca95b02SDimitry Andric Size <= Section->VirtualSize - OffsetIntoSection) {
4843ca95b02SDimitry Andric uintptr_t Begin =
4853ca95b02SDimitry Andric uintptr_t(base()) + Section->PointerToRawData + OffsetIntoSection;
4863ca95b02SDimitry Andric Contents =
4873ca95b02SDimitry Andric ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);
4883ca95b02SDimitry Andric return std::error_code();
4893ca95b02SDimitry Andric }
4903ca95b02SDimitry Andric }
4913ca95b02SDimitry Andric return object_error::parse_failed;
4923ca95b02SDimitry Andric }
4933ca95b02SDimitry Andric
494f785676fSDimitry Andric // Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
495f785676fSDimitry Andric // table entry.
getHintName(uint32_t Rva,uint16_t & Hint,StringRef & Name) const49691bc56edSDimitry Andric std::error_code COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
49791bc56edSDimitry Andric StringRef &Name) const {
498f785676fSDimitry Andric uintptr_t IntPtr = 0;
49991bc56edSDimitry Andric if (std::error_code EC = getRvaPtr(Rva, IntPtr))
50091bc56edSDimitry Andric return EC;
501f785676fSDimitry Andric const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);
502f785676fSDimitry Andric Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);
503f785676fSDimitry Andric Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));
50497bc6c73SDimitry Andric return std::error_code();
505f785676fSDimitry Andric }
506f785676fSDimitry Andric
507d88c1a5aSDimitry Andric std::error_code
getDebugPDBInfo(const debug_directory * DebugDir,const codeview::DebugInfo * & PDBInfo,StringRef & PDBFileName) const508d88c1a5aSDimitry Andric COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
509d88c1a5aSDimitry Andric const codeview::DebugInfo *&PDBInfo,
5103ca95b02SDimitry Andric StringRef &PDBFileName) const {
5113ca95b02SDimitry Andric ArrayRef<uint8_t> InfoBytes;
5123ca95b02SDimitry Andric if (std::error_code EC = getRvaAndSizeAsBytes(
5133ca95b02SDimitry Andric DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes))
5143ca95b02SDimitry Andric return EC;
515d88c1a5aSDimitry Andric if (InfoBytes.size() < sizeof(*PDBInfo) + 1)
5163ca95b02SDimitry Andric return object_error::parse_failed;
517d88c1a5aSDimitry Andric PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());
518d88c1a5aSDimitry Andric InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));
5193ca95b02SDimitry Andric PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
5203ca95b02SDimitry Andric InfoBytes.size());
5213ca95b02SDimitry Andric // Truncate the name at the first null byte. Ignore any padding.
5223ca95b02SDimitry Andric PDBFileName = PDBFileName.split('\0').first;
5233ca95b02SDimitry Andric return std::error_code();
5243ca95b02SDimitry Andric }
5253ca95b02SDimitry Andric
526d88c1a5aSDimitry Andric std::error_code
getDebugPDBInfo(const codeview::DebugInfo * & PDBInfo,StringRef & PDBFileName) const527d88c1a5aSDimitry Andric COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,
5283ca95b02SDimitry Andric StringRef &PDBFileName) const {
5293ca95b02SDimitry Andric for (const debug_directory &D : debug_directories())
5303ca95b02SDimitry Andric if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
5313ca95b02SDimitry Andric return getDebugPDBInfo(&D, PDBInfo, PDBFileName);
5323ca95b02SDimitry Andric // If we get here, there is no PDB info to return.
5333ca95b02SDimitry Andric PDBInfo = nullptr;
5343ca95b02SDimitry Andric PDBFileName = StringRef();
5353ca95b02SDimitry Andric return std::error_code();
5363ca95b02SDimitry Andric }
5373ca95b02SDimitry Andric
538f785676fSDimitry Andric // Find the import table.
initImportTablePtr()53991bc56edSDimitry Andric std::error_code COFFObjectFile::initImportTablePtr() {
540f785676fSDimitry Andric // First, we get the RVA of the import table. If the file lacks a pointer to
541f785676fSDimitry Andric // the import table, do nothing.
542f785676fSDimitry Andric const data_directory *DataEntry;
543f785676fSDimitry Andric if (getDataDirectory(COFF::IMPORT_TABLE, DataEntry))
54497bc6c73SDimitry Andric return std::error_code();
545f785676fSDimitry Andric
546f785676fSDimitry Andric // Do nothing if the pointer to import table is NULL.
547f785676fSDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
54897bc6c73SDimitry Andric return std::error_code();
549f785676fSDimitry Andric
550f785676fSDimitry Andric uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;
551f785676fSDimitry Andric
552f785676fSDimitry Andric // Find the section that contains the RVA. This is needed because the RVA is
553f785676fSDimitry Andric // the import table's memory address which is different from its file offset.
554f785676fSDimitry Andric uintptr_t IntPtr = 0;
55591bc56edSDimitry Andric if (std::error_code EC = getRvaPtr(ImportTableRva, IntPtr))
55691bc56edSDimitry Andric return EC;
5573ca95b02SDimitry Andric if (std::error_code EC = checkOffset(Data, IntPtr, DataEntry->Size))
5583ca95b02SDimitry Andric return EC;
559f785676fSDimitry Andric ImportDirectory = reinterpret_cast<
560d88c1a5aSDimitry Andric const coff_import_directory_table_entry *>(IntPtr);
56197bc6c73SDimitry Andric return std::error_code();
562f785676fSDimitry Andric }
563f785676fSDimitry Andric
56439d628a0SDimitry Andric // Initializes DelayImportDirectory and NumberOfDelayImportDirectory.
initDelayImportTablePtr()56539d628a0SDimitry Andric std::error_code COFFObjectFile::initDelayImportTablePtr() {
56639d628a0SDimitry Andric const data_directory *DataEntry;
56739d628a0SDimitry Andric if (getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR, DataEntry))
56897bc6c73SDimitry Andric return std::error_code();
56939d628a0SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
57097bc6c73SDimitry Andric return std::error_code();
57139d628a0SDimitry Andric
57239d628a0SDimitry Andric uint32_t RVA = DataEntry->RelativeVirtualAddress;
57339d628a0SDimitry Andric NumberOfDelayImportDirectory = DataEntry->Size /
57439d628a0SDimitry Andric sizeof(delay_import_directory_table_entry) - 1;
57539d628a0SDimitry Andric
57639d628a0SDimitry Andric uintptr_t IntPtr = 0;
57739d628a0SDimitry Andric if (std::error_code EC = getRvaPtr(RVA, IntPtr))
57839d628a0SDimitry Andric return EC;
57939d628a0SDimitry Andric DelayImportDirectory = reinterpret_cast<
58039d628a0SDimitry Andric const delay_import_directory_table_entry *>(IntPtr);
58197bc6c73SDimitry Andric return std::error_code();
58239d628a0SDimitry Andric }
58339d628a0SDimitry Andric
58491bc56edSDimitry Andric // Find the export table.
initExportTablePtr()58591bc56edSDimitry Andric std::error_code COFFObjectFile::initExportTablePtr() {
58691bc56edSDimitry Andric // First, we get the RVA of the export table. If the file lacks a pointer to
58791bc56edSDimitry Andric // the export table, do nothing.
58891bc56edSDimitry Andric const data_directory *DataEntry;
58991bc56edSDimitry Andric if (getDataDirectory(COFF::EXPORT_TABLE, DataEntry))
59097bc6c73SDimitry Andric return std::error_code();
59191bc56edSDimitry Andric
59291bc56edSDimitry Andric // Do nothing if the pointer to export table is NULL.
59391bc56edSDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
59497bc6c73SDimitry Andric return std::error_code();
59591bc56edSDimitry Andric
59691bc56edSDimitry Andric uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
59791bc56edSDimitry Andric uintptr_t IntPtr = 0;
59891bc56edSDimitry Andric if (std::error_code EC = getRvaPtr(ExportTableRva, IntPtr))
59991bc56edSDimitry Andric return EC;
60091bc56edSDimitry Andric ExportDirectory =
60191bc56edSDimitry Andric reinterpret_cast<const export_directory_table_entry *>(IntPtr);
60297bc6c73SDimitry Andric return std::error_code();
60391bc56edSDimitry Andric }
60491bc56edSDimitry Andric
initBaseRelocPtr()60539d628a0SDimitry Andric std::error_code COFFObjectFile::initBaseRelocPtr() {
60639d628a0SDimitry Andric const data_directory *DataEntry;
60739d628a0SDimitry Andric if (getDataDirectory(COFF::BASE_RELOCATION_TABLE, DataEntry))
60897bc6c73SDimitry Andric return std::error_code();
60939d628a0SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
61097bc6c73SDimitry Andric return std::error_code();
61139d628a0SDimitry Andric
61239d628a0SDimitry Andric uintptr_t IntPtr = 0;
61339d628a0SDimitry Andric if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
61439d628a0SDimitry Andric return EC;
61539d628a0SDimitry Andric BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(
61639d628a0SDimitry Andric IntPtr);
61739d628a0SDimitry Andric BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(
61839d628a0SDimitry Andric IntPtr + DataEntry->Size);
619*b5893f02SDimitry Andric // FIXME: Verify the section containing BaseRelocHeader has at least
620*b5893f02SDimitry Andric // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
62197bc6c73SDimitry Andric return std::error_code();
62239d628a0SDimitry Andric }
62339d628a0SDimitry Andric
initDebugDirectoryPtr()6243ca95b02SDimitry Andric std::error_code COFFObjectFile::initDebugDirectoryPtr() {
6253ca95b02SDimitry Andric // Get the RVA of the debug directory. Do nothing if it does not exist.
6263ca95b02SDimitry Andric const data_directory *DataEntry;
6273ca95b02SDimitry Andric if (getDataDirectory(COFF::DEBUG_DIRECTORY, DataEntry))
6283ca95b02SDimitry Andric return std::error_code();
6293ca95b02SDimitry Andric
6303ca95b02SDimitry Andric // Do nothing if the RVA is NULL.
6313ca95b02SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
6323ca95b02SDimitry Andric return std::error_code();
6333ca95b02SDimitry Andric
6343ca95b02SDimitry Andric // Check that the size is a multiple of the entry size.
6353ca95b02SDimitry Andric if (DataEntry->Size % sizeof(debug_directory) != 0)
6363ca95b02SDimitry Andric return object_error::parse_failed;
6373ca95b02SDimitry Andric
6383ca95b02SDimitry Andric uintptr_t IntPtr = 0;
6393ca95b02SDimitry Andric if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
6403ca95b02SDimitry Andric return EC;
6413ca95b02SDimitry Andric DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
642*b5893f02SDimitry Andric DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(
643*b5893f02SDimitry Andric IntPtr + DataEntry->Size);
644*b5893f02SDimitry Andric // FIXME: Verify the section containing DebugDirectoryBegin has at least
645*b5893f02SDimitry Andric // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
6463ca95b02SDimitry Andric return std::error_code();
6473ca95b02SDimitry Andric }
6483ca95b02SDimitry Andric
initLoadConfigPtr()649edd7eaddSDimitry Andric std::error_code COFFObjectFile::initLoadConfigPtr() {
650edd7eaddSDimitry Andric // Get the RVA of the debug directory. Do nothing if it does not exist.
651edd7eaddSDimitry Andric const data_directory *DataEntry;
652edd7eaddSDimitry Andric if (getDataDirectory(COFF::LOAD_CONFIG_TABLE, DataEntry))
653edd7eaddSDimitry Andric return std::error_code();
654edd7eaddSDimitry Andric
655edd7eaddSDimitry Andric // Do nothing if the RVA is NULL.
656edd7eaddSDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
657edd7eaddSDimitry Andric return std::error_code();
658edd7eaddSDimitry Andric uintptr_t IntPtr = 0;
659edd7eaddSDimitry Andric if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
660edd7eaddSDimitry Andric return EC;
661edd7eaddSDimitry Andric
662edd7eaddSDimitry Andric LoadConfig = (const void *)IntPtr;
663edd7eaddSDimitry Andric return std::error_code();
664edd7eaddSDimitry Andric }
665edd7eaddSDimitry Andric
COFFObjectFile(MemoryBufferRef Object,std::error_code & EC)66639d628a0SDimitry Andric COFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC)
66739d628a0SDimitry Andric : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
66839d628a0SDimitry Andric COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
66939d628a0SDimitry Andric DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),
67039d628a0SDimitry Andric SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),
6713ca95b02SDimitry Andric ImportDirectory(nullptr),
67239d628a0SDimitry Andric DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0),
6733ca95b02SDimitry Andric ExportDirectory(nullptr), BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
6743ca95b02SDimitry Andric DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr) {
67517a519f9SDimitry Andric // Check that we at least have enough room for a header.
67639d628a0SDimitry Andric if (!checkSize(Data, EC, sizeof(coff_file_header)))
67791bc56edSDimitry Andric return;
6783b0f4066SDimitry Andric
679f785676fSDimitry Andric // The current location in the file where we are looking at.
680f785676fSDimitry Andric uint64_t CurPtr = 0;
681f785676fSDimitry Andric
682f785676fSDimitry Andric // PE header is optional and is present only in executables. If it exists,
683f785676fSDimitry Andric // it is placed right after COFF header.
68491bc56edSDimitry Andric bool HasPEHeader = false;
68517a519f9SDimitry Andric
68617a519f9SDimitry Andric // Check if this is a PE/COFF file.
68739d628a0SDimitry Andric if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {
6883b0f4066SDimitry Andric // PE/COFF, seek through MS-DOS compatibility stub and 4-byte
6893b0f4066SDimitry Andric // PE signature to find 'normal' COFF header.
69039d628a0SDimitry Andric const auto *DH = reinterpret_cast<const dos_header *>(base());
69139d628a0SDimitry Andric if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {
69239d628a0SDimitry Andric CurPtr = DH->AddressOfNewExeHeader;
693f785676fSDimitry Andric // Check the PE magic bytes. ("PE\0\0")
69439d628a0SDimitry Andric if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {
69591bc56edSDimitry Andric EC = object_error::parse_failed;
69617a519f9SDimitry Andric return;
69717a519f9SDimitry Andric }
69839d628a0SDimitry Andric CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.
69991bc56edSDimitry Andric HasPEHeader = true;
7003b0f4066SDimitry Andric }
70139d628a0SDimitry Andric }
7023b0f4066SDimitry Andric
70339d628a0SDimitry Andric if ((EC = getObject(COFFHeader, Data, base() + CurPtr)))
70417a519f9SDimitry Andric return;
70539d628a0SDimitry Andric
70639d628a0SDimitry Andric // It might be a bigobj file, let's check. Note that COFF bigobj and COFF
70739d628a0SDimitry Andric // import libraries share a common prefix but bigobj is more restrictive.
70839d628a0SDimitry Andric if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
70939d628a0SDimitry Andric COFFHeader->NumberOfSections == uint16_t(0xffff) &&
71039d628a0SDimitry Andric checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {
71139d628a0SDimitry Andric if ((EC = getObject(COFFBigObjHeader, Data, base() + CurPtr)))
71239d628a0SDimitry Andric return;
71339d628a0SDimitry Andric
71439d628a0SDimitry Andric // Verify that we are dealing with bigobj.
71539d628a0SDimitry Andric if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&
71639d628a0SDimitry Andric std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,
71739d628a0SDimitry Andric sizeof(COFF::BigObjMagic)) == 0) {
71839d628a0SDimitry Andric COFFHeader = nullptr;
71939d628a0SDimitry Andric CurPtr += sizeof(coff_bigobj_file_header);
72039d628a0SDimitry Andric } else {
72139d628a0SDimitry Andric // It's not a bigobj.
72239d628a0SDimitry Andric COFFBigObjHeader = nullptr;
72339d628a0SDimitry Andric }
72439d628a0SDimitry Andric }
72539d628a0SDimitry Andric if (COFFHeader) {
72639d628a0SDimitry Andric // The prior checkSize call may have failed. This isn't a hard error
72739d628a0SDimitry Andric // because we were just trying to sniff out bigobj.
72897bc6c73SDimitry Andric EC = std::error_code();
729f785676fSDimitry Andric CurPtr += sizeof(coff_file_header);
73017a519f9SDimitry Andric
73139d628a0SDimitry Andric if (COFFHeader->isImportLibrary())
73239d628a0SDimitry Andric return;
73339d628a0SDimitry Andric }
73439d628a0SDimitry Andric
73591bc56edSDimitry Andric if (HasPEHeader) {
73691bc56edSDimitry Andric const pe32_header *Header;
73739d628a0SDimitry Andric if ((EC = getObject(Header, Data, base() + CurPtr)))
73817a519f9SDimitry Andric return;
73991bc56edSDimitry Andric
74091bc56edSDimitry Andric const uint8_t *DataDirAddr;
74191bc56edSDimitry Andric uint64_t DataDirSize;
74239d628a0SDimitry Andric if (Header->Magic == COFF::PE32Header::PE32) {
74391bc56edSDimitry Andric PE32Header = Header;
74491bc56edSDimitry Andric DataDirAddr = base() + CurPtr + sizeof(pe32_header);
74591bc56edSDimitry Andric DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;
74639d628a0SDimitry Andric } else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {
74791bc56edSDimitry Andric PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);
74891bc56edSDimitry Andric DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);
74991bc56edSDimitry Andric DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
75091bc56edSDimitry Andric } else {
75191bc56edSDimitry Andric // It's neither PE32 nor PE32+.
75291bc56edSDimitry Andric EC = object_error::parse_failed;
75317a519f9SDimitry Andric return;
75417a519f9SDimitry Andric }
75539d628a0SDimitry Andric if ((EC = getObject(DataDirectory, Data, DataDirAddr, DataDirSize)))
75691bc56edSDimitry Andric return;
757dff0c46cSDimitry Andric }
75817a519f9SDimitry Andric
759d88c1a5aSDimitry Andric if (COFFHeader)
760d88c1a5aSDimitry Andric CurPtr += COFFHeader->SizeOfOptionalHeader;
761d88c1a5aSDimitry Andric
76239d628a0SDimitry Andric if ((EC = getObject(SectionTable, Data, base() + CurPtr,
76339d628a0SDimitry Andric (uint64_t)getNumberOfSections() * sizeof(coff_section))))
764f785676fSDimitry Andric return;
765f785676fSDimitry Andric
766f785676fSDimitry Andric // Initialize the pointer to the symbol table.
76739d628a0SDimitry Andric if (getPointerToSymbolTable() != 0) {
768d88c1a5aSDimitry Andric if ((EC = initSymbolTablePtr())) {
769d88c1a5aSDimitry Andric SymbolTable16 = nullptr;
770d88c1a5aSDimitry Andric SymbolTable32 = nullptr;
771d88c1a5aSDimitry Andric StringTable = nullptr;
772d88c1a5aSDimitry Andric StringTableSize = 0;
773d88c1a5aSDimitry Andric }
77439d628a0SDimitry Andric } else {
77539d628a0SDimitry Andric // We had better not have any symbols if we don't have a symbol table.
77639d628a0SDimitry Andric if (getNumberOfSymbols() != 0) {
77739d628a0SDimitry Andric EC = object_error::parse_failed;
77839d628a0SDimitry Andric return;
77939d628a0SDimitry Andric }
78039d628a0SDimitry Andric }
781f785676fSDimitry Andric
782f785676fSDimitry Andric // Initialize the pointer to the beginning of the import table.
78391bc56edSDimitry Andric if ((EC = initImportTablePtr()))
784f785676fSDimitry Andric return;
78539d628a0SDimitry Andric if ((EC = initDelayImportTablePtr()))
78639d628a0SDimitry Andric return;
787f785676fSDimitry Andric
78891bc56edSDimitry Andric // Initialize the pointer to the export table.
78991bc56edSDimitry Andric if ((EC = initExportTablePtr()))
79091bc56edSDimitry Andric return;
79191bc56edSDimitry Andric
79239d628a0SDimitry Andric // Initialize the pointer to the base relocation table.
79339d628a0SDimitry Andric if ((EC = initBaseRelocPtr()))
79439d628a0SDimitry Andric return;
79539d628a0SDimitry Andric
7963ca95b02SDimitry Andric // Initialize the pointer to the export table.
7973ca95b02SDimitry Andric if ((EC = initDebugDirectoryPtr()))
7983ca95b02SDimitry Andric return;
7993ca95b02SDimitry Andric
800edd7eaddSDimitry Andric if ((EC = initLoadConfigPtr()))
801edd7eaddSDimitry Andric return;
802edd7eaddSDimitry Andric
80397bc6c73SDimitry Andric EC = std::error_code();
8042754fe60SDimitry Andric }
8052754fe60SDimitry Andric
symbol_begin() const806d88c1a5aSDimitry Andric basic_symbol_iterator COFFObjectFile::symbol_begin() const {
80791bc56edSDimitry Andric DataRefImpl Ret;
80839d628a0SDimitry Andric Ret.p = getSymbolTable();
80991bc56edSDimitry Andric return basic_symbol_iterator(SymbolRef(Ret, this));
8102754fe60SDimitry Andric }
8112754fe60SDimitry Andric
symbol_end() const812d88c1a5aSDimitry Andric basic_symbol_iterator COFFObjectFile::symbol_end() const {
8132754fe60SDimitry Andric // The symbol table ends where the string table begins.
81491bc56edSDimitry Andric DataRefImpl Ret;
81591bc56edSDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(StringTable);
81691bc56edSDimitry Andric return basic_symbol_iterator(SymbolRef(Ret, this));
8172754fe60SDimitry Andric }
8182754fe60SDimitry Andric
import_directory_begin() const819f785676fSDimitry Andric import_directory_iterator COFFObjectFile::import_directory_begin() const {
8203ca95b02SDimitry Andric if (!ImportDirectory)
8213ca95b02SDimitry Andric return import_directory_end();
822d88c1a5aSDimitry Andric if (ImportDirectory->isNull())
8233ca95b02SDimitry Andric return import_directory_end();
82491bc56edSDimitry Andric return import_directory_iterator(
82591bc56edSDimitry Andric ImportDirectoryEntryRef(ImportDirectory, 0, this));
826f785676fSDimitry Andric }
827f785676fSDimitry Andric
import_directory_end() const828f785676fSDimitry Andric import_directory_iterator COFFObjectFile::import_directory_end() const {
82991bc56edSDimitry Andric return import_directory_iterator(
8303ca95b02SDimitry Andric ImportDirectoryEntryRef(nullptr, -1, this));
831f785676fSDimitry Andric }
832dff0c46cSDimitry Andric
83339d628a0SDimitry Andric delay_import_directory_iterator
delay_import_directory_begin() const83439d628a0SDimitry Andric COFFObjectFile::delay_import_directory_begin() const {
83539d628a0SDimitry Andric return delay_import_directory_iterator(
83639d628a0SDimitry Andric DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));
83739d628a0SDimitry Andric }
83839d628a0SDimitry Andric
83939d628a0SDimitry Andric delay_import_directory_iterator
delay_import_directory_end() const84039d628a0SDimitry Andric COFFObjectFile::delay_import_directory_end() const {
84139d628a0SDimitry Andric return delay_import_directory_iterator(
84239d628a0SDimitry Andric DelayImportDirectoryEntryRef(
84339d628a0SDimitry Andric DelayImportDirectory, NumberOfDelayImportDirectory, this));
84439d628a0SDimitry Andric }
84539d628a0SDimitry Andric
export_directory_begin() const84691bc56edSDimitry Andric export_directory_iterator COFFObjectFile::export_directory_begin() const {
84791bc56edSDimitry Andric return export_directory_iterator(
84891bc56edSDimitry Andric ExportDirectoryEntryRef(ExportDirectory, 0, this));
8492754fe60SDimitry Andric }
8502754fe60SDimitry Andric
export_directory_end() const85191bc56edSDimitry Andric export_directory_iterator COFFObjectFile::export_directory_end() const {
85291bc56edSDimitry Andric if (!ExportDirectory)
85391bc56edSDimitry Andric return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));
85491bc56edSDimitry Andric ExportDirectoryEntryRef Ref(ExportDirectory,
85591bc56edSDimitry Andric ExportDirectory->AddressTableEntries, this);
85691bc56edSDimitry Andric return export_directory_iterator(Ref);
85791bc56edSDimitry Andric }
85891bc56edSDimitry Andric
section_begin() const85991bc56edSDimitry Andric section_iterator COFFObjectFile::section_begin() const {
86091bc56edSDimitry Andric DataRefImpl Ret;
86191bc56edSDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(SectionTable);
86291bc56edSDimitry Andric return section_iterator(SectionRef(Ret, this));
86391bc56edSDimitry Andric }
86491bc56edSDimitry Andric
section_end() const86591bc56edSDimitry Andric section_iterator COFFObjectFile::section_end() const {
86691bc56edSDimitry Andric DataRefImpl Ret;
86739d628a0SDimitry Andric int NumSections =
86839d628a0SDimitry Andric COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();
86991bc56edSDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);
87091bc56edSDimitry Andric return section_iterator(SectionRef(Ret, this));
8712754fe60SDimitry Andric }
8722754fe60SDimitry Andric
base_reloc_begin() const87339d628a0SDimitry Andric base_reloc_iterator COFFObjectFile::base_reloc_begin() const {
87439d628a0SDimitry Andric return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));
87539d628a0SDimitry Andric }
87639d628a0SDimitry Andric
base_reloc_end() const87739d628a0SDimitry Andric base_reloc_iterator COFFObjectFile::base_reloc_end() const {
87839d628a0SDimitry Andric return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));
87939d628a0SDimitry Andric }
88039d628a0SDimitry Andric
getBytesInAddress() const8812754fe60SDimitry Andric uint8_t COFFObjectFile::getBytesInAddress() const {
882a580b014SDimitry Andric return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;
8832754fe60SDimitry Andric }
8842754fe60SDimitry Andric
getFileFormatName() const8852754fe60SDimitry Andric StringRef COFFObjectFile::getFileFormatName() const {
88639d628a0SDimitry Andric switch(getMachine()) {
8872754fe60SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
8882754fe60SDimitry Andric return "COFF-i386";
8892754fe60SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
8902754fe60SDimitry Andric return "COFF-x86-64";
89191bc56edSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
89291bc56edSDimitry Andric return "COFF-ARM";
8937d523365SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
8947d523365SDimitry Andric return "COFF-ARM64";
8952754fe60SDimitry Andric default:
8962754fe60SDimitry Andric return "COFF-<unknown arch>";
8972754fe60SDimitry Andric }
8982754fe60SDimitry Andric }
8992754fe60SDimitry Andric
getArch() const9002cab237bSDimitry Andric Triple::ArchType COFFObjectFile::getArch() const {
90139d628a0SDimitry Andric switch (getMachine()) {
9022754fe60SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
9032754fe60SDimitry Andric return Triple::x86;
9042754fe60SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
9052754fe60SDimitry Andric return Triple::x86_64;
90691bc56edSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
90791bc56edSDimitry Andric return Triple::thumb;
9087d523365SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
9097d523365SDimitry Andric return Triple::aarch64;
9102754fe60SDimitry Andric default:
9112754fe60SDimitry Andric return Triple::UnknownArch;
9122754fe60SDimitry Andric }
9132754fe60SDimitry Andric }
9142754fe60SDimitry Andric
getStartAddress() const9154ba319b5SDimitry Andric Expected<uint64_t> COFFObjectFile::getStartAddress() const {
9164ba319b5SDimitry Andric if (PE32Header)
9174ba319b5SDimitry Andric return PE32Header->AddressOfEntryPoint;
9184ba319b5SDimitry Andric return 0;
9194ba319b5SDimitry Andric }
9204ba319b5SDimitry Andric
92139d628a0SDimitry Andric iterator_range<import_directory_iterator>
import_directories() const92239d628a0SDimitry Andric COFFObjectFile::import_directories() const {
92339d628a0SDimitry Andric return make_range(import_directory_begin(), import_directory_end());
924f785676fSDimitry Andric }
925f785676fSDimitry Andric
92639d628a0SDimitry Andric iterator_range<delay_import_directory_iterator>
delay_import_directories() const92739d628a0SDimitry Andric COFFObjectFile::delay_import_directories() const {
92839d628a0SDimitry Andric return make_range(delay_import_directory_begin(),
92939d628a0SDimitry Andric delay_import_directory_end());
93039d628a0SDimitry Andric }
93139d628a0SDimitry Andric
93239d628a0SDimitry Andric iterator_range<export_directory_iterator>
export_directories() const93339d628a0SDimitry Andric COFFObjectFile::export_directories() const {
93439d628a0SDimitry Andric return make_range(export_directory_begin(), export_directory_end());
93539d628a0SDimitry Andric }
93639d628a0SDimitry Andric
base_relocs() const93739d628a0SDimitry Andric iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {
93839d628a0SDimitry Andric return make_range(base_reloc_begin(), base_reloc_end());
939f785676fSDimitry Andric }
940f785676fSDimitry Andric
941*b5893f02SDimitry Andric std::error_code
getCOFFHeader(const coff_file_header * & Res) const942*b5893f02SDimitry Andric COFFObjectFile::getCOFFHeader(const coff_file_header *&Res) const {
943*b5893f02SDimitry Andric Res = COFFHeader;
944*b5893f02SDimitry Andric return std::error_code();
945*b5893f02SDimitry Andric }
946*b5893f02SDimitry Andric
947*b5893f02SDimitry Andric std::error_code
getCOFFBigObjHeader(const coff_bigobj_file_header * & Res) const948*b5893f02SDimitry Andric COFFObjectFile::getCOFFBigObjHeader(const coff_bigobj_file_header *&Res) const {
949*b5893f02SDimitry Andric Res = COFFBigObjHeader;
950*b5893f02SDimitry Andric return std::error_code();
951*b5893f02SDimitry Andric }
952*b5893f02SDimitry Andric
getPE32Header(const pe32_header * & Res) const95391bc56edSDimitry Andric std::error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const {
954f785676fSDimitry Andric Res = PE32Header;
95597bc6c73SDimitry Andric return std::error_code();
956f785676fSDimitry Andric }
957f785676fSDimitry Andric
95891bc56edSDimitry Andric std::error_code
getPE32PlusHeader(const pe32plus_header * & Res) const95991bc56edSDimitry Andric COFFObjectFile::getPE32PlusHeader(const pe32plus_header *&Res) const {
96091bc56edSDimitry Andric Res = PE32PlusHeader;
96197bc6c73SDimitry Andric return std::error_code();
962dff0c46cSDimitry Andric }
963dff0c46cSDimitry Andric
96491bc56edSDimitry Andric std::error_code
getDataDirectory(uint32_t Index,const data_directory * & Res) const96591bc56edSDimitry Andric COFFObjectFile::getDataDirectory(uint32_t Index,
96691bc56edSDimitry Andric const data_directory *&Res) const {
9674ba319b5SDimitry Andric // Error if there's no data directory or the index is out of range.
96839d628a0SDimitry Andric if (!DataDirectory) {
96939d628a0SDimitry Andric Res = nullptr;
97091bc56edSDimitry Andric return object_error::parse_failed;
97139d628a0SDimitry Andric }
97291bc56edSDimitry Andric assert(PE32Header || PE32PlusHeader);
97391bc56edSDimitry Andric uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize
97491bc56edSDimitry Andric : PE32PlusHeader->NumberOfRvaAndSize;
97539d628a0SDimitry Andric if (Index >= NumEnt) {
97639d628a0SDimitry Andric Res = nullptr;
97791bc56edSDimitry Andric return object_error::parse_failed;
97839d628a0SDimitry Andric }
97991bc56edSDimitry Andric Res = &DataDirectory[Index];
98097bc6c73SDimitry Andric return std::error_code();
98191bc56edSDimitry Andric }
98291bc56edSDimitry Andric
getSection(int32_t Index,const coff_section * & Result) const98391bc56edSDimitry Andric std::error_code COFFObjectFile::getSection(int32_t Index,
98417a519f9SDimitry Andric const coff_section *&Result) const {
98591bc56edSDimitry Andric Result = nullptr;
98639d628a0SDimitry Andric if (COFF::isReservedSectionNumber(Index))
98797bc6c73SDimitry Andric return std::error_code();
98839d628a0SDimitry Andric if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {
98917a519f9SDimitry Andric // We already verified the section table data, so no need to check again.
99091bc56edSDimitry Andric Result = SectionTable + (Index - 1);
99197bc6c73SDimitry Andric return std::error_code();
9922754fe60SDimitry Andric }
99339d628a0SDimitry Andric return object_error::parse_failed;
99439d628a0SDimitry Andric }
9952754fe60SDimitry Andric
getSection(StringRef SectionName,const coff_section * & Result) const9964ba319b5SDimitry Andric std::error_code COFFObjectFile::getSection(StringRef SectionName,
9974ba319b5SDimitry Andric const coff_section *&Result) const {
9984ba319b5SDimitry Andric Result = nullptr;
9994ba319b5SDimitry Andric StringRef SecName;
10004ba319b5SDimitry Andric for (const SectionRef &Section : sections()) {
10014ba319b5SDimitry Andric if (std::error_code E = Section.getName(SecName))
10024ba319b5SDimitry Andric return E;
10034ba319b5SDimitry Andric if (SecName == SectionName) {
10044ba319b5SDimitry Andric Result = getCOFFSection(Section);
10054ba319b5SDimitry Andric return std::error_code();
10064ba319b5SDimitry Andric }
10074ba319b5SDimitry Andric }
10084ba319b5SDimitry Andric return object_error::parse_failed;
10094ba319b5SDimitry Andric }
10104ba319b5SDimitry Andric
getString(uint32_t Offset,StringRef & Result) const101191bc56edSDimitry Andric std::error_code COFFObjectFile::getString(uint32_t Offset,
101217a519f9SDimitry Andric StringRef &Result) const {
101317a519f9SDimitry Andric if (StringTableSize <= 4)
101417a519f9SDimitry Andric // Tried to get a string from an empty string table.
101517a519f9SDimitry Andric return object_error::parse_failed;
101691bc56edSDimitry Andric if (Offset >= StringTableSize)
101717a519f9SDimitry Andric return object_error::unexpected_eof;
101891bc56edSDimitry Andric Result = StringRef(StringTable + Offset);
101997bc6c73SDimitry Andric return std::error_code();
10202754fe60SDimitry Andric }
10212754fe60SDimitry Andric
getSymbolName(COFFSymbolRef Symbol,StringRef & Res) const102239d628a0SDimitry Andric std::error_code COFFObjectFile::getSymbolName(COFFSymbolRef Symbol,
1023dff0c46cSDimitry Andric StringRef &Res) const {
10243dac3a9bSDimitry Andric return getSymbolName(Symbol.getGeneric(), Res);
10253dac3a9bSDimitry Andric }
10263dac3a9bSDimitry Andric
getSymbolName(const coff_symbol_generic * Symbol,StringRef & Res) const10273dac3a9bSDimitry Andric std::error_code COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol,
10283dac3a9bSDimitry Andric StringRef &Res) const {
1029dff0c46cSDimitry Andric // Check for string table entry. First 4 bytes are 0.
10303dac3a9bSDimitry Andric if (Symbol->Name.Offset.Zeroes == 0) {
10313dac3a9bSDimitry Andric if (std::error_code EC = getString(Symbol->Name.Offset.Offset, Res))
103291bc56edSDimitry Andric return EC;
103397bc6c73SDimitry Andric return std::error_code();
1034dff0c46cSDimitry Andric }
1035dff0c46cSDimitry Andric
10363dac3a9bSDimitry Andric if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)
1037dff0c46cSDimitry Andric // Null terminated, let ::strlen figure out the length.
10383dac3a9bSDimitry Andric Res = StringRef(Symbol->Name.ShortName);
1039dff0c46cSDimitry Andric else
1040dff0c46cSDimitry Andric // Not null terminated, use all 8 bytes.
10413dac3a9bSDimitry Andric Res = StringRef(Symbol->Name.ShortName, COFF::NameSize);
104297bc6c73SDimitry Andric return std::error_code();
1043dff0c46cSDimitry Andric }
1044dff0c46cSDimitry Andric
104539d628a0SDimitry Andric ArrayRef<uint8_t>
getSymbolAuxData(COFFSymbolRef Symbol) const104639d628a0SDimitry Andric COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {
104791bc56edSDimitry Andric const uint8_t *Aux = nullptr;
10487ae0e2c9SDimitry Andric
104939d628a0SDimitry Andric size_t SymbolSize = getSymbolTableEntrySize();
105039d628a0SDimitry Andric if (Symbol.getNumberOfAuxSymbols() > 0) {
10517ae0e2c9SDimitry Andric // AUX data comes immediately after the symbol in COFF
105239d628a0SDimitry Andric Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;
10537ae0e2c9SDimitry Andric #ifndef NDEBUG
105491bc56edSDimitry Andric // Verify that the Aux symbol points to a valid entry in the symbol table.
105591bc56edSDimitry Andric uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());
105639d628a0SDimitry Andric if (Offset < getPointerToSymbolTable() ||
105739d628a0SDimitry Andric Offset >=
105839d628a0SDimitry Andric getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))
10597ae0e2c9SDimitry Andric report_fatal_error("Aux Symbol data was outside of symbol table.");
10607ae0e2c9SDimitry Andric
106139d628a0SDimitry Andric assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&
106239d628a0SDimitry Andric "Aux Symbol data did not point to the beginning of a symbol");
10637ae0e2c9SDimitry Andric #endif
10647ae0e2c9SDimitry Andric }
106539d628a0SDimitry Andric return makeArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);
10667ae0e2c9SDimitry Andric }
10677ae0e2c9SDimitry Andric
getSymbolIndex(COFFSymbolRef Symbol) const1068*b5893f02SDimitry Andric uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {
1069*b5893f02SDimitry Andric uintptr_t Offset =
1070*b5893f02SDimitry Andric reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();
1071*b5893f02SDimitry Andric assert(Offset % getSymbolTableEntrySize() == 0 &&
1072*b5893f02SDimitry Andric "Symbol did not point to the beginning of a symbol");
1073*b5893f02SDimitry Andric size_t Index = Offset / getSymbolTableEntrySize();
1074*b5893f02SDimitry Andric assert(Index < getNumberOfSymbols());
1075*b5893f02SDimitry Andric return Index;
1076*b5893f02SDimitry Andric }
1077*b5893f02SDimitry Andric
getSectionName(const coff_section * Sec,StringRef & Res) const107891bc56edSDimitry Andric std::error_code COFFObjectFile::getSectionName(const coff_section *Sec,
1079dff0c46cSDimitry Andric StringRef &Res) const {
1080dff0c46cSDimitry Andric StringRef Name;
108139d628a0SDimitry Andric if (Sec->Name[COFF::NameSize - 1] == 0)
1082dff0c46cSDimitry Andric // Null terminated, let ::strlen figure out the length.
1083dff0c46cSDimitry Andric Name = Sec->Name;
1084dff0c46cSDimitry Andric else
1085dff0c46cSDimitry Andric // Not null terminated, use all 8 bytes.
108639d628a0SDimitry Andric Name = StringRef(Sec->Name, COFF::NameSize);
1087dff0c46cSDimitry Andric
1088dff0c46cSDimitry Andric // Check for string table entry. First byte is '/'.
108939d628a0SDimitry Andric if (Name.startswith("/")) {
1090dff0c46cSDimitry Andric uint32_t Offset;
109139d628a0SDimitry Andric if (Name.startswith("//")) {
109291bc56edSDimitry Andric if (decodeBase64StringEntry(Name.substr(2), Offset))
109391bc56edSDimitry Andric return object_error::parse_failed;
109491bc56edSDimitry Andric } else {
1095dff0c46cSDimitry Andric if (Name.substr(1).getAsInteger(10, Offset))
1096dff0c46cSDimitry Andric return object_error::parse_failed;
109791bc56edSDimitry Andric }
109891bc56edSDimitry Andric if (std::error_code EC = getString(Offset, Name))
109991bc56edSDimitry Andric return EC;
1100dff0c46cSDimitry Andric }
1101dff0c46cSDimitry Andric
1102dff0c46cSDimitry Andric Res = Name;
110397bc6c73SDimitry Andric return std::error_code();
1104dff0c46cSDimitry Andric }
1105dff0c46cSDimitry Andric
getSectionSize(const coff_section * Sec) const110639d628a0SDimitry Andric uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {
110739d628a0SDimitry Andric // SizeOfRawData and VirtualSize change what they represent depending on
110839d628a0SDimitry Andric // whether or not we have an executable image.
110939d628a0SDimitry Andric //
111039d628a0SDimitry Andric // For object files, SizeOfRawData contains the size of section's data;
1111875ed548SDimitry Andric // VirtualSize should be zero but isn't due to buggy COFF writers.
111239d628a0SDimitry Andric //
111339d628a0SDimitry Andric // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the
111439d628a0SDimitry Andric // actual section size is in VirtualSize. It is possible for VirtualSize to
111539d628a0SDimitry Andric // be greater than SizeOfRawData; the contents past that point should be
111639d628a0SDimitry Andric // considered to be zero.
1117875ed548SDimitry Andric if (getDOSHeader())
1118875ed548SDimitry Andric return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
1119875ed548SDimitry Andric return Sec->SizeOfRawData;
112039d628a0SDimitry Andric }
112139d628a0SDimitry Andric
112291bc56edSDimitry Andric std::error_code
getSectionContents(const coff_section * Sec,ArrayRef<uint8_t> & Res) const112391bc56edSDimitry Andric COFFObjectFile::getSectionContents(const coff_section *Sec,
1124dff0c46cSDimitry Andric ArrayRef<uint8_t> &Res) const {
11253ca95b02SDimitry Andric // In COFF, a virtual section won't have any in-file
11263ca95b02SDimitry Andric // content, so the file pointer to the content will be zero.
11273ca95b02SDimitry Andric if (Sec->PointerToRawData == 0)
11285517e702SDimitry Andric return std::error_code();
1129dff0c46cSDimitry Andric // The only thing that we need to verify is that the contents is contained
1130dff0c46cSDimitry Andric // within the file bounds. We don't need to make sure it doesn't cover other
1131dff0c46cSDimitry Andric // data, as there's nothing that says that is not allowed.
1132dff0c46cSDimitry Andric uintptr_t ConStart = uintptr_t(base()) + Sec->PointerToRawData;
113339d628a0SDimitry Andric uint32_t SectionSize = getSectionSize(Sec);
113439d628a0SDimitry Andric if (checkOffset(Data, ConStart, SectionSize))
1135dff0c46cSDimitry Andric return object_error::parse_failed;
113639d628a0SDimitry Andric Res = makeArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);
113797bc6c73SDimitry Andric return std::error_code();
1138dff0c46cSDimitry Andric }
1139dff0c46cSDimitry Andric
toRel(DataRefImpl Rel) const11406122f3e6SDimitry Andric const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {
11416122f3e6SDimitry Andric return reinterpret_cast<const coff_relocation*>(Rel.p);
11426122f3e6SDimitry Andric }
114391bc56edSDimitry Andric
moveRelocationNext(DataRefImpl & Rel) const114491bc56edSDimitry Andric void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
11456122f3e6SDimitry Andric Rel.p = reinterpret_cast<uintptr_t>(
11466122f3e6SDimitry Andric reinterpret_cast<const coff_relocation*>(Rel.p) + 1);
11476122f3e6SDimitry Andric }
114891bc56edSDimitry Andric
getRelocationOffset(DataRefImpl Rel) const11493dac3a9bSDimitry Andric uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
115039d628a0SDimitry Andric const coff_relocation *R = toRel(Rel);
11513dac3a9bSDimitry Andric return R->VirtualAddress;
1152dff0c46cSDimitry Andric }
115391bc56edSDimitry Andric
getRelocationSymbol(DataRefImpl Rel) const1154f785676fSDimitry Andric symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
11556122f3e6SDimitry Andric const coff_relocation *R = toRel(Rel);
115691bc56edSDimitry Andric DataRefImpl Ref;
115739d628a0SDimitry Andric if (R->SymbolTableIndex >= getNumberOfSymbols())
115839d628a0SDimitry Andric return symbol_end();
115939d628a0SDimitry Andric if (SymbolTable16)
116039d628a0SDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);
116139d628a0SDimitry Andric else if (SymbolTable32)
116239d628a0SDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);
116339d628a0SDimitry Andric else
116439d628a0SDimitry Andric llvm_unreachable("no symbol table pointer!");
116591bc56edSDimitry Andric return symbol_iterator(SymbolRef(Ref, this));
11666122f3e6SDimitry Andric }
116791bc56edSDimitry Andric
getRelocationType(DataRefImpl Rel) const11683dac3a9bSDimitry Andric uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {
11696122f3e6SDimitry Andric const coff_relocation* R = toRel(Rel);
11703dac3a9bSDimitry Andric return R->Type;
11716122f3e6SDimitry Andric }
11726122f3e6SDimitry Andric
117391bc56edSDimitry Andric const coff_section *
getCOFFSection(const SectionRef & Section) const117491bc56edSDimitry Andric COFFObjectFile::getCOFFSection(const SectionRef &Section) const {
117591bc56edSDimitry Andric return toSec(Section.getRawDataRefImpl());
11767ae0e2c9SDimitry Andric }
11777ae0e2c9SDimitry Andric
getCOFFSymbol(const DataRefImpl & Ref) const117839d628a0SDimitry Andric COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {
117939d628a0SDimitry Andric if (SymbolTable16)
118039d628a0SDimitry Andric return toSymb<coff_symbol16>(Ref);
118139d628a0SDimitry Andric if (SymbolTable32)
118239d628a0SDimitry Andric return toSymb<coff_symbol32>(Ref);
118339d628a0SDimitry Andric llvm_unreachable("no symbol table pointer!");
118439d628a0SDimitry Andric }
118539d628a0SDimitry Andric
getCOFFSymbol(const SymbolRef & Symbol) const118639d628a0SDimitry Andric COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {
118739d628a0SDimitry Andric return getCOFFSymbol(Symbol.getRawDataRefImpl());
11887ae0e2c9SDimitry Andric }
11897ae0e2c9SDimitry Andric
119091bc56edSDimitry Andric const coff_relocation *
getCOFFRelocation(const RelocationRef & Reloc) const119191bc56edSDimitry Andric COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {
119291bc56edSDimitry Andric return toRel(Reloc.getRawDataRefImpl());
11937ae0e2c9SDimitry Andric }
11947ae0e2c9SDimitry Andric
11954ba319b5SDimitry Andric ArrayRef<coff_relocation>
getRelocations(const coff_section * Sec) const11963dac3a9bSDimitry Andric COFFObjectFile::getRelocations(const coff_section *Sec) const {
11974ba319b5SDimitry Andric return {getFirstReloc(Sec, Data, base()),
11984ba319b5SDimitry Andric getNumberOfRelocations(Sec, Data, base())};
11993dac3a9bSDimitry Andric }
12003dac3a9bSDimitry Andric
120191bc56edSDimitry Andric #define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \
120291bc56edSDimitry Andric case COFF::reloc_type: \
1203*b5893f02SDimitry Andric return #reloc_type;
12046122f3e6SDimitry Andric
getRelocationTypeName(uint16_t Type) const1205*b5893f02SDimitry Andric StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
120639d628a0SDimitry Andric switch (getMachine()) {
12076122f3e6SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
1208*b5893f02SDimitry Andric switch (Type) {
12096122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);
12106122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);
12116122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);
12126122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);
12136122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);
12146122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);
12156122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);
12166122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);
12176122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);
12186122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);
12196122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);
12206122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);
12216122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);
12226122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);
12236122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);
12246122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);
12256122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);
12266122f3e6SDimitry Andric default:
1227*b5893f02SDimitry Andric return "Unknown";
122891bc56edSDimitry Andric }
122991bc56edSDimitry Andric break;
123091bc56edSDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
1231*b5893f02SDimitry Andric switch (Type) {
123291bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);
123391bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);
123491bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);
123591bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);
123691bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);
123791bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);
123891bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);
123991bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);
124091bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);
124191bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);
124291bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);
124391bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);
124491bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);
124591bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);
124691bc56edSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);
124791bc56edSDimitry Andric default:
1248*b5893f02SDimitry Andric return "Unknown";
12496122f3e6SDimitry Andric }
12506122f3e6SDimitry Andric break;
1251a580b014SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
1252*b5893f02SDimitry Andric switch (Type) {
1253a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);
1254a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);
1255a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);
1256a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);
1257a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);
1258a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);
1259a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);
1260a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);
1261a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);
1262a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);
1263a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);
1264a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);
1265a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);
1266a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);
1267a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);
1268a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);
1269a580b014SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);
1270a580b014SDimitry Andric default:
1271*b5893f02SDimitry Andric return "Unknown";
1272a580b014SDimitry Andric }
1273a580b014SDimitry Andric break;
12746122f3e6SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
1275*b5893f02SDimitry Andric switch (Type) {
12766122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);
12776122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);
12786122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);
12796122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);
12806122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);
12816122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);
12826122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);
12836122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);
12846122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);
12856122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);
12866122f3e6SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);
12876122f3e6SDimitry Andric default:
1288*b5893f02SDimitry Andric return "Unknown";
12896122f3e6SDimitry Andric }
12906122f3e6SDimitry Andric break;
12916122f3e6SDimitry Andric default:
1292*b5893f02SDimitry Andric return "Unknown";
12936122f3e6SDimitry Andric }
12946122f3e6SDimitry Andric }
12956122f3e6SDimitry Andric
12966122f3e6SDimitry Andric #undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME
12976122f3e6SDimitry Andric
getRelocationTypeName(DataRefImpl Rel,SmallVectorImpl<char> & Result) const1298*b5893f02SDimitry Andric void COFFObjectFile::getRelocationTypeName(
1299*b5893f02SDimitry Andric DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
1300*b5893f02SDimitry Andric const coff_relocation *Reloc = toRel(Rel);
1301*b5893f02SDimitry Andric StringRef Res = getRelocationTypeName(Reloc->Type);
1302*b5893f02SDimitry Andric Result.append(Res.begin(), Res.end());
1303*b5893f02SDimitry Andric }
1304*b5893f02SDimitry Andric
isRelocatableObject() const130539d628a0SDimitry Andric bool COFFObjectFile::isRelocatableObject() const {
130639d628a0SDimitry Andric return !DataDirectory;
1307dff0c46cSDimitry Andric }
1308dff0c46cSDimitry Andric
mapDebugSectionName(StringRef Name) const1309*b5893f02SDimitry Andric StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {
1310*b5893f02SDimitry Andric return StringSwitch<StringRef>(Name)
1311*b5893f02SDimitry Andric .Case("eh_fram", "eh_frame")
1312*b5893f02SDimitry Andric .Default(Name);
1313*b5893f02SDimitry Andric }
1314*b5893f02SDimitry Andric
1315f785676fSDimitry Andric bool ImportDirectoryEntryRef::
operator ==(const ImportDirectoryEntryRef & Other) const1316f785676fSDimitry Andric operator==(const ImportDirectoryEntryRef &Other) const {
131791bc56edSDimitry Andric return ImportTable == Other.ImportTable && Index == Other.Index;
1318f785676fSDimitry Andric }
1319f785676fSDimitry Andric
moveNext()132091bc56edSDimitry Andric void ImportDirectoryEntryRef::moveNext() {
132191bc56edSDimitry Andric ++Index;
1322d88c1a5aSDimitry Andric if (ImportTable[Index].isNull()) {
13233ca95b02SDimitry Andric Index = -1;
13243ca95b02SDimitry Andric ImportTable = nullptr;
13253ca95b02SDimitry Andric }
1326f785676fSDimitry Andric }
1327f785676fSDimitry Andric
getImportTableEntry(const coff_import_directory_table_entry * & Result) const132891bc56edSDimitry Andric std::error_code ImportDirectoryEntryRef::getImportTableEntry(
1329d88c1a5aSDimitry Andric const coff_import_directory_table_entry *&Result) const {
13303ca95b02SDimitry Andric return getObject(Result, OwningObject->Data, ImportTable + Index);
1331f785676fSDimitry Andric }
1332f785676fSDimitry Andric
133339d628a0SDimitry Andric static imported_symbol_iterator
makeImportedSymbolIterator(const COFFObjectFile * Object,uintptr_t Ptr,int Index)133439d628a0SDimitry Andric makeImportedSymbolIterator(const COFFObjectFile *Object,
133539d628a0SDimitry Andric uintptr_t Ptr, int Index) {
133639d628a0SDimitry Andric if (Object->getBytesInAddress() == 4) {
133739d628a0SDimitry Andric auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);
133839d628a0SDimitry Andric return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
133939d628a0SDimitry Andric }
134039d628a0SDimitry Andric auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);
134139d628a0SDimitry Andric return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
134239d628a0SDimitry Andric }
134339d628a0SDimitry Andric
134439d628a0SDimitry Andric static imported_symbol_iterator
importedSymbolBegin(uint32_t RVA,const COFFObjectFile * Object)134539d628a0SDimitry Andric importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {
134639d628a0SDimitry Andric uintptr_t IntPtr = 0;
134739d628a0SDimitry Andric Object->getRvaPtr(RVA, IntPtr);
134839d628a0SDimitry Andric return makeImportedSymbolIterator(Object, IntPtr, 0);
134939d628a0SDimitry Andric }
135039d628a0SDimitry Andric
135139d628a0SDimitry Andric static imported_symbol_iterator
importedSymbolEnd(uint32_t RVA,const COFFObjectFile * Object)135239d628a0SDimitry Andric importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {
135339d628a0SDimitry Andric uintptr_t IntPtr = 0;
135439d628a0SDimitry Andric Object->getRvaPtr(RVA, IntPtr);
135539d628a0SDimitry Andric // Forward the pointer to the last entry which is null.
135639d628a0SDimitry Andric int Index = 0;
135739d628a0SDimitry Andric if (Object->getBytesInAddress() == 4) {
135839d628a0SDimitry Andric auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);
135939d628a0SDimitry Andric while (*Entry++)
136039d628a0SDimitry Andric ++Index;
136139d628a0SDimitry Andric } else {
136239d628a0SDimitry Andric auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);
136339d628a0SDimitry Andric while (*Entry++)
136439d628a0SDimitry Andric ++Index;
136539d628a0SDimitry Andric }
136639d628a0SDimitry Andric return makeImportedSymbolIterator(Object, IntPtr, Index);
136739d628a0SDimitry Andric }
136839d628a0SDimitry Andric
136939d628a0SDimitry Andric imported_symbol_iterator
imported_symbol_begin() const137039d628a0SDimitry Andric ImportDirectoryEntryRef::imported_symbol_begin() const {
1371d88c1a5aSDimitry Andric return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,
137239d628a0SDimitry Andric OwningObject);
137339d628a0SDimitry Andric }
137439d628a0SDimitry Andric
137539d628a0SDimitry Andric imported_symbol_iterator
imported_symbol_end() const137639d628a0SDimitry Andric ImportDirectoryEntryRef::imported_symbol_end() const {
1377d88c1a5aSDimitry Andric return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,
137839d628a0SDimitry Andric OwningObject);
137939d628a0SDimitry Andric }
138039d628a0SDimitry Andric
138139d628a0SDimitry Andric iterator_range<imported_symbol_iterator>
imported_symbols() const138239d628a0SDimitry Andric ImportDirectoryEntryRef::imported_symbols() const {
138339d628a0SDimitry Andric return make_range(imported_symbol_begin(), imported_symbol_end());
138439d628a0SDimitry Andric }
138539d628a0SDimitry Andric
lookup_table_begin() const1386d88c1a5aSDimitry Andric imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {
1387d88c1a5aSDimitry Andric return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,
1388d88c1a5aSDimitry Andric OwningObject);
1389d88c1a5aSDimitry Andric }
1390d88c1a5aSDimitry Andric
lookup_table_end() const1391d88c1a5aSDimitry Andric imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {
1392d88c1a5aSDimitry Andric return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,
1393d88c1a5aSDimitry Andric OwningObject);
1394d88c1a5aSDimitry Andric }
1395d88c1a5aSDimitry Andric
1396d88c1a5aSDimitry Andric iterator_range<imported_symbol_iterator>
lookup_table_symbols() const1397d88c1a5aSDimitry Andric ImportDirectoryEntryRef::lookup_table_symbols() const {
1398d88c1a5aSDimitry Andric return make_range(lookup_table_begin(), lookup_table_end());
1399d88c1a5aSDimitry Andric }
1400d88c1a5aSDimitry Andric
getName(StringRef & Result) const140191bc56edSDimitry Andric std::error_code ImportDirectoryEntryRef::getName(StringRef &Result) const {
1402f785676fSDimitry Andric uintptr_t IntPtr = 0;
140391bc56edSDimitry Andric if (std::error_code EC =
140439d628a0SDimitry Andric OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr))
140591bc56edSDimitry Andric return EC;
140691bc56edSDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
140797bc6c73SDimitry Andric return std::error_code();
1408f785676fSDimitry Andric }
1409f785676fSDimitry Andric
141039d628a0SDimitry Andric std::error_code
getImportLookupTableRVA(uint32_t & Result) const141139d628a0SDimitry Andric ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {
141239d628a0SDimitry Andric Result = ImportTable[Index].ImportLookupTableRVA;
141397bc6c73SDimitry Andric return std::error_code();
141439d628a0SDimitry Andric }
141539d628a0SDimitry Andric
141639d628a0SDimitry Andric std::error_code
getImportAddressTableRVA(uint32_t & Result) const141739d628a0SDimitry Andric ImportDirectoryEntryRef::getImportAddressTableRVA(uint32_t &Result) const {
141839d628a0SDimitry Andric Result = ImportTable[Index].ImportAddressTableRVA;
141997bc6c73SDimitry Andric return std::error_code();
142039d628a0SDimitry Andric }
142139d628a0SDimitry Andric
142239d628a0SDimitry Andric bool DelayImportDirectoryEntryRef::
operator ==(const DelayImportDirectoryEntryRef & Other) const142339d628a0SDimitry Andric operator==(const DelayImportDirectoryEntryRef &Other) const {
142439d628a0SDimitry Andric return Table == Other.Table && Index == Other.Index;
142539d628a0SDimitry Andric }
142639d628a0SDimitry Andric
moveNext()142739d628a0SDimitry Andric void DelayImportDirectoryEntryRef::moveNext() {
142839d628a0SDimitry Andric ++Index;
142939d628a0SDimitry Andric }
143039d628a0SDimitry Andric
143139d628a0SDimitry Andric imported_symbol_iterator
imported_symbol_begin() const143239d628a0SDimitry Andric DelayImportDirectoryEntryRef::imported_symbol_begin() const {
143339d628a0SDimitry Andric return importedSymbolBegin(Table[Index].DelayImportNameTable,
143439d628a0SDimitry Andric OwningObject);
143539d628a0SDimitry Andric }
143639d628a0SDimitry Andric
143739d628a0SDimitry Andric imported_symbol_iterator
imported_symbol_end() const143839d628a0SDimitry Andric DelayImportDirectoryEntryRef::imported_symbol_end() const {
143939d628a0SDimitry Andric return importedSymbolEnd(Table[Index].DelayImportNameTable,
144039d628a0SDimitry Andric OwningObject);
144139d628a0SDimitry Andric }
144239d628a0SDimitry Andric
144339d628a0SDimitry Andric iterator_range<imported_symbol_iterator>
imported_symbols() const144439d628a0SDimitry Andric DelayImportDirectoryEntryRef::imported_symbols() const {
144539d628a0SDimitry Andric return make_range(imported_symbol_begin(), imported_symbol_end());
144639d628a0SDimitry Andric }
144739d628a0SDimitry Andric
getName(StringRef & Result) const144839d628a0SDimitry Andric std::error_code DelayImportDirectoryEntryRef::getName(StringRef &Result) const {
144939d628a0SDimitry Andric uintptr_t IntPtr = 0;
145039d628a0SDimitry Andric if (std::error_code EC = OwningObject->getRvaPtr(Table[Index].Name, IntPtr))
145139d628a0SDimitry Andric return EC;
145239d628a0SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
145397bc6c73SDimitry Andric return std::error_code();
145439d628a0SDimitry Andric }
145539d628a0SDimitry Andric
145639d628a0SDimitry Andric std::error_code DelayImportDirectoryEntryRef::
getDelayImportTable(const delay_import_directory_table_entry * & Result) const145739d628a0SDimitry Andric getDelayImportTable(const delay_import_directory_table_entry *&Result) const {
145839d628a0SDimitry Andric Result = Table;
145997bc6c73SDimitry Andric return std::error_code();
146039d628a0SDimitry Andric }
146139d628a0SDimitry Andric
146239d628a0SDimitry Andric std::error_code DelayImportDirectoryEntryRef::
getImportAddress(int AddrIndex,uint64_t & Result) const146339d628a0SDimitry Andric getImportAddress(int AddrIndex, uint64_t &Result) const {
146439d628a0SDimitry Andric uint32_t RVA = Table[Index].DelayImportAddressTable +
146539d628a0SDimitry Andric AddrIndex * (OwningObject->is64() ? 8 : 4);
146639d628a0SDimitry Andric uintptr_t IntPtr = 0;
146739d628a0SDimitry Andric if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr))
146839d628a0SDimitry Andric return EC;
146939d628a0SDimitry Andric if (OwningObject->is64())
147039d628a0SDimitry Andric Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);
147139d628a0SDimitry Andric else
147239d628a0SDimitry Andric Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);
147397bc6c73SDimitry Andric return std::error_code();
147439d628a0SDimitry Andric }
147539d628a0SDimitry Andric
147691bc56edSDimitry Andric bool ExportDirectoryEntryRef::
operator ==(const ExportDirectoryEntryRef & Other) const147791bc56edSDimitry Andric operator==(const ExportDirectoryEntryRef &Other) const {
147891bc56edSDimitry Andric return ExportTable == Other.ExportTable && Index == Other.Index;
14792754fe60SDimitry Andric }
14802754fe60SDimitry Andric
moveNext()148191bc56edSDimitry Andric void ExportDirectoryEntryRef::moveNext() {
148291bc56edSDimitry Andric ++Index;
148391bc56edSDimitry Andric }
148491bc56edSDimitry Andric
148591bc56edSDimitry Andric // Returns the name of the current export symbol. If the symbol is exported only
148691bc56edSDimitry Andric // by ordinal, the empty string is set as a result.
getDllName(StringRef & Result) const148791bc56edSDimitry Andric std::error_code ExportDirectoryEntryRef::getDllName(StringRef &Result) const {
148891bc56edSDimitry Andric uintptr_t IntPtr = 0;
148991bc56edSDimitry Andric if (std::error_code EC =
149091bc56edSDimitry Andric OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr))
149191bc56edSDimitry Andric return EC;
149291bc56edSDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
149397bc6c73SDimitry Andric return std::error_code();
149491bc56edSDimitry Andric }
149591bc56edSDimitry Andric
149691bc56edSDimitry Andric // Returns the starting ordinal number.
149791bc56edSDimitry Andric std::error_code
getOrdinalBase(uint32_t & Result) const149891bc56edSDimitry Andric ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {
149991bc56edSDimitry Andric Result = ExportTable->OrdinalBase;
150097bc6c73SDimitry Andric return std::error_code();
150191bc56edSDimitry Andric }
150291bc56edSDimitry Andric
150391bc56edSDimitry Andric // Returns the export ordinal of the current export symbol.
getOrdinal(uint32_t & Result) const150491bc56edSDimitry Andric std::error_code ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
150591bc56edSDimitry Andric Result = ExportTable->OrdinalBase + Index;
150697bc6c73SDimitry Andric return std::error_code();
150791bc56edSDimitry Andric }
150891bc56edSDimitry Andric
150991bc56edSDimitry Andric // Returns the address of the current export symbol.
getExportRVA(uint32_t & Result) const151091bc56edSDimitry Andric std::error_code ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
151191bc56edSDimitry Andric uintptr_t IntPtr = 0;
151291bc56edSDimitry Andric if (std::error_code EC =
151391bc56edSDimitry Andric OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr))
151491bc56edSDimitry Andric return EC;
151591bc56edSDimitry Andric const export_address_table_entry *entry =
151691bc56edSDimitry Andric reinterpret_cast<const export_address_table_entry *>(IntPtr);
151791bc56edSDimitry Andric Result = entry[Index].ExportRVA;
151897bc6c73SDimitry Andric return std::error_code();
151991bc56edSDimitry Andric }
152091bc56edSDimitry Andric
152191bc56edSDimitry Andric // Returns the name of the current export symbol. If the symbol is exported only
152291bc56edSDimitry Andric // by ordinal, the empty string is set as a result.
152391bc56edSDimitry Andric std::error_code
getSymbolName(StringRef & Result) const152491bc56edSDimitry Andric ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
152591bc56edSDimitry Andric uintptr_t IntPtr = 0;
152691bc56edSDimitry Andric if (std::error_code EC =
152791bc56edSDimitry Andric OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr))
152891bc56edSDimitry Andric return EC;
152991bc56edSDimitry Andric const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
153091bc56edSDimitry Andric
153191bc56edSDimitry Andric uint32_t NumEntries = ExportTable->NumberOfNamePointers;
153291bc56edSDimitry Andric int Offset = 0;
153391bc56edSDimitry Andric for (const ulittle16_t *I = Start, *E = Start + NumEntries;
153491bc56edSDimitry Andric I < E; ++I, ++Offset) {
153591bc56edSDimitry Andric if (*I != Index)
153691bc56edSDimitry Andric continue;
153791bc56edSDimitry Andric if (std::error_code EC =
153891bc56edSDimitry Andric OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr))
153991bc56edSDimitry Andric return EC;
154091bc56edSDimitry Andric const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
154191bc56edSDimitry Andric if (std::error_code EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr))
154291bc56edSDimitry Andric return EC;
154391bc56edSDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
154497bc6c73SDimitry Andric return std::error_code();
154591bc56edSDimitry Andric }
154691bc56edSDimitry Andric Result = "";
154797bc6c73SDimitry Andric return std::error_code();
154891bc56edSDimitry Andric }
154991bc56edSDimitry Andric
isForwarder(bool & Result) const1550444ed5c5SDimitry Andric std::error_code ExportDirectoryEntryRef::isForwarder(bool &Result) const {
1551444ed5c5SDimitry Andric const data_directory *DataEntry;
1552444ed5c5SDimitry Andric if (auto EC = OwningObject->getDataDirectory(COFF::EXPORT_TABLE, DataEntry))
1553444ed5c5SDimitry Andric return EC;
1554444ed5c5SDimitry Andric uint32_t RVA;
1555444ed5c5SDimitry Andric if (auto EC = getExportRVA(RVA))
1556444ed5c5SDimitry Andric return EC;
1557444ed5c5SDimitry Andric uint32_t Begin = DataEntry->RelativeVirtualAddress;
1558444ed5c5SDimitry Andric uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;
1559444ed5c5SDimitry Andric Result = (Begin <= RVA && RVA < End);
1560444ed5c5SDimitry Andric return std::error_code();
1561444ed5c5SDimitry Andric }
1562444ed5c5SDimitry Andric
getForwardTo(StringRef & Result) const1563444ed5c5SDimitry Andric std::error_code ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
1564444ed5c5SDimitry Andric uint32_t RVA;
1565444ed5c5SDimitry Andric if (auto EC = getExportRVA(RVA))
1566444ed5c5SDimitry Andric return EC;
1567444ed5c5SDimitry Andric uintptr_t IntPtr = 0;
1568444ed5c5SDimitry Andric if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr))
1569444ed5c5SDimitry Andric return EC;
1570444ed5c5SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
1571444ed5c5SDimitry Andric return std::error_code();
1572444ed5c5SDimitry Andric }
1573444ed5c5SDimitry Andric
157439d628a0SDimitry Andric bool ImportedSymbolRef::
operator ==(const ImportedSymbolRef & Other) const157539d628a0SDimitry Andric operator==(const ImportedSymbolRef &Other) const {
157639d628a0SDimitry Andric return Entry32 == Other.Entry32 && Entry64 == Other.Entry64
157739d628a0SDimitry Andric && Index == Other.Index;
157839d628a0SDimitry Andric }
157939d628a0SDimitry Andric
moveNext()158039d628a0SDimitry Andric void ImportedSymbolRef::moveNext() {
158139d628a0SDimitry Andric ++Index;
158239d628a0SDimitry Andric }
158339d628a0SDimitry Andric
158439d628a0SDimitry Andric std::error_code
getSymbolName(StringRef & Result) const158539d628a0SDimitry Andric ImportedSymbolRef::getSymbolName(StringRef &Result) const {
158639d628a0SDimitry Andric uint32_t RVA;
158739d628a0SDimitry Andric if (Entry32) {
158839d628a0SDimitry Andric // If a symbol is imported only by ordinal, it has no name.
158939d628a0SDimitry Andric if (Entry32[Index].isOrdinal())
159097bc6c73SDimitry Andric return std::error_code();
159139d628a0SDimitry Andric RVA = Entry32[Index].getHintNameRVA();
159239d628a0SDimitry Andric } else {
159339d628a0SDimitry Andric if (Entry64[Index].isOrdinal())
159497bc6c73SDimitry Andric return std::error_code();
159539d628a0SDimitry Andric RVA = Entry64[Index].getHintNameRVA();
159639d628a0SDimitry Andric }
159739d628a0SDimitry Andric uintptr_t IntPtr = 0;
159839d628a0SDimitry Andric if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr))
159939d628a0SDimitry Andric return EC;
160039d628a0SDimitry Andric // +2 because the first two bytes is hint.
160139d628a0SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));
160297bc6c73SDimitry Andric return std::error_code();
160339d628a0SDimitry Andric }
160439d628a0SDimitry Andric
isOrdinal(bool & Result) const16053ca95b02SDimitry Andric std::error_code ImportedSymbolRef::isOrdinal(bool &Result) const {
16063ca95b02SDimitry Andric if (Entry32)
16073ca95b02SDimitry Andric Result = Entry32[Index].isOrdinal();
16083ca95b02SDimitry Andric else
16093ca95b02SDimitry Andric Result = Entry64[Index].isOrdinal();
16103ca95b02SDimitry Andric return std::error_code();
16113ca95b02SDimitry Andric }
16123ca95b02SDimitry Andric
getHintNameRVA(uint32_t & Result) const16133ca95b02SDimitry Andric std::error_code ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {
16143ca95b02SDimitry Andric if (Entry32)
16153ca95b02SDimitry Andric Result = Entry32[Index].getHintNameRVA();
16163ca95b02SDimitry Andric else
16173ca95b02SDimitry Andric Result = Entry64[Index].getHintNameRVA();
16183ca95b02SDimitry Andric return std::error_code();
16193ca95b02SDimitry Andric }
16203ca95b02SDimitry Andric
getOrdinal(uint16_t & Result) const162139d628a0SDimitry Andric std::error_code ImportedSymbolRef::getOrdinal(uint16_t &Result) const {
162239d628a0SDimitry Andric uint32_t RVA;
162339d628a0SDimitry Andric if (Entry32) {
162439d628a0SDimitry Andric if (Entry32[Index].isOrdinal()) {
162539d628a0SDimitry Andric Result = Entry32[Index].getOrdinal();
162697bc6c73SDimitry Andric return std::error_code();
162739d628a0SDimitry Andric }
162839d628a0SDimitry Andric RVA = Entry32[Index].getHintNameRVA();
162939d628a0SDimitry Andric } else {
163039d628a0SDimitry Andric if (Entry64[Index].isOrdinal()) {
163139d628a0SDimitry Andric Result = Entry64[Index].getOrdinal();
163297bc6c73SDimitry Andric return std::error_code();
163339d628a0SDimitry Andric }
163439d628a0SDimitry Andric RVA = Entry64[Index].getHintNameRVA();
163539d628a0SDimitry Andric }
163639d628a0SDimitry Andric uintptr_t IntPtr = 0;
163739d628a0SDimitry Andric if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr))
163839d628a0SDimitry Andric return EC;
163939d628a0SDimitry Andric Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);
164097bc6c73SDimitry Andric return std::error_code();
164139d628a0SDimitry Andric }
164239d628a0SDimitry Andric
16432cab237bSDimitry Andric Expected<std::unique_ptr<COFFObjectFile>>
createCOFFObjectFile(MemoryBufferRef Object)164439d628a0SDimitry Andric ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {
164591bc56edSDimitry Andric std::error_code EC;
164639d628a0SDimitry Andric std::unique_ptr<COFFObjectFile> Ret(new COFFObjectFile(Object, EC));
164791bc56edSDimitry Andric if (EC)
16482cab237bSDimitry Andric return errorCodeToError(EC);
164939d628a0SDimitry Andric return std::move(Ret);
165039d628a0SDimitry Andric }
165139d628a0SDimitry Andric
operator ==(const BaseRelocRef & Other) const165239d628a0SDimitry Andric bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {
165339d628a0SDimitry Andric return Header == Other.Header && Index == Other.Index;
165439d628a0SDimitry Andric }
165539d628a0SDimitry Andric
moveNext()165639d628a0SDimitry Andric void BaseRelocRef::moveNext() {
165739d628a0SDimitry Andric // Header->BlockSize is the size of the current block, including the
165839d628a0SDimitry Andric // size of the header itself.
165939d628a0SDimitry Andric uint32_t Size = sizeof(*Header) +
166039d628a0SDimitry Andric sizeof(coff_base_reloc_block_entry) * (Index + 1);
166139d628a0SDimitry Andric if (Size == Header->BlockSize) {
166239d628a0SDimitry Andric // .reloc contains a list of base relocation blocks. Each block
166339d628a0SDimitry Andric // consists of the header followed by entries. The header contains
166439d628a0SDimitry Andric // how many entories will follow. When we reach the end of the
166539d628a0SDimitry Andric // current block, proceed to the next block.
166639d628a0SDimitry Andric Header = reinterpret_cast<const coff_base_reloc_block_header *>(
166739d628a0SDimitry Andric reinterpret_cast<const uint8_t *>(Header) + Size);
166839d628a0SDimitry Andric Index = 0;
166939d628a0SDimitry Andric } else {
167039d628a0SDimitry Andric ++Index;
167139d628a0SDimitry Andric }
167239d628a0SDimitry Andric }
167339d628a0SDimitry Andric
getType(uint8_t & Type) const167439d628a0SDimitry Andric std::error_code BaseRelocRef::getType(uint8_t &Type) const {
167539d628a0SDimitry Andric auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
167639d628a0SDimitry Andric Type = Entry[Index].getType();
167797bc6c73SDimitry Andric return std::error_code();
167839d628a0SDimitry Andric }
167939d628a0SDimitry Andric
getRVA(uint32_t & Result) const168039d628a0SDimitry Andric std::error_code BaseRelocRef::getRVA(uint32_t &Result) const {
168139d628a0SDimitry Andric auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
168239d628a0SDimitry Andric Result = Header->PageRVA + Entry[Index].getOffset();
168397bc6c73SDimitry Andric return std::error_code();
168491bc56edSDimitry Andric }
16850f5676f4SDimitry Andric
16862cab237bSDimitry Andric #define RETURN_IF_ERROR(E) \
16872cab237bSDimitry Andric if (E) \
16882cab237bSDimitry Andric return E;
16890f5676f4SDimitry Andric
16902cab237bSDimitry Andric Expected<ArrayRef<UTF16>>
getDirStringAtOffset(uint32_t Offset)16912cab237bSDimitry Andric ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {
16920f5676f4SDimitry Andric BinaryStreamReader Reader = BinaryStreamReader(BBS);
16930f5676f4SDimitry Andric Reader.setOffset(Offset);
16940f5676f4SDimitry Andric uint16_t Length;
16950f5676f4SDimitry Andric RETURN_IF_ERROR(Reader.readInteger(Length));
16960f5676f4SDimitry Andric ArrayRef<UTF16> RawDirString;
16970f5676f4SDimitry Andric RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));
16980f5676f4SDimitry Andric return RawDirString;
16990f5676f4SDimitry Andric }
17000f5676f4SDimitry Andric
17012cab237bSDimitry Andric Expected<ArrayRef<UTF16>>
getEntryNameString(const coff_resource_dir_entry & Entry)17020f5676f4SDimitry Andric ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {
17030f5676f4SDimitry Andric return getDirStringAtOffset(Entry.Identifier.getNameOffset());
17040f5676f4SDimitry Andric }
17050f5676f4SDimitry Andric
17062cab237bSDimitry Andric Expected<const coff_resource_dir_table &>
getTableAtOffset(uint32_t Offset)17070f5676f4SDimitry Andric ResourceSectionRef::getTableAtOffset(uint32_t Offset) {
17080f5676f4SDimitry Andric const coff_resource_dir_table *Table = nullptr;
17090f5676f4SDimitry Andric
17100f5676f4SDimitry Andric BinaryStreamReader Reader(BBS);
17110f5676f4SDimitry Andric Reader.setOffset(Offset);
17120f5676f4SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Table));
17130f5676f4SDimitry Andric assert(Table != nullptr);
17140f5676f4SDimitry Andric return *Table;
17150f5676f4SDimitry Andric }
17160f5676f4SDimitry Andric
17172cab237bSDimitry Andric Expected<const coff_resource_dir_table &>
getEntrySubDir(const coff_resource_dir_entry & Entry)17180f5676f4SDimitry Andric ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {
17190f5676f4SDimitry Andric return getTableAtOffset(Entry.Offset.value());
17200f5676f4SDimitry Andric }
17210f5676f4SDimitry Andric
getBaseTable()17222cab237bSDimitry Andric Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {
17230f5676f4SDimitry Andric return getTableAtOffset(0);
17240f5676f4SDimitry Andric }
1725