1218885Sdim//===- COFFObjectFile.cpp - COFF object file implementation -----*- C++ -*-===// 2218885Sdim// 3218885Sdim// The LLVM Compiler Infrastructure 4218885Sdim// 5218885Sdim// This file is distributed under the University of Illinois Open Source 6218885Sdim// License. See LICENSE.TXT for details. 7218885Sdim// 8218885Sdim//===----------------------------------------------------------------------===// 9218885Sdim// 10218885Sdim// This file declares the COFFObjectFile class. 11218885Sdim// 12218885Sdim//===----------------------------------------------------------------------===// 13218885Sdim 14224145Sdim#include "llvm/Object/COFF.h" 15234353Sdim#include "llvm/ADT/ArrayRef.h" 16226633Sdim#include "llvm/ADT/SmallString.h" 17218885Sdim#include "llvm/ADT/StringSwitch.h" 18218885Sdim#include "llvm/ADT/Triple.h" 19288943Sdim#include "llvm/ADT/iterator_range.h" 20276479Sdim#include "llvm/Support/COFF.h" 21261991Sdim#include "llvm/Support/Debug.h" 22261991Sdim#include "llvm/Support/raw_ostream.h" 23261991Sdim#include <cctype> 24276479Sdim#include <limits> 25218885Sdim 26218885Sdimusing namespace llvm; 27218885Sdimusing namespace object; 28218885Sdim 29218885Sdimusing support::ulittle16_t; 30218885Sdimusing support::ulittle32_t; 31280031Sdimusing support::ulittle64_t; 32218885Sdimusing support::little16_t; 33218885Sdim 34224145Sdim// Returns false if size is greater than the buffer size. And sets ec. 35280031Sdimstatic bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) { 36276479Sdim if (M.getBufferSize() < Size) { 37276479Sdim EC = object_error::unexpected_eof; 38224145Sdim return false; 39224145Sdim } 40224145Sdim return true; 41218885Sdim} 42218885Sdim 43280031Sdimstatic std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, 44280031Sdim const uint64_t Size) { 45280031Sdim if (Addr + Size < Addr || Addr + Size < Size || 46280031Sdim Addr + Size > uintptr_t(M.getBufferEnd()) || 47280031Sdim Addr < uintptr_t(M.getBufferStart())) { 48280031Sdim return object_error::unexpected_eof; 49280031Sdim } 50288943Sdim return std::error_code(); 51280031Sdim} 52280031Sdim 53261991Sdim// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. 54261991Sdim// Returns unexpected_eof if error. 55276479Sdimtemplate <typename T> 56280031Sdimstatic std::error_code getObject(const T *&Obj, MemoryBufferRef M, 57280031Sdim const void *Ptr, 58280031Sdim const uint64_t Size = sizeof(T)) { 59261991Sdim uintptr_t Addr = uintptr_t(Ptr); 60280031Sdim if (std::error_code EC = checkOffset(M, Addr, Size)) 61280031Sdim return EC; 62261991Sdim Obj = reinterpret_cast<const T *>(Addr); 63288943Sdim return std::error_code(); 64224145Sdim} 65276479Sdim 66276479Sdim// Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without 67276479Sdim// prefixed slashes. 68276479Sdimstatic bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) { 69276479Sdim assert(Str.size() <= 6 && "String too long, possible overflow."); 70276479Sdim if (Str.size() > 6) 71276479Sdim return true; 72276479Sdim 73276479Sdim uint64_t Value = 0; 74276479Sdim while (!Str.empty()) { 75276479Sdim unsigned CharVal; 76276479Sdim if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..25 77276479Sdim CharVal = Str[0] - 'A'; 78276479Sdim else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..51 79276479Sdim CharVal = Str[0] - 'a' + 26; 80276479Sdim else if (Str[0] >= '0' && Str[0] <= '9') // 52..61 81276479Sdim CharVal = Str[0] - '0' + 52; 82276479Sdim else if (Str[0] == '+') // 62 83276479Sdim CharVal = 62; 84276479Sdim else if (Str[0] == '/') // 63 85276479Sdim CharVal = 63; 86276479Sdim else 87276479Sdim return true; 88276479Sdim 89276479Sdim Value = (Value * 64) + CharVal; 90276479Sdim Str = Str.substr(1); 91276479Sdim } 92276479Sdim 93276479Sdim if (Value > std::numeric_limits<uint32_t>::max()) 94276479Sdim return true; 95276479Sdim 96276479Sdim Result = static_cast<uint32_t>(Value); 97276479Sdim return false; 98224145Sdim} 99218885Sdim 100280031Sdimtemplate <typename coff_symbol_type> 101280031Sdimconst coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const { 102280031Sdim const coff_symbol_type *Addr = 103280031Sdim reinterpret_cast<const coff_symbol_type *>(Ref.p); 104218885Sdim 105280031Sdim assert(!checkOffset(Data, uintptr_t(Addr), sizeof(*Addr))); 106280031Sdim#ifndef NDEBUG 107224145Sdim // Verify that the symbol points to a valid entry in the symbol table. 108276479Sdim uintptr_t Offset = uintptr_t(Addr) - uintptr_t(base()); 109218885Sdim 110280031Sdim assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 && 111280031Sdim "Symbol did not point to the beginning of a symbol"); 112280031Sdim#endif 113218885Sdim 114276479Sdim return Addr; 115218885Sdim} 116218885Sdim 117276479Sdimconst coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const { 118276479Sdim const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p); 119218885Sdim 120224145Sdim# ifndef NDEBUG 121224145Sdim // Verify that the section points to a valid entry in the section table. 122280031Sdim if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections())) 123224145Sdim report_fatal_error("Section was outside of section table."); 124218885Sdim 125276479Sdim uintptr_t Offset = uintptr_t(Addr) - uintptr_t(SectionTable); 126276479Sdim assert(Offset % sizeof(coff_section) == 0 && 127224145Sdim "Section did not point to the beginning of a section"); 128224145Sdim# endif 129218885Sdim 130276479Sdim return Addr; 131224145Sdim} 132218885Sdim 133276479Sdimvoid COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const { 134280031Sdim auto End = reinterpret_cast<uintptr_t>(StringTable); 135280031Sdim if (SymbolTable16) { 136280031Sdim const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref); 137280031Sdim Symb += 1 + Symb->NumberOfAuxSymbols; 138280031Sdim Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End); 139280031Sdim } else if (SymbolTable32) { 140280031Sdim const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref); 141280031Sdim Symb += 1 + Symb->NumberOfAuxSymbols; 142280031Sdim Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End); 143280031Sdim } else { 144280031Sdim llvm_unreachable("no symbol table pointer!"); 145280031Sdim } 146218885Sdim} 147218885Sdim 148288943SdimErrorOr<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const { 149280031Sdim COFFSymbolRef Symb = getCOFFSymbol(Ref); 150288943Sdim StringRef Result; 151288943Sdim std::error_code EC = getSymbolName(Symb, Result); 152288943Sdim if (EC) 153288943Sdim return EC; 154288943Sdim return Result; 155218885Sdim} 156218885Sdim 157288943Sdimuint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const { 158288943Sdim return getCOFFSymbol(Ref).getValue(); 159288943Sdim} 160288943Sdim 161288943SdimErrorOr<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const { 162288943Sdim uint64_t Result = getSymbolValue(Ref); 163280031Sdim COFFSymbolRef Symb = getCOFFSymbol(Ref); 164280031Sdim int32_t SectionNumber = Symb.getSectionNumber(); 165280031Sdim 166288943Sdim if (Symb.isAnyUndefined() || Symb.isCommon() || 167288943Sdim COFF::isReservedSectionNumber(SectionNumber)) 168288943Sdim return Result; 169280031Sdim 170288943Sdim const coff_section *Section = nullptr; 171288943Sdim if (std::error_code EC = getSection(SectionNumber, Section)) 172288943Sdim return EC; 173288943Sdim Result += Section->VirtualAddress; 174296417Sdim 175296417Sdim // The section VirtualAddress does not include ImageBase, and we want to 176296417Sdim // return virtual addresses. 177296417Sdim Result += getImageBase(); 178296417Sdim 179288943Sdim return Result; 180218885Sdim} 181218885Sdim 182288943SdimSymbolRef::Type COFFObjectFile::getSymbolType(DataRefImpl Ref) const { 183280031Sdim COFFSymbolRef Symb = getCOFFSymbol(Ref); 184280031Sdim int32_t SectionNumber = Symb.getSectionNumber(); 185280031Sdim 186296417Sdim if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION) 187296417Sdim return SymbolRef::ST_Function; 188288943Sdim if (Symb.isAnyUndefined()) 189288943Sdim return SymbolRef::ST_Unknown; 190288943Sdim if (Symb.isCommon()) 191288943Sdim return SymbolRef::ST_Data; 192288943Sdim if (Symb.isFileRecord()) 193288943Sdim return SymbolRef::ST_File; 194288943Sdim 195288943Sdim // TODO: perhaps we need a new symbol type ST_Section. 196288943Sdim if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition()) 197288943Sdim return SymbolRef::ST_Debug; 198288943Sdim 199288943Sdim if (!COFF::isReservedSectionNumber(SectionNumber)) 200288943Sdim return SymbolRef::ST_Data; 201288943Sdim 202288943Sdim return SymbolRef::ST_Other; 203226633Sdim} 204226633Sdim 205276479Sdimuint32_t COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const { 206280031Sdim COFFSymbolRef Symb = getCOFFSymbol(Ref); 207276479Sdim uint32_t Result = SymbolRef::SF_None; 208234353Sdim 209280031Sdim if (Symb.isExternal() || Symb.isWeakExternal()) 210234353Sdim Result |= SymbolRef::SF_Global; 211234353Sdim 212280031Sdim if (Symb.isWeakExternal()) 213234353Sdim Result |= SymbolRef::SF_Weak; 214234353Sdim 215280031Sdim if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE) 216234353Sdim Result |= SymbolRef::SF_Absolute; 217234353Sdim 218280031Sdim if (Symb.isFileRecord()) 219280031Sdim Result |= SymbolRef::SF_FormatSpecific; 220280031Sdim 221280031Sdim if (Symb.isSectionDefinition()) 222280031Sdim Result |= SymbolRef::SF_FormatSpecific; 223280031Sdim 224280031Sdim if (Symb.isCommon()) 225280031Sdim Result |= SymbolRef::SF_Common; 226280031Sdim 227280031Sdim if (Symb.isAnyUndefined()) 228280031Sdim Result |= SymbolRef::SF_Undefined; 229280031Sdim 230276479Sdim return Result; 231226633Sdim} 232226633Sdim 233288943Sdimuint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const { 234280031Sdim COFFSymbolRef Symb = getCOFFSymbol(Ref); 235288943Sdim return Symb.getValue(); 236218885Sdim} 237218885Sdim 238296417SdimErrorOr<section_iterator> 239296417SdimCOFFObjectFile::getSymbolSection(DataRefImpl Ref) const { 240280031Sdim COFFSymbolRef Symb = getCOFFSymbol(Ref); 241296417Sdim if (COFF::isReservedSectionNumber(Symb.getSectionNumber())) 242296417Sdim return section_end(); 243296417Sdim const coff_section *Sec = nullptr; 244296417Sdim if (std::error_code EC = getSection(Symb.getSectionNumber(), Sec)) 245296417Sdim return EC; 246296417Sdim DataRefImpl Ret; 247296417Sdim Ret.p = reinterpret_cast<uintptr_t>(Sec); 248296417Sdim return section_iterator(SectionRef(Ret, this)); 249218885Sdim} 250218885Sdim 251288943Sdimunsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const { 252288943Sdim COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl()); 253288943Sdim return Symb.getSectionNumber(); 254288943Sdim} 255288943Sdim 256276479Sdimvoid COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const { 257276479Sdim const coff_section *Sec = toSec(Ref); 258276479Sdim Sec += 1; 259276479Sdim Ref.p = reinterpret_cast<uintptr_t>(Sec); 260243830Sdim} 261243830Sdim 262276479Sdimstd::error_code COFFObjectFile::getSectionName(DataRefImpl Ref, 263276479Sdim StringRef &Result) const { 264276479Sdim const coff_section *Sec = toSec(Ref); 265276479Sdim return getSectionName(Sec, Result); 266218885Sdim} 267218885Sdim 268280031Sdimuint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const { 269276479Sdim const coff_section *Sec = toSec(Ref); 270296417Sdim uint64_t Result = Sec->VirtualAddress; 271296417Sdim 272296417Sdim // The section VirtualAddress does not include ImageBase, and we want to 273296417Sdim // return virtual addresses. 274296417Sdim Result += getImageBase(); 275296417Sdim return Result; 276218885Sdim} 277218885Sdim 278280031Sdimuint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const { 279280031Sdim return getSectionSize(toSec(Ref)); 280218885Sdim} 281218885Sdim 282276479Sdimstd::error_code COFFObjectFile::getSectionContents(DataRefImpl Ref, 283276479Sdim StringRef &Result) const { 284276479Sdim const coff_section *Sec = toSec(Ref); 285234353Sdim ArrayRef<uint8_t> Res; 286276479Sdim std::error_code EC = getSectionContents(Sec, Res); 287234353Sdim Result = StringRef(reinterpret_cast<const char*>(Res.data()), Res.size()); 288234353Sdim return EC; 289218885Sdim} 290218885Sdim 291280031Sdimuint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const { 292276479Sdim const coff_section *Sec = toSec(Ref); 293280031Sdim return uint64_t(1) << (((Sec->Characteristics & 0x00F00000) >> 20) - 1); 294226633Sdim} 295226633Sdim 296280031Sdimbool COFFObjectFile::isSectionText(DataRefImpl Ref) const { 297276479Sdim const coff_section *Sec = toSec(Ref); 298280031Sdim return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE; 299218885Sdim} 300218885Sdim 301280031Sdimbool COFFObjectFile::isSectionData(DataRefImpl Ref) const { 302276479Sdim const coff_section *Sec = toSec(Ref); 303280031Sdim return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA; 304226633Sdim} 305226633Sdim 306280031Sdimbool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const { 307276479Sdim const coff_section *Sec = toSec(Ref); 308288943Sdim const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA | 309288943Sdim COFF::IMAGE_SCN_MEM_READ | 310288943Sdim COFF::IMAGE_SCN_MEM_WRITE; 311288943Sdim return (Sec->Characteristics & BssFlags) == BssFlags; 312226633Sdim} 313226633Sdim 314288943Sdimunsigned COFFObjectFile::getSectionID(SectionRef Sec) const { 315288943Sdim uintptr_t Offset = 316288943Sdim uintptr_t(Sec.getRawDataRefImpl().p) - uintptr_t(SectionTable); 317288943Sdim assert((Offset % sizeof(coff_section)) == 0); 318288943Sdim return (Offset / sizeof(coff_section)) + 1; 319288943Sdim} 320288943Sdim 321280031Sdimbool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const { 322276479Sdim const coff_section *Sec = toSec(Ref); 323288943Sdim // In COFF, a virtual section won't have any in-file 324288943Sdim // content, so the file pointer to the content will be zero. 325288943Sdim return Sec->PointerToRawData == 0; 326234353Sdim} 327234353Sdim 328276479Sdimstatic uint32_t getNumberOfRelocations(const coff_section *Sec, 329280031Sdim MemoryBufferRef M, const uint8_t *base) { 330276479Sdim // The field for the number of relocations in COFF section table is only 331276479Sdim // 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to 332276479Sdim // NumberOfRelocations field, and the actual relocation count is stored in the 333276479Sdim // VirtualAddress field in the first relocation entry. 334276479Sdim if (Sec->hasExtendedRelocations()) { 335280031Sdim const coff_relocation *FirstReloc; 336280031Sdim if (getObject(FirstReloc, M, reinterpret_cast<const coff_relocation*>( 337280031Sdim base + Sec->PointerToRelocations))) 338280031Sdim return 0; 339280031Sdim // -1 to exclude this first relocation entry. 340280031Sdim return FirstReloc->VirtualAddress - 1; 341276479Sdim } 342276479Sdim return Sec->NumberOfRelocations; 343226633Sdim} 344226633Sdim 345280031Sdimstatic const coff_relocation * 346280031SdimgetFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) { 347280031Sdim uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base); 348280031Sdim if (!NumRelocs) 349280031Sdim return nullptr; 350280031Sdim auto begin = reinterpret_cast<const coff_relocation *>( 351280031Sdim Base + Sec->PointerToRelocations); 352280031Sdim if (Sec->hasExtendedRelocations()) { 353280031Sdim // Skip the first relocation entry repurposed to store the number of 354280031Sdim // relocations. 355280031Sdim begin++; 356280031Sdim } 357280031Sdim if (checkOffset(M, uintptr_t(begin), sizeof(coff_relocation) * NumRelocs)) 358280031Sdim return nullptr; 359280031Sdim return begin; 360280031Sdim} 361280031Sdim 362280031Sdimrelocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const { 363280031Sdim const coff_section *Sec = toSec(Ref); 364280031Sdim const coff_relocation *begin = getFirstReloc(Sec, Data, base()); 365288943Sdim if (begin && Sec->VirtualAddress != 0) 366288943Sdim report_fatal_error("Sections with relocations should have an address of 0"); 367280031Sdim DataRefImpl Ret; 368280031Sdim Ret.p = reinterpret_cast<uintptr_t>(begin); 369280031Sdim return relocation_iterator(RelocationRef(Ret, this)); 370280031Sdim} 371280031Sdim 372276479Sdimrelocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const { 373276479Sdim const coff_section *Sec = toSec(Ref); 374280031Sdim const coff_relocation *I = getFirstReloc(Sec, Data, base()); 375280031Sdim if (I) 376280031Sdim I += getNumberOfRelocations(Sec, Data, base()); 377276479Sdim DataRefImpl Ret; 378280031Sdim Ret.p = reinterpret_cast<uintptr_t>(I); 379276479Sdim return relocation_iterator(RelocationRef(Ret, this)); 380226633Sdim} 381226633Sdim 382261991Sdim// Initialize the pointer to the symbol table. 383276479Sdimstd::error_code COFFObjectFile::initSymbolTablePtr() { 384280031Sdim if (COFFHeader) 385280031Sdim if (std::error_code EC = getObject( 386280031Sdim SymbolTable16, Data, base() + getPointerToSymbolTable(), 387280031Sdim (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize())) 388280031Sdim return EC; 389261991Sdim 390280031Sdim if (COFFBigObjHeader) 391280031Sdim if (std::error_code EC = getObject( 392280031Sdim SymbolTable32, Data, base() + getPointerToSymbolTable(), 393280031Sdim (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize())) 394280031Sdim return EC; 395280031Sdim 396261991Sdim // Find string table. The first four byte of the string table contains the 397261991Sdim // total size of the string table, including the size field itself. If the 398261991Sdim // string table is empty, the value of the first four byte would be 4. 399280031Sdim uint32_t StringTableOffset = getPointerToSymbolTable() + 400280031Sdim getNumberOfSymbols() * getSymbolTableEntrySize(); 401280031Sdim const uint8_t *StringTableAddr = base() + StringTableOffset; 402261991Sdim const ulittle32_t *StringTableSizePtr; 403280031Sdim if (std::error_code EC = getObject(StringTableSizePtr, Data, StringTableAddr)) 404276479Sdim return EC; 405261991Sdim StringTableSize = *StringTableSizePtr; 406276479Sdim if (std::error_code EC = 407280031Sdim getObject(StringTable, Data, StringTableAddr, StringTableSize)) 408276479Sdim return EC; 409261991Sdim 410276479Sdim // Treat table sizes < 4 as empty because contrary to the PECOFF spec, some 411276479Sdim // tools like cvtres write a size of 0 for an empty table instead of 4. 412276479Sdim if (StringTableSize < 4) 413276479Sdim StringTableSize = 4; 414276479Sdim 415261991Sdim // Check that the string table is null terminated if has any in it. 416276479Sdim if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0) 417261991Sdim return object_error::parse_failed; 418288943Sdim return std::error_code(); 419261991Sdim} 420261991Sdim 421296417Sdimuint64_t COFFObjectFile::getImageBase() const { 422296417Sdim if (PE32Header) 423296417Sdim return PE32Header->ImageBase; 424296417Sdim else if (PE32PlusHeader) 425296417Sdim return PE32PlusHeader->ImageBase; 426296417Sdim // This actually comes up in practice. 427296417Sdim return 0; 428296417Sdim} 429296417Sdim 430276479Sdim// Returns the file offset for the given VA. 431276479Sdimstd::error_code COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const { 432296417Sdim uint64_t ImageBase = getImageBase(); 433276479Sdim uint64_t Rva = Addr - ImageBase; 434276479Sdim assert(Rva <= UINT32_MAX); 435276479Sdim return getRvaPtr((uint32_t)Rva, Res); 436276479Sdim} 437276479Sdim 438261991Sdim// Returns the file offset for the given RVA. 439276479Sdimstd::error_code COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const { 440276479Sdim for (const SectionRef &S : sections()) { 441276479Sdim const coff_section *Section = getCOFFSection(S); 442261991Sdim uint32_t SectionStart = Section->VirtualAddress; 443261991Sdim uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize; 444276479Sdim if (SectionStart <= Addr && Addr < SectionEnd) { 445276479Sdim uint32_t Offset = Addr - SectionStart; 446261991Sdim Res = uintptr_t(base()) + Section->PointerToRawData + Offset; 447288943Sdim return std::error_code(); 448261991Sdim } 449261991Sdim } 450261991Sdim return object_error::parse_failed; 451261991Sdim} 452261991Sdim 453261991Sdim// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name 454261991Sdim// table entry. 455276479Sdimstd::error_code COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint, 456276479Sdim StringRef &Name) const { 457261991Sdim uintptr_t IntPtr = 0; 458276479Sdim if (std::error_code EC = getRvaPtr(Rva, IntPtr)) 459276479Sdim return EC; 460261991Sdim const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr); 461261991Sdim Hint = *reinterpret_cast<const ulittle16_t *>(Ptr); 462261991Sdim Name = StringRef(reinterpret_cast<const char *>(Ptr + 2)); 463288943Sdim return std::error_code(); 464261991Sdim} 465261991Sdim 466261991Sdim// Find the import table. 467276479Sdimstd::error_code COFFObjectFile::initImportTablePtr() { 468261991Sdim // First, we get the RVA of the import table. If the file lacks a pointer to 469261991Sdim // the import table, do nothing. 470261991Sdim const data_directory *DataEntry; 471261991Sdim if (getDataDirectory(COFF::IMPORT_TABLE, DataEntry)) 472288943Sdim return std::error_code(); 473261991Sdim 474261991Sdim // Do nothing if the pointer to import table is NULL. 475261991Sdim if (DataEntry->RelativeVirtualAddress == 0) 476288943Sdim return std::error_code(); 477261991Sdim 478261991Sdim uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress; 479280031Sdim // -1 because the last entry is the null entry. 480261991Sdim NumberOfImportDirectory = DataEntry->Size / 481280031Sdim sizeof(import_directory_table_entry) - 1; 482261991Sdim 483261991Sdim // Find the section that contains the RVA. This is needed because the RVA is 484261991Sdim // the import table's memory address which is different from its file offset. 485261991Sdim uintptr_t IntPtr = 0; 486276479Sdim if (std::error_code EC = getRvaPtr(ImportTableRva, IntPtr)) 487276479Sdim return EC; 488261991Sdim ImportDirectory = reinterpret_cast< 489261991Sdim const import_directory_table_entry *>(IntPtr); 490288943Sdim return std::error_code(); 491276479Sdim} 492261991Sdim 493280031Sdim// Initializes DelayImportDirectory and NumberOfDelayImportDirectory. 494280031Sdimstd::error_code COFFObjectFile::initDelayImportTablePtr() { 495280031Sdim const data_directory *DataEntry; 496280031Sdim if (getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR, DataEntry)) 497288943Sdim return std::error_code(); 498280031Sdim if (DataEntry->RelativeVirtualAddress == 0) 499288943Sdim return std::error_code(); 500280031Sdim 501280031Sdim uint32_t RVA = DataEntry->RelativeVirtualAddress; 502280031Sdim NumberOfDelayImportDirectory = DataEntry->Size / 503280031Sdim sizeof(delay_import_directory_table_entry) - 1; 504280031Sdim 505280031Sdim uintptr_t IntPtr = 0; 506280031Sdim if (std::error_code EC = getRvaPtr(RVA, IntPtr)) 507280031Sdim return EC; 508280031Sdim DelayImportDirectory = reinterpret_cast< 509280031Sdim const delay_import_directory_table_entry *>(IntPtr); 510288943Sdim return std::error_code(); 511280031Sdim} 512280031Sdim 513276479Sdim// Find the export table. 514276479Sdimstd::error_code COFFObjectFile::initExportTablePtr() { 515276479Sdim // First, we get the RVA of the export table. If the file lacks a pointer to 516276479Sdim // the export table, do nothing. 517276479Sdim const data_directory *DataEntry; 518276479Sdim if (getDataDirectory(COFF::EXPORT_TABLE, DataEntry)) 519288943Sdim return std::error_code(); 520276479Sdim 521276479Sdim // Do nothing if the pointer to export table is NULL. 522276479Sdim if (DataEntry->RelativeVirtualAddress == 0) 523288943Sdim return std::error_code(); 524276479Sdim 525276479Sdim uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress; 526276479Sdim uintptr_t IntPtr = 0; 527276479Sdim if (std::error_code EC = getRvaPtr(ExportTableRva, IntPtr)) 528276479Sdim return EC; 529276479Sdim ExportDirectory = 530276479Sdim reinterpret_cast<const export_directory_table_entry *>(IntPtr); 531288943Sdim return std::error_code(); 532261991Sdim} 533261991Sdim 534280031Sdimstd::error_code COFFObjectFile::initBaseRelocPtr() { 535280031Sdim const data_directory *DataEntry; 536280031Sdim if (getDataDirectory(COFF::BASE_RELOCATION_TABLE, DataEntry)) 537288943Sdim return std::error_code(); 538280031Sdim if (DataEntry->RelativeVirtualAddress == 0) 539288943Sdim return std::error_code(); 540280031Sdim 541280031Sdim uintptr_t IntPtr = 0; 542280031Sdim if (std::error_code EC = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) 543280031Sdim return EC; 544280031Sdim BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>( 545280031Sdim IntPtr); 546280031Sdim BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>( 547280031Sdim IntPtr + DataEntry->Size); 548288943Sdim return std::error_code(); 549280031Sdim} 550280031Sdim 551280031SdimCOFFObjectFile::COFFObjectFile(MemoryBufferRef Object, std::error_code &EC) 552280031Sdim : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr), 553280031Sdim COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr), 554280031Sdim DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr), 555280031Sdim SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0), 556280031Sdim ImportDirectory(nullptr), NumberOfImportDirectory(0), 557280031Sdim DelayImportDirectory(nullptr), NumberOfDelayImportDirectory(0), 558280031Sdim ExportDirectory(nullptr), BaseRelocHeader(nullptr), 559280031Sdim BaseRelocEnd(nullptr) { 560224145Sdim // Check that we at least have enough room for a header. 561280031Sdim if (!checkSize(Data, EC, sizeof(coff_file_header))) 562276479Sdim return; 563221345Sdim 564261991Sdim // The current location in the file where we are looking at. 565261991Sdim uint64_t CurPtr = 0; 566224145Sdim 567261991Sdim // PE header is optional and is present only in executables. If it exists, 568261991Sdim // it is placed right after COFF header. 569276479Sdim bool HasPEHeader = false; 570261991Sdim 571224145Sdim // Check if this is a PE/COFF file. 572280031Sdim if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) { 573221345Sdim // PE/COFF, seek through MS-DOS compatibility stub and 4-byte 574221345Sdim // PE signature to find 'normal' COFF header. 575280031Sdim const auto *DH = reinterpret_cast<const dos_header *>(base()); 576280031Sdim if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') { 577280031Sdim CurPtr = DH->AddressOfNewExeHeader; 578280031Sdim // Check the PE magic bytes. ("PE\0\0") 579280031Sdim if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) { 580280031Sdim EC = object_error::parse_failed; 581280031Sdim return; 582280031Sdim } 583280031Sdim CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes. 584280031Sdim HasPEHeader = true; 585224145Sdim } 586221345Sdim } 587221345Sdim 588280031Sdim if ((EC = getObject(COFFHeader, Data, base() + CurPtr))) 589224145Sdim return; 590226633Sdim 591280031Sdim // It might be a bigobj file, let's check. Note that COFF bigobj and COFF 592280031Sdim // import libraries share a common prefix but bigobj is more restrictive. 593280031Sdim if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN && 594280031Sdim COFFHeader->NumberOfSections == uint16_t(0xffff) && 595280031Sdim checkSize(Data, EC, sizeof(coff_bigobj_file_header))) { 596280031Sdim if ((EC = getObject(COFFBigObjHeader, Data, base() + CurPtr))) 597280031Sdim return; 598280031Sdim 599280031Sdim // Verify that we are dealing with bigobj. 600280031Sdim if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion && 601280031Sdim std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic, 602280031Sdim sizeof(COFF::BigObjMagic)) == 0) { 603280031Sdim COFFHeader = nullptr; 604280031Sdim CurPtr += sizeof(coff_bigobj_file_header); 605280031Sdim } else { 606280031Sdim // It's not a bigobj. 607280031Sdim COFFBigObjHeader = nullptr; 608280031Sdim } 609280031Sdim } 610280031Sdim if (COFFHeader) { 611280031Sdim // The prior checkSize call may have failed. This isn't a hard error 612280031Sdim // because we were just trying to sniff out bigobj. 613288943Sdim EC = std::error_code(); 614280031Sdim CurPtr += sizeof(coff_file_header); 615280031Sdim 616280031Sdim if (COFFHeader->isImportLibrary()) 617280031Sdim return; 618280031Sdim } 619280031Sdim 620276479Sdim if (HasPEHeader) { 621276479Sdim const pe32_header *Header; 622280031Sdim if ((EC = getObject(Header, Data, base() + CurPtr))) 623234353Sdim return; 624276479Sdim 625276479Sdim const uint8_t *DataDirAddr; 626276479Sdim uint64_t DataDirSize; 627280031Sdim if (Header->Magic == COFF::PE32Header::PE32) { 628276479Sdim PE32Header = Header; 629276479Sdim DataDirAddr = base() + CurPtr + sizeof(pe32_header); 630276479Sdim DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize; 631280031Sdim } else if (Header->Magic == COFF::PE32Header::PE32_PLUS) { 632276479Sdim PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header); 633276479Sdim DataDirAddr = base() + CurPtr + sizeof(pe32plus_header); 634276479Sdim DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize; 635276479Sdim } else { 636276479Sdim // It's neither PE32 nor PE32+. 637276479Sdim EC = object_error::parse_failed; 638276479Sdim return; 639261991Sdim } 640280031Sdim if ((EC = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))) 641276479Sdim return; 642261991Sdim CurPtr += COFFHeader->SizeOfOptionalHeader; 643261991Sdim } 644218885Sdim 645280031Sdim if ((EC = getObject(SectionTable, Data, base() + CurPtr, 646280031Sdim (uint64_t)getNumberOfSections() * sizeof(coff_section)))) 647276479Sdim return; 648224145Sdim 649261991Sdim // Initialize the pointer to the symbol table. 650280031Sdim if (getPointerToSymbolTable() != 0) { 651276479Sdim if ((EC = initSymbolTablePtr())) 652234353Sdim return; 653280031Sdim } else { 654280031Sdim // We had better not have any symbols if we don't have a symbol table. 655280031Sdim if (getNumberOfSymbols() != 0) { 656280031Sdim EC = object_error::parse_failed; 657280031Sdim return; 658280031Sdim } 659280031Sdim } 660226633Sdim 661261991Sdim // Initialize the pointer to the beginning of the import table. 662276479Sdim if ((EC = initImportTablePtr())) 663261991Sdim return; 664280031Sdim if ((EC = initDelayImportTablePtr())) 665280031Sdim return; 666261991Sdim 667276479Sdim // Initialize the pointer to the export table. 668276479Sdim if ((EC = initExportTablePtr())) 669276479Sdim return; 670276479Sdim 671280031Sdim // Initialize the pointer to the base relocation table. 672280031Sdim if ((EC = initBaseRelocPtr())) 673280031Sdim return; 674280031Sdim 675288943Sdim EC = std::error_code(); 676218885Sdim} 677218885Sdim 678276479Sdimbasic_symbol_iterator COFFObjectFile::symbol_begin_impl() const { 679276479Sdim DataRefImpl Ret; 680280031Sdim Ret.p = getSymbolTable(); 681276479Sdim return basic_symbol_iterator(SymbolRef(Ret, this)); 682218885Sdim} 683218885Sdim 684276479Sdimbasic_symbol_iterator COFFObjectFile::symbol_end_impl() const { 685218885Sdim // The symbol table ends where the string table begins. 686276479Sdim DataRefImpl Ret; 687276479Sdim Ret.p = reinterpret_cast<uintptr_t>(StringTable); 688276479Sdim return basic_symbol_iterator(SymbolRef(Ret, this)); 689218885Sdim} 690218885Sdim 691261991Sdimimport_directory_iterator COFFObjectFile::import_directory_begin() const { 692276479Sdim return import_directory_iterator( 693276479Sdim ImportDirectoryEntryRef(ImportDirectory, 0, this)); 694261991Sdim} 695234353Sdim 696261991Sdimimport_directory_iterator COFFObjectFile::import_directory_end() const { 697276479Sdim return import_directory_iterator( 698276479Sdim ImportDirectoryEntryRef(ImportDirectory, NumberOfImportDirectory, this)); 699261991Sdim} 700261991Sdim 701280031Sdimdelay_import_directory_iterator 702280031SdimCOFFObjectFile::delay_import_directory_begin() const { 703280031Sdim return delay_import_directory_iterator( 704280031Sdim DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this)); 705280031Sdim} 706280031Sdim 707280031Sdimdelay_import_directory_iterator 708280031SdimCOFFObjectFile::delay_import_directory_end() const { 709280031Sdim return delay_import_directory_iterator( 710280031Sdim DelayImportDirectoryEntryRef( 711280031Sdim DelayImportDirectory, NumberOfDelayImportDirectory, this)); 712280031Sdim} 713280031Sdim 714276479Sdimexport_directory_iterator COFFObjectFile::export_directory_begin() const { 715276479Sdim return export_directory_iterator( 716276479Sdim ExportDirectoryEntryRef(ExportDirectory, 0, this)); 717218885Sdim} 718218885Sdim 719276479Sdimexport_directory_iterator COFFObjectFile::export_directory_end() const { 720276479Sdim if (!ExportDirectory) 721276479Sdim return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this)); 722276479Sdim ExportDirectoryEntryRef Ref(ExportDirectory, 723276479Sdim ExportDirectory->AddressTableEntries, this); 724276479Sdim return export_directory_iterator(Ref); 725276479Sdim} 726276479Sdim 727276479Sdimsection_iterator COFFObjectFile::section_begin() const { 728276479Sdim DataRefImpl Ret; 729276479Sdim Ret.p = reinterpret_cast<uintptr_t>(SectionTable); 730276479Sdim return section_iterator(SectionRef(Ret, this)); 731276479Sdim} 732276479Sdim 733276479Sdimsection_iterator COFFObjectFile::section_end() const { 734276479Sdim DataRefImpl Ret; 735280031Sdim int NumSections = 736280031Sdim COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections(); 737276479Sdim Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections); 738276479Sdim return section_iterator(SectionRef(Ret, this)); 739218885Sdim} 740218885Sdim 741280031Sdimbase_reloc_iterator COFFObjectFile::base_reloc_begin() const { 742280031Sdim return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this)); 743280031Sdim} 744280031Sdim 745280031Sdimbase_reloc_iterator COFFObjectFile::base_reloc_end() const { 746280031Sdim return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this)); 747280031Sdim} 748280031Sdim 749218885Sdimuint8_t COFFObjectFile::getBytesInAddress() const { 750218885Sdim return getArch() == Triple::x86_64 ? 8 : 4; 751218885Sdim} 752218885Sdim 753218885SdimStringRef COFFObjectFile::getFileFormatName() const { 754280031Sdim switch(getMachine()) { 755218885Sdim case COFF::IMAGE_FILE_MACHINE_I386: 756218885Sdim return "COFF-i386"; 757218885Sdim case COFF::IMAGE_FILE_MACHINE_AMD64: 758218885Sdim return "COFF-x86-64"; 759276479Sdim case COFF::IMAGE_FILE_MACHINE_ARMNT: 760276479Sdim return "COFF-ARM"; 761296417Sdim case COFF::IMAGE_FILE_MACHINE_ARM64: 762296417Sdim return "COFF-ARM64"; 763218885Sdim default: 764218885Sdim return "COFF-<unknown arch>"; 765218885Sdim } 766218885Sdim} 767218885Sdim 768218885Sdimunsigned COFFObjectFile::getArch() const { 769280031Sdim switch (getMachine()) { 770218885Sdim case COFF::IMAGE_FILE_MACHINE_I386: 771218885Sdim return Triple::x86; 772218885Sdim case COFF::IMAGE_FILE_MACHINE_AMD64: 773218885Sdim return Triple::x86_64; 774276479Sdim case COFF::IMAGE_FILE_MACHINE_ARMNT: 775276479Sdim return Triple::thumb; 776296417Sdim case COFF::IMAGE_FILE_MACHINE_ARM64: 777296417Sdim return Triple::aarch64; 778218885Sdim default: 779218885Sdim return Triple::UnknownArch; 780218885Sdim } 781218885Sdim} 782218885Sdim 783280031Sdimiterator_range<import_directory_iterator> 784280031SdimCOFFObjectFile::import_directories() const { 785280031Sdim return make_range(import_directory_begin(), import_directory_end()); 786261991Sdim} 787261991Sdim 788280031Sdimiterator_range<delay_import_directory_iterator> 789280031SdimCOFFObjectFile::delay_import_directories() const { 790280031Sdim return make_range(delay_import_directory_begin(), 791280031Sdim delay_import_directory_end()); 792234353Sdim} 793234353Sdim 794280031Sdimiterator_range<export_directory_iterator> 795280031SdimCOFFObjectFile::export_directories() const { 796280031Sdim return make_range(export_directory_begin(), export_directory_end()); 797280031Sdim} 798280031Sdim 799280031Sdimiterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const { 800280031Sdim return make_range(base_reloc_begin(), base_reloc_end()); 801280031Sdim} 802280031Sdim 803276479Sdimstd::error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const { 804261991Sdim Res = PE32Header; 805288943Sdim return std::error_code(); 806261991Sdim} 807261991Sdim 808276479Sdimstd::error_code 809276479SdimCOFFObjectFile::getPE32PlusHeader(const pe32plus_header *&Res) const { 810276479Sdim Res = PE32PlusHeader; 811288943Sdim return std::error_code(); 812276479Sdim} 813276479Sdim 814276479Sdimstd::error_code 815276479SdimCOFFObjectFile::getDataDirectory(uint32_t Index, 816276479Sdim const data_directory *&Res) const { 817261991Sdim // Error if if there's no data directory or the index is out of range. 818280031Sdim if (!DataDirectory) { 819280031Sdim Res = nullptr; 820261991Sdim return object_error::parse_failed; 821280031Sdim } 822276479Sdim assert(PE32Header || PE32PlusHeader); 823276479Sdim uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize 824276479Sdim : PE32PlusHeader->NumberOfRvaAndSize; 825280031Sdim if (Index >= NumEnt) { 826280031Sdim Res = nullptr; 827276479Sdim return object_error::parse_failed; 828280031Sdim } 829276479Sdim Res = &DataDirectory[Index]; 830288943Sdim return std::error_code(); 831261991Sdim} 832261991Sdim 833276479Sdimstd::error_code COFFObjectFile::getSection(int32_t Index, 834276479Sdim const coff_section *&Result) const { 835280031Sdim Result = nullptr; 836276479Sdim if (COFF::isReservedSectionNumber(Index)) 837288943Sdim return std::error_code(); 838280031Sdim if (static_cast<uint32_t>(Index) <= getNumberOfSections()) { 839224145Sdim // We already verified the section table data, so no need to check again. 840276479Sdim Result = SectionTable + (Index - 1); 841288943Sdim return std::error_code(); 842280031Sdim } 843280031Sdim return object_error::parse_failed; 844218885Sdim} 845218885Sdim 846276479Sdimstd::error_code COFFObjectFile::getString(uint32_t Offset, 847276479Sdim StringRef &Result) const { 848224145Sdim if (StringTableSize <= 4) 849224145Sdim // Tried to get a string from an empty string table. 850224145Sdim return object_error::parse_failed; 851276479Sdim if (Offset >= StringTableSize) 852224145Sdim return object_error::unexpected_eof; 853276479Sdim Result = StringRef(StringTable + Offset); 854288943Sdim return std::error_code(); 855218885Sdim} 856218885Sdim 857280031Sdimstd::error_code COFFObjectFile::getSymbolName(COFFSymbolRef Symbol, 858276479Sdim StringRef &Res) const { 859288943Sdim return getSymbolName(Symbol.getGeneric(), Res); 860288943Sdim} 861288943Sdim 862288943Sdimstd::error_code COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol, 863288943Sdim StringRef &Res) const { 864234353Sdim // Check for string table entry. First 4 bytes are 0. 865288943Sdim if (Symbol->Name.Offset.Zeroes == 0) { 866288943Sdim if (std::error_code EC = getString(Symbol->Name.Offset.Offset, Res)) 867276479Sdim return EC; 868288943Sdim return std::error_code(); 869234353Sdim } 870234353Sdim 871288943Sdim if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0) 872234353Sdim // Null terminated, let ::strlen figure out the length. 873288943Sdim Res = StringRef(Symbol->Name.ShortName); 874234353Sdim else 875234353Sdim // Not null terminated, use all 8 bytes. 876288943Sdim Res = StringRef(Symbol->Name.ShortName, COFF::NameSize); 877288943Sdim return std::error_code(); 878234353Sdim} 879234353Sdim 880280031SdimArrayRef<uint8_t> 881280031SdimCOFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const { 882276479Sdim const uint8_t *Aux = nullptr; 883261991Sdim 884280031Sdim size_t SymbolSize = getSymbolTableEntrySize(); 885280031Sdim if (Symbol.getNumberOfAuxSymbols() > 0) { 886280031Sdim // AUX data comes immediately after the symbol in COFF 887280031Sdim Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize; 888239462Sdim# ifndef NDEBUG 889276479Sdim // Verify that the Aux symbol points to a valid entry in the symbol table. 890276479Sdim uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base()); 891280031Sdim if (Offset < getPointerToSymbolTable() || 892280031Sdim Offset >= 893280031Sdim getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize)) 894239462Sdim report_fatal_error("Aux Symbol data was outside of symbol table."); 895239462Sdim 896280031Sdim assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 && 897280031Sdim "Aux Symbol data did not point to the beginning of a symbol"); 898239462Sdim# endif 899239462Sdim } 900280031Sdim return makeArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize); 901239462Sdim} 902239462Sdim 903276479Sdimstd::error_code COFFObjectFile::getSectionName(const coff_section *Sec, 904276479Sdim StringRef &Res) const { 905234353Sdim StringRef Name; 906280031Sdim if (Sec->Name[COFF::NameSize - 1] == 0) 907234353Sdim // Null terminated, let ::strlen figure out the length. 908234353Sdim Name = Sec->Name; 909234353Sdim else 910234353Sdim // Not null terminated, use all 8 bytes. 911280031Sdim Name = StringRef(Sec->Name, COFF::NameSize); 912234353Sdim 913234353Sdim // Check for string table entry. First byte is '/'. 914280031Sdim if (Name.startswith("/")) { 915234353Sdim uint32_t Offset; 916280031Sdim if (Name.startswith("//")) { 917276479Sdim if (decodeBase64StringEntry(Name.substr(2), Offset)) 918276479Sdim return object_error::parse_failed; 919276479Sdim } else { 920276479Sdim if (Name.substr(1).getAsInteger(10, Offset)) 921276479Sdim return object_error::parse_failed; 922276479Sdim } 923276479Sdim if (std::error_code EC = getString(Offset, Name)) 924276479Sdim return EC; 925234353Sdim } 926234353Sdim 927234353Sdim Res = Name; 928288943Sdim return std::error_code(); 929234353Sdim} 930234353Sdim 931280031Sdimuint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const { 932280031Sdim // SizeOfRawData and VirtualSize change what they represent depending on 933280031Sdim // whether or not we have an executable image. 934280031Sdim // 935280031Sdim // For object files, SizeOfRawData contains the size of section's data; 936288943Sdim // VirtualSize should be zero but isn't due to buggy COFF writers. 937280031Sdim // 938280031Sdim // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the 939280031Sdim // actual section size is in VirtualSize. It is possible for VirtualSize to 940280031Sdim // be greater than SizeOfRawData; the contents past that point should be 941280031Sdim // considered to be zero. 942288943Sdim if (getDOSHeader()) 943288943Sdim return std::min(Sec->VirtualSize, Sec->SizeOfRawData); 944288943Sdim return Sec->SizeOfRawData; 945280031Sdim} 946280031Sdim 947276479Sdimstd::error_code 948276479SdimCOFFObjectFile::getSectionContents(const coff_section *Sec, 949276479Sdim ArrayRef<uint8_t> &Res) const { 950280031Sdim // PointerToRawData and SizeOfRawData won't make sense for BSS sections, 951280031Sdim // don't do anything interesting for them. 952280031Sdim assert((Sec->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA) == 0 && 953280031Sdim "BSS sections don't have contents!"); 954234353Sdim // The only thing that we need to verify is that the contents is contained 955234353Sdim // within the file bounds. We don't need to make sure it doesn't cover other 956234353Sdim // data, as there's nothing that says that is not allowed. 957234353Sdim uintptr_t ConStart = uintptr_t(base()) + Sec->PointerToRawData; 958280031Sdim uint32_t SectionSize = getSectionSize(Sec); 959280031Sdim if (checkOffset(Data, ConStart, SectionSize)) 960234353Sdim return object_error::parse_failed; 961280031Sdim Res = makeArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize); 962288943Sdim return std::error_code(); 963234353Sdim} 964234353Sdim 965226633Sdimconst coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const { 966226633Sdim return reinterpret_cast<const coff_relocation*>(Rel.p); 967226633Sdim} 968276479Sdim 969276479Sdimvoid COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { 970226633Sdim Rel.p = reinterpret_cast<uintptr_t>( 971226633Sdim reinterpret_cast<const coff_relocation*>(Rel.p) + 1); 972226633Sdim} 973276479Sdim 974288943Sdimuint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { 975280031Sdim const coff_relocation *R = toRel(Rel); 976288943Sdim return R->VirtualAddress; 977234353Sdim} 978276479Sdim 979261991Sdimsymbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { 980280031Sdim const coff_relocation *R = toRel(Rel); 981276479Sdim DataRefImpl Ref; 982280031Sdim if (R->SymbolTableIndex >= getNumberOfSymbols()) 983280031Sdim return symbol_end(); 984280031Sdim if (SymbolTable16) 985280031Sdim Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex); 986280031Sdim else if (SymbolTable32) 987280031Sdim Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex); 988280031Sdim else 989280031Sdim llvm_unreachable("no symbol table pointer!"); 990276479Sdim return symbol_iterator(SymbolRef(Ref, this)); 991226633Sdim} 992276479Sdim 993288943Sdimuint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const { 994226633Sdim const coff_relocation* R = toRel(Rel); 995288943Sdim return R->Type; 996226633Sdim} 997226633Sdim 998276479Sdimconst coff_section * 999276479SdimCOFFObjectFile::getCOFFSection(const SectionRef &Section) const { 1000276479Sdim return toSec(Section.getRawDataRefImpl()); 1001239462Sdim} 1002239462Sdim 1003280031SdimCOFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const { 1004280031Sdim if (SymbolTable16) 1005280031Sdim return toSymb<coff_symbol16>(Ref); 1006280031Sdim if (SymbolTable32) 1007280031Sdim return toSymb<coff_symbol32>(Ref); 1008280031Sdim llvm_unreachable("no symbol table pointer!"); 1009239462Sdim} 1010239462Sdim 1011280031SdimCOFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const { 1012280031Sdim return getCOFFSymbol(Symbol.getRawDataRefImpl()); 1013280031Sdim} 1014280031Sdim 1015276479Sdimconst coff_relocation * 1016276479SdimCOFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const { 1017276479Sdim return toRel(Reloc.getRawDataRefImpl()); 1018239462Sdim} 1019239462Sdim 1020288943Sdimiterator_range<const coff_relocation *> 1021288943SdimCOFFObjectFile::getRelocations(const coff_section *Sec) const { 1022288943Sdim const coff_relocation *I = getFirstReloc(Sec, Data, base()); 1023288943Sdim const coff_relocation *E = I; 1024288943Sdim if (I) 1025288943Sdim E += getNumberOfRelocations(Sec, Data, base()); 1026288943Sdim return make_range(I, E); 1027288943Sdim} 1028288943Sdim 1029276479Sdim#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \ 1030276479Sdim case COFF::reloc_type: \ 1031276479Sdim Res = #reloc_type; \ 1032276479Sdim break; 1033226633Sdim 1034288943Sdimvoid COFFObjectFile::getRelocationTypeName( 1035288943Sdim DataRefImpl Rel, SmallVectorImpl<char> &Result) const { 1036276479Sdim const coff_relocation *Reloc = toRel(Rel); 1037276479Sdim StringRef Res; 1038280031Sdim switch (getMachine()) { 1039226633Sdim case COFF::IMAGE_FILE_MACHINE_AMD64: 1040276479Sdim switch (Reloc->Type) { 1041226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE); 1042226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64); 1043226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32); 1044226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB); 1045226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32); 1046226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1); 1047226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2); 1048226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3); 1049226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4); 1050226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5); 1051226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION); 1052226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL); 1053226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7); 1054226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN); 1055226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32); 1056226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR); 1057226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32); 1058226633Sdim default: 1059276479Sdim Res = "Unknown"; 1060226633Sdim } 1061226633Sdim break; 1062276479Sdim case COFF::IMAGE_FILE_MACHINE_ARMNT: 1063276479Sdim switch (Reloc->Type) { 1064276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE); 1065276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32); 1066276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB); 1067276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24); 1068276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11); 1069276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN); 1070276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24); 1071276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11); 1072276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION); 1073276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL); 1074276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A); 1075276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T); 1076276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T); 1077276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T); 1078276479Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T); 1079276479Sdim default: 1080276479Sdim Res = "Unknown"; 1081276479Sdim } 1082276479Sdim break; 1083226633Sdim case COFF::IMAGE_FILE_MACHINE_I386: 1084276479Sdim switch (Reloc->Type) { 1085226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE); 1086226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16); 1087226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16); 1088226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32); 1089226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB); 1090226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12); 1091226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION); 1092226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL); 1093226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN); 1094226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7); 1095226633Sdim LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32); 1096226633Sdim default: 1097276479Sdim Res = "Unknown"; 1098226633Sdim } 1099226633Sdim break; 1100226633Sdim default: 1101276479Sdim Res = "Unknown"; 1102226633Sdim } 1103276479Sdim Result.append(Res.begin(), Res.end()); 1104226633Sdim} 1105226633Sdim 1106226633Sdim#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME 1107226633Sdim 1108280031Sdimbool COFFObjectFile::isRelocatableObject() const { 1109280031Sdim return !DataDirectory; 1110234353Sdim} 1111234353Sdim 1112261991Sdimbool ImportDirectoryEntryRef:: 1113261991Sdimoperator==(const ImportDirectoryEntryRef &Other) const { 1114276479Sdim return ImportTable == Other.ImportTable && Index == Other.Index; 1115261991Sdim} 1116261991Sdim 1117276479Sdimvoid ImportDirectoryEntryRef::moveNext() { 1118276479Sdim ++Index; 1119261991Sdim} 1120261991Sdim 1121276479Sdimstd::error_code ImportDirectoryEntryRef::getImportTableEntry( 1122276479Sdim const import_directory_table_entry *&Result) const { 1123280031Sdim Result = ImportTable + Index; 1124288943Sdim return std::error_code(); 1125261991Sdim} 1126261991Sdim 1127280031Sdimstatic imported_symbol_iterator 1128280031SdimmakeImportedSymbolIterator(const COFFObjectFile *Object, 1129280031Sdim uintptr_t Ptr, int Index) { 1130280031Sdim if (Object->getBytesInAddress() == 4) { 1131280031Sdim auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr); 1132280031Sdim return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object)); 1133280031Sdim } 1134280031Sdim auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr); 1135280031Sdim return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object)); 1136280031Sdim} 1137280031Sdim 1138280031Sdimstatic imported_symbol_iterator 1139280031SdimimportedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) { 1140280031Sdim uintptr_t IntPtr = 0; 1141280031Sdim Object->getRvaPtr(RVA, IntPtr); 1142280031Sdim return makeImportedSymbolIterator(Object, IntPtr, 0); 1143280031Sdim} 1144280031Sdim 1145280031Sdimstatic imported_symbol_iterator 1146280031SdimimportedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) { 1147280031Sdim uintptr_t IntPtr = 0; 1148280031Sdim Object->getRvaPtr(RVA, IntPtr); 1149280031Sdim // Forward the pointer to the last entry which is null. 1150280031Sdim int Index = 0; 1151280031Sdim if (Object->getBytesInAddress() == 4) { 1152280031Sdim auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr); 1153280031Sdim while (*Entry++) 1154280031Sdim ++Index; 1155280031Sdim } else { 1156280031Sdim auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr); 1157280031Sdim while (*Entry++) 1158280031Sdim ++Index; 1159280031Sdim } 1160280031Sdim return makeImportedSymbolIterator(Object, IntPtr, Index); 1161280031Sdim} 1162280031Sdim 1163280031Sdimimported_symbol_iterator 1164280031SdimImportDirectoryEntryRef::imported_symbol_begin() const { 1165280031Sdim return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA, 1166280031Sdim OwningObject); 1167280031Sdim} 1168280031Sdim 1169280031Sdimimported_symbol_iterator 1170280031SdimImportDirectoryEntryRef::imported_symbol_end() const { 1171280031Sdim return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA, 1172280031Sdim OwningObject); 1173280031Sdim} 1174280031Sdim 1175280031Sdimiterator_range<imported_symbol_iterator> 1176280031SdimImportDirectoryEntryRef::imported_symbols() const { 1177280031Sdim return make_range(imported_symbol_begin(), imported_symbol_end()); 1178280031Sdim} 1179280031Sdim 1180276479Sdimstd::error_code ImportDirectoryEntryRef::getName(StringRef &Result) const { 1181276479Sdim uintptr_t IntPtr = 0; 1182276479Sdim if (std::error_code EC = 1183280031Sdim OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr)) 1184276479Sdim return EC; 1185276479Sdim Result = StringRef(reinterpret_cast<const char *>(IntPtr)); 1186288943Sdim return std::error_code(); 1187261991Sdim} 1188261991Sdim 1189280031Sdimstd::error_code 1190280031SdimImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const { 1191280031Sdim Result = ImportTable[Index].ImportLookupTableRVA; 1192288943Sdim return std::error_code(); 1193280031Sdim} 1194280031Sdim 1195280031Sdimstd::error_code 1196280031SdimImportDirectoryEntryRef::getImportAddressTableRVA(uint32_t &Result) const { 1197280031Sdim Result = ImportTable[Index].ImportAddressTableRVA; 1198288943Sdim return std::error_code(); 1199280031Sdim} 1200280031Sdim 1201276479Sdimstd::error_code ImportDirectoryEntryRef::getImportLookupEntry( 1202276479Sdim const import_lookup_table_entry32 *&Result) const { 1203261991Sdim uintptr_t IntPtr = 0; 1204280031Sdim uint32_t RVA = ImportTable[Index].ImportLookupTableRVA; 1205280031Sdim if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) 1206276479Sdim return EC; 1207276479Sdim Result = reinterpret_cast<const import_lookup_table_entry32 *>(IntPtr); 1208288943Sdim return std::error_code(); 1209261991Sdim} 1210261991Sdim 1211280031Sdimbool DelayImportDirectoryEntryRef:: 1212280031Sdimoperator==(const DelayImportDirectoryEntryRef &Other) const { 1213280031Sdim return Table == Other.Table && Index == Other.Index; 1214280031Sdim} 1215280031Sdim 1216280031Sdimvoid DelayImportDirectoryEntryRef::moveNext() { 1217280031Sdim ++Index; 1218280031Sdim} 1219280031Sdim 1220280031Sdimimported_symbol_iterator 1221280031SdimDelayImportDirectoryEntryRef::imported_symbol_begin() const { 1222280031Sdim return importedSymbolBegin(Table[Index].DelayImportNameTable, 1223280031Sdim OwningObject); 1224280031Sdim} 1225280031Sdim 1226280031Sdimimported_symbol_iterator 1227280031SdimDelayImportDirectoryEntryRef::imported_symbol_end() const { 1228280031Sdim return importedSymbolEnd(Table[Index].DelayImportNameTable, 1229280031Sdim OwningObject); 1230280031Sdim} 1231280031Sdim 1232280031Sdimiterator_range<imported_symbol_iterator> 1233280031SdimDelayImportDirectoryEntryRef::imported_symbols() const { 1234280031Sdim return make_range(imported_symbol_begin(), imported_symbol_end()); 1235280031Sdim} 1236280031Sdim 1237280031Sdimstd::error_code DelayImportDirectoryEntryRef::getName(StringRef &Result) const { 1238280031Sdim uintptr_t IntPtr = 0; 1239280031Sdim if (std::error_code EC = OwningObject->getRvaPtr(Table[Index].Name, IntPtr)) 1240280031Sdim return EC; 1241280031Sdim Result = StringRef(reinterpret_cast<const char *>(IntPtr)); 1242288943Sdim return std::error_code(); 1243280031Sdim} 1244280031Sdim 1245280031Sdimstd::error_code DelayImportDirectoryEntryRef:: 1246280031SdimgetDelayImportTable(const delay_import_directory_table_entry *&Result) const { 1247280031Sdim Result = Table; 1248288943Sdim return std::error_code(); 1249280031Sdim} 1250280031Sdim 1251280031Sdimstd::error_code DelayImportDirectoryEntryRef:: 1252280031SdimgetImportAddress(int AddrIndex, uint64_t &Result) const { 1253280031Sdim uint32_t RVA = Table[Index].DelayImportAddressTable + 1254280031Sdim AddrIndex * (OwningObject->is64() ? 8 : 4); 1255280031Sdim uintptr_t IntPtr = 0; 1256280031Sdim if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) 1257280031Sdim return EC; 1258280031Sdim if (OwningObject->is64()) 1259280031Sdim Result = *reinterpret_cast<const ulittle64_t *>(IntPtr); 1260280031Sdim else 1261280031Sdim Result = *reinterpret_cast<const ulittle32_t *>(IntPtr); 1262288943Sdim return std::error_code(); 1263280031Sdim} 1264280031Sdim 1265276479Sdimbool ExportDirectoryEntryRef:: 1266276479Sdimoperator==(const ExportDirectoryEntryRef &Other) const { 1267276479Sdim return ExportTable == Other.ExportTable && Index == Other.Index; 1268276479Sdim} 1269276479Sdim 1270276479Sdimvoid ExportDirectoryEntryRef::moveNext() { 1271276479Sdim ++Index; 1272276479Sdim} 1273276479Sdim 1274276479Sdim// Returns the name of the current export symbol. If the symbol is exported only 1275276479Sdim// by ordinal, the empty string is set as a result. 1276276479Sdimstd::error_code ExportDirectoryEntryRef::getDllName(StringRef &Result) const { 1277261991Sdim uintptr_t IntPtr = 0; 1278276479Sdim if (std::error_code EC = 1279276479Sdim OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr)) 1280276479Sdim return EC; 1281276479Sdim Result = StringRef(reinterpret_cast<const char *>(IntPtr)); 1282288943Sdim return std::error_code(); 1283261991Sdim} 1284261991Sdim 1285276479Sdim// Returns the starting ordinal number. 1286276479Sdimstd::error_code 1287276479SdimExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const { 1288276479Sdim Result = ExportTable->OrdinalBase; 1289288943Sdim return std::error_code(); 1290276479Sdim} 1291218885Sdim 1292276479Sdim// Returns the export ordinal of the current export symbol. 1293276479Sdimstd::error_code ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const { 1294276479Sdim Result = ExportTable->OrdinalBase + Index; 1295288943Sdim return std::error_code(); 1296276479Sdim} 1297276479Sdim 1298276479Sdim// Returns the address of the current export symbol. 1299276479Sdimstd::error_code ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const { 1300276479Sdim uintptr_t IntPtr = 0; 1301276479Sdim if (std::error_code EC = 1302276479Sdim OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr)) 1303276479Sdim return EC; 1304276479Sdim const export_address_table_entry *entry = 1305276479Sdim reinterpret_cast<const export_address_table_entry *>(IntPtr); 1306276479Sdim Result = entry[Index].ExportRVA; 1307288943Sdim return std::error_code(); 1308276479Sdim} 1309276479Sdim 1310276479Sdim// Returns the name of the current export symbol. If the symbol is exported only 1311276479Sdim// by ordinal, the empty string is set as a result. 1312276479Sdimstd::error_code 1313276479SdimExportDirectoryEntryRef::getSymbolName(StringRef &Result) const { 1314276479Sdim uintptr_t IntPtr = 0; 1315276479Sdim if (std::error_code EC = 1316276479Sdim OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr)) 1317276479Sdim return EC; 1318276479Sdim const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr); 1319276479Sdim 1320276479Sdim uint32_t NumEntries = ExportTable->NumberOfNamePointers; 1321276479Sdim int Offset = 0; 1322276479Sdim for (const ulittle16_t *I = Start, *E = Start + NumEntries; 1323276479Sdim I < E; ++I, ++Offset) { 1324276479Sdim if (*I != Index) 1325276479Sdim continue; 1326276479Sdim if (std::error_code EC = 1327276479Sdim OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr)) 1328276479Sdim return EC; 1329276479Sdim const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr); 1330276479Sdim if (std::error_code EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr)) 1331276479Sdim return EC; 1332276479Sdim Result = StringRef(reinterpret_cast<const char *>(IntPtr)); 1333288943Sdim return std::error_code(); 1334218885Sdim } 1335276479Sdim Result = ""; 1336288943Sdim return std::error_code(); 1337276479Sdim} 1338218885Sdim 1339296417Sdimstd::error_code ExportDirectoryEntryRef::isForwarder(bool &Result) const { 1340296417Sdim const data_directory *DataEntry; 1341296417Sdim if (auto EC = OwningObject->getDataDirectory(COFF::EXPORT_TABLE, DataEntry)) 1342296417Sdim return EC; 1343296417Sdim uint32_t RVA; 1344296417Sdim if (auto EC = getExportRVA(RVA)) 1345296417Sdim return EC; 1346296417Sdim uint32_t Begin = DataEntry->RelativeVirtualAddress; 1347296417Sdim uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size; 1348296417Sdim Result = (Begin <= RVA && RVA < End); 1349296417Sdim return std::error_code(); 1350296417Sdim} 1351296417Sdim 1352296417Sdimstd::error_code ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const { 1353296417Sdim uint32_t RVA; 1354296417Sdim if (auto EC = getExportRVA(RVA)) 1355296417Sdim return EC; 1356296417Sdim uintptr_t IntPtr = 0; 1357296417Sdim if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr)) 1358296417Sdim return EC; 1359296417Sdim Result = StringRef(reinterpret_cast<const char *>(IntPtr)); 1360296417Sdim return std::error_code(); 1361296417Sdim} 1362296417Sdim 1363280031Sdimbool ImportedSymbolRef:: 1364280031Sdimoperator==(const ImportedSymbolRef &Other) const { 1365280031Sdim return Entry32 == Other.Entry32 && Entry64 == Other.Entry64 1366280031Sdim && Index == Other.Index; 1367280031Sdim} 1368280031Sdim 1369280031Sdimvoid ImportedSymbolRef::moveNext() { 1370280031Sdim ++Index; 1371280031Sdim} 1372280031Sdim 1373280031Sdimstd::error_code 1374280031SdimImportedSymbolRef::getSymbolName(StringRef &Result) const { 1375280031Sdim uint32_t RVA; 1376280031Sdim if (Entry32) { 1377280031Sdim // If a symbol is imported only by ordinal, it has no name. 1378280031Sdim if (Entry32[Index].isOrdinal()) 1379288943Sdim return std::error_code(); 1380280031Sdim RVA = Entry32[Index].getHintNameRVA(); 1381280031Sdim } else { 1382280031Sdim if (Entry64[Index].isOrdinal()) 1383288943Sdim return std::error_code(); 1384280031Sdim RVA = Entry64[Index].getHintNameRVA(); 1385280031Sdim } 1386280031Sdim uintptr_t IntPtr = 0; 1387280031Sdim if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) 1388280031Sdim return EC; 1389280031Sdim // +2 because the first two bytes is hint. 1390280031Sdim Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2)); 1391288943Sdim return std::error_code(); 1392280031Sdim} 1393280031Sdim 1394280031Sdimstd::error_code ImportedSymbolRef::getOrdinal(uint16_t &Result) const { 1395280031Sdim uint32_t RVA; 1396280031Sdim if (Entry32) { 1397280031Sdim if (Entry32[Index].isOrdinal()) { 1398280031Sdim Result = Entry32[Index].getOrdinal(); 1399288943Sdim return std::error_code(); 1400280031Sdim } 1401280031Sdim RVA = Entry32[Index].getHintNameRVA(); 1402280031Sdim } else { 1403280031Sdim if (Entry64[Index].isOrdinal()) { 1404280031Sdim Result = Entry64[Index].getOrdinal(); 1405288943Sdim return std::error_code(); 1406280031Sdim } 1407280031Sdim RVA = Entry64[Index].getHintNameRVA(); 1408280031Sdim } 1409280031Sdim uintptr_t IntPtr = 0; 1410280031Sdim if (std::error_code EC = OwningObject->getRvaPtr(RVA, IntPtr)) 1411280031Sdim return EC; 1412280031Sdim Result = *reinterpret_cast<const ulittle16_t *>(IntPtr); 1413288943Sdim return std::error_code(); 1414280031Sdim} 1415280031Sdim 1416280031SdimErrorOr<std::unique_ptr<COFFObjectFile>> 1417280031SdimObjectFile::createCOFFObjectFile(MemoryBufferRef Object) { 1418276479Sdim std::error_code EC; 1419280031Sdim std::unique_ptr<COFFObjectFile> Ret(new COFFObjectFile(Object, EC)); 1420276479Sdim if (EC) 1421276479Sdim return EC; 1422280031Sdim return std::move(Ret); 1423276479Sdim} 1424280031Sdim 1425280031Sdimbool BaseRelocRef::operator==(const BaseRelocRef &Other) const { 1426280031Sdim return Header == Other.Header && Index == Other.Index; 1427280031Sdim} 1428280031Sdim 1429280031Sdimvoid BaseRelocRef::moveNext() { 1430280031Sdim // Header->BlockSize is the size of the current block, including the 1431280031Sdim // size of the header itself. 1432280031Sdim uint32_t Size = sizeof(*Header) + 1433280031Sdim sizeof(coff_base_reloc_block_entry) * (Index + 1); 1434280031Sdim if (Size == Header->BlockSize) { 1435280031Sdim // .reloc contains a list of base relocation blocks. Each block 1436280031Sdim // consists of the header followed by entries. The header contains 1437280031Sdim // how many entories will follow. When we reach the end of the 1438280031Sdim // current block, proceed to the next block. 1439280031Sdim Header = reinterpret_cast<const coff_base_reloc_block_header *>( 1440280031Sdim reinterpret_cast<const uint8_t *>(Header) + Size); 1441280031Sdim Index = 0; 1442280031Sdim } else { 1443280031Sdim ++Index; 1444280031Sdim } 1445280031Sdim} 1446280031Sdim 1447280031Sdimstd::error_code BaseRelocRef::getType(uint8_t &Type) const { 1448280031Sdim auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1); 1449280031Sdim Type = Entry[Index].getType(); 1450288943Sdim return std::error_code(); 1451280031Sdim} 1452280031Sdim 1453280031Sdimstd::error_code BaseRelocRef::getRVA(uint32_t &Result) const { 1454280031Sdim auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1); 1455280031Sdim Result = Header->PageRVA + Entry[Index].getOffset(); 1456288943Sdim return std::error_code(); 1457280031Sdim} 1458