1d99dafe2SDimitry Andric //===- COFFObjectFile.cpp - COFF object file implementation ---------------===//
2cf099d11SDimitry Andric //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6cf099d11SDimitry Andric //
7cf099d11SDimitry Andric //===----------------------------------------------------------------------===//
8cf099d11SDimitry Andric //
9cf099d11SDimitry Andric // This file declares the COFFObjectFile class.
10cf099d11SDimitry Andric //
11cf099d11SDimitry Andric //===----------------------------------------------------------------------===//
12cf099d11SDimitry Andric
1363faed5bSDimitry Andric #include "llvm/ADT/ArrayRef.h"
14d99dafe2SDimitry Andric #include "llvm/ADT/StringRef.h"
15cfca06d7SDimitry Andric #include "llvm/ADT/StringSwitch.h"
161a82d4c0SDimitry Andric #include "llvm/ADT/iterator_range.h"
17d99dafe2SDimitry Andric #include "llvm/Object/Binary.h"
18d99dafe2SDimitry Andric #include "llvm/Object/COFF.h"
19d99dafe2SDimitry Andric #include "llvm/Object/Error.h"
20d99dafe2SDimitry Andric #include "llvm/Object/ObjectFile.h"
21ac9a064cSDimitry Andric #include "llvm/Object/WindowsMachineFlag.h"
22c46e6a59SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
23d99dafe2SDimitry Andric #include "llvm/Support/Endian.h"
24d99dafe2SDimitry Andric #include "llvm/Support/Error.h"
25d99dafe2SDimitry Andric #include "llvm/Support/ErrorHandling.h"
26d99dafe2SDimitry Andric #include "llvm/Support/MathExtras.h"
27145449b1SDimitry Andric #include "llvm/Support/MemoryBufferRef.h"
28d99dafe2SDimitry Andric #include <algorithm>
29d99dafe2SDimitry Andric #include <cassert>
30b60736ecSDimitry Andric #include <cinttypes>
31d99dafe2SDimitry Andric #include <cstddef>
32d99dafe2SDimitry Andric #include <cstring>
335ca98fd9SDimitry Andric #include <limits>
34d99dafe2SDimitry Andric #include <memory>
35d99dafe2SDimitry Andric #include <system_error>
36cf099d11SDimitry Andric
37cf099d11SDimitry Andric using namespace llvm;
38cf099d11SDimitry Andric using namespace object;
39cf099d11SDimitry Andric
40cf099d11SDimitry Andric using support::ulittle16_t;
41cf099d11SDimitry Andric using support::ulittle32_t;
4267c32a98SDimitry Andric using support::ulittle64_t;
43cf099d11SDimitry Andric using support::little16_t;
44cf099d11SDimitry Andric
45411bd29eSDimitry Andric // Returns false if size is greater than the buffer size. And sets ec.
checkSize(MemoryBufferRef M,std::error_code & EC,uint64_t Size)4667c32a98SDimitry Andric static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) {
475ca98fd9SDimitry Andric if (M.getBufferSize() < Size) {
485ca98fd9SDimitry Andric EC = object_error::unexpected_eof;
49411bd29eSDimitry Andric return false;
50411bd29eSDimitry Andric }
51411bd29eSDimitry Andric return true;
52cf099d11SDimitry Andric }
53cf099d11SDimitry Andric
54f8af5cf6SDimitry Andric // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
55f8af5cf6SDimitry Andric // Returns unexpected_eof if error.
56f8af5cf6SDimitry Andric template <typename T>
getObject(const T * & Obj,MemoryBufferRef M,const void * Ptr,const uint64_t Size=sizeof (T))57cfca06d7SDimitry Andric static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr,
5867c32a98SDimitry Andric const uint64_t Size = sizeof(T)) {
59b60736ecSDimitry Andric uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);
60cfca06d7SDimitry Andric if (Error E = Binary::checkOffset(M, Addr, Size))
61cfca06d7SDimitry Andric return E;
62f8af5cf6SDimitry Andric Obj = reinterpret_cast<const T *>(Addr);
63cfca06d7SDimitry Andric return Error::success();
64411bd29eSDimitry Andric }
655ca98fd9SDimitry Andric
665ca98fd9SDimitry Andric // Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without
675ca98fd9SDimitry Andric // prefixed slashes.
decodeBase64StringEntry(StringRef Str,uint32_t & Result)685ca98fd9SDimitry Andric static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {
695ca98fd9SDimitry Andric assert(Str.size() <= 6 && "String too long, possible overflow.");
705ca98fd9SDimitry Andric if (Str.size() > 6)
715ca98fd9SDimitry Andric return true;
725ca98fd9SDimitry Andric
735ca98fd9SDimitry Andric uint64_t Value = 0;
745ca98fd9SDimitry Andric while (!Str.empty()) {
755ca98fd9SDimitry Andric unsigned CharVal;
765ca98fd9SDimitry Andric if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..25
775ca98fd9SDimitry Andric CharVal = Str[0] - 'A';
785ca98fd9SDimitry Andric else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..51
795ca98fd9SDimitry Andric CharVal = Str[0] - 'a' + 26;
805ca98fd9SDimitry Andric else if (Str[0] >= '0' && Str[0] <= '9') // 52..61
815ca98fd9SDimitry Andric CharVal = Str[0] - '0' + 52;
825ca98fd9SDimitry Andric else if (Str[0] == '+') // 62
835ca98fd9SDimitry Andric CharVal = 62;
845ca98fd9SDimitry Andric else if (Str[0] == '/') // 63
855ca98fd9SDimitry Andric CharVal = 63;
865ca98fd9SDimitry Andric else
875ca98fd9SDimitry Andric return true;
885ca98fd9SDimitry Andric
895ca98fd9SDimitry Andric Value = (Value * 64) + CharVal;
905ca98fd9SDimitry Andric Str = Str.substr(1);
91cf099d11SDimitry Andric }
92cf099d11SDimitry Andric
935ca98fd9SDimitry Andric if (Value > std::numeric_limits<uint32_t>::max())
945ca98fd9SDimitry Andric return true;
955ca98fd9SDimitry Andric
965ca98fd9SDimitry Andric Result = static_cast<uint32_t>(Value);
975ca98fd9SDimitry Andric return false;
985ca98fd9SDimitry Andric }
995ca98fd9SDimitry Andric
10067c32a98SDimitry Andric template <typename coff_symbol_type>
toSymb(DataRefImpl Ref) const10167c32a98SDimitry Andric const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {
10267c32a98SDimitry Andric const coff_symbol_type *Addr =
10367c32a98SDimitry Andric reinterpret_cast<const coff_symbol_type *>(Ref.p);
104cf099d11SDimitry Andric
105b60736ecSDimitry Andric assert(!checkOffset(Data, reinterpret_cast<uintptr_t>(Addr), sizeof(*Addr)));
106411bd29eSDimitry Andric #ifndef NDEBUG
107411bd29eSDimitry Andric // Verify that the symbol points to a valid entry in the symbol table.
108b60736ecSDimitry Andric uintptr_t Offset =
109b60736ecSDimitry Andric reinterpret_cast<uintptr_t>(Addr) - reinterpret_cast<uintptr_t>(base());
110411bd29eSDimitry Andric
11167c32a98SDimitry Andric assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&
11267c32a98SDimitry Andric "Symbol did not point to the beginning of a symbol");
113411bd29eSDimitry Andric #endif
114411bd29eSDimitry Andric
1155ca98fd9SDimitry Andric return Addr;
116cf099d11SDimitry Andric }
117cf099d11SDimitry Andric
toSec(DataRefImpl Ref) const1185ca98fd9SDimitry Andric const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {
1195ca98fd9SDimitry Andric const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p);
120cf099d11SDimitry Andric
121411bd29eSDimitry Andric #ifndef NDEBUG
122411bd29eSDimitry Andric // Verify that the section points to a valid entry in the section table.
12367c32a98SDimitry Andric if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))
124411bd29eSDimitry Andric report_fatal_error("Section was outside of section table.");
125cf099d11SDimitry Andric
126b60736ecSDimitry Andric uintptr_t Offset = reinterpret_cast<uintptr_t>(Addr) -
127b60736ecSDimitry Andric reinterpret_cast<uintptr_t>(SectionTable);
1285ca98fd9SDimitry Andric assert(Offset % sizeof(coff_section) == 0 &&
129411bd29eSDimitry Andric "Section did not point to the beginning of a section");
130411bd29eSDimitry Andric #endif
131cf099d11SDimitry Andric
1325ca98fd9SDimitry Andric return Addr;
133411bd29eSDimitry Andric }
134cf099d11SDimitry Andric
moveSymbolNext(DataRefImpl & Ref) const1355ca98fd9SDimitry Andric void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {
13667c32a98SDimitry Andric auto End = reinterpret_cast<uintptr_t>(StringTable);
13767c32a98SDimitry Andric if (SymbolTable16) {
13867c32a98SDimitry Andric const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);
1395ca98fd9SDimitry Andric Symb += 1 + Symb->NumberOfAuxSymbols;
14067c32a98SDimitry Andric Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
14167c32a98SDimitry Andric } else if (SymbolTable32) {
14267c32a98SDimitry Andric const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);
14367c32a98SDimitry Andric Symb += 1 + Symb->NumberOfAuxSymbols;
14467c32a98SDimitry Andric Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
14567c32a98SDimitry Andric } else {
14667c32a98SDimitry Andric llvm_unreachable("no symbol table pointer!");
14767c32a98SDimitry Andric }
148cf099d11SDimitry Andric }
149cf099d11SDimitry Andric
getSymbolName(DataRefImpl Ref) const15001095a5dSDimitry Andric Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {
151cfca06d7SDimitry Andric return getSymbolName(getCOFFSymbol(Ref));
1521a82d4c0SDimitry Andric }
1531a82d4c0SDimitry Andric
getSymbolValueImpl(DataRefImpl Ref) const154ee8648bdSDimitry Andric uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {
155ee8648bdSDimitry Andric return getCOFFSymbol(Ref).getValue();
156cf099d11SDimitry Andric }
157cf099d11SDimitry Andric
getSymbolAlignment(DataRefImpl Ref) const158b915e9e0SDimitry Andric uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const {
159b915e9e0SDimitry Andric // MSVC/link.exe seems to align symbols to the next-power-of-2
160b915e9e0SDimitry Andric // up to 32 bytes.
161b915e9e0SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
162b915e9e0SDimitry Andric return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));
163b915e9e0SDimitry Andric }
164b915e9e0SDimitry Andric
getSymbolAddress(DataRefImpl Ref) const16501095a5dSDimitry Andric Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {
166cfca06d7SDimitry Andric uint64_t Result = cantFail(getSymbolValue(Ref));
16767c32a98SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
16867c32a98SDimitry Andric int32_t SectionNumber = Symb.getSectionNumber();
1691a82d4c0SDimitry Andric
1701a82d4c0SDimitry Andric if (Symb.isAnyUndefined() || Symb.isCommon() ||
1711a82d4c0SDimitry Andric COFF::isReservedSectionNumber(SectionNumber))
172ee8648bdSDimitry Andric return Result;
1731a82d4c0SDimitry Andric
174cfca06d7SDimitry Andric Expected<const coff_section *> Section = getSection(SectionNumber);
175cfca06d7SDimitry Andric if (!Section)
176cfca06d7SDimitry Andric return Section.takeError();
177cfca06d7SDimitry Andric Result += (*Section)->VirtualAddress;
178dd58ef01SDimitry Andric
179dd58ef01SDimitry Andric // The section VirtualAddress does not include ImageBase, and we want to
180dd58ef01SDimitry Andric // return virtual addresses.
181dd58ef01SDimitry Andric Result += getImageBase();
182dd58ef01SDimitry Andric
183ee8648bdSDimitry Andric return Result;
18467c32a98SDimitry Andric }
18567c32a98SDimitry Andric
getSymbolType(DataRefImpl Ref) const18601095a5dSDimitry Andric Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {
18767c32a98SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
18867c32a98SDimitry Andric int32_t SectionNumber = Symb.getSectionNumber();
18967c32a98SDimitry Andric
190dd58ef01SDimitry Andric if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
191dd58ef01SDimitry Andric return SymbolRef::ST_Function;
1921a82d4c0SDimitry Andric if (Symb.isAnyUndefined())
1931a82d4c0SDimitry Andric return SymbolRef::ST_Unknown;
1941a82d4c0SDimitry Andric if (Symb.isCommon())
1951a82d4c0SDimitry Andric return SymbolRef::ST_Data;
1961a82d4c0SDimitry Andric if (Symb.isFileRecord())
1971a82d4c0SDimitry Andric return SymbolRef::ST_File;
1981a82d4c0SDimitry Andric
1995a5ac124SDimitry Andric // TODO: perhaps we need a new symbol type ST_Section.
2001a82d4c0SDimitry Andric if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())
2011a82d4c0SDimitry Andric return SymbolRef::ST_Debug;
2021a82d4c0SDimitry Andric
2031a82d4c0SDimitry Andric if (!COFF::isReservedSectionNumber(SectionNumber))
2041a82d4c0SDimitry Andric return SymbolRef::ST_Data;
2051a82d4c0SDimitry Andric
2061a82d4c0SDimitry Andric return SymbolRef::ST_Other;
20730815c53SDimitry Andric }
20830815c53SDimitry Andric
getSymbolFlags(DataRefImpl Ref) const209cfca06d7SDimitry Andric Expected<uint32_t> COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {
21067c32a98SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
2115ca98fd9SDimitry Andric uint32_t Result = SymbolRef::SF_None;
21263faed5bSDimitry Andric
21367c32a98SDimitry Andric if (Symb.isExternal() || Symb.isWeakExternal())
21463faed5bSDimitry Andric Result |= SymbolRef::SF_Global;
21563faed5bSDimitry Andric
216eb11fae6SDimitry Andric if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {
21763faed5bSDimitry Andric Result |= SymbolRef::SF_Weak;
218eb11fae6SDimitry Andric if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)
219eb11fae6SDimitry Andric Result |= SymbolRef::SF_Undefined;
22093c91e39SDimitry Andric }
22163faed5bSDimitry Andric
22267c32a98SDimitry Andric if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)
22363faed5bSDimitry Andric Result |= SymbolRef::SF_Absolute;
22463faed5bSDimitry Andric
22567c32a98SDimitry Andric if (Symb.isFileRecord())
22667c32a98SDimitry Andric Result |= SymbolRef::SF_FormatSpecific;
22767c32a98SDimitry Andric
22867c32a98SDimitry Andric if (Symb.isSectionDefinition())
22967c32a98SDimitry Andric Result |= SymbolRef::SF_FormatSpecific;
23067c32a98SDimitry Andric
23167c32a98SDimitry Andric if (Symb.isCommon())
23267c32a98SDimitry Andric Result |= SymbolRef::SF_Common;
23367c32a98SDimitry Andric
234eb11fae6SDimitry Andric if (Symb.isUndefined())
23567c32a98SDimitry Andric Result |= SymbolRef::SF_Undefined;
23667c32a98SDimitry Andric
2375ca98fd9SDimitry Andric return Result;
23830815c53SDimitry Andric }
23930815c53SDimitry Andric
getCommonSymbolSizeImpl(DataRefImpl Ref) const2401a82d4c0SDimitry Andric uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {
24167c32a98SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
24285d8b2bbSDimitry Andric return Symb.getValue();
24367c32a98SDimitry Andric }
244cf099d11SDimitry Andric
24501095a5dSDimitry Andric Expected<section_iterator>
getSymbolSection(DataRefImpl Ref) const246dd58ef01SDimitry Andric COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {
24767c32a98SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Ref);
248dd58ef01SDimitry Andric if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))
249dd58ef01SDimitry Andric return section_end();
250cfca06d7SDimitry Andric Expected<const coff_section *> Sec = getSection(Symb.getSectionNumber());
251cfca06d7SDimitry Andric if (!Sec)
252cfca06d7SDimitry Andric return Sec.takeError();
253dd58ef01SDimitry Andric DataRefImpl Ret;
254cfca06d7SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(*Sec);
255dd58ef01SDimitry Andric return section_iterator(SectionRef(Ret, this));
256cf099d11SDimitry Andric }
257cf099d11SDimitry Andric
getSymbolSectionID(SymbolRef Sym) const2581a82d4c0SDimitry Andric unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {
2591a82d4c0SDimitry Andric COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());
2601a82d4c0SDimitry Andric return Symb.getSectionNumber();
2611a82d4c0SDimitry Andric }
2621a82d4c0SDimitry Andric
moveSectionNext(DataRefImpl & Ref) const2635ca98fd9SDimitry Andric void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {
2645ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
2655ca98fd9SDimitry Andric Sec += 1;
2665ca98fd9SDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(Sec);
267522600a2SDimitry Andric }
268522600a2SDimitry Andric
getSectionName(DataRefImpl Ref) const269e6d15924SDimitry Andric Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const {
2705ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
271e6d15924SDimitry Andric return getSectionName(Sec);
272cf099d11SDimitry Andric }
273cf099d11SDimitry Andric
getSectionAddress(DataRefImpl Ref) const27467c32a98SDimitry Andric uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {
2755ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
276dd58ef01SDimitry Andric uint64_t Result = Sec->VirtualAddress;
277dd58ef01SDimitry Andric
278dd58ef01SDimitry Andric // The section VirtualAddress does not include ImageBase, and we want to
279dd58ef01SDimitry Andric // return virtual addresses.
280dd58ef01SDimitry Andric Result += getImageBase();
281dd58ef01SDimitry Andric return Result;
282cf099d11SDimitry Andric }
283cf099d11SDimitry Andric
getSectionIndex(DataRefImpl Sec) const284ab44ce3dSDimitry Andric uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
285ab44ce3dSDimitry Andric return toSec(Sec) - SectionTable;
286ab44ce3dSDimitry Andric }
287ab44ce3dSDimitry Andric
getSectionSize(DataRefImpl Ref) const28867c32a98SDimitry Andric uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {
28967c32a98SDimitry Andric return getSectionSize(toSec(Ref));
290cf099d11SDimitry Andric }
291cf099d11SDimitry Andric
292e6d15924SDimitry Andric Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Ref) const293e6d15924SDimitry Andric COFFObjectFile::getSectionContents(DataRefImpl Ref) const {
2945ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
29563faed5bSDimitry Andric ArrayRef<uint8_t> Res;
296e6d15924SDimitry Andric if (Error E = getSectionContents(Sec, Res))
297ac9a064cSDimitry Andric return E;
298e6d15924SDimitry Andric return Res;
299cf099d11SDimitry Andric }
300cf099d11SDimitry Andric
getSectionAlignment(DataRefImpl Ref) const30167c32a98SDimitry Andric uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {
3025ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
30301095a5dSDimitry Andric return Sec->getAlignment();
30401095a5dSDimitry Andric }
30501095a5dSDimitry Andric
isSectionCompressed(DataRefImpl Sec) const30601095a5dSDimitry Andric bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
30701095a5dSDimitry Andric return false;
30830815c53SDimitry Andric }
30930815c53SDimitry Andric
isSectionText(DataRefImpl Ref) const31067c32a98SDimitry Andric bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {
3115ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
31267c32a98SDimitry Andric return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;
313cf099d11SDimitry Andric }
314cf099d11SDimitry Andric
isSectionData(DataRefImpl Ref) const31567c32a98SDimitry Andric bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {
3165ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
31767c32a98SDimitry Andric return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
31830815c53SDimitry Andric }
31930815c53SDimitry Andric
isSectionBSS(DataRefImpl Ref) const32067c32a98SDimitry Andric bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {
3215ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
3225a5ac124SDimitry Andric const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
3235a5ac124SDimitry Andric COFF::IMAGE_SCN_MEM_READ |
3245a5ac124SDimitry Andric COFF::IMAGE_SCN_MEM_WRITE;
3255a5ac124SDimitry Andric return (Sec->Characteristics & BssFlags) == BssFlags;
32630815c53SDimitry Andric }
32730815c53SDimitry Andric
328cfca06d7SDimitry Andric // The .debug sections are the only debug sections for COFF
329cfca06d7SDimitry Andric // (\see MCObjectFileInfo.cpp).
isDebugSection(DataRefImpl Ref) const330344a3780SDimitry Andric bool COFFObjectFile::isDebugSection(DataRefImpl Ref) const {
331344a3780SDimitry Andric Expected<StringRef> SectionNameOrErr = getSectionName(Ref);
332344a3780SDimitry Andric if (!SectionNameOrErr) {
333344a3780SDimitry Andric // TODO: Report the error message properly.
334344a3780SDimitry Andric consumeError(SectionNameOrErr.takeError());
335344a3780SDimitry Andric return false;
336344a3780SDimitry Andric }
337344a3780SDimitry Andric StringRef SectionName = SectionNameOrErr.get();
338312c0ed1SDimitry Andric return SectionName.starts_with(".debug");
339cfca06d7SDimitry Andric }
340cfca06d7SDimitry Andric
getSectionID(SectionRef Sec) const3411a82d4c0SDimitry Andric unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {
3421a82d4c0SDimitry Andric uintptr_t Offset =
343b60736ecSDimitry Andric Sec.getRawDataRefImpl().p - reinterpret_cast<uintptr_t>(SectionTable);
3441a82d4c0SDimitry Andric assert((Offset % sizeof(coff_section)) == 0);
3451a82d4c0SDimitry Andric return (Offset / sizeof(coff_section)) + 1;
3461a82d4c0SDimitry Andric }
3471a82d4c0SDimitry Andric
isSectionVirtual(DataRefImpl Ref) const34867c32a98SDimitry Andric bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {
3495ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
3505a5ac124SDimitry Andric // In COFF, a virtual section won't have any in-file
3515a5ac124SDimitry Andric // content, so the file pointer to the content will be zero.
3525a5ac124SDimitry Andric return Sec->PointerToRawData == 0;
35363faed5bSDimitry Andric }
35463faed5bSDimitry Andric
getNumberOfRelocations(const coff_section * Sec,MemoryBufferRef M,const uint8_t * base)3555ca98fd9SDimitry Andric static uint32_t getNumberOfRelocations(const coff_section *Sec,
35667c32a98SDimitry Andric MemoryBufferRef M, const uint8_t *base) {
3575ca98fd9SDimitry Andric // The field for the number of relocations in COFF section table is only
3585ca98fd9SDimitry Andric // 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to
3595ca98fd9SDimitry Andric // NumberOfRelocations field, and the actual relocation count is stored in the
3605ca98fd9SDimitry Andric // VirtualAddress field in the first relocation entry.
3615ca98fd9SDimitry Andric if (Sec->hasExtendedRelocations()) {
36267c32a98SDimitry Andric const coff_relocation *FirstReloc;
363cfca06d7SDimitry Andric if (Error E = getObject(FirstReloc, M,
364cfca06d7SDimitry Andric reinterpret_cast<const coff_relocation *>(
365cfca06d7SDimitry Andric base + Sec->PointerToRelocations))) {
366cfca06d7SDimitry Andric consumeError(std::move(E));
36767c32a98SDimitry Andric return 0;
368cfca06d7SDimitry Andric }
36967c32a98SDimitry Andric // -1 to exclude this first relocation entry.
37067c32a98SDimitry Andric return FirstReloc->VirtualAddress - 1;
3715ca98fd9SDimitry Andric }
3725ca98fd9SDimitry Andric return Sec->NumberOfRelocations;
3735ca98fd9SDimitry Andric }
37430815c53SDimitry Andric
37567c32a98SDimitry Andric static const coff_relocation *
getFirstReloc(const coff_section * Sec,MemoryBufferRef M,const uint8_t * Base)37667c32a98SDimitry Andric getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {
37767c32a98SDimitry Andric uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);
37867c32a98SDimitry Andric if (!NumRelocs)
37967c32a98SDimitry Andric return nullptr;
38067c32a98SDimitry Andric auto begin = reinterpret_cast<const coff_relocation *>(
38167c32a98SDimitry Andric Base + Sec->PointerToRelocations);
38267c32a98SDimitry Andric if (Sec->hasExtendedRelocations()) {
38367c32a98SDimitry Andric // Skip the first relocation entry repurposed to store the number of
38467c32a98SDimitry Andric // relocations.
38567c32a98SDimitry Andric begin++;
38667c32a98SDimitry Andric }
387b60736ecSDimitry Andric if (auto E = Binary::checkOffset(M, reinterpret_cast<uintptr_t>(begin),
388cfca06d7SDimitry Andric sizeof(coff_relocation) * NumRelocs)) {
389cfca06d7SDimitry Andric consumeError(std::move(E));
39067c32a98SDimitry Andric return nullptr;
391cfca06d7SDimitry Andric }
39267c32a98SDimitry Andric return begin;
39367c32a98SDimitry Andric }
39467c32a98SDimitry Andric
section_rel_begin(DataRefImpl Ref) const39567c32a98SDimitry Andric relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {
39667c32a98SDimitry Andric const coff_section *Sec = toSec(Ref);
39767c32a98SDimitry Andric const coff_relocation *begin = getFirstReloc(Sec, Data, base());
398ee8648bdSDimitry Andric if (begin && Sec->VirtualAddress != 0)
399ee8648bdSDimitry Andric report_fatal_error("Sections with relocations should have an address of 0");
40067c32a98SDimitry Andric DataRefImpl Ret;
40167c32a98SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(begin);
40267c32a98SDimitry Andric return relocation_iterator(RelocationRef(Ret, this));
40367c32a98SDimitry Andric }
40467c32a98SDimitry Andric
section_rel_end(DataRefImpl Ref) const4055ca98fd9SDimitry Andric relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {
4065ca98fd9SDimitry Andric const coff_section *Sec = toSec(Ref);
40767c32a98SDimitry Andric const coff_relocation *I = getFirstReloc(Sec, Data, base());
40867c32a98SDimitry Andric if (I)
40967c32a98SDimitry Andric I += getNumberOfRelocations(Sec, Data, base());
4105ca98fd9SDimitry Andric DataRefImpl Ret;
41167c32a98SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(I);
4125ca98fd9SDimitry Andric return relocation_iterator(RelocationRef(Ret, this));
41330815c53SDimitry Andric }
41430815c53SDimitry Andric
415f8af5cf6SDimitry Andric // Initialize the pointer to the symbol table.
initSymbolTablePtr()416cfca06d7SDimitry Andric Error COFFObjectFile::initSymbolTablePtr() {
41767c32a98SDimitry Andric if (COFFHeader)
418cfca06d7SDimitry Andric if (Error E = getObject(
41967c32a98SDimitry Andric SymbolTable16, Data, base() + getPointerToSymbolTable(),
42067c32a98SDimitry Andric (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
421cfca06d7SDimitry Andric return E;
42267c32a98SDimitry Andric
42367c32a98SDimitry Andric if (COFFBigObjHeader)
424cfca06d7SDimitry Andric if (Error E = getObject(
42567c32a98SDimitry Andric SymbolTable32, Data, base() + getPointerToSymbolTable(),
42667c32a98SDimitry Andric (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
427cfca06d7SDimitry Andric return E;
428f8af5cf6SDimitry Andric
429f8af5cf6SDimitry Andric // Find string table. The first four byte of the string table contains the
430f8af5cf6SDimitry Andric // total size of the string table, including the size field itself. If the
431f8af5cf6SDimitry Andric // string table is empty, the value of the first four byte would be 4.
43267c32a98SDimitry Andric uint32_t StringTableOffset = getPointerToSymbolTable() +
43367c32a98SDimitry Andric getNumberOfSymbols() * getSymbolTableEntrySize();
43467c32a98SDimitry Andric const uint8_t *StringTableAddr = base() + StringTableOffset;
435f8af5cf6SDimitry Andric const ulittle32_t *StringTableSizePtr;
436cfca06d7SDimitry Andric if (Error E = getObject(StringTableSizePtr, Data, StringTableAddr))
437cfca06d7SDimitry Andric return E;
438f8af5cf6SDimitry Andric StringTableSize = *StringTableSizePtr;
439cfca06d7SDimitry Andric if (Error E = getObject(StringTable, Data, StringTableAddr, StringTableSize))
440cfca06d7SDimitry Andric return E;
4415ca98fd9SDimitry Andric
4425ca98fd9SDimitry Andric // Treat table sizes < 4 as empty because contrary to the PECOFF spec, some
4435ca98fd9SDimitry Andric // tools like cvtres write a size of 0 for an empty table instead of 4.
4445ca98fd9SDimitry Andric if (StringTableSize < 4)
4455ca98fd9SDimitry Andric StringTableSize = 4;
446f8af5cf6SDimitry Andric
447f8af5cf6SDimitry Andric // Check that the string table is null terminated if has any in it.
4485ca98fd9SDimitry Andric if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)
449145449b1SDimitry Andric return createStringError(object_error::parse_failed,
450145449b1SDimitry Andric "string table missing null terminator");
451cfca06d7SDimitry Andric return Error::success();
452f8af5cf6SDimitry Andric }
453f8af5cf6SDimitry Andric
getImageBase() const454dd58ef01SDimitry Andric uint64_t COFFObjectFile::getImageBase() const {
455dd58ef01SDimitry Andric if (PE32Header)
456dd58ef01SDimitry Andric return PE32Header->ImageBase;
457dd58ef01SDimitry Andric else if (PE32PlusHeader)
458dd58ef01SDimitry Andric return PE32PlusHeader->ImageBase;
459dd58ef01SDimitry Andric // This actually comes up in practice.
460dd58ef01SDimitry Andric return 0;
461dd58ef01SDimitry Andric }
462dd58ef01SDimitry Andric
4635ca98fd9SDimitry Andric // Returns the file offset for the given VA.
getVaPtr(uint64_t Addr,uintptr_t & Res) const464cfca06d7SDimitry Andric Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
465dd58ef01SDimitry Andric uint64_t ImageBase = getImageBase();
4665ca98fd9SDimitry Andric uint64_t Rva = Addr - ImageBase;
4675ca98fd9SDimitry Andric assert(Rva <= UINT32_MAX);
4685ca98fd9SDimitry Andric return getRvaPtr((uint32_t)Rva, Res);
4695ca98fd9SDimitry Andric }
4705ca98fd9SDimitry Andric
471f8af5cf6SDimitry Andric // Returns the file offset for the given RVA.
getRvaPtr(uint32_t Addr,uintptr_t & Res,const char * ErrorContext) const472145449b1SDimitry Andric Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res,
473145449b1SDimitry Andric const char *ErrorContext) const {
4745ca98fd9SDimitry Andric for (const SectionRef &S : sections()) {
4755ca98fd9SDimitry Andric const coff_section *Section = getCOFFSection(S);
476f8af5cf6SDimitry Andric uint32_t SectionStart = Section->VirtualAddress;
477f8af5cf6SDimitry Andric uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
4785ca98fd9SDimitry Andric if (SectionStart <= Addr && Addr < SectionEnd) {
479145449b1SDimitry Andric // A table/directory entry can be pointing to somewhere in a stripped
480145449b1SDimitry Andric // section, in an object that went through `objcopy --only-keep-debug`.
481145449b1SDimitry Andric // In this case we don't want to cause the parsing of the object file to
482145449b1SDimitry Andric // fail, otherwise it will be impossible to use this object as debug info
483145449b1SDimitry Andric // in LLDB. Return SectionStrippedError here so that
484145449b1SDimitry Andric // COFFObjectFile::initialize can ignore the error.
485145449b1SDimitry Andric // Somewhat common binaries may have RVAs pointing outside of the
486145449b1SDimitry Andric // provided raw data. Instead of rejecting the binaries, just
487145449b1SDimitry Andric // treat the section as stripped for these purposes.
488145449b1SDimitry Andric if (Section->SizeOfRawData < Section->VirtualSize &&
489145449b1SDimitry Andric Addr >= SectionStart + Section->SizeOfRawData) {
490145449b1SDimitry Andric return make_error<SectionStrippedError>();
491145449b1SDimitry Andric }
4925ca98fd9SDimitry Andric uint32_t Offset = Addr - SectionStart;
493b60736ecSDimitry Andric Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +
494b60736ecSDimitry Andric Offset;
495cfca06d7SDimitry Andric return Error::success();
496f8af5cf6SDimitry Andric }
497f8af5cf6SDimitry Andric }
498145449b1SDimitry Andric if (ErrorContext)
499145449b1SDimitry Andric return createStringError(object_error::parse_failed,
500145449b1SDimitry Andric "RVA 0x%" PRIx32 " for %s not found", Addr,
501145449b1SDimitry Andric ErrorContext);
502145449b1SDimitry Andric return createStringError(object_error::parse_failed,
503145449b1SDimitry Andric "RVA 0x%" PRIx32 " not found", Addr);
504f8af5cf6SDimitry Andric }
505f8af5cf6SDimitry Andric
getRvaAndSizeAsBytes(uint32_t RVA,uint32_t Size,ArrayRef<uint8_t> & Contents,const char * ErrorContext) const506cfca06d7SDimitry Andric Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
507145449b1SDimitry Andric ArrayRef<uint8_t> &Contents,
508145449b1SDimitry Andric const char *ErrorContext) const {
50901095a5dSDimitry Andric for (const SectionRef &S : sections()) {
51001095a5dSDimitry Andric const coff_section *Section = getCOFFSection(S);
51101095a5dSDimitry Andric uint32_t SectionStart = Section->VirtualAddress;
51201095a5dSDimitry Andric // Check if this RVA is within the section bounds. Be careful about integer
51301095a5dSDimitry Andric // overflow.
51401095a5dSDimitry Andric uint32_t OffsetIntoSection = RVA - SectionStart;
51501095a5dSDimitry Andric if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
51601095a5dSDimitry Andric Size <= Section->VirtualSize - OffsetIntoSection) {
517b60736ecSDimitry Andric uintptr_t Begin = reinterpret_cast<uintptr_t>(base()) +
518b60736ecSDimitry Andric Section->PointerToRawData + OffsetIntoSection;
51901095a5dSDimitry Andric Contents =
52001095a5dSDimitry Andric ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);
521cfca06d7SDimitry Andric return Error::success();
52201095a5dSDimitry Andric }
52301095a5dSDimitry Andric }
524145449b1SDimitry Andric if (ErrorContext)
525145449b1SDimitry Andric return createStringError(object_error::parse_failed,
526145449b1SDimitry Andric "RVA 0x%" PRIx32 " for %s not found", RVA,
527145449b1SDimitry Andric ErrorContext);
528145449b1SDimitry Andric return createStringError(object_error::parse_failed,
529145449b1SDimitry Andric "RVA 0x%" PRIx32 " not found", RVA);
53001095a5dSDimitry Andric }
53101095a5dSDimitry Andric
532f8af5cf6SDimitry Andric // Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
533f8af5cf6SDimitry Andric // table entry.
getHintName(uint32_t Rva,uint16_t & Hint,StringRef & Name) const534cfca06d7SDimitry Andric Error COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
5355ca98fd9SDimitry Andric StringRef &Name) const {
536f8af5cf6SDimitry Andric uintptr_t IntPtr = 0;
537cfca06d7SDimitry Andric if (Error E = getRvaPtr(Rva, IntPtr))
538cfca06d7SDimitry Andric return E;
539f8af5cf6SDimitry Andric const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);
540f8af5cf6SDimitry Andric Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);
541f8af5cf6SDimitry Andric Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));
542cfca06d7SDimitry Andric return Error::success();
543f8af5cf6SDimitry Andric }
544f8af5cf6SDimitry Andric
getDebugPDBInfo(const debug_directory * DebugDir,const codeview::DebugInfo * & PDBInfo,StringRef & PDBFileName) const545cfca06d7SDimitry Andric Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
546b915e9e0SDimitry Andric const codeview::DebugInfo *&PDBInfo,
54701095a5dSDimitry Andric StringRef &PDBFileName) const {
54801095a5dSDimitry Andric ArrayRef<uint8_t> InfoBytes;
549145449b1SDimitry Andric if (Error E =
550145449b1SDimitry Andric getRvaAndSizeAsBytes(DebugDir->AddressOfRawData, DebugDir->SizeOfData,
551145449b1SDimitry Andric InfoBytes, "PDB info"))
552cfca06d7SDimitry Andric return E;
553b915e9e0SDimitry Andric if (InfoBytes.size() < sizeof(*PDBInfo) + 1)
554145449b1SDimitry Andric return createStringError(object_error::parse_failed, "PDB info too small");
555b915e9e0SDimitry Andric PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());
556b915e9e0SDimitry Andric InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));
55701095a5dSDimitry Andric PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
55801095a5dSDimitry Andric InfoBytes.size());
55901095a5dSDimitry Andric // Truncate the name at the first null byte. Ignore any padding.
56001095a5dSDimitry Andric PDBFileName = PDBFileName.split('\0').first;
561cfca06d7SDimitry Andric return Error::success();
56201095a5dSDimitry Andric }
56301095a5dSDimitry Andric
getDebugPDBInfo(const codeview::DebugInfo * & PDBInfo,StringRef & PDBFileName) const564cfca06d7SDimitry Andric Error COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,
56501095a5dSDimitry Andric StringRef &PDBFileName) const {
56601095a5dSDimitry Andric for (const debug_directory &D : debug_directories())
56701095a5dSDimitry Andric if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
56801095a5dSDimitry Andric return getDebugPDBInfo(&D, PDBInfo, PDBFileName);
56901095a5dSDimitry Andric // If we get here, there is no PDB info to return.
57001095a5dSDimitry Andric PDBInfo = nullptr;
57101095a5dSDimitry Andric PDBFileName = StringRef();
572cfca06d7SDimitry Andric return Error::success();
57301095a5dSDimitry Andric }
57401095a5dSDimitry Andric
575f8af5cf6SDimitry Andric // Find the import table.
initImportTablePtr()576cfca06d7SDimitry Andric Error COFFObjectFile::initImportTablePtr() {
577f8af5cf6SDimitry Andric // First, we get the RVA of the import table. If the file lacks a pointer to
578f8af5cf6SDimitry Andric // the import table, do nothing.
579cfca06d7SDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::IMPORT_TABLE);
580cfca06d7SDimitry Andric if (!DataEntry)
581cfca06d7SDimitry Andric return Error::success();
582f8af5cf6SDimitry Andric
583f8af5cf6SDimitry Andric // Do nothing if the pointer to import table is NULL.
584f8af5cf6SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
585cfca06d7SDimitry Andric return Error::success();
586f8af5cf6SDimitry Andric
587f8af5cf6SDimitry Andric uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;
588f8af5cf6SDimitry Andric
589f8af5cf6SDimitry Andric // Find the section that contains the RVA. This is needed because the RVA is
590f8af5cf6SDimitry Andric // the import table's memory address which is different from its file offset.
591f8af5cf6SDimitry Andric uintptr_t IntPtr = 0;
592145449b1SDimitry Andric if (Error E = getRvaPtr(ImportTableRva, IntPtr, "import table"))
593cfca06d7SDimitry Andric return E;
594cfca06d7SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
595cfca06d7SDimitry Andric return E;
596f8af5cf6SDimitry Andric ImportDirectory = reinterpret_cast<
597b915e9e0SDimitry Andric const coff_import_directory_table_entry *>(IntPtr);
598cfca06d7SDimitry Andric return Error::success();
599f8af5cf6SDimitry Andric }
600f8af5cf6SDimitry Andric
60167c32a98SDimitry Andric // Initializes DelayImportDirectory and NumberOfDelayImportDirectory.
initDelayImportTablePtr()602cfca06d7SDimitry Andric Error COFFObjectFile::initDelayImportTablePtr() {
603cfca06d7SDimitry Andric const data_directory *DataEntry =
604cfca06d7SDimitry Andric getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR);
605cfca06d7SDimitry Andric if (!DataEntry)
606cfca06d7SDimitry Andric return Error::success();
60767c32a98SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
608cfca06d7SDimitry Andric return Error::success();
60967c32a98SDimitry Andric
61067c32a98SDimitry Andric uint32_t RVA = DataEntry->RelativeVirtualAddress;
61167c32a98SDimitry Andric NumberOfDelayImportDirectory = DataEntry->Size /
61267c32a98SDimitry Andric sizeof(delay_import_directory_table_entry) - 1;
61367c32a98SDimitry Andric
61467c32a98SDimitry Andric uintptr_t IntPtr = 0;
615145449b1SDimitry Andric if (Error E = getRvaPtr(RVA, IntPtr, "delay import table"))
616cfca06d7SDimitry Andric return E;
617145449b1SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
618145449b1SDimitry Andric return E;
619145449b1SDimitry Andric
62067c32a98SDimitry Andric DelayImportDirectory = reinterpret_cast<
62167c32a98SDimitry Andric const delay_import_directory_table_entry *>(IntPtr);
622cfca06d7SDimitry Andric return Error::success();
62367c32a98SDimitry Andric }
62467c32a98SDimitry Andric
6255ca98fd9SDimitry Andric // Find the export table.
initExportTablePtr()626cfca06d7SDimitry Andric Error COFFObjectFile::initExportTablePtr() {
6275ca98fd9SDimitry Andric // First, we get the RVA of the export table. If the file lacks a pointer to
6285ca98fd9SDimitry Andric // the export table, do nothing.
629cfca06d7SDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::EXPORT_TABLE);
630cfca06d7SDimitry Andric if (!DataEntry)
631cfca06d7SDimitry Andric return Error::success();
6325ca98fd9SDimitry Andric
6335ca98fd9SDimitry Andric // Do nothing if the pointer to export table is NULL.
6345ca98fd9SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
635cfca06d7SDimitry Andric return Error::success();
6365ca98fd9SDimitry Andric
6375ca98fd9SDimitry Andric uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
6385ca98fd9SDimitry Andric uintptr_t IntPtr = 0;
639145449b1SDimitry Andric if (Error E = getRvaPtr(ExportTableRva, IntPtr, "export table"))
640cfca06d7SDimitry Andric return E;
641145449b1SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
642145449b1SDimitry Andric return E;
643145449b1SDimitry Andric
6445ca98fd9SDimitry Andric ExportDirectory =
6455ca98fd9SDimitry Andric reinterpret_cast<const export_directory_table_entry *>(IntPtr);
646cfca06d7SDimitry Andric return Error::success();
6475ca98fd9SDimitry Andric }
6485ca98fd9SDimitry Andric
initBaseRelocPtr()649cfca06d7SDimitry Andric Error COFFObjectFile::initBaseRelocPtr() {
650cfca06d7SDimitry Andric const data_directory *DataEntry =
651cfca06d7SDimitry Andric getDataDirectory(COFF::BASE_RELOCATION_TABLE);
652cfca06d7SDimitry Andric if (!DataEntry)
653cfca06d7SDimitry Andric return Error::success();
65467c32a98SDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
655cfca06d7SDimitry Andric return Error::success();
65667c32a98SDimitry Andric
65767c32a98SDimitry Andric uintptr_t IntPtr = 0;
658145449b1SDimitry Andric if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
659145449b1SDimitry Andric "base reloc table"))
660cfca06d7SDimitry Andric return E;
661145449b1SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
662145449b1SDimitry Andric return E;
663145449b1SDimitry Andric
66467c32a98SDimitry Andric BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(
66567c32a98SDimitry Andric IntPtr);
66667c32a98SDimitry Andric BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(
66767c32a98SDimitry Andric IntPtr + DataEntry->Size);
668d8e91e46SDimitry Andric // FIXME: Verify the section containing BaseRelocHeader has at least
669d8e91e46SDimitry Andric // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
670cfca06d7SDimitry Andric return Error::success();
67167c32a98SDimitry Andric }
67267c32a98SDimitry Andric
initDebugDirectoryPtr()673cfca06d7SDimitry Andric Error COFFObjectFile::initDebugDirectoryPtr() {
67401095a5dSDimitry Andric // Get the RVA of the debug directory. Do nothing if it does not exist.
675cfca06d7SDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::DEBUG_DIRECTORY);
676cfca06d7SDimitry Andric if (!DataEntry)
677cfca06d7SDimitry Andric return Error::success();
67801095a5dSDimitry Andric
67901095a5dSDimitry Andric // Do nothing if the RVA is NULL.
68001095a5dSDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
681cfca06d7SDimitry Andric return Error::success();
68201095a5dSDimitry Andric
68301095a5dSDimitry Andric // Check that the size is a multiple of the entry size.
68401095a5dSDimitry Andric if (DataEntry->Size % sizeof(debug_directory) != 0)
685145449b1SDimitry Andric return createStringError(object_error::parse_failed,
686145449b1SDimitry Andric "debug directory has uneven size");
68701095a5dSDimitry Andric
68801095a5dSDimitry Andric uintptr_t IntPtr = 0;
689145449b1SDimitry Andric if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
690145449b1SDimitry Andric "debug directory"))
691cfca06d7SDimitry Andric return E;
692145449b1SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
693145449b1SDimitry Andric return E;
694145449b1SDimitry Andric
69501095a5dSDimitry Andric DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
696d8e91e46SDimitry Andric DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(
697d8e91e46SDimitry Andric IntPtr + DataEntry->Size);
698d8e91e46SDimitry Andric // FIXME: Verify the section containing DebugDirectoryBegin has at least
699d8e91e46SDimitry Andric // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
700cfca06d7SDimitry Andric return Error::success();
70101095a5dSDimitry Andric }
70201095a5dSDimitry Andric
initTLSDirectoryPtr()703b60736ecSDimitry Andric Error COFFObjectFile::initTLSDirectoryPtr() {
704b60736ecSDimitry Andric // Get the RVA of the TLS directory. Do nothing if it does not exist.
705b60736ecSDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);
706b60736ecSDimitry Andric if (!DataEntry)
707b60736ecSDimitry Andric return Error::success();
708b60736ecSDimitry Andric
709b60736ecSDimitry Andric // Do nothing if the RVA is NULL.
710b60736ecSDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
711b60736ecSDimitry Andric return Error::success();
712b60736ecSDimitry Andric
713b60736ecSDimitry Andric uint64_t DirSize =
714b60736ecSDimitry Andric is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32);
715b60736ecSDimitry Andric
716b60736ecSDimitry Andric // Check that the size is correct.
717b60736ecSDimitry Andric if (DataEntry->Size != DirSize)
718b60736ecSDimitry Andric return createStringError(
719b60736ecSDimitry Andric object_error::parse_failed,
720b60736ecSDimitry Andric "TLS Directory size (%u) is not the expected size (%" PRIu64 ").",
721b60736ecSDimitry Andric static_cast<uint32_t>(DataEntry->Size), DirSize);
722b60736ecSDimitry Andric
723b60736ecSDimitry Andric uintptr_t IntPtr = 0;
724145449b1SDimitry Andric if (Error E =
725145449b1SDimitry Andric getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory"))
726145449b1SDimitry Andric return E;
727145449b1SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
728b60736ecSDimitry Andric return E;
729b60736ecSDimitry Andric
730b60736ecSDimitry Andric if (is64())
731b60736ecSDimitry Andric TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
732b60736ecSDimitry Andric else
733b60736ecSDimitry Andric TLSDirectory32 = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);
734b60736ecSDimitry Andric
735b60736ecSDimitry Andric return Error::success();
736b60736ecSDimitry Andric }
737b60736ecSDimitry Andric
initLoadConfigPtr()738cfca06d7SDimitry Andric Error COFFObjectFile::initLoadConfigPtr() {
73908bbd35aSDimitry Andric // Get the RVA of the debug directory. Do nothing if it does not exist.
740cfca06d7SDimitry Andric const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);
741cfca06d7SDimitry Andric if (!DataEntry)
742cfca06d7SDimitry Andric return Error::success();
74308bbd35aSDimitry Andric
74408bbd35aSDimitry Andric // Do nothing if the RVA is NULL.
74508bbd35aSDimitry Andric if (DataEntry->RelativeVirtualAddress == 0)
746cfca06d7SDimitry Andric return Error::success();
74708bbd35aSDimitry Andric uintptr_t IntPtr = 0;
748145449b1SDimitry Andric if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr,
749145449b1SDimitry Andric "load config table"))
750145449b1SDimitry Andric return E;
751145449b1SDimitry Andric if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
752cfca06d7SDimitry Andric return E;
75308bbd35aSDimitry Andric
75408bbd35aSDimitry Andric LoadConfig = (const void *)IntPtr;
7557fa27ce4SDimitry Andric
7567fa27ce4SDimitry Andric if (is64()) {
7577fa27ce4SDimitry Andric auto Config = getLoadConfig64();
7587fa27ce4SDimitry Andric if (Config->Size >=
7597fa27ce4SDimitry Andric offsetof(coff_load_configuration64, CHPEMetadataPointer) +
7607fa27ce4SDimitry Andric sizeof(Config->CHPEMetadataPointer) &&
7617fa27ce4SDimitry Andric Config->CHPEMetadataPointer) {
7627fa27ce4SDimitry Andric uint64_t ChpeOff = Config->CHPEMetadataPointer;
7637fa27ce4SDimitry Andric if (Error E =
7647fa27ce4SDimitry Andric getRvaPtr(ChpeOff - getImageBase(), IntPtr, "CHPE metadata"))
7657fa27ce4SDimitry Andric return E;
7667fa27ce4SDimitry Andric if (Error E = checkOffset(Data, IntPtr, sizeof(CHPEMetadata)))
7677fa27ce4SDimitry Andric return E;
7687fa27ce4SDimitry Andric
7697fa27ce4SDimitry Andric CHPEMetadata = reinterpret_cast<const chpe_metadata *>(IntPtr);
7707fa27ce4SDimitry Andric
7717fa27ce4SDimitry Andric // Validate CHPE metadata
7727fa27ce4SDimitry Andric if (CHPEMetadata->CodeMapCount) {
7737fa27ce4SDimitry Andric if (Error E = getRvaPtr(CHPEMetadata->CodeMap, IntPtr, "CHPE code map"))
7747fa27ce4SDimitry Andric return E;
7757fa27ce4SDimitry Andric if (Error E = checkOffset(Data, IntPtr,
7767fa27ce4SDimitry Andric CHPEMetadata->CodeMapCount *
7777fa27ce4SDimitry Andric sizeof(chpe_range_entry)))
7787fa27ce4SDimitry Andric return E;
7797fa27ce4SDimitry Andric }
7807fa27ce4SDimitry Andric
7817fa27ce4SDimitry Andric if (CHPEMetadata->CodeRangesToEntryPointsCount) {
7827fa27ce4SDimitry Andric if (Error E = getRvaPtr(CHPEMetadata->CodeRangesToEntryPoints, IntPtr,
7837fa27ce4SDimitry Andric "CHPE entry point ranges"))
7847fa27ce4SDimitry Andric return E;
7857fa27ce4SDimitry Andric if (Error E = checkOffset(Data, IntPtr,
7867fa27ce4SDimitry Andric CHPEMetadata->CodeRangesToEntryPointsCount *
7877fa27ce4SDimitry Andric sizeof(chpe_code_range_entry)))
7887fa27ce4SDimitry Andric return E;
7897fa27ce4SDimitry Andric }
7907fa27ce4SDimitry Andric
7917fa27ce4SDimitry Andric if (CHPEMetadata->RedirectionMetadataCount) {
7927fa27ce4SDimitry Andric if (Error E = getRvaPtr(CHPEMetadata->RedirectionMetadata, IntPtr,
7937fa27ce4SDimitry Andric "CHPE redirection metadata"))
7947fa27ce4SDimitry Andric return E;
7957fa27ce4SDimitry Andric if (Error E = checkOffset(Data, IntPtr,
7967fa27ce4SDimitry Andric CHPEMetadata->RedirectionMetadataCount *
7977fa27ce4SDimitry Andric sizeof(chpe_redirection_entry)))
7987fa27ce4SDimitry Andric return E;
7997fa27ce4SDimitry Andric }
8007fa27ce4SDimitry Andric }
8017fa27ce4SDimitry Andric }
8027fa27ce4SDimitry Andric
803cfca06d7SDimitry Andric return Error::success();
80408bbd35aSDimitry Andric }
80508bbd35aSDimitry Andric
806cfca06d7SDimitry Andric Expected<std::unique_ptr<COFFObjectFile>>
create(MemoryBufferRef Object)807cfca06d7SDimitry Andric COFFObjectFile::create(MemoryBufferRef Object) {
808cfca06d7SDimitry Andric std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object)));
809cfca06d7SDimitry Andric if (Error E = Obj->initialize())
810ac9a064cSDimitry Andric return E;
811cfca06d7SDimitry Andric return std::move(Obj);
812cfca06d7SDimitry Andric }
813cfca06d7SDimitry Andric
COFFObjectFile(MemoryBufferRef Object)814cfca06d7SDimitry Andric COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)
81567c32a98SDimitry Andric : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
81667c32a98SDimitry Andric COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
81767c32a98SDimitry Andric DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),
81867c32a98SDimitry Andric SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),
819cfca06d7SDimitry Andric ImportDirectory(nullptr), DelayImportDirectory(nullptr),
820cfca06d7SDimitry Andric NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),
821cfca06d7SDimitry Andric BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
822b60736ecSDimitry Andric DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),
823b60736ecSDimitry Andric TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}
824cfca06d7SDimitry Andric
ignoreStrippedErrors(Error E)825145449b1SDimitry Andric static Error ignoreStrippedErrors(Error E) {
826145449b1SDimitry Andric if (E.isA<SectionStrippedError>()) {
827145449b1SDimitry Andric consumeError(std::move(E));
828145449b1SDimitry Andric return Error::success();
829145449b1SDimitry Andric }
830145449b1SDimitry Andric return E;
831145449b1SDimitry Andric }
832145449b1SDimitry Andric
initialize()833cfca06d7SDimitry Andric Error COFFObjectFile::initialize() {
834411bd29eSDimitry Andric // Check that we at least have enough room for a header.
835cfca06d7SDimitry Andric std::error_code EC;
83667c32a98SDimitry Andric if (!checkSize(Data, EC, sizeof(coff_file_header)))
837cfca06d7SDimitry Andric return errorCodeToError(EC);
8386b943ff3SDimitry Andric
839f8af5cf6SDimitry Andric // The current location in the file where we are looking at.
840f8af5cf6SDimitry Andric uint64_t CurPtr = 0;
841f8af5cf6SDimitry Andric
842f8af5cf6SDimitry Andric // PE header is optional and is present only in executables. If it exists,
843f8af5cf6SDimitry Andric // it is placed right after COFF header.
8445ca98fd9SDimitry Andric bool HasPEHeader = false;
845411bd29eSDimitry Andric
846411bd29eSDimitry Andric // Check if this is a PE/COFF file.
84767c32a98SDimitry Andric if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {
8486b943ff3SDimitry Andric // PE/COFF, seek through MS-DOS compatibility stub and 4-byte
8496b943ff3SDimitry Andric // PE signature to find 'normal' COFF header.
85067c32a98SDimitry Andric const auto *DH = reinterpret_cast<const dos_header *>(base());
85167c32a98SDimitry Andric if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {
85267c32a98SDimitry Andric CurPtr = DH->AddressOfNewExeHeader;
853f8af5cf6SDimitry Andric // Check the PE magic bytes. ("PE\0\0")
85467c32a98SDimitry Andric if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {
855145449b1SDimitry Andric return createStringError(object_error::parse_failed,
856145449b1SDimitry Andric "incorrect PE magic");
857411bd29eSDimitry Andric }
85867c32a98SDimitry Andric CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.
8595ca98fd9SDimitry Andric HasPEHeader = true;
8606b943ff3SDimitry Andric }
86167c32a98SDimitry Andric }
8626b943ff3SDimitry Andric
863cfca06d7SDimitry Andric if (Error E = getObject(COFFHeader, Data, base() + CurPtr))
864cfca06d7SDimitry Andric return E;
86567c32a98SDimitry Andric
86667c32a98SDimitry Andric // It might be a bigobj file, let's check. Note that COFF bigobj and COFF
86767c32a98SDimitry Andric // import libraries share a common prefix but bigobj is more restrictive.
86867c32a98SDimitry Andric if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
86967c32a98SDimitry Andric COFFHeader->NumberOfSections == uint16_t(0xffff) &&
87067c32a98SDimitry Andric checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {
871cfca06d7SDimitry Andric if (Error E = getObject(COFFBigObjHeader, Data, base() + CurPtr))
872cfca06d7SDimitry Andric return E;
87367c32a98SDimitry Andric
87467c32a98SDimitry Andric // Verify that we are dealing with bigobj.
87567c32a98SDimitry Andric if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&
87667c32a98SDimitry Andric std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,
87767c32a98SDimitry Andric sizeof(COFF::BigObjMagic)) == 0) {
87867c32a98SDimitry Andric COFFHeader = nullptr;
87967c32a98SDimitry Andric CurPtr += sizeof(coff_bigobj_file_header);
88067c32a98SDimitry Andric } else {
88167c32a98SDimitry Andric // It's not a bigobj.
88267c32a98SDimitry Andric COFFBigObjHeader = nullptr;
88367c32a98SDimitry Andric }
88467c32a98SDimitry Andric }
88567c32a98SDimitry Andric if (COFFHeader) {
88667c32a98SDimitry Andric // The prior checkSize call may have failed. This isn't a hard error
88767c32a98SDimitry Andric // because we were just trying to sniff out bigobj.
88885d8b2bbSDimitry Andric EC = std::error_code();
889f8af5cf6SDimitry Andric CurPtr += sizeof(coff_file_header);
890411bd29eSDimitry Andric
89167c32a98SDimitry Andric if (COFFHeader->isImportLibrary())
892cfca06d7SDimitry Andric return errorCodeToError(EC);
89367c32a98SDimitry Andric }
89467c32a98SDimitry Andric
8955ca98fd9SDimitry Andric if (HasPEHeader) {
8965ca98fd9SDimitry Andric const pe32_header *Header;
897cfca06d7SDimitry Andric if (Error E = getObject(Header, Data, base() + CurPtr))
898cfca06d7SDimitry Andric return E;
8995ca98fd9SDimitry Andric
9005ca98fd9SDimitry Andric const uint8_t *DataDirAddr;
9015ca98fd9SDimitry Andric uint64_t DataDirSize;
90267c32a98SDimitry Andric if (Header->Magic == COFF::PE32Header::PE32) {
9035ca98fd9SDimitry Andric PE32Header = Header;
9045ca98fd9SDimitry Andric DataDirAddr = base() + CurPtr + sizeof(pe32_header);
9055ca98fd9SDimitry Andric DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;
90667c32a98SDimitry Andric } else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {
9075ca98fd9SDimitry Andric PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);
9085ca98fd9SDimitry Andric DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);
9095ca98fd9SDimitry Andric DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
9105ca98fd9SDimitry Andric } else {
9115ca98fd9SDimitry Andric // It's neither PE32 nor PE32+.
912145449b1SDimitry Andric return createStringError(object_error::parse_failed,
913145449b1SDimitry Andric "incorrect PE magic");
914411bd29eSDimitry Andric }
915cfca06d7SDimitry Andric if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))
916cfca06d7SDimitry Andric return E;
91763faed5bSDimitry Andric }
918411bd29eSDimitry Andric
919b915e9e0SDimitry Andric if (COFFHeader)
920b915e9e0SDimitry Andric CurPtr += COFFHeader->SizeOfOptionalHeader;
921b915e9e0SDimitry Andric
922cfca06d7SDimitry Andric assert(COFFHeader || COFFBigObjHeader);
923cfca06d7SDimitry Andric
924cfca06d7SDimitry Andric if (Error E =
925cfca06d7SDimitry Andric getObject(SectionTable, Data, base() + CurPtr,
926cfca06d7SDimitry Andric (uint64_t)getNumberOfSections() * sizeof(coff_section)))
927cfca06d7SDimitry Andric return E;
928f8af5cf6SDimitry Andric
929f8af5cf6SDimitry Andric // Initialize the pointer to the symbol table.
93067c32a98SDimitry Andric if (getPointerToSymbolTable() != 0) {
931cfca06d7SDimitry Andric if (Error E = initSymbolTablePtr()) {
932cfca06d7SDimitry Andric // Recover from errors reading the symbol table.
933cfca06d7SDimitry Andric consumeError(std::move(E));
934b915e9e0SDimitry Andric SymbolTable16 = nullptr;
935b915e9e0SDimitry Andric SymbolTable32 = nullptr;
936b915e9e0SDimitry Andric StringTable = nullptr;
937b915e9e0SDimitry Andric StringTableSize = 0;
938b915e9e0SDimitry Andric }
93967c32a98SDimitry Andric } else {
94067c32a98SDimitry Andric // We had better not have any symbols if we don't have a symbol table.
94167c32a98SDimitry Andric if (getNumberOfSymbols() != 0) {
942145449b1SDimitry Andric return createStringError(object_error::parse_failed,
943145449b1SDimitry Andric "symbol table missing");
94467c32a98SDimitry Andric }
94567c32a98SDimitry Andric }
946f8af5cf6SDimitry Andric
947f8af5cf6SDimitry Andric // Initialize the pointer to the beginning of the import table.
948145449b1SDimitry Andric if (Error E = ignoreStrippedErrors(initImportTablePtr()))
949cfca06d7SDimitry Andric return E;
950145449b1SDimitry Andric if (Error E = ignoreStrippedErrors(initDelayImportTablePtr()))
951cfca06d7SDimitry Andric return E;
952f8af5cf6SDimitry Andric
9535ca98fd9SDimitry Andric // Initialize the pointer to the export table.
954145449b1SDimitry Andric if (Error E = ignoreStrippedErrors(initExportTablePtr()))
955cfca06d7SDimitry Andric return E;
9565ca98fd9SDimitry Andric
95767c32a98SDimitry Andric // Initialize the pointer to the base relocation table.
958145449b1SDimitry Andric if (Error E = ignoreStrippedErrors(initBaseRelocPtr()))
959cfca06d7SDimitry Andric return E;
96067c32a98SDimitry Andric
961b60736ecSDimitry Andric // Initialize the pointer to the debug directory.
962145449b1SDimitry Andric if (Error E = ignoreStrippedErrors(initDebugDirectoryPtr()))
963cfca06d7SDimitry Andric return E;
96401095a5dSDimitry Andric
965b60736ecSDimitry Andric // Initialize the pointer to the TLS directory.
966145449b1SDimitry Andric if (Error E = ignoreStrippedErrors(initTLSDirectoryPtr()))
967b60736ecSDimitry Andric return E;
968b60736ecSDimitry Andric
969145449b1SDimitry Andric if (Error E = ignoreStrippedErrors(initLoadConfigPtr()))
970cfca06d7SDimitry Andric return E;
97108bbd35aSDimitry Andric
972cfca06d7SDimitry Andric return Error::success();
973cf099d11SDimitry Andric }
974cf099d11SDimitry Andric
symbol_begin() const975b915e9e0SDimitry Andric basic_symbol_iterator COFFObjectFile::symbol_begin() const {
9765ca98fd9SDimitry Andric DataRefImpl Ret;
97767c32a98SDimitry Andric Ret.p = getSymbolTable();
9785ca98fd9SDimitry Andric return basic_symbol_iterator(SymbolRef(Ret, this));
979cf099d11SDimitry Andric }
980cf099d11SDimitry Andric
symbol_end() const981b915e9e0SDimitry Andric basic_symbol_iterator COFFObjectFile::symbol_end() const {
982cf099d11SDimitry Andric // The symbol table ends where the string table begins.
9835ca98fd9SDimitry Andric DataRefImpl Ret;
9845ca98fd9SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(StringTable);
9855ca98fd9SDimitry Andric return basic_symbol_iterator(SymbolRef(Ret, this));
986cf099d11SDimitry Andric }
987cf099d11SDimitry Andric
import_directory_begin() const988f8af5cf6SDimitry Andric import_directory_iterator COFFObjectFile::import_directory_begin() const {
98901095a5dSDimitry Andric if (!ImportDirectory)
99001095a5dSDimitry Andric return import_directory_end();
991b915e9e0SDimitry Andric if (ImportDirectory->isNull())
99201095a5dSDimitry Andric return import_directory_end();
9935ca98fd9SDimitry Andric return import_directory_iterator(
9945ca98fd9SDimitry Andric ImportDirectoryEntryRef(ImportDirectory, 0, this));
995f8af5cf6SDimitry Andric }
996f8af5cf6SDimitry Andric
import_directory_end() const997f8af5cf6SDimitry Andric import_directory_iterator COFFObjectFile::import_directory_end() const {
9985ca98fd9SDimitry Andric return import_directory_iterator(
99901095a5dSDimitry Andric ImportDirectoryEntryRef(nullptr, -1, this));
1000f8af5cf6SDimitry Andric }
100163faed5bSDimitry Andric
100267c32a98SDimitry Andric delay_import_directory_iterator
delay_import_directory_begin() const100367c32a98SDimitry Andric COFFObjectFile::delay_import_directory_begin() const {
100467c32a98SDimitry Andric return delay_import_directory_iterator(
100567c32a98SDimitry Andric DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));
100667c32a98SDimitry Andric }
100767c32a98SDimitry Andric
100867c32a98SDimitry Andric delay_import_directory_iterator
delay_import_directory_end() const100967c32a98SDimitry Andric COFFObjectFile::delay_import_directory_end() const {
101067c32a98SDimitry Andric return delay_import_directory_iterator(
101167c32a98SDimitry Andric DelayImportDirectoryEntryRef(
101267c32a98SDimitry Andric DelayImportDirectory, NumberOfDelayImportDirectory, this));
101367c32a98SDimitry Andric }
101467c32a98SDimitry Andric
export_directory_begin() const10155ca98fd9SDimitry Andric export_directory_iterator COFFObjectFile::export_directory_begin() const {
10165ca98fd9SDimitry Andric return export_directory_iterator(
10175ca98fd9SDimitry Andric ExportDirectoryEntryRef(ExportDirectory, 0, this));
1018cf099d11SDimitry Andric }
1019cf099d11SDimitry Andric
export_directory_end() const10205ca98fd9SDimitry Andric export_directory_iterator COFFObjectFile::export_directory_end() const {
10215ca98fd9SDimitry Andric if (!ExportDirectory)
10225ca98fd9SDimitry Andric return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));
10235ca98fd9SDimitry Andric ExportDirectoryEntryRef Ref(ExportDirectory,
10245ca98fd9SDimitry Andric ExportDirectory->AddressTableEntries, this);
10255ca98fd9SDimitry Andric return export_directory_iterator(Ref);
10265ca98fd9SDimitry Andric }
10275ca98fd9SDimitry Andric
section_begin() const10285ca98fd9SDimitry Andric section_iterator COFFObjectFile::section_begin() const {
10295ca98fd9SDimitry Andric DataRefImpl Ret;
10305ca98fd9SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(SectionTable);
10315ca98fd9SDimitry Andric return section_iterator(SectionRef(Ret, this));
10325ca98fd9SDimitry Andric }
10335ca98fd9SDimitry Andric
section_end() const10345ca98fd9SDimitry Andric section_iterator COFFObjectFile::section_end() const {
10355ca98fd9SDimitry Andric DataRefImpl Ret;
103667c32a98SDimitry Andric int NumSections =
103767c32a98SDimitry Andric COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();
10385ca98fd9SDimitry Andric Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);
10395ca98fd9SDimitry Andric return section_iterator(SectionRef(Ret, this));
1040cf099d11SDimitry Andric }
1041cf099d11SDimitry Andric
base_reloc_begin() const104267c32a98SDimitry Andric base_reloc_iterator COFFObjectFile::base_reloc_begin() const {
104367c32a98SDimitry Andric return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));
104467c32a98SDimitry Andric }
104567c32a98SDimitry Andric
base_reloc_end() const104667c32a98SDimitry Andric base_reloc_iterator COFFObjectFile::base_reloc_end() const {
104767c32a98SDimitry Andric return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));
104867c32a98SDimitry Andric }
104967c32a98SDimitry Andric
getBytesInAddress() const1050cf099d11SDimitry Andric uint8_t COFFObjectFile::getBytesInAddress() const {
10519df3605dSDimitry Andric return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;
1052cf099d11SDimitry Andric }
1053cf099d11SDimitry Andric
getFileFormatName() const1054cf099d11SDimitry Andric StringRef COFFObjectFile::getFileFormatName() const {
105567c32a98SDimitry Andric switch(getMachine()) {
1056cf099d11SDimitry Andric case COFF::IMAGE_FILE_MACHINE_I386:
1057cf099d11SDimitry Andric return "COFF-i386";
1058cf099d11SDimitry Andric case COFF::IMAGE_FILE_MACHINE_AMD64:
1059cf099d11SDimitry Andric return "COFF-x86-64";
10605ca98fd9SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARMNT:
10615ca98fd9SDimitry Andric return "COFF-ARM";
1062dd58ef01SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64:
1063dd58ef01SDimitry Andric return "COFF-ARM64";
1064e3b55780SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64EC:
1065e3b55780SDimitry Andric return "COFF-ARM64EC";
10667fa27ce4SDimitry Andric case COFF::IMAGE_FILE_MACHINE_ARM64X:
10677fa27ce4SDimitry Andric return "COFF-ARM64X";
1068cf099d11SDimitry Andric default:
1069cf099d11SDimitry Andric return "COFF-<unknown arch>";
1070cf099d11SDimitry Andric }
1071cf099d11SDimitry Andric }
1072cf099d11SDimitry Andric
getArch() const1073044eb2f6SDimitry Andric Triple::ArchType COFFObjectFile::getArch() const {
1074ac9a064cSDimitry Andric return getMachineArchType(getMachine());
1075cf099d11SDimitry Andric }
1076cf099d11SDimitry Andric
getStartAddress() const1077eb11fae6SDimitry Andric Expected<uint64_t> COFFObjectFile::getStartAddress() const {
1078eb11fae6SDimitry Andric if (PE32Header)
1079eb11fae6SDimitry Andric return PE32Header->AddressOfEntryPoint;
1080eb11fae6SDimitry Andric return 0;
1081eb11fae6SDimitry Andric }
1082eb11fae6SDimitry Andric
108367c32a98SDimitry Andric iterator_range<import_directory_iterator>
import_directories() const108467c32a98SDimitry Andric COFFObjectFile::import_directories() const {
108567c32a98SDimitry Andric return make_range(import_directory_begin(), import_directory_end());
1086f8af5cf6SDimitry Andric }
1087f8af5cf6SDimitry Andric
108867c32a98SDimitry Andric iterator_range<delay_import_directory_iterator>
delay_import_directories() const108967c32a98SDimitry Andric COFFObjectFile::delay_import_directories() const {
109067c32a98SDimitry Andric return make_range(delay_import_directory_begin(),
109167c32a98SDimitry Andric delay_import_directory_end());
109267c32a98SDimitry Andric }
109367c32a98SDimitry Andric
109467c32a98SDimitry Andric iterator_range<export_directory_iterator>
export_directories() const109567c32a98SDimitry Andric COFFObjectFile::export_directories() const {
109667c32a98SDimitry Andric return make_range(export_directory_begin(), export_directory_end());
109767c32a98SDimitry Andric }
109867c32a98SDimitry Andric
base_relocs() const109967c32a98SDimitry Andric iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {
110067c32a98SDimitry Andric return make_range(base_reloc_begin(), base_reloc_end());
1101f8af5cf6SDimitry Andric }
1102f8af5cf6SDimitry Andric
getDataDirectory(uint32_t Index) const1103cfca06d7SDimitry Andric const data_directory *COFFObjectFile::getDataDirectory(uint32_t Index) const {
1104cfca06d7SDimitry Andric if (!DataDirectory)
1105cfca06d7SDimitry Andric return nullptr;
11065ca98fd9SDimitry Andric assert(PE32Header || PE32PlusHeader);
11075ca98fd9SDimitry Andric uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize
11085ca98fd9SDimitry Andric : PE32PlusHeader->NumberOfRvaAndSize;
1109cfca06d7SDimitry Andric if (Index >= NumEnt)
1110cfca06d7SDimitry Andric return nullptr;
1111cfca06d7SDimitry Andric return &DataDirectory[Index];
11125ca98fd9SDimitry Andric }
11135ca98fd9SDimitry Andric
getSection(int32_t Index) const1114cfca06d7SDimitry Andric Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {
1115cfca06d7SDimitry Andric // Perhaps getting the section of a reserved section index should be an error,
1116cfca06d7SDimitry Andric // but callers rely on this to return null.
111767c32a98SDimitry Andric if (COFF::isReservedSectionNumber(Index))
1118cfca06d7SDimitry Andric return (const coff_section *)nullptr;
111967c32a98SDimitry Andric if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {
1120411bd29eSDimitry Andric // We already verified the section table data, so no need to check again.
1121cfca06d7SDimitry Andric return SectionTable + (Index - 1);
1122cf099d11SDimitry Andric }
1123145449b1SDimitry Andric return createStringError(object_error::parse_failed,
1124145449b1SDimitry Andric "section index out of bounds");
112567c32a98SDimitry Andric }
1126cf099d11SDimitry Andric
getString(uint32_t Offset) const1127cfca06d7SDimitry Andric Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {
1128411bd29eSDimitry Andric if (StringTableSize <= 4)
1129411bd29eSDimitry Andric // Tried to get a string from an empty string table.
1130145449b1SDimitry Andric return createStringError(object_error::parse_failed, "string table empty");
11315ca98fd9SDimitry Andric if (Offset >= StringTableSize)
1132cfca06d7SDimitry Andric return errorCodeToError(object_error::unexpected_eof);
1133cfca06d7SDimitry Andric return StringRef(StringTable + Offset);
1134cf099d11SDimitry Andric }
1135cf099d11SDimitry Andric
getSymbolName(COFFSymbolRef Symbol) const1136cfca06d7SDimitry Andric Expected<StringRef> COFFObjectFile::getSymbolName(COFFSymbolRef Symbol) const {
1137cfca06d7SDimitry Andric return getSymbolName(Symbol.getGeneric());
11381a82d4c0SDimitry Andric }
11391a82d4c0SDimitry Andric
1140cfca06d7SDimitry Andric Expected<StringRef>
getSymbolName(const coff_symbol_generic * Symbol) const1141cfca06d7SDimitry Andric COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol) const {
114263faed5bSDimitry Andric // Check for string table entry. First 4 bytes are 0.
1143cfca06d7SDimitry Andric if (Symbol->Name.Offset.Zeroes == 0)
1144cfca06d7SDimitry Andric return getString(Symbol->Name.Offset.Offset);
114563faed5bSDimitry Andric
114663faed5bSDimitry Andric // Null terminated, let ::strlen figure out the length.
1147cfca06d7SDimitry Andric if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)
1148cfca06d7SDimitry Andric return StringRef(Symbol->Name.ShortName);
1149cfca06d7SDimitry Andric
115063faed5bSDimitry Andric // Not null terminated, use all 8 bytes.
1151cfca06d7SDimitry Andric return StringRef(Symbol->Name.ShortName, COFF::NameSize);
115263faed5bSDimitry Andric }
115363faed5bSDimitry Andric
115467c32a98SDimitry Andric ArrayRef<uint8_t>
getSymbolAuxData(COFFSymbolRef Symbol) const115567c32a98SDimitry Andric COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {
11565ca98fd9SDimitry Andric const uint8_t *Aux = nullptr;
115758b69754SDimitry Andric
115867c32a98SDimitry Andric size_t SymbolSize = getSymbolTableEntrySize();
115967c32a98SDimitry Andric if (Symbol.getNumberOfAuxSymbols() > 0) {
116058b69754SDimitry Andric // AUX data comes immediately after the symbol in COFF
116167c32a98SDimitry Andric Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;
116258b69754SDimitry Andric #ifndef NDEBUG
11635ca98fd9SDimitry Andric // Verify that the Aux symbol points to a valid entry in the symbol table.
11645ca98fd9SDimitry Andric uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());
116567c32a98SDimitry Andric if (Offset < getPointerToSymbolTable() ||
116667c32a98SDimitry Andric Offset >=
116767c32a98SDimitry Andric getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))
116858b69754SDimitry Andric report_fatal_error("Aux Symbol data was outside of symbol table.");
116958b69754SDimitry Andric
117067c32a98SDimitry Andric assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&
117167c32a98SDimitry Andric "Aux Symbol data did not point to the beginning of a symbol");
117258b69754SDimitry Andric #endif
117358b69754SDimitry Andric }
1174e3b55780SDimitry Andric return ArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);
117558b69754SDimitry Andric }
117658b69754SDimitry Andric
getSymbolIndex(COFFSymbolRef Symbol) const1177d8e91e46SDimitry Andric uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {
1178d8e91e46SDimitry Andric uintptr_t Offset =
1179d8e91e46SDimitry Andric reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();
1180d8e91e46SDimitry Andric assert(Offset % getSymbolTableEntrySize() == 0 &&
1181d8e91e46SDimitry Andric "Symbol did not point to the beginning of a symbol");
1182d8e91e46SDimitry Andric size_t Index = Offset / getSymbolTableEntrySize();
1183d8e91e46SDimitry Andric assert(Index < getNumberOfSymbols());
1184d8e91e46SDimitry Andric return Index;
1185d8e91e46SDimitry Andric }
1186d8e91e46SDimitry Andric
1187e6d15924SDimitry Andric Expected<StringRef>
getSectionName(const coff_section * Sec) const1188e6d15924SDimitry Andric COFFObjectFile::getSectionName(const coff_section *Sec) const {
1189145449b1SDimitry Andric StringRef Name = StringRef(Sec->Name, COFF::NameSize).split('\0').first;
119063faed5bSDimitry Andric
119163faed5bSDimitry Andric // Check for string table entry. First byte is '/'.
1192312c0ed1SDimitry Andric if (Name.starts_with("/")) {
119363faed5bSDimitry Andric uint32_t Offset;
1194312c0ed1SDimitry Andric if (Name.starts_with("//")) {
11955ca98fd9SDimitry Andric if (decodeBase64StringEntry(Name.substr(2), Offset))
1196e6d15924SDimitry Andric return createStringError(object_error::parse_failed,
1197cfca06d7SDimitry Andric "invalid section name");
11985ca98fd9SDimitry Andric } else {
119963faed5bSDimitry Andric if (Name.substr(1).getAsInteger(10, Offset))
1200e6d15924SDimitry Andric return createStringError(object_error::parse_failed,
1201e6d15924SDimitry Andric "invalid section name");
12025ca98fd9SDimitry Andric }
1203cfca06d7SDimitry Andric return getString(Offset);
120463faed5bSDimitry Andric }
120563faed5bSDimitry Andric
1206e6d15924SDimitry Andric return Name;
120763faed5bSDimitry Andric }
120863faed5bSDimitry Andric
getSectionSize(const coff_section * Sec) const120967c32a98SDimitry Andric uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {
121067c32a98SDimitry Andric // SizeOfRawData and VirtualSize change what they represent depending on
121167c32a98SDimitry Andric // whether or not we have an executable image.
121267c32a98SDimitry Andric //
121367c32a98SDimitry Andric // For object files, SizeOfRawData contains the size of section's data;
1214ee8648bdSDimitry Andric // VirtualSize should be zero but isn't due to buggy COFF writers.
121567c32a98SDimitry Andric //
121667c32a98SDimitry Andric // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the
121767c32a98SDimitry Andric // actual section size is in VirtualSize. It is possible for VirtualSize to
121867c32a98SDimitry Andric // be greater than SizeOfRawData; the contents past that point should be
121967c32a98SDimitry Andric // considered to be zero.
1220ee8648bdSDimitry Andric if (getDOSHeader())
1221ee8648bdSDimitry Andric return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
1222ee8648bdSDimitry Andric return Sec->SizeOfRawData;
122367c32a98SDimitry Andric }
122467c32a98SDimitry Andric
getSectionContents(const coff_section * Sec,ArrayRef<uint8_t> & Res) const1225e6d15924SDimitry Andric Error COFFObjectFile::getSectionContents(const coff_section *Sec,
122663faed5bSDimitry Andric ArrayRef<uint8_t> &Res) const {
122701095a5dSDimitry Andric // In COFF, a virtual section won't have any in-file
122801095a5dSDimitry Andric // content, so the file pointer to the content will be zero.
122901095a5dSDimitry Andric if (Sec->PointerToRawData == 0)
1230e6d15924SDimitry Andric return Error::success();
123163faed5bSDimitry Andric // The only thing that we need to verify is that the contents is contained
123263faed5bSDimitry Andric // within the file bounds. We don't need to make sure it doesn't cover other
123363faed5bSDimitry Andric // data, as there's nothing that says that is not allowed.
1234b60736ecSDimitry Andric uintptr_t ConStart =
1235b60736ecSDimitry Andric reinterpret_cast<uintptr_t>(base()) + Sec->PointerToRawData;
123667c32a98SDimitry Andric uint32_t SectionSize = getSectionSize(Sec);
1237cfca06d7SDimitry Andric if (Error E = checkOffset(Data, ConStart, SectionSize))
1238cfca06d7SDimitry Andric return E;
1239e3b55780SDimitry Andric Res = ArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);
1240e6d15924SDimitry Andric return Error::success();
124163faed5bSDimitry Andric }
124263faed5bSDimitry Andric
toRel(DataRefImpl Rel) const124330815c53SDimitry Andric const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {
124430815c53SDimitry Andric return reinterpret_cast<const coff_relocation*>(Rel.p);
124530815c53SDimitry Andric }
12465ca98fd9SDimitry Andric
moveRelocationNext(DataRefImpl & Rel) const12475ca98fd9SDimitry Andric void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
124830815c53SDimitry Andric Rel.p = reinterpret_cast<uintptr_t>(
124930815c53SDimitry Andric reinterpret_cast<const coff_relocation*>(Rel.p) + 1);
125030815c53SDimitry Andric }
12515ca98fd9SDimitry Andric
getRelocationOffset(DataRefImpl Rel) const12521a82d4c0SDimitry Andric uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
125367c32a98SDimitry Andric const coff_relocation *R = toRel(Rel);
12541a82d4c0SDimitry Andric return R->VirtualAddress;
125563faed5bSDimitry Andric }
12565ca98fd9SDimitry Andric
getRelocationSymbol(DataRefImpl Rel) const1257f8af5cf6SDimitry Andric symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
125830815c53SDimitry Andric const coff_relocation *R = toRel(Rel);
12595ca98fd9SDimitry Andric DataRefImpl Ref;
126067c32a98SDimitry Andric if (R->SymbolTableIndex >= getNumberOfSymbols())
126167c32a98SDimitry Andric return symbol_end();
126267c32a98SDimitry Andric if (SymbolTable16)
126367c32a98SDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);
126467c32a98SDimitry Andric else if (SymbolTable32)
126567c32a98SDimitry Andric Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);
126667c32a98SDimitry Andric else
126767c32a98SDimitry Andric llvm_unreachable("no symbol table pointer!");
12685ca98fd9SDimitry Andric return symbol_iterator(SymbolRef(Ref, this));
126930815c53SDimitry Andric }
12705ca98fd9SDimitry Andric
getRelocationType(DataRefImpl Rel) const12711a82d4c0SDimitry Andric uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {
127230815c53SDimitry Andric const coff_relocation* R = toRel(Rel);
12731a82d4c0SDimitry Andric return R->Type;
127430815c53SDimitry Andric }
127530815c53SDimitry Andric
12765ca98fd9SDimitry Andric const coff_section *
getCOFFSection(const SectionRef & Section) const12775ca98fd9SDimitry Andric COFFObjectFile::getCOFFSection(const SectionRef &Section) const {
12785ca98fd9SDimitry Andric return toSec(Section.getRawDataRefImpl());
127958b69754SDimitry Andric }
128058b69754SDimitry Andric
getCOFFSymbol(const DataRefImpl & Ref) const128167c32a98SDimitry Andric COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {
128267c32a98SDimitry Andric if (SymbolTable16)
128367c32a98SDimitry Andric return toSymb<coff_symbol16>(Ref);
128467c32a98SDimitry Andric if (SymbolTable32)
128567c32a98SDimitry Andric return toSymb<coff_symbol32>(Ref);
128667c32a98SDimitry Andric llvm_unreachable("no symbol table pointer!");
128767c32a98SDimitry Andric }
128867c32a98SDimitry Andric
getCOFFSymbol(const SymbolRef & Symbol) const128967c32a98SDimitry Andric COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {
129067c32a98SDimitry Andric return getCOFFSymbol(Symbol.getRawDataRefImpl());
129158b69754SDimitry Andric }
129258b69754SDimitry Andric
12935ca98fd9SDimitry Andric const coff_relocation *
getCOFFRelocation(const RelocationRef & Reloc) const12945ca98fd9SDimitry Andric COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {
12955ca98fd9SDimitry Andric return toRel(Reloc.getRawDataRefImpl());
129658b69754SDimitry Andric }
129758b69754SDimitry Andric
1298eb11fae6SDimitry Andric ArrayRef<coff_relocation>
getRelocations(const coff_section * Sec) const12991a82d4c0SDimitry Andric COFFObjectFile::getRelocations(const coff_section *Sec) const {
1300eb11fae6SDimitry Andric return {getFirstReloc(Sec, Data, base()),
1301eb11fae6SDimitry Andric getNumberOfRelocations(Sec, Data, base())};
13021a82d4c0SDimitry Andric }
13031a82d4c0SDimitry Andric
13045ca98fd9SDimitry Andric #define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \
13055ca98fd9SDimitry Andric case COFF::reloc_type: \
1306d8e91e46SDimitry Andric return #reloc_type;
130730815c53SDimitry Andric
getRelocationTypeName(uint16_t Type) const1308d8e91e46SDimitry Andric StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
1309ac9a064cSDimitry Andric switch (getArch()) {
1310ac9a064cSDimitry Andric case Triple::x86_64:
1311d8e91e46SDimitry Andric switch (Type) {
131230815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);
131330815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);
131430815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);
131530815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);
131630815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);
131730815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);
131830815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);
131930815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);
132030815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);
132130815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);
132230815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);
132330815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);
132430815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);
132530815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);
132630815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);
132730815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);
132830815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);
132930815c53SDimitry Andric default:
1330d8e91e46SDimitry Andric return "Unknown";
13315ca98fd9SDimitry Andric }
13325ca98fd9SDimitry Andric break;
1333ac9a064cSDimitry Andric case Triple::thumb:
1334d8e91e46SDimitry Andric switch (Type) {
13355ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);
13365ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);
13375ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);
13385ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);
13395ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);
13405ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);
13415ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);
13425ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);
1343e6d15924SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32);
13445ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);
13455ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);
13465ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);
13475ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);
13485ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);
13495ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);
13505ca98fd9SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);
1351e6d15924SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR);
13525ca98fd9SDimitry Andric default:
1353d8e91e46SDimitry Andric return "Unknown";
135430815c53SDimitry Andric }
135530815c53SDimitry Andric break;
1356ac9a064cSDimitry Andric case Triple::aarch64:
1357d8e91e46SDimitry Andric switch (Type) {
13589df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);
13599df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);
13609df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);
13619df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);
13629df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);
13639df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);
13649df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);
13659df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);
13669df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);
13679df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);
13689df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);
13699df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);
13709df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);
13719df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);
13729df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);
13739df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);
13749df3605dSDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);
1375e6d15924SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32);
13769df3605dSDimitry Andric default:
1377d8e91e46SDimitry Andric return "Unknown";
13789df3605dSDimitry Andric }
13799df3605dSDimitry Andric break;
1380ac9a064cSDimitry Andric case Triple::x86:
1381d8e91e46SDimitry Andric switch (Type) {
138230815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);
138330815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);
138430815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);
138530815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);
138630815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);
138730815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);
138830815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);
138930815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);
139030815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);
139130815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);
139230815c53SDimitry Andric LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);
139330815c53SDimitry Andric default:
1394d8e91e46SDimitry Andric return "Unknown";
139530815c53SDimitry Andric }
139630815c53SDimitry Andric break;
139730815c53SDimitry Andric default:
1398d8e91e46SDimitry Andric return "Unknown";
139930815c53SDimitry Andric }
140030815c53SDimitry Andric }
140130815c53SDimitry Andric
140230815c53SDimitry Andric #undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME
140330815c53SDimitry Andric
getRelocationTypeName(DataRefImpl Rel,SmallVectorImpl<char> & Result) const1404d8e91e46SDimitry Andric void COFFObjectFile::getRelocationTypeName(
1405d8e91e46SDimitry Andric DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
1406d8e91e46SDimitry Andric const coff_relocation *Reloc = toRel(Rel);
1407d8e91e46SDimitry Andric StringRef Res = getRelocationTypeName(Reloc->Type);
1408d8e91e46SDimitry Andric Result.append(Res.begin(), Res.end());
1409d8e91e46SDimitry Andric }
1410d8e91e46SDimitry Andric
isRelocatableObject() const141167c32a98SDimitry Andric bool COFFObjectFile::isRelocatableObject() const {
141267c32a98SDimitry Andric return !DataDirectory;
141363faed5bSDimitry Andric }
141463faed5bSDimitry Andric
mapDebugSectionName(StringRef Name) const1415d8e91e46SDimitry Andric StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {
1416d8e91e46SDimitry Andric return StringSwitch<StringRef>(Name)
1417d8e91e46SDimitry Andric .Case("eh_fram", "eh_frame")
1418d8e91e46SDimitry Andric .Default(Name);
1419d8e91e46SDimitry Andric }
1420d8e91e46SDimitry Andric
1421f8af5cf6SDimitry Andric bool ImportDirectoryEntryRef::
operator ==(const ImportDirectoryEntryRef & Other) const1422f8af5cf6SDimitry Andric operator==(const ImportDirectoryEntryRef &Other) const {
14235ca98fd9SDimitry Andric return ImportTable == Other.ImportTable && Index == Other.Index;
1424f8af5cf6SDimitry Andric }
1425f8af5cf6SDimitry Andric
moveNext()14265ca98fd9SDimitry Andric void ImportDirectoryEntryRef::moveNext() {
14275ca98fd9SDimitry Andric ++Index;
1428b915e9e0SDimitry Andric if (ImportTable[Index].isNull()) {
142901095a5dSDimitry Andric Index = -1;
143001095a5dSDimitry Andric ImportTable = nullptr;
143101095a5dSDimitry Andric }
1432f8af5cf6SDimitry Andric }
1433f8af5cf6SDimitry Andric
getImportTableEntry(const coff_import_directory_table_entry * & Result) const1434cfca06d7SDimitry Andric Error ImportDirectoryEntryRef::getImportTableEntry(
1435b915e9e0SDimitry Andric const coff_import_directory_table_entry *&Result) const {
143601095a5dSDimitry Andric return getObject(Result, OwningObject->Data, ImportTable + Index);
1437f8af5cf6SDimitry Andric }
1438f8af5cf6SDimitry Andric
143967c32a98SDimitry Andric static imported_symbol_iterator
makeImportedSymbolIterator(const COFFObjectFile * Object,uintptr_t Ptr,int Index)144067c32a98SDimitry Andric makeImportedSymbolIterator(const COFFObjectFile *Object,
144167c32a98SDimitry Andric uintptr_t Ptr, int Index) {
144267c32a98SDimitry Andric if (Object->getBytesInAddress() == 4) {
144367c32a98SDimitry Andric auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);
144467c32a98SDimitry Andric return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
144567c32a98SDimitry Andric }
144667c32a98SDimitry Andric auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);
144767c32a98SDimitry Andric return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
144867c32a98SDimitry Andric }
144967c32a98SDimitry Andric
145067c32a98SDimitry Andric static imported_symbol_iterator
importedSymbolBegin(uint32_t RVA,const COFFObjectFile * Object)145167c32a98SDimitry Andric importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {
145267c32a98SDimitry Andric uintptr_t IntPtr = 0;
1453cfca06d7SDimitry Andric // FIXME: Handle errors.
1454cfca06d7SDimitry Andric cantFail(Object->getRvaPtr(RVA, IntPtr));
145567c32a98SDimitry Andric return makeImportedSymbolIterator(Object, IntPtr, 0);
145667c32a98SDimitry Andric }
145767c32a98SDimitry Andric
145867c32a98SDimitry Andric static imported_symbol_iterator
importedSymbolEnd(uint32_t RVA,const COFFObjectFile * Object)145967c32a98SDimitry Andric importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {
146067c32a98SDimitry Andric uintptr_t IntPtr = 0;
1461cfca06d7SDimitry Andric // FIXME: Handle errors.
1462cfca06d7SDimitry Andric cantFail(Object->getRvaPtr(RVA, IntPtr));
146367c32a98SDimitry Andric // Forward the pointer to the last entry which is null.
146467c32a98SDimitry Andric int Index = 0;
146567c32a98SDimitry Andric if (Object->getBytesInAddress() == 4) {
146667c32a98SDimitry Andric auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);
146767c32a98SDimitry Andric while (*Entry++)
146867c32a98SDimitry Andric ++Index;
146967c32a98SDimitry Andric } else {
147067c32a98SDimitry Andric auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);
147167c32a98SDimitry Andric while (*Entry++)
147267c32a98SDimitry Andric ++Index;
147367c32a98SDimitry Andric }
147467c32a98SDimitry Andric return makeImportedSymbolIterator(Object, IntPtr, Index);
147567c32a98SDimitry Andric }
147667c32a98SDimitry Andric
147767c32a98SDimitry Andric imported_symbol_iterator
imported_symbol_begin() const147867c32a98SDimitry Andric ImportDirectoryEntryRef::imported_symbol_begin() const {
1479b915e9e0SDimitry Andric return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,
148067c32a98SDimitry Andric OwningObject);
148167c32a98SDimitry Andric }
148267c32a98SDimitry Andric
148367c32a98SDimitry Andric imported_symbol_iterator
imported_symbol_end() const148467c32a98SDimitry Andric ImportDirectoryEntryRef::imported_symbol_end() const {
1485b915e9e0SDimitry Andric return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,
148667c32a98SDimitry Andric OwningObject);
148767c32a98SDimitry Andric }
148867c32a98SDimitry Andric
148967c32a98SDimitry Andric iterator_range<imported_symbol_iterator>
imported_symbols() const149067c32a98SDimitry Andric ImportDirectoryEntryRef::imported_symbols() const {
149167c32a98SDimitry Andric return make_range(imported_symbol_begin(), imported_symbol_end());
149267c32a98SDimitry Andric }
149367c32a98SDimitry Andric
lookup_table_begin() const1494b915e9e0SDimitry Andric imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {
1495b915e9e0SDimitry Andric return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,
1496b915e9e0SDimitry Andric OwningObject);
1497b915e9e0SDimitry Andric }
1498b915e9e0SDimitry Andric
lookup_table_end() const1499b915e9e0SDimitry Andric imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {
1500b915e9e0SDimitry Andric return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,
1501b915e9e0SDimitry Andric OwningObject);
1502b915e9e0SDimitry Andric }
1503b915e9e0SDimitry Andric
1504b915e9e0SDimitry Andric iterator_range<imported_symbol_iterator>
lookup_table_symbols() const1505b915e9e0SDimitry Andric ImportDirectoryEntryRef::lookup_table_symbols() const {
1506b915e9e0SDimitry Andric return make_range(lookup_table_begin(), lookup_table_end());
1507b915e9e0SDimitry Andric }
1508b915e9e0SDimitry Andric
getName(StringRef & Result) const1509cfca06d7SDimitry Andric Error ImportDirectoryEntryRef::getName(StringRef &Result) const {
1510f8af5cf6SDimitry Andric uintptr_t IntPtr = 0;
1511145449b1SDimitry Andric if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr,
1512145449b1SDimitry Andric "import directory name"))
1513cfca06d7SDimitry Andric return E;
15145ca98fd9SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
1515cfca06d7SDimitry Andric return Error::success();
1516f8af5cf6SDimitry Andric }
1517f8af5cf6SDimitry Andric
1518cfca06d7SDimitry Andric Error
getImportLookupTableRVA(uint32_t & Result) const151967c32a98SDimitry Andric ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {
152067c32a98SDimitry Andric Result = ImportTable[Index].ImportLookupTableRVA;
1521cfca06d7SDimitry Andric return Error::success();
152267c32a98SDimitry Andric }
152367c32a98SDimitry Andric
getImportAddressTableRVA(uint32_t & Result) const1524cfca06d7SDimitry Andric Error ImportDirectoryEntryRef::getImportAddressTableRVA(
1525cfca06d7SDimitry Andric uint32_t &Result) const {
152667c32a98SDimitry Andric Result = ImportTable[Index].ImportAddressTableRVA;
1527cfca06d7SDimitry Andric return Error::success();
152867c32a98SDimitry Andric }
152967c32a98SDimitry Andric
153067c32a98SDimitry Andric bool DelayImportDirectoryEntryRef::
operator ==(const DelayImportDirectoryEntryRef & Other) const153167c32a98SDimitry Andric operator==(const DelayImportDirectoryEntryRef &Other) const {
153267c32a98SDimitry Andric return Table == Other.Table && Index == Other.Index;
153367c32a98SDimitry Andric }
153467c32a98SDimitry Andric
moveNext()153567c32a98SDimitry Andric void DelayImportDirectoryEntryRef::moveNext() {
153667c32a98SDimitry Andric ++Index;
153767c32a98SDimitry Andric }
153867c32a98SDimitry Andric
153967c32a98SDimitry Andric imported_symbol_iterator
imported_symbol_begin() const154067c32a98SDimitry Andric DelayImportDirectoryEntryRef::imported_symbol_begin() const {
154167c32a98SDimitry Andric return importedSymbolBegin(Table[Index].DelayImportNameTable,
154267c32a98SDimitry Andric OwningObject);
154367c32a98SDimitry Andric }
154467c32a98SDimitry Andric
154567c32a98SDimitry Andric imported_symbol_iterator
imported_symbol_end() const154667c32a98SDimitry Andric DelayImportDirectoryEntryRef::imported_symbol_end() const {
154767c32a98SDimitry Andric return importedSymbolEnd(Table[Index].DelayImportNameTable,
154867c32a98SDimitry Andric OwningObject);
154967c32a98SDimitry Andric }
155067c32a98SDimitry Andric
155167c32a98SDimitry Andric iterator_range<imported_symbol_iterator>
imported_symbols() const155267c32a98SDimitry Andric DelayImportDirectoryEntryRef::imported_symbols() const {
155367c32a98SDimitry Andric return make_range(imported_symbol_begin(), imported_symbol_end());
155467c32a98SDimitry Andric }
155567c32a98SDimitry Andric
getName(StringRef & Result) const1556cfca06d7SDimitry Andric Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {
155767c32a98SDimitry Andric uintptr_t IntPtr = 0;
1558145449b1SDimitry Andric if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr,
1559145449b1SDimitry Andric "delay import directory name"))
1560cfca06d7SDimitry Andric return E;
156167c32a98SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
1562cfca06d7SDimitry Andric return Error::success();
156367c32a98SDimitry Andric }
156467c32a98SDimitry Andric
getDelayImportTable(const delay_import_directory_table_entry * & Result) const1565cfca06d7SDimitry Andric Error DelayImportDirectoryEntryRef::getDelayImportTable(
1566cfca06d7SDimitry Andric const delay_import_directory_table_entry *&Result) const {
1567e6d15924SDimitry Andric Result = &Table[Index];
1568cfca06d7SDimitry Andric return Error::success();
156967c32a98SDimitry Andric }
157067c32a98SDimitry Andric
getImportAddress(int AddrIndex,uint64_t & Result) const1571cfca06d7SDimitry Andric Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,
1572cfca06d7SDimitry Andric uint64_t &Result) const {
157367c32a98SDimitry Andric uint32_t RVA = Table[Index].DelayImportAddressTable +
157467c32a98SDimitry Andric AddrIndex * (OwningObject->is64() ? 8 : 4);
157567c32a98SDimitry Andric uintptr_t IntPtr = 0;
1576145449b1SDimitry Andric if (Error E = OwningObject->getRvaPtr(RVA, IntPtr, "import address"))
1577cfca06d7SDimitry Andric return E;
157867c32a98SDimitry Andric if (OwningObject->is64())
157967c32a98SDimitry Andric Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);
158067c32a98SDimitry Andric else
158167c32a98SDimitry Andric Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);
1582cfca06d7SDimitry Andric return Error::success();
158367c32a98SDimitry Andric }
158467c32a98SDimitry Andric
15855ca98fd9SDimitry Andric bool ExportDirectoryEntryRef::
operator ==(const ExportDirectoryEntryRef & Other) const15865ca98fd9SDimitry Andric operator==(const ExportDirectoryEntryRef &Other) const {
15875ca98fd9SDimitry Andric return ExportTable == Other.ExportTable && Index == Other.Index;
1588cf099d11SDimitry Andric }
1589cf099d11SDimitry Andric
moveNext()15905ca98fd9SDimitry Andric void ExportDirectoryEntryRef::moveNext() {
15915ca98fd9SDimitry Andric ++Index;
15925ca98fd9SDimitry Andric }
15935ca98fd9SDimitry Andric
15945ca98fd9SDimitry Andric // Returns the name of the current export symbol. If the symbol is exported only
15955ca98fd9SDimitry Andric // by ordinal, the empty string is set as a result.
getDllName(StringRef & Result) const1596cfca06d7SDimitry Andric Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {
15975ca98fd9SDimitry Andric uintptr_t IntPtr = 0;
1598145449b1SDimitry Andric if (Error E =
1599145449b1SDimitry Andric OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr, "dll name"))
1600cfca06d7SDimitry Andric return E;
16015ca98fd9SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
1602cfca06d7SDimitry Andric return Error::success();
16035ca98fd9SDimitry Andric }
16045ca98fd9SDimitry Andric
16055ca98fd9SDimitry Andric // Returns the starting ordinal number.
getOrdinalBase(uint32_t & Result) const1606cfca06d7SDimitry Andric Error ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {
16075ca98fd9SDimitry Andric Result = ExportTable->OrdinalBase;
1608cfca06d7SDimitry Andric return Error::success();
16095ca98fd9SDimitry Andric }
16105ca98fd9SDimitry Andric
16115ca98fd9SDimitry Andric // Returns the export ordinal of the current export symbol.
getOrdinal(uint32_t & Result) const1612cfca06d7SDimitry Andric Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
16135ca98fd9SDimitry Andric Result = ExportTable->OrdinalBase + Index;
1614cfca06d7SDimitry Andric return Error::success();
16155ca98fd9SDimitry Andric }
16165ca98fd9SDimitry Andric
16175ca98fd9SDimitry Andric // Returns the address of the current export symbol.
getExportRVA(uint32_t & Result) const1618cfca06d7SDimitry Andric Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
16195ca98fd9SDimitry Andric uintptr_t IntPtr = 0;
1620145449b1SDimitry Andric if (Error EC = OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA,
1621145449b1SDimitry Andric IntPtr, "export address"))
16225ca98fd9SDimitry Andric return EC;
16235ca98fd9SDimitry Andric const export_address_table_entry *entry =
16245ca98fd9SDimitry Andric reinterpret_cast<const export_address_table_entry *>(IntPtr);
16255ca98fd9SDimitry Andric Result = entry[Index].ExportRVA;
1626cfca06d7SDimitry Andric return Error::success();
16275ca98fd9SDimitry Andric }
16285ca98fd9SDimitry Andric
16295ca98fd9SDimitry Andric // Returns the name of the current export symbol. If the symbol is exported only
16305ca98fd9SDimitry Andric // by ordinal, the empty string is set as a result.
1631cfca06d7SDimitry Andric Error
getSymbolName(StringRef & Result) const16325ca98fd9SDimitry Andric ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
16335ca98fd9SDimitry Andric uintptr_t IntPtr = 0;
1634145449b1SDimitry Andric if (Error EC = OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr,
1635145449b1SDimitry Andric "export ordinal table"))
16365ca98fd9SDimitry Andric return EC;
16375ca98fd9SDimitry Andric const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
16385ca98fd9SDimitry Andric
16395ca98fd9SDimitry Andric uint32_t NumEntries = ExportTable->NumberOfNamePointers;
16405ca98fd9SDimitry Andric int Offset = 0;
16415ca98fd9SDimitry Andric for (const ulittle16_t *I = Start, *E = Start + NumEntries;
16425ca98fd9SDimitry Andric I < E; ++I, ++Offset) {
16435ca98fd9SDimitry Andric if (*I != Index)
16445ca98fd9SDimitry Andric continue;
1645145449b1SDimitry Andric if (Error EC = OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr,
1646145449b1SDimitry Andric "export table entry"))
16475ca98fd9SDimitry Andric return EC;
16485ca98fd9SDimitry Andric const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
1649145449b1SDimitry Andric if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr,
1650145449b1SDimitry Andric "export symbol name"))
16515ca98fd9SDimitry Andric return EC;
16525ca98fd9SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
1653cfca06d7SDimitry Andric return Error::success();
16545ca98fd9SDimitry Andric }
16555ca98fd9SDimitry Andric Result = "";
1656cfca06d7SDimitry Andric return Error::success();
16575ca98fd9SDimitry Andric }
16585ca98fd9SDimitry Andric
isForwarder(bool & Result) const1659cfca06d7SDimitry Andric Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {
1660cfca06d7SDimitry Andric const data_directory *DataEntry =
1661cfca06d7SDimitry Andric OwningObject->getDataDirectory(COFF::EXPORT_TABLE);
1662cfca06d7SDimitry Andric if (!DataEntry)
1663145449b1SDimitry Andric return createStringError(object_error::parse_failed,
1664145449b1SDimitry Andric "export table missing");
1665050e163aSDimitry Andric uint32_t RVA;
1666050e163aSDimitry Andric if (auto EC = getExportRVA(RVA))
1667050e163aSDimitry Andric return EC;
1668050e163aSDimitry Andric uint32_t Begin = DataEntry->RelativeVirtualAddress;
1669050e163aSDimitry Andric uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;
1670050e163aSDimitry Andric Result = (Begin <= RVA && RVA < End);
1671cfca06d7SDimitry Andric return Error::success();
1672050e163aSDimitry Andric }
1673050e163aSDimitry Andric
getForwardTo(StringRef & Result) const1674cfca06d7SDimitry Andric Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
1675050e163aSDimitry Andric uint32_t RVA;
1676050e163aSDimitry Andric if (auto EC = getExportRVA(RVA))
1677050e163aSDimitry Andric return EC;
1678050e163aSDimitry Andric uintptr_t IntPtr = 0;
1679145449b1SDimitry Andric if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr, "export forward target"))
1680050e163aSDimitry Andric return EC;
1681050e163aSDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr));
1682cfca06d7SDimitry Andric return Error::success();
1683050e163aSDimitry Andric }
1684050e163aSDimitry Andric
168567c32a98SDimitry Andric bool ImportedSymbolRef::
operator ==(const ImportedSymbolRef & Other) const168667c32a98SDimitry Andric operator==(const ImportedSymbolRef &Other) const {
168767c32a98SDimitry Andric return Entry32 == Other.Entry32 && Entry64 == Other.Entry64
168867c32a98SDimitry Andric && Index == Other.Index;
168967c32a98SDimitry Andric }
169067c32a98SDimitry Andric
moveNext()169167c32a98SDimitry Andric void ImportedSymbolRef::moveNext() {
169267c32a98SDimitry Andric ++Index;
169367c32a98SDimitry Andric }
169467c32a98SDimitry Andric
getSymbolName(StringRef & Result) const1695cfca06d7SDimitry Andric Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {
169667c32a98SDimitry Andric uint32_t RVA;
169767c32a98SDimitry Andric if (Entry32) {
169867c32a98SDimitry Andric // If a symbol is imported only by ordinal, it has no name.
169967c32a98SDimitry Andric if (Entry32[Index].isOrdinal())
1700cfca06d7SDimitry Andric return Error::success();
170167c32a98SDimitry Andric RVA = Entry32[Index].getHintNameRVA();
170267c32a98SDimitry Andric } else {
170367c32a98SDimitry Andric if (Entry64[Index].isOrdinal())
1704cfca06d7SDimitry Andric return Error::success();
170567c32a98SDimitry Andric RVA = Entry64[Index].getHintNameRVA();
170667c32a98SDimitry Andric }
170767c32a98SDimitry Andric uintptr_t IntPtr = 0;
1708145449b1SDimitry Andric if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol name"))
170967c32a98SDimitry Andric return EC;
171067c32a98SDimitry Andric // +2 because the first two bytes is hint.
171167c32a98SDimitry Andric Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));
1712cfca06d7SDimitry Andric return Error::success();
171367c32a98SDimitry Andric }
171467c32a98SDimitry Andric
isOrdinal(bool & Result) const1715cfca06d7SDimitry Andric Error ImportedSymbolRef::isOrdinal(bool &Result) const {
171601095a5dSDimitry Andric if (Entry32)
171701095a5dSDimitry Andric Result = Entry32[Index].isOrdinal();
171801095a5dSDimitry Andric else
171901095a5dSDimitry Andric Result = Entry64[Index].isOrdinal();
1720cfca06d7SDimitry Andric return Error::success();
172101095a5dSDimitry Andric }
172201095a5dSDimitry Andric
getHintNameRVA(uint32_t & Result) const1723cfca06d7SDimitry Andric Error ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {
172401095a5dSDimitry Andric if (Entry32)
172501095a5dSDimitry Andric Result = Entry32[Index].getHintNameRVA();
172601095a5dSDimitry Andric else
172701095a5dSDimitry Andric Result = Entry64[Index].getHintNameRVA();
1728cfca06d7SDimitry Andric return Error::success();
172901095a5dSDimitry Andric }
173001095a5dSDimitry Andric
getOrdinal(uint16_t & Result) const1731cfca06d7SDimitry Andric Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {
173267c32a98SDimitry Andric uint32_t RVA;
173367c32a98SDimitry Andric if (Entry32) {
173467c32a98SDimitry Andric if (Entry32[Index].isOrdinal()) {
173567c32a98SDimitry Andric Result = Entry32[Index].getOrdinal();
1736cfca06d7SDimitry Andric return Error::success();
173767c32a98SDimitry Andric }
173867c32a98SDimitry Andric RVA = Entry32[Index].getHintNameRVA();
173967c32a98SDimitry Andric } else {
174067c32a98SDimitry Andric if (Entry64[Index].isOrdinal()) {
174167c32a98SDimitry Andric Result = Entry64[Index].getOrdinal();
1742cfca06d7SDimitry Andric return Error::success();
174367c32a98SDimitry Andric }
174467c32a98SDimitry Andric RVA = Entry64[Index].getHintNameRVA();
174567c32a98SDimitry Andric }
174667c32a98SDimitry Andric uintptr_t IntPtr = 0;
1747145449b1SDimitry Andric if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol ordinal"))
174867c32a98SDimitry Andric return EC;
174967c32a98SDimitry Andric Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);
1750cfca06d7SDimitry Andric return Error::success();
175167c32a98SDimitry Andric }
175267c32a98SDimitry Andric
1753044eb2f6SDimitry Andric Expected<std::unique_ptr<COFFObjectFile>>
createCOFFObjectFile(MemoryBufferRef Object)175467c32a98SDimitry Andric ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {
1755cfca06d7SDimitry Andric return COFFObjectFile::create(Object);
175667c32a98SDimitry Andric }
175767c32a98SDimitry Andric
operator ==(const BaseRelocRef & Other) const175867c32a98SDimitry Andric bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {
175967c32a98SDimitry Andric return Header == Other.Header && Index == Other.Index;
176067c32a98SDimitry Andric }
176167c32a98SDimitry Andric
moveNext()176267c32a98SDimitry Andric void BaseRelocRef::moveNext() {
176367c32a98SDimitry Andric // Header->BlockSize is the size of the current block, including the
176467c32a98SDimitry Andric // size of the header itself.
176567c32a98SDimitry Andric uint32_t Size = sizeof(*Header) +
176667c32a98SDimitry Andric sizeof(coff_base_reloc_block_entry) * (Index + 1);
176767c32a98SDimitry Andric if (Size == Header->BlockSize) {
176867c32a98SDimitry Andric // .reloc contains a list of base relocation blocks. Each block
176967c32a98SDimitry Andric // consists of the header followed by entries. The header contains
177067c32a98SDimitry Andric // how many entories will follow. When we reach the end of the
177167c32a98SDimitry Andric // current block, proceed to the next block.
177267c32a98SDimitry Andric Header = reinterpret_cast<const coff_base_reloc_block_header *>(
177367c32a98SDimitry Andric reinterpret_cast<const uint8_t *>(Header) + Size);
177467c32a98SDimitry Andric Index = 0;
177567c32a98SDimitry Andric } else {
177667c32a98SDimitry Andric ++Index;
177767c32a98SDimitry Andric }
177867c32a98SDimitry Andric }
177967c32a98SDimitry Andric
getType(uint8_t & Type) const1780cfca06d7SDimitry Andric Error BaseRelocRef::getType(uint8_t &Type) const {
178167c32a98SDimitry Andric auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
178267c32a98SDimitry Andric Type = Entry[Index].getType();
1783cfca06d7SDimitry Andric return Error::success();
178467c32a98SDimitry Andric }
178567c32a98SDimitry Andric
getRVA(uint32_t & Result) const1786cfca06d7SDimitry Andric Error BaseRelocRef::getRVA(uint32_t &Result) const {
178767c32a98SDimitry Andric auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
178867c32a98SDimitry Andric Result = Header->PageRVA + Entry[Index].getOffset();
1789cfca06d7SDimitry Andric return Error::success();
17905ca98fd9SDimitry Andric }
1791c46e6a59SDimitry Andric
17921d5ae102SDimitry Andric #define RETURN_IF_ERROR(Expr) \
17931d5ae102SDimitry Andric do { \
17941d5ae102SDimitry Andric Error E = (Expr); \
1795044eb2f6SDimitry Andric if (E) \
17961d5ae102SDimitry Andric return std::move(E); \
17971d5ae102SDimitry Andric } while (0)
1798c46e6a59SDimitry Andric
1799044eb2f6SDimitry Andric Expected<ArrayRef<UTF16>>
getDirStringAtOffset(uint32_t Offset)1800044eb2f6SDimitry Andric ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {
1801c46e6a59SDimitry Andric BinaryStreamReader Reader = BinaryStreamReader(BBS);
1802c46e6a59SDimitry Andric Reader.setOffset(Offset);
1803c46e6a59SDimitry Andric uint16_t Length;
1804c46e6a59SDimitry Andric RETURN_IF_ERROR(Reader.readInteger(Length));
1805c46e6a59SDimitry Andric ArrayRef<UTF16> RawDirString;
1806c46e6a59SDimitry Andric RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));
1807c46e6a59SDimitry Andric return RawDirString;
1808c46e6a59SDimitry Andric }
1809c46e6a59SDimitry Andric
1810044eb2f6SDimitry Andric Expected<ArrayRef<UTF16>>
getEntryNameString(const coff_resource_dir_entry & Entry)1811c46e6a59SDimitry Andric ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {
1812c46e6a59SDimitry Andric return getDirStringAtOffset(Entry.Identifier.getNameOffset());
1813c46e6a59SDimitry Andric }
1814c46e6a59SDimitry Andric
1815044eb2f6SDimitry Andric Expected<const coff_resource_dir_table &>
getTableAtOffset(uint32_t Offset)1816c46e6a59SDimitry Andric ResourceSectionRef::getTableAtOffset(uint32_t Offset) {
1817c46e6a59SDimitry Andric const coff_resource_dir_table *Table = nullptr;
1818c46e6a59SDimitry Andric
1819c46e6a59SDimitry Andric BinaryStreamReader Reader(BBS);
1820c46e6a59SDimitry Andric Reader.setOffset(Offset);
1821c46e6a59SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Table));
1822c46e6a59SDimitry Andric assert(Table != nullptr);
1823c46e6a59SDimitry Andric return *Table;
1824c46e6a59SDimitry Andric }
1825c46e6a59SDimitry Andric
18261d5ae102SDimitry Andric Expected<const coff_resource_dir_entry &>
getTableEntryAtOffset(uint32_t Offset)18271d5ae102SDimitry Andric ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {
18281d5ae102SDimitry Andric const coff_resource_dir_entry *Entry = nullptr;
18291d5ae102SDimitry Andric
18301d5ae102SDimitry Andric BinaryStreamReader Reader(BBS);
18311d5ae102SDimitry Andric Reader.setOffset(Offset);
18321d5ae102SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Entry));
18331d5ae102SDimitry Andric assert(Entry != nullptr);
18341d5ae102SDimitry Andric return *Entry;
18351d5ae102SDimitry Andric }
18361d5ae102SDimitry Andric
18371d5ae102SDimitry Andric Expected<const coff_resource_data_entry &>
getDataEntryAtOffset(uint32_t Offset)18381d5ae102SDimitry Andric ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {
18391d5ae102SDimitry Andric const coff_resource_data_entry *Entry = nullptr;
18401d5ae102SDimitry Andric
18411d5ae102SDimitry Andric BinaryStreamReader Reader(BBS);
18421d5ae102SDimitry Andric Reader.setOffset(Offset);
18431d5ae102SDimitry Andric RETURN_IF_ERROR(Reader.readObject(Entry));
18441d5ae102SDimitry Andric assert(Entry != nullptr);
18451d5ae102SDimitry Andric return *Entry;
18461d5ae102SDimitry Andric }
18471d5ae102SDimitry Andric
1848044eb2f6SDimitry Andric Expected<const coff_resource_dir_table &>
getEntrySubDir(const coff_resource_dir_entry & Entry)1849c46e6a59SDimitry Andric ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {
18501d5ae102SDimitry Andric assert(Entry.Offset.isSubDir());
1851c46e6a59SDimitry Andric return getTableAtOffset(Entry.Offset.value());
1852c46e6a59SDimitry Andric }
1853c46e6a59SDimitry Andric
18541d5ae102SDimitry Andric Expected<const coff_resource_data_entry &>
getEntryData(const coff_resource_dir_entry & Entry)18551d5ae102SDimitry Andric ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {
18561d5ae102SDimitry Andric assert(!Entry.Offset.isSubDir());
18571d5ae102SDimitry Andric return getDataEntryAtOffset(Entry.Offset.value());
18581d5ae102SDimitry Andric }
18591d5ae102SDimitry Andric
getBaseTable()1860044eb2f6SDimitry Andric Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {
1861c46e6a59SDimitry Andric return getTableAtOffset(0);
1862c46e6a59SDimitry Andric }
18631d5ae102SDimitry Andric
18641d5ae102SDimitry Andric Expected<const coff_resource_dir_entry &>
getTableEntry(const coff_resource_dir_table & Table,uint32_t Index)18651d5ae102SDimitry Andric ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,
18661d5ae102SDimitry Andric uint32_t Index) {
18671d5ae102SDimitry Andric if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))
18681d5ae102SDimitry Andric return createStringError(object_error::parse_failed, "index out of range");
18691d5ae102SDimitry Andric const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);
18701d5ae102SDimitry Andric ptrdiff_t TableOffset = TablePtr - BBS.data().data();
18711d5ae102SDimitry Andric return getTableEntryAtOffset(TableOffset + sizeof(Table) +
18721d5ae102SDimitry Andric Index * sizeof(coff_resource_dir_entry));
18731d5ae102SDimitry Andric }
18741d5ae102SDimitry Andric
load(const COFFObjectFile * O)18751d5ae102SDimitry Andric Error ResourceSectionRef::load(const COFFObjectFile *O) {
18761d5ae102SDimitry Andric for (const SectionRef &S : O->sections()) {
18771d5ae102SDimitry Andric Expected<StringRef> Name = S.getName();
18781d5ae102SDimitry Andric if (!Name)
18791d5ae102SDimitry Andric return Name.takeError();
18801d5ae102SDimitry Andric
18811d5ae102SDimitry Andric if (*Name == ".rsrc" || *Name == ".rsrc$01")
18821d5ae102SDimitry Andric return load(O, S);
18831d5ae102SDimitry Andric }
18841d5ae102SDimitry Andric return createStringError(object_error::parse_failed,
18851d5ae102SDimitry Andric "no resource section found");
18861d5ae102SDimitry Andric }
18871d5ae102SDimitry Andric
load(const COFFObjectFile * O,const SectionRef & S)18881d5ae102SDimitry Andric Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {
18891d5ae102SDimitry Andric Obj = O;
18901d5ae102SDimitry Andric Section = S;
18911d5ae102SDimitry Andric Expected<StringRef> Contents = Section.getContents();
18921d5ae102SDimitry Andric if (!Contents)
18931d5ae102SDimitry Andric return Contents.takeError();
1894b1c73532SDimitry Andric BBS = BinaryByteStream(*Contents, llvm::endianness::little);
18951d5ae102SDimitry Andric const coff_section *COFFSect = Obj->getCOFFSection(Section);
18961d5ae102SDimitry Andric ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);
18971d5ae102SDimitry Andric Relocs.reserve(OrigRelocs.size());
18981d5ae102SDimitry Andric for (const coff_relocation &R : OrigRelocs)
18991d5ae102SDimitry Andric Relocs.push_back(&R);
1900b60736ecSDimitry Andric llvm::sort(Relocs, [](const coff_relocation *A, const coff_relocation *B) {
19011d5ae102SDimitry Andric return A->VirtualAddress < B->VirtualAddress;
19021d5ae102SDimitry Andric });
19031d5ae102SDimitry Andric return Error::success();
19041d5ae102SDimitry Andric }
19051d5ae102SDimitry Andric
19061d5ae102SDimitry Andric Expected<StringRef>
getContents(const coff_resource_data_entry & Entry)19071d5ae102SDimitry Andric ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
19081d5ae102SDimitry Andric if (!Obj)
19091d5ae102SDimitry Andric return createStringError(object_error::parse_failed, "no object provided");
19101d5ae102SDimitry Andric
19111d5ae102SDimitry Andric // Find a potential relocation at the DataRVA field (first member of
19121d5ae102SDimitry Andric // the coff_resource_data_entry struct).
19131d5ae102SDimitry Andric const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);
19141d5ae102SDimitry Andric ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();
19151d5ae102SDimitry Andric coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),
19161d5ae102SDimitry Andric ulittle16_t(0)};
19171d5ae102SDimitry Andric auto RelocsForOffset =
19181d5ae102SDimitry Andric std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,
19191d5ae102SDimitry Andric [](const coff_relocation *A, const coff_relocation *B) {
19201d5ae102SDimitry Andric return A->VirtualAddress < B->VirtualAddress;
19211d5ae102SDimitry Andric });
19221d5ae102SDimitry Andric
19231d5ae102SDimitry Andric if (RelocsForOffset.first != RelocsForOffset.second) {
19241d5ae102SDimitry Andric // We found a relocation with the right offset. Check that it does have
19251d5ae102SDimitry Andric // the expected type.
19261d5ae102SDimitry Andric const coff_relocation &R = **RelocsForOffset.first;
19271d5ae102SDimitry Andric uint16_t RVAReloc;
1928ac9a064cSDimitry Andric switch (Obj->getArch()) {
1929ac9a064cSDimitry Andric case Triple::x86:
19301d5ae102SDimitry Andric RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;
19311d5ae102SDimitry Andric break;
1932ac9a064cSDimitry Andric case Triple::x86_64:
19331d5ae102SDimitry Andric RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;
19341d5ae102SDimitry Andric break;
1935ac9a064cSDimitry Andric case Triple::thumb:
19361d5ae102SDimitry Andric RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;
19371d5ae102SDimitry Andric break;
1938ac9a064cSDimitry Andric case Triple::aarch64:
19391d5ae102SDimitry Andric RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
19401d5ae102SDimitry Andric break;
19411d5ae102SDimitry Andric default:
19421d5ae102SDimitry Andric return createStringError(object_error::parse_failed,
19431d5ae102SDimitry Andric "unsupported architecture");
19441d5ae102SDimitry Andric }
19451d5ae102SDimitry Andric if (R.Type != RVAReloc)
19461d5ae102SDimitry Andric return createStringError(object_error::parse_failed,
19471d5ae102SDimitry Andric "unexpected relocation type");
19481d5ae102SDimitry Andric // Get the relocation's symbol
19491d5ae102SDimitry Andric Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);
19501d5ae102SDimitry Andric if (!Sym)
19511d5ae102SDimitry Andric return Sym.takeError();
19521d5ae102SDimitry Andric // And the symbol's section
1953cfca06d7SDimitry Andric Expected<const coff_section *> Section =
1954cfca06d7SDimitry Andric Obj->getSection(Sym->getSectionNumber());
1955cfca06d7SDimitry Andric if (!Section)
1956cfca06d7SDimitry Andric return Section.takeError();
19571d5ae102SDimitry Andric // Add the initial value of DataRVA to the symbol's offset to find the
19581d5ae102SDimitry Andric // data it points at.
19591d5ae102SDimitry Andric uint64_t Offset = Entry.DataRVA + Sym->getValue();
19601d5ae102SDimitry Andric ArrayRef<uint8_t> Contents;
1961cfca06d7SDimitry Andric if (Error E = Obj->getSectionContents(*Section, Contents))
1962ac9a064cSDimitry Andric return E;
19631d5ae102SDimitry Andric if (Offset + Entry.DataSize > Contents.size())
19641d5ae102SDimitry Andric return createStringError(object_error::parse_failed,
19651d5ae102SDimitry Andric "data outside of section");
19661d5ae102SDimitry Andric // Return a reference to the data inside the section.
19671d5ae102SDimitry Andric return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,
19681d5ae102SDimitry Andric Entry.DataSize);
19691d5ae102SDimitry Andric } else {
19701d5ae102SDimitry Andric // Relocatable objects need a relocation for the DataRVA field.
19711d5ae102SDimitry Andric if (Obj->isRelocatableObject())
19721d5ae102SDimitry Andric return createStringError(object_error::parse_failed,
19731d5ae102SDimitry Andric "no relocation found for DataRVA");
19741d5ae102SDimitry Andric
19751d5ae102SDimitry Andric // Locate the section that contains the address that DataRVA points at.
19761d5ae102SDimitry Andric uint64_t VA = Entry.DataRVA + Obj->getImageBase();
19771d5ae102SDimitry Andric for (const SectionRef &S : Obj->sections()) {
19781d5ae102SDimitry Andric if (VA >= S.getAddress() &&
19791d5ae102SDimitry Andric VA + Entry.DataSize <= S.getAddress() + S.getSize()) {
19801d5ae102SDimitry Andric uint64_t Offset = VA - S.getAddress();
19811d5ae102SDimitry Andric Expected<StringRef> Contents = S.getContents();
19821d5ae102SDimitry Andric if (!Contents)
19831d5ae102SDimitry Andric return Contents.takeError();
19841d5ae102SDimitry Andric return Contents->slice(Offset, Offset + Entry.DataSize);
19851d5ae102SDimitry Andric }
19861d5ae102SDimitry Andric }
19871d5ae102SDimitry Andric return createStringError(object_error::parse_failed,
19881d5ae102SDimitry Andric "address not found in image");
19891d5ae102SDimitry Andric }
19901d5ae102SDimitry Andric }
1991