2017-04-20 01:02:10 +02:00
|
|
|
//===- COFFObjectFile.cpp - COFF object file implementation ---------------===//
|
2011-01-20 07:38:34 +01:00
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-01-20 07:38:34 +01:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file declares the COFFObjectFile class.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2012-03-19 21:27:37 +01:00
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
2017-04-20 01:02:10 +02:00
|
|
|
#include "llvm/ADT/StringRef.h"
|
2020-05-28 16:26:15 +02:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2011-01-20 07:38:34 +01:00
|
|
|
#include "llvm/ADT/Triple.h"
|
2015-06-25 02:07:39 +02:00
|
|
|
#include "llvm/ADT/iterator_range.h"
|
2017-06-07 05:48:56 +02:00
|
|
|
#include "llvm/BinaryFormat/COFF.h"
|
2017-04-20 01:02:10 +02:00
|
|
|
#include "llvm/Object/Binary.h"
|
|
|
|
#include "llvm/Object/COFF.h"
|
|
|
|
#include "llvm/Object/Error.h"
|
|
|
|
#include "llvm/Object/ObjectFile.h"
|
2017-05-08 04:47:07 +02:00
|
|
|
#include "llvm/Support/BinaryStreamReader.h"
|
2017-04-20 01:02:10 +02:00
|
|
|
#include "llvm/Support/Endian.h"
|
|
|
|
#include "llvm/Support/Error.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/MathExtras.h"
|
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
2020-10-18 17:41:52 +02:00
|
|
|
#include <cinttypes>
|
2017-04-20 01:02:10 +02:00
|
|
|
#include <cstddef>
|
|
|
|
#include <cstring>
|
2014-02-22 17:12:20 +01:00
|
|
|
#include <limits>
|
2017-04-20 01:02:10 +02:00
|
|
|
#include <memory>
|
|
|
|
#include <system_error>
|
2011-01-20 07:38:34 +01:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace object;
|
|
|
|
|
|
|
|
using support::ulittle16_t;
|
|
|
|
using support::ulittle32_t;
|
2014-10-03 00:05:29 +02:00
|
|
|
using support::ulittle64_t;
|
2011-01-20 07:38:34 +01:00
|
|
|
using support::little16_t;
|
|
|
|
|
2011-06-25 19:55:23 +02:00
|
|
|
// Returns false if size is greater than the buffer size. And sets ec.
|
2014-08-19 20:44:46 +02:00
|
|
|
static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) {
|
2014-06-23 23:53:12 +02:00
|
|
|
if (M.getBufferSize() < Size) {
|
2014-01-16 21:11:48 +01:00
|
|
|
EC = object_error::unexpected_eof;
|
2011-06-25 19:55:23 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-20 01:23:29 +02:00
|
|
|
// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
|
|
|
|
// Returns unexpected_eof if error.
|
2014-06-13 04:24:39 +02:00
|
|
|
template <typename T>
|
2020-06-11 22:00:54 +02:00
|
|
|
static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr,
|
|
|
|
const uint64_t Size = sizeof(T)) {
|
2020-03-23 03:20:04 +01:00
|
|
|
uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);
|
2020-06-06 01:12:38 +02:00
|
|
|
if (Error E = Binary::checkOffset(M, Addr, Size))
|
2020-06-11 22:00:54 +02:00
|
|
|
return E;
|
2013-07-20 01:23:29 +02:00
|
|
|
Obj = reinterpret_cast<const T *>(Addr);
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2011-06-25 19:55:23 +02:00
|
|
|
}
|
|
|
|
|
2014-02-22 17:12:20 +01:00
|
|
|
// Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without
|
|
|
|
// prefixed slashes.
|
|
|
|
static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {
|
|
|
|
assert(Str.size() <= 6 && "String too long, possible overflow.");
|
|
|
|
if (Str.size() > 6)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
uint64_t Value = 0;
|
|
|
|
while (!Str.empty()) {
|
|
|
|
unsigned CharVal;
|
|
|
|
if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..25
|
|
|
|
CharVal = Str[0] - 'A';
|
|
|
|
else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..51
|
|
|
|
CharVal = Str[0] - 'a' + 26;
|
|
|
|
else if (Str[0] >= '0' && Str[0] <= '9') // 52..61
|
|
|
|
CharVal = Str[0] - '0' + 52;
|
|
|
|
else if (Str[0] == '+') // 62
|
2014-02-26 00:49:11 +01:00
|
|
|
CharVal = 62;
|
2014-02-22 17:12:20 +01:00
|
|
|
else if (Str[0] == '/') // 63
|
2014-02-26 00:49:11 +01:00
|
|
|
CharVal = 63;
|
2014-02-22 17:12:20 +01:00
|
|
|
else
|
|
|
|
return true;
|
|
|
|
|
|
|
|
Value = (Value * 64) + CharVal;
|
|
|
|
Str = Str.substr(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Value > std::numeric_limits<uint32_t>::max())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
Result = static_cast<uint32_t>(Value);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-09-10 14:51:52 +02:00
|
|
|
template <typename coff_symbol_type>
|
|
|
|
const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {
|
|
|
|
const coff_symbol_type *Addr =
|
|
|
|
reinterpret_cast<const coff_symbol_type *>(Ref.p);
|
2011-06-25 19:55:23 +02:00
|
|
|
|
2020-03-23 03:20:04 +01:00
|
|
|
assert(!checkOffset(Data, reinterpret_cast<uintptr_t>(Addr), sizeof(*Addr)));
|
2014-09-10 14:51:52 +02:00
|
|
|
#ifndef NDEBUG
|
2011-06-25 19:55:23 +02:00
|
|
|
// Verify that the symbol points to a valid entry in the symbol table.
|
2020-03-23 03:20:04 +01:00
|
|
|
uintptr_t Offset =
|
|
|
|
reinterpret_cast<uintptr_t>(Addr) - reinterpret_cast<uintptr_t>(base());
|
2011-06-25 19:55:23 +02:00
|
|
|
|
2014-09-10 14:51:52 +02:00
|
|
|
assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&
|
|
|
|
"Symbol did not point to the beginning of a symbol");
|
|
|
|
#endif
|
2011-06-25 19:55:23 +02:00
|
|
|
|
2014-01-16 21:11:48 +01:00
|
|
|
return Addr;
|
2011-06-25 19:55:23 +02:00
|
|
|
}
|
|
|
|
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {
|
|
|
|
const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p);
|
2011-06-25 19:55:23 +02:00
|
|
|
|
2017-04-20 01:02:10 +02:00
|
|
|
#ifndef NDEBUG
|
2011-06-25 19:55:23 +02:00
|
|
|
// Verify that the section points to a valid entry in the section table.
|
2014-09-10 14:51:52 +02:00
|
|
|
if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))
|
2011-06-25 19:55:23 +02:00
|
|
|
report_fatal_error("Section was outside of section table.");
|
|
|
|
|
2020-03-23 03:20:04 +01:00
|
|
|
uintptr_t Offset = reinterpret_cast<uintptr_t>(Addr) -
|
|
|
|
reinterpret_cast<uintptr_t>(SectionTable);
|
2014-01-16 21:11:48 +01:00
|
|
|
assert(Offset % sizeof(coff_section) == 0 &&
|
2011-06-25 19:55:23 +02:00
|
|
|
"Section did not point to the beginning of a section");
|
2017-04-20 01:02:10 +02:00
|
|
|
#endif
|
2011-06-25 19:55:23 +02:00
|
|
|
|
2014-01-16 21:11:48 +01:00
|
|
|
return Addr;
|
2011-06-25 19:55:23 +02:00
|
|
|
}
|
|
|
|
|
2014-01-30 03:49:50 +01:00
|
|
|
void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {
|
2014-11-17 12:17:17 +01:00
|
|
|
auto End = reinterpret_cast<uintptr_t>(StringTable);
|
2014-09-10 14:51:52 +02:00
|
|
|
if (SymbolTable16) {
|
|
|
|
const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);
|
|
|
|
Symb += 1 + Symb->NumberOfAuxSymbols;
|
2014-11-17 12:17:17 +01:00
|
|
|
Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
|
2014-09-10 14:51:52 +02:00
|
|
|
} else if (SymbolTable32) {
|
|
|
|
const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);
|
|
|
|
Symb += 1 + Symb->NumberOfAuxSymbols;
|
2014-11-17 12:17:17 +01:00
|
|
|
Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
|
2014-09-10 14:51:52 +02:00
|
|
|
} else {
|
|
|
|
llvm_unreachable("no symbol table pointer!");
|
|
|
|
}
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2016-04-20 23:24:34 +02:00
|
|
|
Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {
|
2020-05-08 19:41:05 +02:00
|
|
|
return getSymbolName(getCOFFSymbol(Ref));
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2015-07-07 19:12:59 +02:00
|
|
|
uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {
|
|
|
|
return getCOFFSymbol(Ref).getValue();
|
2015-06-24 21:11:10 +02:00
|
|
|
}
|
|
|
|
|
2016-11-02 18:32:19 +01:00
|
|
|
uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const {
|
|
|
|
// MSVC/link.exe seems to align symbols to the next-power-of-2
|
|
|
|
// up to 32 bytes.
|
|
|
|
COFFSymbolRef Symb = getCOFFSymbol(Ref);
|
2016-11-11 04:07:45 +01:00
|
|
|
return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));
|
2016-11-02 18:32:19 +01:00
|
|
|
}
|
|
|
|
|
2016-06-24 20:24:42 +02:00
|
|
|
Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {
|
2020-05-02 08:04:04 +02:00
|
|
|
uint64_t Result = cantFail(getSymbolValue(Ref));
|
2014-09-10 14:51:52 +02:00
|
|
|
COFFSymbolRef Symb = getCOFFSymbol(Ref);
|
2015-06-24 19:08:44 +02:00
|
|
|
int32_t SectionNumber = Symb.getSectionNumber();
|
2015-06-24 21:11:10 +02:00
|
|
|
|
|
|
|
if (Symb.isAnyUndefined() || Symb.isCommon() ||
|
|
|
|
COFF::isReservedSectionNumber(SectionNumber))
|
2015-07-03 20:19:00 +02:00
|
|
|
return Result;
|
2014-10-31 06:07:00 +01:00
|
|
|
|
2020-05-08 19:41:05 +02:00
|
|
|
Expected<const coff_section *> Section = getSection(SectionNumber);
|
|
|
|
if (!Section)
|
|
|
|
return Section.takeError();
|
|
|
|
Result += (*Section)->VirtualAddress;
|
2015-07-31 18:14:22 +02:00
|
|
|
|
|
|
|
// The section VirtualAddress does not include ImageBase, and we want to
|
|
|
|
// return virtual addresses.
|
2015-10-09 02:15:08 +02:00
|
|
|
Result += getImageBase();
|
2015-07-31 18:14:22 +02:00
|
|
|
|
2015-07-03 20:19:00 +02:00
|
|
|
return Result;
|
2011-09-14 03:22:52 +02:00
|
|
|
}
|
|
|
|
|
2016-05-02 22:28:12 +02:00
|
|
|
Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {
|
2014-09-10 14:51:52 +02:00
|
|
|
COFFSymbolRef Symb = getCOFFSymbol(Ref);
|
2014-10-31 06:07:00 +01:00
|
|
|
int32_t SectionNumber = Symb.getSectionNumber();
|
2015-06-26 14:18:49 +02:00
|
|
|
|
2015-08-06 07:26:35 +02:00
|
|
|
if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
|
|
|
|
return SymbolRef::ST_Function;
|
2015-06-26 14:18:49 +02:00
|
|
|
if (Symb.isAnyUndefined())
|
|
|
|
return SymbolRef::ST_Unknown;
|
|
|
|
if (Symb.isCommon())
|
|
|
|
return SymbolRef::ST_Data;
|
|
|
|
if (Symb.isFileRecord())
|
|
|
|
return SymbolRef::ST_File;
|
|
|
|
|
|
|
|
// TODO: perhaps we need a new symbol type ST_Section.
|
|
|
|
if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())
|
|
|
|
return SymbolRef::ST_Debug;
|
|
|
|
|
|
|
|
if (!COFF::isReservedSectionNumber(SectionNumber))
|
|
|
|
return SymbolRef::ST_Data;
|
|
|
|
|
|
|
|
return SymbolRef::ST_Other;
|
2011-09-14 03:22:52 +02:00
|
|
|
}
|
|
|
|
|
2020-04-10 14:24:21 +02:00
|
|
|
Expected<uint32_t> COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {
|
2014-09-10 14:51:52 +02:00
|
|
|
COFFSymbolRef Symb = getCOFFSymbol(Ref);
|
2014-01-31 21:57:12 +01:00
|
|
|
uint32_t Result = SymbolRef::SF_None;
|
2012-02-29 00:47:53 +01:00
|
|
|
|
2014-10-31 06:07:00 +01:00
|
|
|
if (Symb.isExternal() || Symb.isWeakExternal())
|
2016-01-25 02:21:45 +01:00
|
|
|
Result |= SymbolRef::SF_Global;
|
2012-02-29 00:47:53 +01:00
|
|
|
|
2018-07-20 22:48:29 +02:00
|
|
|
if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {
|
2012-02-29 00:47:53 +01:00
|
|
|
Result |= SymbolRef::SF_Weak;
|
2018-07-20 22:48:29 +02:00
|
|
|
if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)
|
|
|
|
Result |= SymbolRef::SF_Undefined;
|
2017-07-18 23:26:38 +02:00
|
|
|
}
|
2012-02-29 00:47:53 +01:00
|
|
|
|
2014-09-10 14:51:52 +02:00
|
|
|
if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)
|
2012-02-29 00:47:53 +01:00
|
|
|
Result |= SymbolRef::SF_Absolute;
|
2011-09-14 03:22:52 +02:00
|
|
|
|
2014-10-31 06:07:00 +01:00
|
|
|
if (Symb.isFileRecord())
|
|
|
|
Result |= SymbolRef::SF_FormatSpecific;
|
|
|
|
|
|
|
|
if (Symb.isSectionDefinition())
|
|
|
|
Result |= SymbolRef::SF_FormatSpecific;
|
|
|
|
|
|
|
|
if (Symb.isCommon())
|
|
|
|
Result |= SymbolRef::SF_Common;
|
|
|
|
|
2018-07-20 22:48:29 +02:00
|
|
|
if (Symb.isUndefined())
|
2014-10-31 06:07:00 +01:00
|
|
|
Result |= SymbolRef::SF_Undefined;
|
|
|
|
|
2014-01-31 21:57:12 +01:00
|
|
|
return Result;
|
2011-10-18 01:54:22 +02:00
|
|
|
}
|
|
|
|
|
2015-06-24 12:20:30 +02:00
|
|
|
uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {
|
2014-10-31 06:07:00 +01:00
|
|
|
COFFSymbolRef Symb = getCOFFSymbol(Ref);
|
2015-06-24 12:20:30 +02:00
|
|
|
return Symb.getValue();
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2016-05-02 22:28:12 +02:00
|
|
|
Expected<section_iterator>
|
2015-08-08 01:27:14 +02:00
|
|
|
COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {
|
2014-09-10 14:51:52 +02:00
|
|
|
COFFSymbolRef Symb = getCOFFSymbol(Ref);
|
2015-08-08 01:27:14 +02:00
|
|
|
if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))
|
|
|
|
return section_end();
|
2020-05-08 19:41:05 +02:00
|
|
|
Expected<const coff_section *> Sec = getSection(Symb.getSectionNumber());
|
|
|
|
if (!Sec)
|
|
|
|
return Sec.takeError();
|
2015-08-08 01:27:14 +02:00
|
|
|
DataRefImpl Ret;
|
2020-05-08 19:41:05 +02:00
|
|
|
Ret.p = reinterpret_cast<uintptr_t>(*Sec);
|
2015-08-08 01:27:14 +02:00
|
|
|
return section_iterator(SectionRef(Ret, this));
|
2011-10-18 01:54:46 +02:00
|
|
|
}
|
|
|
|
|
2015-06-24 21:57:32 +02:00
|
|
|
unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {
|
|
|
|
COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());
|
|
|
|
return Symb.getSectionNumber();
|
|
|
|
}
|
|
|
|
|
2014-01-30 03:49:50 +01:00
|
|
|
void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
|
|
|
Sec += 1;
|
|
|
|
Ref.p = reinterpret_cast<uintptr_t>(Sec);
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2019-05-02 12:32:03 +02:00
|
|
|
Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
2019-05-02 12:32:03 +02:00
|
|
|
return getSectionName(Sec);
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2014-10-08 17:28:58 +02:00
|
|
|
uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
2015-07-31 19:40:24 +02:00
|
|
|
uint64_t Result = Sec->VirtualAddress;
|
|
|
|
|
|
|
|
// The section VirtualAddress does not include ImageBase, and we want to
|
|
|
|
// return virtual addresses.
|
2015-10-09 02:15:08 +02:00
|
|
|
Result += getImageBase();
|
2015-07-31 19:40:24 +02:00
|
|
|
return Result;
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2017-05-27 20:10:23 +02:00
|
|
|
uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
|
|
|
|
return toSec(Sec) - SectionTable;
|
|
|
|
}
|
|
|
|
|
2014-10-08 17:28:58 +02:00
|
|
|
uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {
|
2014-10-09 10:42:31 +02:00
|
|
|
return getSectionSize(toSec(Ref));
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2019-05-14 06:22:51 +02:00
|
|
|
Expected<ArrayRef<uint8_t>>
|
|
|
|
COFFObjectFile::getSectionContents(DataRefImpl Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
2012-03-19 21:27:37 +01:00
|
|
|
ArrayRef<uint8_t> Res;
|
2019-05-14 06:22:51 +02:00
|
|
|
if (Error E = getSectionContents(Sec, Res))
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(E);
|
2019-05-14 06:22:51 +02:00
|
|
|
return Res;
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2014-10-08 17:28:58 +02:00
|
|
|
uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
2016-03-17 17:55:18 +01:00
|
|
|
return Sec->getAlignment();
|
2011-10-10 23:55:43 +02:00
|
|
|
}
|
|
|
|
|
2016-05-24 14:48:46 +02:00
|
|
|
bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-10-08 17:28:58 +02:00
|
|
|
bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
2014-10-08 17:28:58 +02:00
|
|
|
return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;
|
2011-09-28 22:57:30 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 17:28:58 +02:00
|
|
|
bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
2014-10-08 17:28:58 +02:00
|
|
|
return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
|
2011-09-28 22:57:30 +02:00
|
|
|
}
|
|
|
|
|
2014-10-08 17:28:58 +02:00
|
|
|
bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
2015-03-07 21:21:27 +01:00
|
|
|
const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
|
|
|
|
COFF::IMAGE_SCN_MEM_READ |
|
|
|
|
COFF::IMAGE_SCN_MEM_WRITE;
|
|
|
|
return (Sec->Characteristics & BssFlags) == BssFlags;
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2020-04-02 10:00:18 +02:00
|
|
|
// The .debug sections are the only debug sections for COFF
|
|
|
|
// (\see MCObjectFileInfo.cpp).
|
2021-05-26 10:47:53 +02:00
|
|
|
bool COFFObjectFile::isDebugSection(DataRefImpl Ref) const {
|
|
|
|
Expected<StringRef> SectionNameOrErr = getSectionName(Ref);
|
|
|
|
if (!SectionNameOrErr) {
|
|
|
|
// TODO: Report the error message properly.
|
|
|
|
consumeError(SectionNameOrErr.takeError());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
StringRef SectionName = SectionNameOrErr.get();
|
2020-04-02 10:00:18 +02:00
|
|
|
return SectionName.startswith(".debug");
|
|
|
|
}
|
|
|
|
|
2015-06-24 21:57:32 +02:00
|
|
|
unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {
|
|
|
|
uintptr_t Offset =
|
2020-03-23 03:20:04 +01:00
|
|
|
Sec.getRawDataRefImpl().p - reinterpret_cast<uintptr_t>(SectionTable);
|
2015-06-24 21:57:32 +02:00
|
|
|
assert((Offset % sizeof(coff_section)) == 0);
|
|
|
|
return (Offset / sizeof(coff_section)) + 1;
|
|
|
|
}
|
|
|
|
|
2014-10-08 17:28:58 +02:00
|
|
|
bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {
|
2014-01-16 21:11:48 +01:00
|
|
|
const coff_section *Sec = toSec(Ref);
|
2018-07-30 21:41:25 +02:00
|
|
|
// In COFF, a virtual section won't have any in-file
|
2015-03-07 21:21:27 +01:00
|
|
|
// content, so the file pointer to the content will be zero.
|
|
|
|
return Sec->PointerToRawData == 0;
|
2012-04-12 22:13:57 +02:00
|
|
|
}
|
|
|
|
|
2014-11-13 09:46:37 +01:00
|
|
|
static uint32_t getNumberOfRelocations(const coff_section *Sec,
|
|
|
|
MemoryBufferRef M, const uint8_t *base) {
|
|
|
|
// The field for the number of relocations in COFF section table is only
|
|
|
|
// 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to
|
|
|
|
// NumberOfRelocations field, and the actual relocation count is stored in the
|
|
|
|
// VirtualAddress field in the first relocation entry.
|
|
|
|
if (Sec->hasExtendedRelocations()) {
|
|
|
|
const coff_relocation *FirstReloc;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(FirstReloc, M,
|
|
|
|
reinterpret_cast<const coff_relocation *>(
|
|
|
|
base + Sec->PointerToRelocations))) {
|
|
|
|
consumeError(std::move(E));
|
2014-11-13 09:46:37 +01:00
|
|
|
return 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
}
|
2014-11-26 23:17:25 +01:00
|
|
|
// -1 to exclude this first relocation entry.
|
|
|
|
return FirstReloc->VirtualAddress - 1;
|
2014-11-13 09:46:37 +01:00
|
|
|
}
|
|
|
|
return Sec->NumberOfRelocations;
|
|
|
|
}
|
|
|
|
|
2014-11-13 10:50:18 +01:00
|
|
|
static const coff_relocation *
|
|
|
|
getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {
|
|
|
|
uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);
|
|
|
|
if (!NumRelocs)
|
|
|
|
return nullptr;
|
|
|
|
auto begin = reinterpret_cast<const coff_relocation *>(
|
|
|
|
Base + Sec->PointerToRelocations);
|
|
|
|
if (Sec->hasExtendedRelocations()) {
|
|
|
|
// Skip the first relocation entry repurposed to store the number of
|
|
|
|
// relocations.
|
|
|
|
begin++;
|
|
|
|
}
|
2020-03-23 03:20:04 +01:00
|
|
|
if (auto E = Binary::checkOffset(M, reinterpret_cast<uintptr_t>(begin),
|
2020-06-06 01:12:38 +02:00
|
|
|
sizeof(coff_relocation) * NumRelocs)) {
|
|
|
|
consumeError(std::move(E));
|
2014-11-13 10:50:18 +01:00
|
|
|
return nullptr;
|
2020-06-06 01:12:38 +02:00
|
|
|
}
|
2014-11-13 10:50:18 +01:00
|
|
|
return begin;
|
|
|
|
}
|
|
|
|
|
2014-01-16 21:11:48 +01:00
|
|
|
relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {
|
|
|
|
const coff_section *Sec = toSec(Ref);
|
2014-11-13 10:50:18 +01:00
|
|
|
const coff_relocation *begin = getFirstReloc(Sec, Data, base());
|
2015-07-06 16:26:07 +02:00
|
|
|
if (begin && Sec->VirtualAddress != 0)
|
|
|
|
report_fatal_error("Sections with relocations should have an address of 0");
|
2014-01-16 21:11:48 +01:00
|
|
|
DataRefImpl Ret;
|
2014-11-13 10:50:18 +01:00
|
|
|
Ret.p = reinterpret_cast<uintptr_t>(begin);
|
2014-01-16 21:11:48 +01:00
|
|
|
return relocation_iterator(RelocationRef(Ret, this));
|
2011-10-07 21:25:32 +02:00
|
|
|
}
|
|
|
|
|
2014-01-16 21:11:48 +01:00
|
|
|
relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {
|
|
|
|
const coff_section *Sec = toSec(Ref);
|
2014-11-13 10:50:18 +01:00
|
|
|
const coff_relocation *I = getFirstReloc(Sec, Data, base());
|
|
|
|
if (I)
|
|
|
|
I += getNumberOfRelocations(Sec, Data, base());
|
2014-01-16 21:11:48 +01:00
|
|
|
DataRefImpl Ret;
|
2014-11-13 10:50:18 +01:00
|
|
|
Ret.p = reinterpret_cast<uintptr_t>(I);
|
2014-01-16 21:11:48 +01:00
|
|
|
return relocation_iterator(RelocationRef(Ret, this));
|
2011-10-07 21:25:32 +02:00
|
|
|
}
|
|
|
|
|
2013-09-27 23:04:00 +02:00
|
|
|
// Initialize the pointer to the symbol table.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::initSymbolTablePtr() {
|
2014-09-10 14:51:52 +02:00
|
|
|
if (COFFHeader)
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(
|
2014-11-17 12:17:17 +01:00
|
|
|
SymbolTable16, Data, base() + getPointerToSymbolTable(),
|
|
|
|
(uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
|
2020-06-11 22:00:54 +02:00
|
|
|
return E;
|
2014-09-10 14:51:52 +02:00
|
|
|
|
|
|
|
if (COFFBigObjHeader)
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(
|
2014-11-17 12:17:17 +01:00
|
|
|
SymbolTable32, Data, base() + getPointerToSymbolTable(),
|
|
|
|
(uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
|
2020-06-11 22:00:54 +02:00
|
|
|
return E;
|
2013-09-27 23:04:00 +02:00
|
|
|
|
|
|
|
// Find string table. The first four byte of the string table contains the
|
|
|
|
// total size of the string table, including the size field itself. If the
|
|
|
|
// string table is empty, the value of the first four byte would be 4.
|
2014-11-14 09:15:42 +01:00
|
|
|
uint32_t StringTableOffset = getPointerToSymbolTable() +
|
|
|
|
getNumberOfSymbols() * getSymbolTableEntrySize();
|
|
|
|
const uint8_t *StringTableAddr = base() + StringTableOffset;
|
2013-09-27 23:04:00 +02:00
|
|
|
const ulittle32_t *StringTableSizePtr;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(StringTableSizePtr, Data, StringTableAddr))
|
|
|
|
return E;
|
2013-09-27 23:04:00 +02:00
|
|
|
StringTableSize = *StringTableSizePtr;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(StringTable, Data, StringTableAddr, StringTableSize))
|
|
|
|
return E;
|
2013-09-27 23:04:00 +02:00
|
|
|
|
2014-02-26 20:51:44 +01:00
|
|
|
// Treat table sizes < 4 as empty because contrary to the PECOFF spec, some
|
|
|
|
// tools like cvtres write a size of 0 for an empty table instead of 4.
|
|
|
|
if (StringTableSize < 4)
|
2020-06-11 22:00:54 +02:00
|
|
|
StringTableSize = 4;
|
2014-02-26 20:51:44 +01:00
|
|
|
|
2013-09-27 23:04:00 +02:00
|
|
|
// Check that the string table is null terminated if has any in it.
|
2014-02-26 20:51:44 +01:00
|
|
|
if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)
|
2020-06-11 22:00:54 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
|
|
|
return Error::success();
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2015-10-09 02:15:08 +02:00
|
|
|
uint64_t COFFObjectFile::getImageBase() const {
|
2015-10-09 02:15:01 +02:00
|
|
|
if (PE32Header)
|
2015-10-09 02:15:08 +02:00
|
|
|
return PE32Header->ImageBase;
|
2015-10-09 02:15:01 +02:00
|
|
|
else if (PE32PlusHeader)
|
2015-10-09 02:15:08 +02:00
|
|
|
return PE32PlusHeader->ImageBase;
|
|
|
|
// This actually comes up in practice.
|
|
|
|
return 0;
|
2015-10-09 02:15:01 +02:00
|
|
|
}
|
|
|
|
|
2014-02-20 07:51:07 +01:00
|
|
|
// Returns the file offset for the given VA.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
|
2015-10-09 02:15:08 +02:00
|
|
|
uint64_t ImageBase = getImageBase();
|
2014-02-20 20:14:56 +01:00
|
|
|
uint64_t Rva = Addr - ImageBase;
|
|
|
|
assert(Rva <= UINT32_MAX);
|
|
|
|
return getRvaPtr((uint32_t)Rva, Res);
|
2014-02-20 07:51:07 +01:00
|
|
|
}
|
|
|
|
|
2013-09-27 23:04:00 +02:00
|
|
|
// Returns the file offset for the given RVA.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const {
|
2014-03-18 07:53:02 +01:00
|
|
|
for (const SectionRef &S : sections()) {
|
|
|
|
const coff_section *Section = getCOFFSection(S);
|
2013-09-27 23:04:00 +02:00
|
|
|
uint32_t SectionStart = Section->VirtualAddress;
|
|
|
|
uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
|
2014-02-20 07:51:07 +01:00
|
|
|
if (SectionStart <= Addr && Addr < SectionEnd) {
|
|
|
|
uint32_t Offset = Addr - SectionStart;
|
2020-03-23 03:20:04 +01:00
|
|
|
Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +
|
|
|
|
Offset;
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
}
|
2020-06-11 22:00:54 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
|
|
|
|
ArrayRef<uint8_t> &Contents) const {
|
2016-06-02 19:10:43 +02:00
|
|
|
for (const SectionRef &S : sections()) {
|
|
|
|
const coff_section *Section = getCOFFSection(S);
|
|
|
|
uint32_t SectionStart = Section->VirtualAddress;
|
|
|
|
// Check if this RVA is within the section bounds. Be careful about integer
|
|
|
|
// overflow.
|
|
|
|
uint32_t OffsetIntoSection = RVA - SectionStart;
|
|
|
|
if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
|
|
|
|
Size <= Section->VirtualSize - OffsetIntoSection) {
|
2020-03-23 03:20:04 +01:00
|
|
|
uintptr_t Begin = reinterpret_cast<uintptr_t>(base()) +
|
|
|
|
Section->PointerToRawData + OffsetIntoSection;
|
2016-06-02 19:10:43 +02:00
|
|
|
Contents =
|
|
|
|
ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-06-02 19:10:43 +02:00
|
|
|
}
|
|
|
|
}
|
2020-06-11 22:00:54 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2016-06-02 19:10:43 +02:00
|
|
|
}
|
|
|
|
|
2013-09-27 23:04:00 +02:00
|
|
|
// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
|
|
|
|
// table entry.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
|
|
|
|
StringRef &Name) const {
|
2013-09-27 23:04:00 +02:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getRvaPtr(Rva, IntPtr))
|
|
|
|
return E;
|
2013-09-27 23:04:00 +02:00
|
|
|
const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);
|
|
|
|
Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);
|
|
|
|
Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
|
|
|
|
const codeview::DebugInfo *&PDBInfo,
|
|
|
|
StringRef &PDBFileName) const {
|
2016-06-02 19:10:43 +02:00
|
|
|
ArrayRef<uint8_t> InfoBytes;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getRvaAndSizeAsBytes(
|
2016-06-02 19:10:43 +02:00
|
|
|
DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes))
|
2020-06-11 22:00:54 +02:00
|
|
|
return E;
|
2016-08-09 02:25:12 +02:00
|
|
|
if (InfoBytes.size() < sizeof(*PDBInfo) + 1)
|
2020-06-11 22:00:54 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2016-08-09 02:25:12 +02:00
|
|
|
PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());
|
|
|
|
InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));
|
2016-06-02 19:10:43 +02:00
|
|
|
PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
|
|
|
|
InfoBytes.size());
|
|
|
|
// Truncate the name at the first null byte. Ignore any padding.
|
|
|
|
PDBFileName = PDBFileName.split('\0').first;
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-06-02 19:10:43 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,
|
|
|
|
StringRef &PDBFileName) const {
|
2016-06-03 22:25:09 +02:00
|
|
|
for (const debug_directory &D : debug_directories())
|
|
|
|
if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
|
|
|
|
return getDebugPDBInfo(&D, PDBInfo, PDBFileName);
|
|
|
|
// If we get here, there is no PDB info to return.
|
|
|
|
PDBInfo = nullptr;
|
|
|
|
PDBFileName = StringRef();
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-06-03 22:25:09 +02:00
|
|
|
}
|
|
|
|
|
2013-09-27 23:04:00 +02:00
|
|
|
// Find the import table.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::initImportTablePtr() {
|
2013-09-27 23:04:00 +02:00
|
|
|
// First, we get the RVA of the import table. If the file lacks a pointer to
|
|
|
|
// the import table, do nothing.
|
2020-06-11 22:00:54 +02:00
|
|
|
const data_directory *DataEntry = getDataDirectory(COFF::IMPORT_TABLE);
|
|
|
|
if (!DataEntry)
|
|
|
|
return Error::success();
|
2013-09-27 23:04:00 +02:00
|
|
|
|
|
|
|
// Do nothing if the pointer to import table is NULL.
|
|
|
|
if (DataEntry->RelativeVirtualAddress == 0)
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2013-09-27 23:04:00 +02:00
|
|
|
|
|
|
|
uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;
|
|
|
|
|
|
|
|
// Find the section that contains the RVA. This is needed because the RVA is
|
|
|
|
// the import table's memory address which is different from its file offset.
|
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getRvaPtr(ImportTableRva, IntPtr))
|
|
|
|
return E;
|
2020-06-06 01:12:38 +02:00
|
|
|
if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
|
2020-06-11 22:00:54 +02:00
|
|
|
return E;
|
2013-09-27 23:04:00 +02:00
|
|
|
ImportDirectory = reinterpret_cast<
|
2016-07-31 21:25:21 +02:00
|
|
|
const coff_import_directory_table_entry *>(IntPtr);
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-01-16 08:05:49 +01:00
|
|
|
}
|
2013-09-27 23:04:00 +02:00
|
|
|
|
2014-10-03 02:41:58 +02:00
|
|
|
// Initializes DelayImportDirectory and NumberOfDelayImportDirectory.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::initDelayImportTablePtr() {
|
|
|
|
const data_directory *DataEntry =
|
|
|
|
getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR);
|
|
|
|
if (!DataEntry)
|
|
|
|
return Error::success();
|
2014-10-03 02:41:58 +02:00
|
|
|
if (DataEntry->RelativeVirtualAddress == 0)
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 02:41:58 +02:00
|
|
|
|
|
|
|
uint32_t RVA = DataEntry->RelativeVirtualAddress;
|
|
|
|
NumberOfDelayImportDirectory = DataEntry->Size /
|
|
|
|
sizeof(delay_import_directory_table_entry) - 1;
|
|
|
|
|
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getRvaPtr(RVA, IntPtr))
|
|
|
|
return E;
|
2014-10-03 02:41:58 +02:00
|
|
|
DelayImportDirectory = reinterpret_cast<
|
|
|
|
const delay_import_directory_table_entry *>(IntPtr);
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 02:41:58 +02:00
|
|
|
}
|
|
|
|
|
2014-01-16 08:05:49 +01:00
|
|
|
// Find the export table.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::initExportTablePtr() {
|
2014-01-16 08:05:49 +01:00
|
|
|
// First, we get the RVA of the export table. If the file lacks a pointer to
|
|
|
|
// the export table, do nothing.
|
2020-06-11 22:00:54 +02:00
|
|
|
const data_directory *DataEntry = getDataDirectory(COFF::EXPORT_TABLE);
|
|
|
|
if (!DataEntry)
|
|
|
|
return Error::success();
|
2014-01-16 08:05:49 +01:00
|
|
|
|
|
|
|
// Do nothing if the pointer to export table is NULL.
|
|
|
|
if (DataEntry->RelativeVirtualAddress == 0)
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-01-16 08:05:49 +01:00
|
|
|
|
|
|
|
uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
|
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getRvaPtr(ExportTableRva, IntPtr))
|
|
|
|
return E;
|
2014-01-17 23:11:27 +01:00
|
|
|
ExportDirectory =
|
|
|
|
reinterpret_cast<const export_directory_table_entry *>(IntPtr);
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::initBaseRelocPtr() {
|
|
|
|
const data_directory *DataEntry =
|
|
|
|
getDataDirectory(COFF::BASE_RELOCATION_TABLE);
|
|
|
|
if (!DataEntry)
|
|
|
|
return Error::success();
|
2014-11-19 01:18:07 +01:00
|
|
|
if (DataEntry->RelativeVirtualAddress == 0)
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-11-19 01:18:07 +01:00
|
|
|
|
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
|
|
|
|
return E;
|
2014-11-19 01:18:07 +01:00
|
|
|
BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(
|
|
|
|
IntPtr);
|
|
|
|
BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(
|
|
|
|
IntPtr + DataEntry->Size);
|
2018-09-05 20:01:04 +02:00
|
|
|
// FIXME: Verify the section containing BaseRelocHeader has at least
|
|
|
|
// DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-11-19 01:18:07 +01:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::initDebugDirectoryPtr() {
|
2016-06-02 19:10:43 +02:00
|
|
|
// Get the RVA of the debug directory. Do nothing if it does not exist.
|
2020-06-11 22:00:54 +02:00
|
|
|
const data_directory *DataEntry = getDataDirectory(COFF::DEBUG_DIRECTORY);
|
|
|
|
if (!DataEntry)
|
|
|
|
return Error::success();
|
2016-06-02 19:10:43 +02:00
|
|
|
|
|
|
|
// Do nothing if the RVA is NULL.
|
|
|
|
if (DataEntry->RelativeVirtualAddress == 0)
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-06-02 19:10:43 +02:00
|
|
|
|
|
|
|
// Check that the size is a multiple of the entry size.
|
|
|
|
if (DataEntry->Size % sizeof(debug_directory) != 0)
|
2020-06-11 22:00:54 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2016-06-02 19:10:43 +02:00
|
|
|
|
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
|
|
|
|
return E;
|
2016-06-02 19:10:43 +02:00
|
|
|
DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
|
2018-09-05 20:01:04 +02:00
|
|
|
DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(
|
|
|
|
IntPtr + DataEntry->Size);
|
|
|
|
// FIXME: Verify the section containing DebugDirectoryBegin has at least
|
|
|
|
// DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-06-02 19:10:43 +02:00
|
|
|
}
|
|
|
|
|
2020-10-08 10:43:50 +02:00
|
|
|
Error COFFObjectFile::initTLSDirectoryPtr() {
|
|
|
|
// Get the RVA of the TLS directory. Do nothing if it does not exist.
|
|
|
|
const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);
|
|
|
|
if (!DataEntry)
|
|
|
|
return Error::success();
|
|
|
|
|
|
|
|
// Do nothing if the RVA is NULL.
|
|
|
|
if (DataEntry->RelativeVirtualAddress == 0)
|
|
|
|
return Error::success();
|
|
|
|
|
|
|
|
uint64_t DirSize =
|
|
|
|
is64() ? sizeof(coff_tls_directory64) : sizeof(coff_tls_directory32);
|
|
|
|
|
|
|
|
// Check that the size is correct.
|
|
|
|
if (DataEntry->Size != DirSize)
|
|
|
|
return createStringError(
|
|
|
|
object_error::parse_failed,
|
2020-10-18 17:41:52 +02:00
|
|
|
"TLS Directory size (%u) is not the expected size (%" PRIu64 ").",
|
2020-10-08 10:43:50 +02:00
|
|
|
static_cast<uint32_t>(DataEntry->Size), DirSize);
|
|
|
|
|
|
|
|
uintptr_t IntPtr = 0;
|
|
|
|
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
|
|
|
|
return E;
|
|
|
|
|
|
|
|
if (is64())
|
|
|
|
TLSDirectory64 = reinterpret_cast<const coff_tls_directory64 *>(IntPtr);
|
|
|
|
else
|
|
|
|
TLSDirectory32 = reinterpret_cast<const coff_tls_directory32 *>(IntPtr);
|
|
|
|
|
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error COFFObjectFile::initLoadConfigPtr() {
|
2017-06-22 03:10:29 +02:00
|
|
|
// Get the RVA of the debug directory. Do nothing if it does not exist.
|
2020-06-11 22:00:54 +02:00
|
|
|
const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);
|
|
|
|
if (!DataEntry)
|
|
|
|
return Error::success();
|
2017-06-22 03:10:29 +02:00
|
|
|
|
|
|
|
// Do nothing if the RVA is NULL.
|
|
|
|
if (DataEntry->RelativeVirtualAddress == 0)
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2017-06-22 03:10:29 +02:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
|
|
|
|
return E;
|
2017-06-22 03:10:29 +02:00
|
|
|
|
|
|
|
LoadConfig = (const void *)IntPtr;
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2017-06-22 03:10:29 +02:00
|
|
|
}
|
|
|
|
|
2020-05-08 22:58:56 +02:00
|
|
|
Expected<std::unique_ptr<COFFObjectFile>>
|
|
|
|
COFFObjectFile::create(MemoryBufferRef Object) {
|
|
|
|
std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object)));
|
|
|
|
if (Error E = Obj->initialize())
|
|
|
|
return std::move(E);
|
|
|
|
return std::move(Obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)
|
2014-08-19 20:44:46 +02:00
|
|
|
: ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
|
2014-09-10 14:51:52 +02:00
|
|
|
COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
|
|
|
|
DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),
|
|
|
|
SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),
|
2020-05-08 22:58:56 +02:00
|
|
|
ImportDirectory(nullptr), DelayImportDirectory(nullptr),
|
|
|
|
NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),
|
|
|
|
BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
|
2020-10-08 10:43:50 +02:00
|
|
|
DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),
|
|
|
|
TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}
|
2020-05-08 22:58:56 +02:00
|
|
|
|
2020-06-06 03:20:11 +02:00
|
|
|
Error COFFObjectFile::initialize() {
|
2011-06-25 19:55:23 +02:00
|
|
|
// Check that we at least have enough room for a header.
|
2020-05-08 22:58:56 +02:00
|
|
|
std::error_code EC;
|
2014-08-19 20:44:46 +02:00
|
|
|
if (!checkSize(Data, EC, sizeof(coff_file_header)))
|
2020-05-08 22:58:56 +02:00
|
|
|
return errorCodeToError(EC);
|
2011-04-04 00:53:19 +02:00
|
|
|
|
2013-06-12 21:10:33 +02:00
|
|
|
// The current location in the file where we are looking at.
|
|
|
|
uint64_t CurPtr = 0;
|
|
|
|
|
|
|
|
// PE header is optional and is present only in executables. If it exists,
|
|
|
|
// it is placed right after COFF header.
|
2014-01-16 21:11:48 +01:00
|
|
|
bool HasPEHeader = false;
|
2011-04-04 00:53:19 +02:00
|
|
|
|
2011-06-25 19:55:23 +02:00
|
|
|
// Check if this is a PE/COFF file.
|
2014-11-05 07:24:35 +01:00
|
|
|
if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {
|
2011-04-04 00:53:19 +02:00
|
|
|
// PE/COFF, seek through MS-DOS compatibility stub and 4-byte
|
|
|
|
// PE signature to find 'normal' COFF header.
|
2014-11-05 07:24:35 +01:00
|
|
|
const auto *DH = reinterpret_cast<const dos_header *>(base());
|
|
|
|
if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {
|
|
|
|
CurPtr = DH->AddressOfNewExeHeader;
|
|
|
|
// Check the PE magic bytes. ("PE\0\0")
|
|
|
|
if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {
|
2020-05-08 22:58:56 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2014-11-05 07:24:35 +01:00
|
|
|
}
|
|
|
|
CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.
|
|
|
|
HasPEHeader = true;
|
2011-06-25 19:55:23 +02:00
|
|
|
}
|
2011-04-04 00:53:19 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(COFFHeader, Data, base() + CurPtr))
|
|
|
|
return E;
|
2014-09-10 14:51:52 +02:00
|
|
|
|
|
|
|
// It might be a bigobj file, let's check. Note that COFF bigobj and COFF
|
|
|
|
// import libraries share a common prefix but bigobj is more restrictive.
|
|
|
|
if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
|
|
|
|
COFFHeader->NumberOfSections == uint16_t(0xffff) &&
|
|
|
|
checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(COFFBigObjHeader, Data, base() + CurPtr))
|
|
|
|
return E;
|
2014-09-10 14:51:52 +02:00
|
|
|
|
|
|
|
// Verify that we are dealing with bigobj.
|
|
|
|
if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&
|
|
|
|
std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,
|
|
|
|
sizeof(COFF::BigObjMagic)) == 0) {
|
|
|
|
COFFHeader = nullptr;
|
|
|
|
CurPtr += sizeof(coff_bigobj_file_header);
|
|
|
|
} else {
|
|
|
|
// It's not a bigobj.
|
|
|
|
COFFBigObjHeader = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (COFFHeader) {
|
|
|
|
// The prior checkSize call may have failed. This isn't a hard error
|
|
|
|
// because we were just trying to sniff out bigobj.
|
2015-06-09 17:20:42 +02:00
|
|
|
EC = std::error_code();
|
2014-09-10 14:51:52 +02:00
|
|
|
CurPtr += sizeof(coff_file_header);
|
|
|
|
|
|
|
|
if (COFFHeader->isImportLibrary())
|
2020-05-08 22:58:56 +02:00
|
|
|
return errorCodeToError(EC);
|
2014-09-10 14:51:52 +02:00
|
|
|
}
|
2013-06-12 21:10:33 +02:00
|
|
|
|
2014-01-16 21:11:48 +01:00
|
|
|
if (HasPEHeader) {
|
2014-01-26 05:15:52 +01:00
|
|
|
const pe32_header *Header;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(Header, Data, base() + CurPtr))
|
|
|
|
return E;
|
2014-01-26 05:15:52 +01:00
|
|
|
|
|
|
|
const uint8_t *DataDirAddr;
|
|
|
|
uint64_t DataDirSize;
|
2014-11-05 07:24:35 +01:00
|
|
|
if (Header->Magic == COFF::PE32Header::PE32) {
|
2014-01-26 05:15:52 +01:00
|
|
|
PE32Header = Header;
|
|
|
|
DataDirAddr = base() + CurPtr + sizeof(pe32_header);
|
|
|
|
DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;
|
2014-11-05 07:24:35 +01:00
|
|
|
} else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {
|
2014-01-26 05:15:52 +01:00
|
|
|
PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);
|
|
|
|
DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);
|
|
|
|
DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
|
|
|
|
} else {
|
|
|
|
// It's neither PE32 nor PE32+.
|
2020-05-08 22:58:56 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2013-07-20 01:23:29 +02:00
|
|
|
}
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))
|
|
|
|
return E;
|
2013-06-12 21:10:33 +02:00
|
|
|
}
|
2011-09-08 22:52:17 +02:00
|
|
|
|
2016-08-12 00:02:44 +02:00
|
|
|
if (COFFHeader)
|
|
|
|
CurPtr += COFFHeader->SizeOfOptionalHeader;
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
assert(COFFHeader || COFFBigObjHeader);
|
|
|
|
|
|
|
|
if (Error E =
|
|
|
|
getObject(SectionTable, Data, base() + CurPtr,
|
|
|
|
(uint64_t)getNumberOfSections() * sizeof(coff_section)))
|
|
|
|
return E;
|
2011-06-25 19:55:23 +02:00
|
|
|
|
2013-09-27 23:04:00 +02:00
|
|
|
// Initialize the pointer to the symbol table.
|
2014-11-17 12:17:17 +01:00
|
|
|
if (getPointerToSymbolTable() != 0) {
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = initSymbolTablePtr()) {
|
|
|
|
// Recover from errors reading the symbol table.
|
|
|
|
consumeError(std::move(E));
|
2016-08-30 22:20:24 +02:00
|
|
|
SymbolTable16 = nullptr;
|
|
|
|
SymbolTable32 = nullptr;
|
|
|
|
StringTable = nullptr;
|
|
|
|
StringTableSize = 0;
|
|
|
|
}
|
2014-11-17 12:17:17 +01:00
|
|
|
} else {
|
|
|
|
// We had better not have any symbols if we don't have a symbol table.
|
|
|
|
if (getNumberOfSymbols() != 0) {
|
2020-05-08 22:58:56 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2014-11-17 12:17:17 +01:00
|
|
|
}
|
|
|
|
}
|
2011-01-20 07:38:34 +01:00
|
|
|
|
2013-09-27 23:04:00 +02:00
|
|
|
// Initialize the pointer to the beginning of the import table.
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = initImportTablePtr())
|
|
|
|
return E;
|
|
|
|
if (Error E = initDelayImportTablePtr())
|
|
|
|
return E;
|
2011-09-08 22:52:17 +02:00
|
|
|
|
2014-01-16 08:05:49 +01:00
|
|
|
// Initialize the pointer to the export table.
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = initExportTablePtr())
|
|
|
|
return E;
|
2014-01-16 08:05:49 +01:00
|
|
|
|
2014-11-19 01:18:07 +01:00
|
|
|
// Initialize the pointer to the base relocation table.
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = initBaseRelocPtr())
|
|
|
|
return E;
|
2014-11-19 01:18:07 +01:00
|
|
|
|
2020-10-08 10:43:50 +02:00
|
|
|
// Initialize the pointer to the debug directory.
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = initDebugDirectoryPtr())
|
|
|
|
return E;
|
2016-06-02 19:10:43 +02:00
|
|
|
|
2020-10-08 10:43:50 +02:00
|
|
|
// Initialize the pointer to the TLS directory.
|
|
|
|
if (Error E = initTLSDirectoryPtr())
|
|
|
|
return E;
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = initLoadConfigPtr())
|
|
|
|
return E;
|
2017-06-22 03:10:29 +02:00
|
|
|
|
2020-05-08 22:58:56 +02:00
|
|
|
return Error::success();
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2016-11-22 04:38:40 +01:00
|
|
|
basic_symbol_iterator COFFObjectFile::symbol_begin() const {
|
2014-01-16 21:11:48 +01:00
|
|
|
DataRefImpl Ret;
|
2014-09-10 14:51:52 +02:00
|
|
|
Ret.p = getSymbolTable();
|
2014-02-21 21:10:59 +01:00
|
|
|
return basic_symbol_iterator(SymbolRef(Ret, this));
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2016-11-22 04:38:40 +01:00
|
|
|
basic_symbol_iterator COFFObjectFile::symbol_end() const {
|
2011-01-20 07:38:34 +01:00
|
|
|
// The symbol table ends where the string table begins.
|
2014-01-16 21:11:48 +01:00
|
|
|
DataRefImpl Ret;
|
|
|
|
Ret.p = reinterpret_cast<uintptr_t>(StringTable);
|
2014-02-21 21:10:59 +01:00
|
|
|
return basic_symbol_iterator(SymbolRef(Ret, this));
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2013-09-27 23:47:05 +02:00
|
|
|
import_directory_iterator COFFObjectFile::import_directory_begin() const {
|
2016-06-26 06:36:32 +02:00
|
|
|
if (!ImportDirectory)
|
|
|
|
return import_directory_end();
|
2016-07-31 21:25:21 +02:00
|
|
|
if (ImportDirectory->isNull())
|
2016-06-26 06:36:32 +02:00
|
|
|
return import_directory_end();
|
2014-01-16 04:13:19 +01:00
|
|
|
return import_directory_iterator(
|
|
|
|
ImportDirectoryEntryRef(ImportDirectory, 0, this));
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2013-09-27 23:47:05 +02:00
|
|
|
import_directory_iterator COFFObjectFile::import_directory_end() const {
|
2014-01-16 04:13:19 +01:00
|
|
|
return import_directory_iterator(
|
2016-06-26 06:36:32 +02:00
|
|
|
ImportDirectoryEntryRef(nullptr, -1, this));
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
2012-03-01 23:19:54 +01:00
|
|
|
|
2014-10-03 02:41:58 +02:00
|
|
|
delay_import_directory_iterator
|
|
|
|
COFFObjectFile::delay_import_directory_begin() const {
|
|
|
|
return delay_import_directory_iterator(
|
|
|
|
DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
delay_import_directory_iterator
|
|
|
|
COFFObjectFile::delay_import_directory_end() const {
|
|
|
|
return delay_import_directory_iterator(
|
|
|
|
DelayImportDirectoryEntryRef(
|
|
|
|
DelayImportDirectory, NumberOfDelayImportDirectory, this));
|
|
|
|
}
|
|
|
|
|
2014-01-16 08:05:49 +01:00
|
|
|
export_directory_iterator COFFObjectFile::export_directory_begin() const {
|
|
|
|
return export_directory_iterator(
|
|
|
|
ExportDirectoryEntryRef(ExportDirectory, 0, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
export_directory_iterator COFFObjectFile::export_directory_end() const {
|
2014-04-15 08:32:26 +02:00
|
|
|
if (!ExportDirectory)
|
|
|
|
return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));
|
2014-01-16 21:11:48 +01:00
|
|
|
ExportDirectoryEntryRef Ref(ExportDirectory,
|
2014-01-16 08:05:49 +01:00
|
|
|
ExportDirectory->AddressTableEntries, this);
|
2014-01-16 21:11:48 +01:00
|
|
|
return export_directory_iterator(Ref);
|
2014-01-16 08:05:49 +01:00
|
|
|
}
|
|
|
|
|
2014-02-10 21:24:04 +01:00
|
|
|
section_iterator COFFObjectFile::section_begin() const {
|
2014-01-16 21:11:48 +01:00
|
|
|
DataRefImpl Ret;
|
|
|
|
Ret.p = reinterpret_cast<uintptr_t>(SectionTable);
|
|
|
|
return section_iterator(SectionRef(Ret, this));
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2014-02-10 21:24:04 +01:00
|
|
|
section_iterator COFFObjectFile::section_end() const {
|
2014-01-16 21:11:48 +01:00
|
|
|
DataRefImpl Ret;
|
2014-09-10 14:51:52 +02:00
|
|
|
int NumSections =
|
|
|
|
COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();
|
2014-01-16 21:11:48 +01:00
|
|
|
Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);
|
|
|
|
return section_iterator(SectionRef(Ret, this));
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2014-11-19 01:18:07 +01:00
|
|
|
base_reloc_iterator COFFObjectFile::base_reloc_begin() const {
|
|
|
|
return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));
|
|
|
|
}
|
|
|
|
|
|
|
|
base_reloc_iterator COFFObjectFile::base_reloc_end() const {
|
|
|
|
return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));
|
|
|
|
}
|
|
|
|
|
2011-01-20 07:38:34 +01:00
|
|
|
uint8_t COFFObjectFile::getBytesInAddress() const {
|
2017-06-30 09:02:13 +02:00
|
|
|
return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
StringRef COFFObjectFile::getFileFormatName() const {
|
2014-09-10 14:51:52 +02:00
|
|
|
switch(getMachine()) {
|
2011-01-20 07:38:34 +01:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_I386:
|
|
|
|
return "COFF-i386";
|
|
|
|
case COFF::IMAGE_FILE_MACHINE_AMD64:
|
|
|
|
return "COFF-x86-64";
|
2014-03-13 08:02:35 +01:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARMNT:
|
|
|
|
return "COFF-ARM";
|
2015-07-28 18:18:17 +02:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARM64:
|
|
|
|
return "COFF-ARM64";
|
2011-01-20 07:38:34 +01:00
|
|
|
default:
|
|
|
|
return "COFF-<unknown arch>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-14 23:07:03 +01:00
|
|
|
Triple::ArchType COFFObjectFile::getArch() const {
|
2014-09-10 14:51:52 +02:00
|
|
|
switch (getMachine()) {
|
2011-01-20 07:38:34 +01:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_I386:
|
|
|
|
return Triple::x86;
|
|
|
|
case COFF::IMAGE_FILE_MACHINE_AMD64:
|
|
|
|
return Triple::x86_64;
|
2014-03-13 08:02:35 +01:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARMNT:
|
|
|
|
return Triple::thumb;
|
2015-07-28 18:18:17 +02:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARM64:
|
|
|
|
return Triple::aarch64;
|
2011-01-20 07:38:34 +01:00
|
|
|
default:
|
|
|
|
return Triple::UnknownArch;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-04 17:25:03 +02:00
|
|
|
Expected<uint64_t> COFFObjectFile::getStartAddress() const {
|
|
|
|
if (PE32Header)
|
|
|
|
return PE32Header->AddressOfEntryPoint;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-10-09 04:16:38 +02:00
|
|
|
iterator_range<import_directory_iterator>
|
|
|
|
COFFObjectFile::import_directories() const {
|
|
|
|
return make_range(import_directory_begin(), import_directory_end());
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator_range<delay_import_directory_iterator>
|
|
|
|
COFFObjectFile::delay_import_directories() const {
|
|
|
|
return make_range(delay_import_directory_begin(),
|
|
|
|
delay_import_directory_end());
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator_range<export_directory_iterator>
|
|
|
|
COFFObjectFile::export_directories() const {
|
|
|
|
return make_range(export_directory_begin(), export_directory_end());
|
|
|
|
}
|
|
|
|
|
2014-11-19 01:18:07 +01:00
|
|
|
iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {
|
|
|
|
return make_range(base_reloc_begin(), base_reloc_end());
|
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
const data_directory *COFFObjectFile::getDataDirectory(uint32_t Index) const {
|
|
|
|
if (!DataDirectory)
|
|
|
|
return nullptr;
|
2014-01-26 05:15:52 +01:00
|
|
|
assert(PE32Header || PE32PlusHeader);
|
|
|
|
uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize
|
|
|
|
: PE32PlusHeader->NumberOfRvaAndSize;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Index >= NumEnt)
|
|
|
|
return nullptr;
|
|
|
|
return &DataDirectory[Index];
|
2013-07-20 01:23:29 +02:00
|
|
|
}
|
|
|
|
|
2020-05-08 19:41:05 +02:00
|
|
|
Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {
|
|
|
|
// Perhaps getting the section of a reserved section index should be an error,
|
|
|
|
// but callers rely on this to return null.
|
2014-03-19 00:37:53 +01:00
|
|
|
if (COFF::isReservedSectionNumber(Index))
|
2020-05-08 19:41:05 +02:00
|
|
|
return (const coff_section *)nullptr;
|
2014-11-17 12:17:17 +01:00
|
|
|
if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {
|
2011-06-25 19:55:23 +02:00
|
|
|
// We already verified the section table data, so no need to check again.
|
2020-05-08 19:41:05 +02:00
|
|
|
return SectionTable + (Index - 1);
|
2018-07-11 12:00:29 +02:00
|
|
|
}
|
2020-05-08 19:41:05 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2018-07-11 12:00:29 +02:00
|
|
|
}
|
|
|
|
|
2020-05-08 19:41:05 +02:00
|
|
|
Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {
|
2011-06-25 19:55:23 +02:00
|
|
|
if (StringTableSize <= 4)
|
|
|
|
// Tried to get a string from an empty string table.
|
2020-05-08 19:41:05 +02:00
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2014-01-16 21:11:48 +01:00
|
|
|
if (Offset >= StringTableSize)
|
2020-05-08 19:41:05 +02:00
|
|
|
return errorCodeToError(object_error::unexpected_eof);
|
|
|
|
return StringRef(StringTable + Offset);
|
2011-01-20 07:38:34 +01:00
|
|
|
}
|
|
|
|
|
2020-05-08 19:41:05 +02:00
|
|
|
Expected<StringRef> COFFObjectFile::getSymbolName(COFFSymbolRef Symbol) const {
|
|
|
|
return getSymbolName(Symbol.getGeneric());
|
2015-06-30 02:03:56 +02:00
|
|
|
}
|
|
|
|
|
2020-05-08 19:41:05 +02:00
|
|
|
Expected<StringRef>
|
|
|
|
COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol) const {
|
2011-10-18 01:53:56 +02:00
|
|
|
// Check for string table entry. First 4 bytes are 0.
|
2020-05-08 19:41:05 +02:00
|
|
|
if (Symbol->Name.Offset.Zeroes == 0)
|
|
|
|
return getString(Symbol->Name.Offset.Offset);
|
2011-10-18 01:53:56 +02:00
|
|
|
|
2020-05-08 19:41:05 +02:00
|
|
|
// Null terminated, let ::strlen figure out the length.
|
2015-06-30 02:03:56 +02:00
|
|
|
if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)
|
2020-05-08 19:41:05 +02:00
|
|
|
return StringRef(Symbol->Name.ShortName);
|
|
|
|
|
|
|
|
// Not null terminated, use all 8 bytes.
|
|
|
|
return StringRef(Symbol->Name.ShortName, COFF::NameSize);
|
2011-10-18 01:53:56 +02:00
|
|
|
}
|
|
|
|
|
2014-09-10 14:51:52 +02:00
|
|
|
ArrayRef<uint8_t>
|
|
|
|
COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {
|
2014-04-15 08:32:26 +02:00
|
|
|
const uint8_t *Aux = nullptr;
|
2013-09-27 23:04:00 +02:00
|
|
|
|
2014-09-10 14:51:52 +02:00
|
|
|
size_t SymbolSize = getSymbolTableEntrySize();
|
|
|
|
if (Symbol.getNumberOfAuxSymbols() > 0) {
|
|
|
|
// AUX data comes immediately after the symbol in COFF
|
|
|
|
Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;
|
2017-04-20 01:02:10 +02:00
|
|
|
#ifndef NDEBUG
|
2014-01-16 21:11:48 +01:00
|
|
|
// Verify that the Aux symbol points to a valid entry in the symbol table.
|
|
|
|
uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());
|
2014-09-10 14:51:52 +02:00
|
|
|
if (Offset < getPointerToSymbolTable() ||
|
|
|
|
Offset >=
|
|
|
|
getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))
|
2012-06-15 03:08:25 +02:00
|
|
|
report_fatal_error("Aux Symbol data was outside of symbol table.");
|
|
|
|
|
2014-09-10 14:51:52 +02:00
|
|
|
assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&
|
|
|
|
"Aux Symbol data did not point to the beginning of a symbol");
|
2017-04-20 01:02:10 +02:00
|
|
|
#endif
|
2012-06-15 03:15:47 +02:00
|
|
|
}
|
2014-09-10 14:51:52 +02:00
|
|
|
return makeArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);
|
2012-06-15 03:08:25 +02:00
|
|
|
}
|
|
|
|
|
2019-01-03 09:08:23 +01:00
|
|
|
uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {
|
|
|
|
uintptr_t Offset =
|
|
|
|
reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();
|
|
|
|
assert(Offset % getSymbolTableEntrySize() == 0 &&
|
|
|
|
"Symbol did not point to the beginning of a symbol");
|
|
|
|
size_t Index = Offset / getSymbolTableEntrySize();
|
|
|
|
assert(Index < getNumberOfSymbols());
|
|
|
|
return Index;
|
|
|
|
}
|
|
|
|
|
2019-05-02 12:32:03 +02:00
|
|
|
Expected<StringRef>
|
|
|
|
COFFObjectFile::getSectionName(const coff_section *Sec) const {
|
2012-03-19 21:27:15 +01:00
|
|
|
StringRef Name;
|
2014-09-10 14:51:52 +02:00
|
|
|
if (Sec->Name[COFF::NameSize - 1] == 0)
|
2012-03-19 21:27:15 +01:00
|
|
|
// Null terminated, let ::strlen figure out the length.
|
|
|
|
Name = Sec->Name;
|
|
|
|
else
|
|
|
|
// Not null terminated, use all 8 bytes.
|
2014-09-10 14:51:52 +02:00
|
|
|
Name = StringRef(Sec->Name, COFF::NameSize);
|
2012-03-19 21:27:15 +01:00
|
|
|
|
|
|
|
// Check for string table entry. First byte is '/'.
|
2014-11-13 08:42:09 +01:00
|
|
|
if (Name.startswith("/")) {
|
2012-03-19 21:27:15 +01:00
|
|
|
uint32_t Offset;
|
2014-11-13 08:42:09 +01:00
|
|
|
if (Name.startswith("//")) {
|
2014-02-22 17:12:20 +01:00
|
|
|
if (decodeBase64StringEntry(Name.substr(2), Offset))
|
2019-05-02 12:32:03 +02:00
|
|
|
return createStringError(object_error::parse_failed,
|
2020-02-24 17:20:49 +01:00
|
|
|
"invalid section name");
|
2014-02-22 17:12:20 +01:00
|
|
|
} else {
|
|
|
|
if (Name.substr(1).getAsInteger(10, Offset))
|
2019-05-02 12:32:03 +02:00
|
|
|
return createStringError(object_error::parse_failed,
|
|
|
|
"invalid section name");
|
2014-02-22 17:12:20 +01:00
|
|
|
}
|
2020-05-08 19:41:05 +02:00
|
|
|
return getString(Offset);
|
2012-03-19 21:27:15 +01:00
|
|
|
}
|
|
|
|
|
2019-05-02 12:32:03 +02:00
|
|
|
return Name;
|
2012-03-19 21:27:15 +01:00
|
|
|
}
|
|
|
|
|
2014-10-09 10:42:31 +02:00
|
|
|
uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {
|
2014-10-09 09:49:28 +02:00
|
|
|
// SizeOfRawData and VirtualSize change what they represent depending on
|
|
|
|
// whether or not we have an executable image.
|
|
|
|
//
|
|
|
|
// For object files, SizeOfRawData contains the size of section's data;
|
2015-07-04 05:25:51 +02:00
|
|
|
// VirtualSize should be zero but isn't due to buggy COFF writers.
|
2014-10-09 09:49:28 +02:00
|
|
|
//
|
|
|
|
// For executables, SizeOfRawData *must* be a multiple of FileAlignment; the
|
|
|
|
// actual section size is in VirtualSize. It is possible for VirtualSize to
|
|
|
|
// be greater than SizeOfRawData; the contents past that point should be
|
|
|
|
// considered to be zero.
|
2015-07-04 05:25:51 +02:00
|
|
|
if (getDOSHeader())
|
|
|
|
return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
|
|
|
|
return Sec->SizeOfRawData;
|
2014-10-09 10:42:31 +02:00
|
|
|
}
|
|
|
|
|
2019-05-14 06:22:51 +02:00
|
|
|
Error COFFObjectFile::getSectionContents(const coff_section *Sec,
|
|
|
|
ArrayRef<uint8_t> &Res) const {
|
2016-05-28 21:45:51 +02:00
|
|
|
// In COFF, a virtual section won't have any in-file
|
|
|
|
// content, so the file pointer to the content will be zero.
|
|
|
|
if (Sec->PointerToRawData == 0)
|
2019-05-14 06:22:51 +02:00
|
|
|
return Error::success();
|
2014-10-09 10:42:31 +02:00
|
|
|
// The only thing that we need to verify is that the contents is contained
|
|
|
|
// within the file bounds. We don't need to make sure it doesn't cover other
|
|
|
|
// data, as there's nothing that says that is not allowed.
|
2020-03-23 03:20:04 +01:00
|
|
|
uintptr_t ConStart =
|
|
|
|
reinterpret_cast<uintptr_t>(base()) + Sec->PointerToRawData;
|
2014-10-09 10:42:31 +02:00
|
|
|
uint32_t SectionSize = getSectionSize(Sec);
|
2020-06-06 01:12:38 +02:00
|
|
|
if (Error E = checkOffset(Data, ConStart, SectionSize))
|
|
|
|
return E;
|
2014-10-09 10:42:31 +02:00
|
|
|
Res = makeArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);
|
2019-05-14 06:22:51 +02:00
|
|
|
return Error::success();
|
2012-03-19 21:27:37 +01:00
|
|
|
}
|
|
|
|
|
2011-09-08 22:52:17 +02:00
|
|
|
const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {
|
2011-10-07 21:25:32 +02:00
|
|
|
return reinterpret_cast<const coff_relocation*>(Rel.p);
|
2011-09-08 22:52:17 +02:00
|
|
|
}
|
2014-01-16 21:11:48 +01:00
|
|
|
|
2014-01-30 03:49:50 +01:00
|
|
|
void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
|
2011-10-07 21:25:32 +02:00
|
|
|
Rel.p = reinterpret_cast<uintptr_t>(
|
|
|
|
reinterpret_cast<const coff_relocation*>(Rel.p) + 1);
|
2011-09-08 22:52:17 +02:00
|
|
|
}
|
2014-01-16 21:11:48 +01:00
|
|
|
|
2015-06-30 01:29:12 +02:00
|
|
|
uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
|
2014-11-13 08:42:07 +01:00
|
|
|
const coff_relocation *R = toRel(Rel);
|
2015-06-30 01:29:12 +02:00
|
|
|
return R->VirtualAddress;
|
2011-09-08 22:52:17 +02:00
|
|
|
}
|
2014-01-16 21:11:48 +01:00
|
|
|
|
2013-06-05 03:33:53 +02:00
|
|
|
symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
|
2014-09-10 14:51:52 +02:00
|
|
|
const coff_relocation *R = toRel(Rel);
|
2014-01-16 21:11:48 +01:00
|
|
|
DataRefImpl Ref;
|
2014-11-17 12:17:17 +01:00
|
|
|
if (R->SymbolTableIndex >= getNumberOfSymbols())
|
|
|
|
return symbol_end();
|
2014-09-10 14:51:52 +02:00
|
|
|
if (SymbolTable16)
|
|
|
|
Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);
|
|
|
|
else if (SymbolTable32)
|
|
|
|
Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);
|
|
|
|
else
|
2014-11-25 08:43:14 +01:00
|
|
|
llvm_unreachable("no symbol table pointer!");
|
2014-01-16 21:11:48 +01:00
|
|
|
return symbol_iterator(SymbolRef(Ref, this));
|
2011-09-08 22:52:17 +02:00
|
|
|
}
|
2014-01-16 21:11:48 +01:00
|
|
|
|
2015-06-30 03:53:01 +02:00
|
|
|
uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {
|
2011-09-08 22:52:17 +02:00
|
|
|
const coff_relocation* R = toRel(Rel);
|
2015-06-30 03:53:01 +02:00
|
|
|
return R->Type;
|
2011-09-08 22:52:17 +02:00
|
|
|
}
|
2011-10-07 21:25:32 +02:00
|
|
|
|
2014-03-18 07:53:02 +01:00
|
|
|
const coff_section *
|
|
|
|
COFFObjectFile::getCOFFSection(const SectionRef &Section) const {
|
|
|
|
return toSec(Section.getRawDataRefImpl());
|
2012-06-15 03:08:25 +02:00
|
|
|
}
|
|
|
|
|
2014-09-10 14:51:52 +02:00
|
|
|
COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {
|
|
|
|
if (SymbolTable16)
|
|
|
|
return toSymb<coff_symbol16>(Ref);
|
|
|
|
if (SymbolTable32)
|
|
|
|
return toSymb<coff_symbol32>(Ref);
|
|
|
|
llvm_unreachable("no symbol table pointer!");
|
|
|
|
}
|
|
|
|
|
|
|
|
COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {
|
|
|
|
return getCOFFSymbol(Symbol.getRawDataRefImpl());
|
2012-06-15 03:08:25 +02:00
|
|
|
}
|
|
|
|
|
2014-02-21 21:10:59 +01:00
|
|
|
const coff_relocation *
|
2014-03-18 07:53:02 +01:00
|
|
|
COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {
|
|
|
|
return toRel(Reloc.getRawDataRefImpl());
|
2012-06-18 21:47:16 +02:00
|
|
|
}
|
|
|
|
|
2018-04-17 03:54:34 +02:00
|
|
|
ArrayRef<coff_relocation>
|
2015-06-25 02:07:39 +02:00
|
|
|
COFFObjectFile::getRelocations(const coff_section *Sec) const {
|
2018-04-17 03:54:34 +02:00
|
|
|
return {getFirstReloc(Sec, Data, base()),
|
|
|
|
getNumberOfRelocations(Sec, Data, base())};
|
2015-06-25 02:07:39 +02:00
|
|
|
}
|
|
|
|
|
2014-03-18 07:53:02 +01:00
|
|
|
#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \
|
|
|
|
case COFF::reloc_type: \
|
2018-08-27 10:42:39 +02:00
|
|
|
return #reloc_type;
|
2011-10-07 21:25:32 +02:00
|
|
|
|
2018-08-27 10:42:39 +02:00
|
|
|
StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
|
2014-09-10 14:51:52 +02:00
|
|
|
switch (getMachine()) {
|
2011-10-07 21:25:32 +02:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_AMD64:
|
2018-08-27 10:42:39 +02:00
|
|
|
switch (Type) {
|
2011-10-07 21:25:32 +02:00
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);
|
|
|
|
default:
|
2018-08-27 10:42:39 +02:00
|
|
|
return "Unknown";
|
2011-10-07 21:25:32 +02:00
|
|
|
}
|
|
|
|
break;
|
2014-04-09 08:18:28 +02:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARMNT:
|
2018-08-27 10:42:39 +02:00
|
|
|
switch (Type) {
|
2014-04-09 08:18:28 +02:00
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);
|
2019-01-27 20:53:36 +01:00
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32);
|
2014-04-09 08:18:28 +02:00
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);
|
2019-01-27 20:53:36 +01:00
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR);
|
2014-04-09 08:18:28 +02:00
|
|
|
default:
|
2018-08-27 10:42:39 +02:00
|
|
|
return "Unknown";
|
2014-04-09 08:18:28 +02:00
|
|
|
}
|
|
|
|
break;
|
2017-06-28 01:58:19 +02:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARM64:
|
2018-08-27 10:42:39 +02:00
|
|
|
switch (Type) {
|
2017-06-28 01:58:19 +02:00
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);
|
2019-01-27 20:53:36 +01:00
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32);
|
2017-06-28 01:58:19 +02:00
|
|
|
default:
|
2018-08-27 10:42:39 +02:00
|
|
|
return "Unknown";
|
2017-06-28 01:58:19 +02:00
|
|
|
}
|
|
|
|
break;
|
2011-10-07 21:25:32 +02:00
|
|
|
case COFF::IMAGE_FILE_MACHINE_I386:
|
2018-08-27 10:42:39 +02:00
|
|
|
switch (Type) {
|
2011-10-07 21:25:32 +02:00
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);
|
|
|
|
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);
|
|
|
|
default:
|
2018-08-27 10:42:39 +02:00
|
|
|
return "Unknown";
|
2011-10-07 21:25:32 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
2018-08-27 10:42:39 +02:00
|
|
|
return "Unknown";
|
2011-10-07 21:25:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME
|
|
|
|
|
2018-08-27 10:42:39 +02:00
|
|
|
void COFFObjectFile::getRelocationTypeName(
|
|
|
|
DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
|
|
|
|
const coff_relocation *Reloc = toRel(Rel);
|
|
|
|
StringRef Res = getRelocationTypeName(Reloc->Type);
|
|
|
|
Result.append(Res.begin(), Res.end());
|
|
|
|
}
|
|
|
|
|
2014-08-17 21:09:37 +02:00
|
|
|
bool COFFObjectFile::isRelocatableObject() const {
|
|
|
|
return !DataDirectory;
|
|
|
|
}
|
|
|
|
|
2018-12-08 19:15:41 +01:00
|
|
|
StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {
|
|
|
|
return StringSwitch<StringRef>(Name)
|
|
|
|
.Case("eh_fram", "eh_frame")
|
|
|
|
.Default(Name);
|
|
|
|
}
|
|
|
|
|
2013-09-27 23:04:00 +02:00
|
|
|
bool ImportDirectoryEntryRef::
|
|
|
|
operator==(const ImportDirectoryEntryRef &Other) const {
|
2014-01-16 04:13:19 +01:00
|
|
|
return ImportTable == Other.ImportTable && Index == Other.Index;
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2014-01-30 03:49:50 +01:00
|
|
|
void ImportDirectoryEntryRef::moveNext() {
|
|
|
|
++Index;
|
2016-07-31 21:25:21 +02:00
|
|
|
if (ImportTable[Index].isNull()) {
|
2016-06-26 06:36:32 +02:00
|
|
|
Index = -1;
|
|
|
|
ImportTable = nullptr;
|
|
|
|
}
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ImportDirectoryEntryRef::getImportTableEntry(
|
2016-07-31 21:25:21 +02:00
|
|
|
const coff_import_directory_table_entry *&Result) const {
|
2016-06-26 06:36:32 +02:00
|
|
|
return getObject(Result, OwningObject->Data, ImportTable + Index);
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 00:05:29 +02:00
|
|
|
static imported_symbol_iterator
|
2014-10-03 02:41:58 +02:00
|
|
|
makeImportedSymbolIterator(const COFFObjectFile *Object,
|
2014-10-03 00:05:29 +02:00
|
|
|
uintptr_t Ptr, int Index) {
|
2014-10-03 02:41:58 +02:00
|
|
|
if (Object->getBytesInAddress() == 4) {
|
2014-10-03 00:05:29 +02:00
|
|
|
auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);
|
2014-10-03 02:41:58 +02:00
|
|
|
return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
|
2014-10-03 00:05:29 +02:00
|
|
|
}
|
|
|
|
auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);
|
2014-10-03 02:41:58 +02:00
|
|
|
return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
|
2014-10-03 00:05:29 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 02:41:58 +02:00
|
|
|
static imported_symbol_iterator
|
|
|
|
importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {
|
2014-10-03 00:05:29 +02:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
// FIXME: Handle errors.
|
|
|
|
cantFail(Object->getRvaPtr(RVA, IntPtr));
|
2014-10-03 02:41:58 +02:00
|
|
|
return makeImportedSymbolIterator(Object, IntPtr, 0);
|
2014-10-03 00:05:29 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 02:41:58 +02:00
|
|
|
static imported_symbol_iterator
|
|
|
|
importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {
|
2014-10-03 00:05:29 +02:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
// FIXME: Handle errors.
|
|
|
|
cantFail(Object->getRvaPtr(RVA, IntPtr));
|
2014-10-03 00:05:29 +02:00
|
|
|
// Forward the pointer to the last entry which is null.
|
|
|
|
int Index = 0;
|
2014-10-03 02:41:58 +02:00
|
|
|
if (Object->getBytesInAddress() == 4) {
|
2014-10-03 00:05:29 +02:00
|
|
|
auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);
|
|
|
|
while (*Entry++)
|
|
|
|
++Index;
|
|
|
|
} else {
|
|
|
|
auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);
|
|
|
|
while (*Entry++)
|
|
|
|
++Index;
|
|
|
|
}
|
2014-10-03 02:41:58 +02:00
|
|
|
return makeImportedSymbolIterator(Object, IntPtr, Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
imported_symbol_iterator
|
|
|
|
ImportDirectoryEntryRef::imported_symbol_begin() const {
|
2016-07-31 21:40:02 +02:00
|
|
|
return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,
|
2014-10-03 02:41:58 +02:00
|
|
|
OwningObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
imported_symbol_iterator
|
|
|
|
ImportDirectoryEntryRef::imported_symbol_end() const {
|
2016-07-31 21:40:02 +02:00
|
|
|
return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,
|
2014-10-03 02:41:58 +02:00
|
|
|
OwningObject);
|
2014-10-03 00:05:29 +02:00
|
|
|
}
|
|
|
|
|
2014-10-09 04:16:38 +02:00
|
|
|
iterator_range<imported_symbol_iterator>
|
|
|
|
ImportDirectoryEntryRef::imported_symbols() const {
|
|
|
|
return make_range(imported_symbol_begin(), imported_symbol_end());
|
|
|
|
}
|
|
|
|
|
2016-07-31 21:40:02 +02:00
|
|
|
imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {
|
|
|
|
return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,
|
|
|
|
OwningObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {
|
|
|
|
return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,
|
|
|
|
OwningObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator_range<imported_symbol_iterator>
|
|
|
|
ImportDirectoryEntryRef::lookup_table_symbols() const {
|
|
|
|
return make_range(lookup_table_begin(), lookup_table_end());
|
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ImportDirectoryEntryRef::getName(StringRef &Result) const {
|
2013-09-27 23:04:00 +02:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr))
|
|
|
|
return E;
|
2014-01-16 04:13:19 +01:00
|
|
|
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2013-09-27 23:04:00 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error
|
2014-10-02 19:02:18 +02:00
|
|
|
ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {
|
|
|
|
Result = ImportTable[Index].ImportLookupTableRVA;
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-02 19:02:18 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ImportDirectoryEntryRef::getImportAddressTableRVA(
|
|
|
|
uint32_t &Result) const {
|
2014-10-02 19:02:18 +02:00
|
|
|
Result = ImportTable[Index].ImportAddressTableRVA;
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-02 19:02:18 +02:00
|
|
|
}
|
|
|
|
|
2014-10-03 02:41:58 +02:00
|
|
|
bool DelayImportDirectoryEntryRef::
|
|
|
|
operator==(const DelayImportDirectoryEntryRef &Other) const {
|
|
|
|
return Table == Other.Table && Index == Other.Index;
|
|
|
|
}
|
|
|
|
|
|
|
|
void DelayImportDirectoryEntryRef::moveNext() {
|
|
|
|
++Index;
|
|
|
|
}
|
|
|
|
|
|
|
|
imported_symbol_iterator
|
|
|
|
DelayImportDirectoryEntryRef::imported_symbol_begin() const {
|
|
|
|
return importedSymbolBegin(Table[Index].DelayImportNameTable,
|
|
|
|
OwningObject);
|
|
|
|
}
|
|
|
|
|
|
|
|
imported_symbol_iterator
|
|
|
|
DelayImportDirectoryEntryRef::imported_symbol_end() const {
|
|
|
|
return importedSymbolEnd(Table[Index].DelayImportNameTable,
|
|
|
|
OwningObject);
|
|
|
|
}
|
|
|
|
|
2014-10-09 04:16:38 +02:00
|
|
|
iterator_range<imported_symbol_iterator>
|
|
|
|
DelayImportDirectoryEntryRef::imported_symbols() const {
|
|
|
|
return make_range(imported_symbol_begin(), imported_symbol_end());
|
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {
|
2014-10-03 02:41:58 +02:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr))
|
|
|
|
return E;
|
2014-10-03 02:41:58 +02:00
|
|
|
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 02:41:58 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error DelayImportDirectoryEntryRef::getDelayImportTable(
|
|
|
|
const delay_import_directory_table_entry *&Result) const {
|
2019-04-04 16:13:28 +02:00
|
|
|
Result = &Table[Index];
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 20:07:18 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,
|
|
|
|
uint64_t &Result) const {
|
2014-11-13 04:22:54 +01:00
|
|
|
uint32_t RVA = Table[Index].DelayImportAddressTable +
|
|
|
|
AddrIndex * (OwningObject->is64() ? 8 : 4);
|
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = OwningObject->getRvaPtr(RVA, IntPtr))
|
|
|
|
return E;
|
2014-11-13 04:22:54 +01:00
|
|
|
if (OwningObject->is64())
|
2014-11-13 21:07:06 +01:00
|
|
|
Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);
|
2014-11-13 04:22:54 +01:00
|
|
|
else
|
2014-11-13 21:07:06 +01:00
|
|
|
Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-11-13 04:22:54 +01:00
|
|
|
}
|
|
|
|
|
2014-01-16 08:05:49 +01:00
|
|
|
bool ExportDirectoryEntryRef::
|
|
|
|
operator==(const ExportDirectoryEntryRef &Other) const {
|
|
|
|
return ExportTable == Other.ExportTable && Index == Other.Index;
|
|
|
|
}
|
|
|
|
|
2014-01-30 03:49:50 +01:00
|
|
|
void ExportDirectoryEntryRef::moveNext() {
|
|
|
|
++Index;
|
2014-01-16 08:05:49 +01:00
|
|
|
}
|
|
|
|
|
2014-01-16 21:50:34 +01:00
|
|
|
// Returns the name of the current export symbol. If the symbol is exported only
|
|
|
|
// by ordinal, the empty string is set as a result.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {
|
2014-01-16 21:50:34 +01:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error E = OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr))
|
|
|
|
return E;
|
2014-01-16 21:50:34 +01:00
|
|
|
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-01-16 21:50:34 +01:00
|
|
|
}
|
|
|
|
|
2014-01-17 23:02:24 +01:00
|
|
|
// Returns the starting ordinal number.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {
|
2014-01-17 23:02:24 +01:00
|
|
|
Result = ExportTable->OrdinalBase;
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-01-17 23:02:24 +01:00
|
|
|
}
|
|
|
|
|
2014-01-16 08:05:49 +01:00
|
|
|
// Returns the export ordinal of the current export symbol.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
|
2014-01-16 08:05:49 +01:00
|
|
|
Result = ExportTable->OrdinalBase + Index;
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-01-16 08:05:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the address of the current export symbol.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
|
2014-01-16 08:05:49 +01:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error EC =
|
2014-06-13 04:24:39 +02:00
|
|
|
OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr))
|
2014-01-16 08:05:49 +01:00
|
|
|
return EC;
|
2014-01-17 23:11:27 +01:00
|
|
|
const export_address_table_entry *entry =
|
|
|
|
reinterpret_cast<const export_address_table_entry *>(IntPtr);
|
2014-01-16 08:05:49 +01:00
|
|
|
Result = entry[Index].ExportRVA;
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-01-16 08:05:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns the name of the current export symbol. If the symbol is exported only
|
|
|
|
// by ordinal, the empty string is set as a result.
|
2020-06-11 22:00:54 +02:00
|
|
|
Error
|
2014-06-13 04:24:39 +02:00
|
|
|
ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
|
2014-01-16 08:05:49 +01:00
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error EC =
|
2014-06-13 04:24:39 +02:00
|
|
|
OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr))
|
2014-01-16 08:05:49 +01:00
|
|
|
return EC;
|
|
|
|
const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
|
|
|
|
|
|
|
|
uint32_t NumEntries = ExportTable->NumberOfNamePointers;
|
|
|
|
int Offset = 0;
|
|
|
|
for (const ulittle16_t *I = Start, *E = Start + NumEntries;
|
|
|
|
I < E; ++I, ++Offset) {
|
|
|
|
if (*I != Index)
|
|
|
|
continue;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error EC =
|
2014-06-13 04:24:39 +02:00
|
|
|
OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr))
|
2014-01-16 08:05:49 +01:00
|
|
|
return EC;
|
|
|
|
const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr))
|
2014-01-16 08:05:49 +01:00
|
|
|
return EC;
|
|
|
|
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-01-16 08:05:49 +01:00
|
|
|
}
|
|
|
|
Result = "";
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-01-16 08:05:49 +01:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {
|
|
|
|
const data_directory *DataEntry =
|
|
|
|
OwningObject->getDataDirectory(COFF::EXPORT_TABLE);
|
|
|
|
if (!DataEntry)
|
|
|
|
return errorCodeToError(object_error::parse_failed);
|
2016-01-13 00:28:42 +01:00
|
|
|
uint32_t RVA;
|
|
|
|
if (auto EC = getExportRVA(RVA))
|
|
|
|
return EC;
|
|
|
|
uint32_t Begin = DataEntry->RelativeVirtualAddress;
|
|
|
|
uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;
|
|
|
|
Result = (Begin <= RVA && RVA < End);
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-01-13 00:28:42 +01:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
|
2016-01-13 00:28:42 +01:00
|
|
|
uint32_t RVA;
|
|
|
|
if (auto EC = getExportRVA(RVA))
|
|
|
|
return EC;
|
|
|
|
uintptr_t IntPtr = 0;
|
|
|
|
if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr))
|
|
|
|
return EC;
|
|
|
|
Result = StringRef(reinterpret_cast<const char *>(IntPtr));
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-01-13 00:28:42 +01:00
|
|
|
}
|
|
|
|
|
2014-10-03 00:05:29 +02:00
|
|
|
bool ImportedSymbolRef::
|
|
|
|
operator==(const ImportedSymbolRef &Other) const {
|
|
|
|
return Entry32 == Other.Entry32 && Entry64 == Other.Entry64
|
|
|
|
&& Index == Other.Index;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ImportedSymbolRef::moveNext() {
|
|
|
|
++Index;
|
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {
|
2014-10-03 00:05:29 +02:00
|
|
|
uint32_t RVA;
|
|
|
|
if (Entry32) {
|
|
|
|
// If a symbol is imported only by ordinal, it has no name.
|
|
|
|
if (Entry32[Index].isOrdinal())
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 00:05:29 +02:00
|
|
|
RVA = Entry32[Index].getHintNameRVA();
|
|
|
|
} else {
|
|
|
|
if (Entry64[Index].isOrdinal())
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 00:05:29 +02:00
|
|
|
RVA = Entry64[Index].getHintNameRVA();
|
|
|
|
}
|
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
|
2014-10-03 00:05:29 +02:00
|
|
|
return EC;
|
|
|
|
// +2 because the first two bytes is hint.
|
|
|
|
Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 00:05:29 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ImportedSymbolRef::isOrdinal(bool &Result) const {
|
2016-06-26 06:36:32 +02:00
|
|
|
if (Entry32)
|
|
|
|
Result = Entry32[Index].isOrdinal();
|
|
|
|
else
|
|
|
|
Result = Entry64[Index].isOrdinal();
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-06-26 06:36:32 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {
|
2016-06-26 06:36:32 +02:00
|
|
|
if (Entry32)
|
|
|
|
Result = Entry32[Index].getHintNameRVA();
|
|
|
|
else
|
|
|
|
Result = Entry64[Index].getHintNameRVA();
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2016-06-26 06:36:32 +02:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {
|
2014-10-03 00:05:29 +02:00
|
|
|
uint32_t RVA;
|
|
|
|
if (Entry32) {
|
|
|
|
if (Entry32[Index].isOrdinal()) {
|
|
|
|
Result = Entry32[Index].getOrdinal();
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 00:05:29 +02:00
|
|
|
}
|
|
|
|
RVA = Entry32[Index].getHintNameRVA();
|
|
|
|
} else {
|
|
|
|
if (Entry64[Index].isOrdinal()) {
|
|
|
|
Result = Entry64[Index].getOrdinal();
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 00:05:29 +02:00
|
|
|
}
|
|
|
|
RVA = Entry64[Index].getHintNameRVA();
|
|
|
|
}
|
|
|
|
uintptr_t IntPtr = 0;
|
2020-06-11 22:00:54 +02:00
|
|
|
if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
|
2014-10-03 00:05:29 +02:00
|
|
|
return EC;
|
|
|
|
Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-10-03 00:05:29 +02:00
|
|
|
}
|
|
|
|
|
2017-10-10 22:00:07 +02:00
|
|
|
Expected<std::unique_ptr<COFFObjectFile>>
|
2014-08-19 20:44:46 +02:00
|
|
|
ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {
|
2020-05-08 22:58:56 +02:00
|
|
|
return COFFObjectFile::create(Object);
|
2014-01-16 21:30:36 +01:00
|
|
|
}
|
2014-11-19 01:18:07 +01:00
|
|
|
|
|
|
|
bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {
|
|
|
|
return Header == Other.Header && Index == Other.Index;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BaseRelocRef::moveNext() {
|
|
|
|
// Header->BlockSize is the size of the current block, including the
|
|
|
|
// size of the header itself.
|
|
|
|
uint32_t Size = sizeof(*Header) +
|
2014-11-19 03:07:10 +01:00
|
|
|
sizeof(coff_base_reloc_block_entry) * (Index + 1);
|
2014-11-19 01:18:07 +01:00
|
|
|
if (Size == Header->BlockSize) {
|
|
|
|
// .reloc contains a list of base relocation blocks. Each block
|
|
|
|
// consists of the header followed by entries. The header contains
|
|
|
|
// how many entories will follow. When we reach the end of the
|
|
|
|
// current block, proceed to the next block.
|
|
|
|
Header = reinterpret_cast<const coff_base_reloc_block_header *>(
|
|
|
|
reinterpret_cast<const uint8_t *>(Header) + Size);
|
|
|
|
Index = 0;
|
|
|
|
} else {
|
|
|
|
++Index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error BaseRelocRef::getType(uint8_t &Type) const {
|
2014-11-19 01:18:07 +01:00
|
|
|
auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
|
|
|
|
Type = Entry[Index].getType();
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-11-19 01:18:07 +01:00
|
|
|
}
|
|
|
|
|
2020-06-11 22:00:54 +02:00
|
|
|
Error BaseRelocRef::getRVA(uint32_t &Result) const {
|
2014-11-19 01:18:07 +01:00
|
|
|
auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
|
|
|
|
Result = Header->PageRVA + Entry[Index].getOffset();
|
2020-06-11 22:00:54 +02:00
|
|
|
return Error::success();
|
2014-11-19 01:18:07 +01:00
|
|
|
}
|
2017-05-08 04:47:07 +02:00
|
|
|
|
2019-08-29 10:59:41 +02:00
|
|
|
#define RETURN_IF_ERROR(Expr) \
|
|
|
|
do { \
|
|
|
|
Error E = (Expr); \
|
|
|
|
if (E) \
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(E); \
|
2019-08-29 10:59:41 +02:00
|
|
|
} while (0)
|
2017-05-08 04:47:07 +02:00
|
|
|
|
2017-10-11 19:05:24 +02:00
|
|
|
Expected<ArrayRef<UTF16>>
|
|
|
|
ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {
|
2017-05-08 04:47:07 +02:00
|
|
|
BinaryStreamReader Reader = BinaryStreamReader(BBS);
|
|
|
|
Reader.setOffset(Offset);
|
|
|
|
uint16_t Length;
|
|
|
|
RETURN_IF_ERROR(Reader.readInteger(Length));
|
|
|
|
ArrayRef<UTF16> RawDirString;
|
|
|
|
RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));
|
2017-05-08 04:47:42 +02:00
|
|
|
return RawDirString;
|
2017-05-08 04:47:07 +02:00
|
|
|
}
|
|
|
|
|
2017-10-11 19:33:11 +02:00
|
|
|
Expected<ArrayRef<UTF16>>
|
2017-05-08 04:47:07 +02:00
|
|
|
ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {
|
2017-10-11 19:33:11 +02:00
|
|
|
return getDirStringAtOffset(Entry.Identifier.getNameOffset());
|
2017-05-08 04:47:07 +02:00
|
|
|
}
|
|
|
|
|
2017-10-11 19:05:24 +02:00
|
|
|
Expected<const coff_resource_dir_table &>
|
2017-05-08 04:47:07 +02:00
|
|
|
ResourceSectionRef::getTableAtOffset(uint32_t Offset) {
|
|
|
|
const coff_resource_dir_table *Table = nullptr;
|
|
|
|
|
|
|
|
BinaryStreamReader Reader(BBS);
|
|
|
|
Reader.setOffset(Offset);
|
|
|
|
RETURN_IF_ERROR(Reader.readObject(Table));
|
|
|
|
assert(Table != nullptr);
|
|
|
|
return *Table;
|
|
|
|
}
|
|
|
|
|
2019-08-29 10:59:56 +02:00
|
|
|
Expected<const coff_resource_dir_entry &>
|
|
|
|
ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {
|
|
|
|
const coff_resource_dir_entry *Entry = nullptr;
|
|
|
|
|
|
|
|
BinaryStreamReader Reader(BBS);
|
|
|
|
Reader.setOffset(Offset);
|
|
|
|
RETURN_IF_ERROR(Reader.readObject(Entry));
|
|
|
|
assert(Entry != nullptr);
|
|
|
|
return *Entry;
|
|
|
|
}
|
|
|
|
|
2019-08-29 11:00:14 +02:00
|
|
|
Expected<const coff_resource_data_entry &>
|
|
|
|
ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {
|
|
|
|
const coff_resource_data_entry *Entry = nullptr;
|
|
|
|
|
|
|
|
BinaryStreamReader Reader(BBS);
|
|
|
|
Reader.setOffset(Offset);
|
|
|
|
RETURN_IF_ERROR(Reader.readObject(Entry));
|
|
|
|
assert(Entry != nullptr);
|
|
|
|
return *Entry;
|
|
|
|
}
|
|
|
|
|
2017-10-11 19:33:11 +02:00
|
|
|
Expected<const coff_resource_dir_table &>
|
2017-05-08 04:47:07 +02:00
|
|
|
ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {
|
2019-08-29 11:00:14 +02:00
|
|
|
assert(Entry.Offset.isSubDir());
|
2017-10-11 19:33:11 +02:00
|
|
|
return getTableAtOffset(Entry.Offset.value());
|
2017-05-08 04:47:07 +02:00
|
|
|
}
|
|
|
|
|
2019-08-29 11:00:14 +02:00
|
|
|
Expected<const coff_resource_data_entry &>
|
|
|
|
ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {
|
|
|
|
assert(!Entry.Offset.isSubDir());
|
|
|
|
return getDataEntryAtOffset(Entry.Offset.value());
|
|
|
|
}
|
|
|
|
|
2017-10-11 19:33:11 +02:00
|
|
|
Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {
|
|
|
|
return getTableAtOffset(0);
|
2017-05-08 04:47:07 +02:00
|
|
|
}
|
2019-08-29 10:59:56 +02:00
|
|
|
|
|
|
|
Expected<const coff_resource_dir_entry &>
|
|
|
|
ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,
|
|
|
|
uint32_t Index) {
|
|
|
|
if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))
|
|
|
|
return createStringError(object_error::parse_failed, "index out of range");
|
|
|
|
const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);
|
|
|
|
ptrdiff_t TableOffset = TablePtr - BBS.data().data();
|
|
|
|
return getTableEntryAtOffset(TableOffset + sizeof(Table) +
|
|
|
|
Index * sizeof(coff_resource_dir_entry));
|
|
|
|
}
|
[COFF] Add a ResourceSectionRef method for getting resource contents
This allows llvm-readobj to print the contents of each resource
when printing resources from an object file or executable, like it
already does for plain .res files.
This requires providing the whole COFFObjectFile to ResourceSectionRef.
This supports both object files and executables. For executables,
the DataRVA field is used as is to look up the right section.
For object files, ideally we would need to complete linking of them
and fix up all relocations to know what the DataRVA field would end up
being. In practice, the only thing that makes sense for an RVA field
is an ADDR32NB relocation. Thus, find a relocation pointing at this
field, verify that it has the expected type, locate the symbol it
points at, look up the section the symbol points at, and read from the
right offset in that section.
This works both for GNU windres object files (which use one single
.rsrc section, with all relocations against the base of the .rsrc
section, with the original value of the DataRVA field being the
offset of the data from the beginning of the .rsrc section) and
cvtres object files (with two separate .rsrc$01 and .rsrc$02 sections,
and one symbol per data entry, with the original pre-relocated DataRVA
field being set to zero).
Differential Revision: https://reviews.llvm.org/D66820
llvm-svn: 370433
2019-08-30 08:55:49 +02:00
|
|
|
|
|
|
|
Error ResourceSectionRef::load(const COFFObjectFile *O) {
|
|
|
|
for (const SectionRef &S : O->sections()) {
|
|
|
|
Expected<StringRef> Name = S.getName();
|
|
|
|
if (!Name)
|
|
|
|
return Name.takeError();
|
|
|
|
|
|
|
|
if (*Name == ".rsrc" || *Name == ".rsrc$01")
|
|
|
|
return load(O, S);
|
|
|
|
}
|
|
|
|
return createStringError(object_error::parse_failed,
|
|
|
|
"no resource section found");
|
|
|
|
}
|
|
|
|
|
|
|
|
Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {
|
|
|
|
Obj = O;
|
|
|
|
Section = S;
|
|
|
|
Expected<StringRef> Contents = Section.getContents();
|
|
|
|
if (!Contents)
|
|
|
|
return Contents.takeError();
|
|
|
|
BBS = BinaryByteStream(*Contents, support::little);
|
|
|
|
const coff_section *COFFSect = Obj->getCOFFSection(Section);
|
|
|
|
ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);
|
|
|
|
Relocs.reserve(OrigRelocs.size());
|
|
|
|
for (const coff_relocation &R : OrigRelocs)
|
|
|
|
Relocs.push_back(&R);
|
2021-01-17 19:39:45 +01:00
|
|
|
llvm::sort(Relocs, [](const coff_relocation *A, const coff_relocation *B) {
|
|
|
|
return A->VirtualAddress < B->VirtualAddress;
|
|
|
|
});
|
[COFF] Add a ResourceSectionRef method for getting resource contents
This allows llvm-readobj to print the contents of each resource
when printing resources from an object file or executable, like it
already does for plain .res files.
This requires providing the whole COFFObjectFile to ResourceSectionRef.
This supports both object files and executables. For executables,
the DataRVA field is used as is to look up the right section.
For object files, ideally we would need to complete linking of them
and fix up all relocations to know what the DataRVA field would end up
being. In practice, the only thing that makes sense for an RVA field
is an ADDR32NB relocation. Thus, find a relocation pointing at this
field, verify that it has the expected type, locate the symbol it
points at, look up the section the symbol points at, and read from the
right offset in that section.
This works both for GNU windres object files (which use one single
.rsrc section, with all relocations against the base of the .rsrc
section, with the original value of the DataRVA field being the
offset of the data from the beginning of the .rsrc section) and
cvtres object files (with two separate .rsrc$01 and .rsrc$02 sections,
and one symbol per data entry, with the original pre-relocated DataRVA
field being set to zero).
Differential Revision: https://reviews.llvm.org/D66820
llvm-svn: 370433
2019-08-30 08:55:49 +02:00
|
|
|
return Error::success();
|
|
|
|
}
|
|
|
|
|
|
|
|
Expected<StringRef>
|
|
|
|
ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
|
|
|
|
if (!Obj)
|
|
|
|
return createStringError(object_error::parse_failed, "no object provided");
|
|
|
|
|
|
|
|
// Find a potential relocation at the DataRVA field (first member of
|
|
|
|
// the coff_resource_data_entry struct).
|
|
|
|
const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);
|
|
|
|
ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();
|
|
|
|
coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),
|
|
|
|
ulittle16_t(0)};
|
|
|
|
auto RelocsForOffset =
|
|
|
|
std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,
|
|
|
|
[](const coff_relocation *A, const coff_relocation *B) {
|
|
|
|
return A->VirtualAddress < B->VirtualAddress;
|
|
|
|
});
|
|
|
|
|
|
|
|
if (RelocsForOffset.first != RelocsForOffset.second) {
|
|
|
|
// We found a relocation with the right offset. Check that it does have
|
|
|
|
// the expected type.
|
|
|
|
const coff_relocation &R = **RelocsForOffset.first;
|
|
|
|
uint16_t RVAReloc;
|
|
|
|
switch (Obj->getMachine()) {
|
|
|
|
case COFF::IMAGE_FILE_MACHINE_I386:
|
|
|
|
RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;
|
|
|
|
break;
|
|
|
|
case COFF::IMAGE_FILE_MACHINE_AMD64:
|
|
|
|
RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;
|
|
|
|
break;
|
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARMNT:
|
|
|
|
RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;
|
|
|
|
break;
|
|
|
|
case COFF::IMAGE_FILE_MACHINE_ARM64:
|
|
|
|
RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return createStringError(object_error::parse_failed,
|
|
|
|
"unsupported architecture");
|
|
|
|
}
|
|
|
|
if (R.Type != RVAReloc)
|
|
|
|
return createStringError(object_error::parse_failed,
|
|
|
|
"unexpected relocation type");
|
|
|
|
// Get the relocation's symbol
|
|
|
|
Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);
|
|
|
|
if (!Sym)
|
|
|
|
return Sym.takeError();
|
|
|
|
// And the symbol's section
|
2020-05-08 19:41:05 +02:00
|
|
|
Expected<const coff_section *> Section =
|
|
|
|
Obj->getSection(Sym->getSectionNumber());
|
|
|
|
if (!Section)
|
|
|
|
return Section.takeError();
|
[COFF] Add a ResourceSectionRef method for getting resource contents
This allows llvm-readobj to print the contents of each resource
when printing resources from an object file or executable, like it
already does for plain .res files.
This requires providing the whole COFFObjectFile to ResourceSectionRef.
This supports both object files and executables. For executables,
the DataRVA field is used as is to look up the right section.
For object files, ideally we would need to complete linking of them
and fix up all relocations to know what the DataRVA field would end up
being. In practice, the only thing that makes sense for an RVA field
is an ADDR32NB relocation. Thus, find a relocation pointing at this
field, verify that it has the expected type, locate the symbol it
points at, look up the section the symbol points at, and read from the
right offset in that section.
This works both for GNU windres object files (which use one single
.rsrc section, with all relocations against the base of the .rsrc
section, with the original value of the DataRVA field being the
offset of the data from the beginning of the .rsrc section) and
cvtres object files (with two separate .rsrc$01 and .rsrc$02 sections,
and one symbol per data entry, with the original pre-relocated DataRVA
field being set to zero).
Differential Revision: https://reviews.llvm.org/D66820
llvm-svn: 370433
2019-08-30 08:55:49 +02:00
|
|
|
// Add the initial value of DataRVA to the symbol's offset to find the
|
|
|
|
// data it points at.
|
|
|
|
uint64_t Offset = Entry.DataRVA + Sym->getValue();
|
|
|
|
ArrayRef<uint8_t> Contents;
|
2020-05-08 19:41:05 +02:00
|
|
|
if (Error E = Obj->getSectionContents(*Section, Contents))
|
2020-02-10 16:06:45 +01:00
|
|
|
return std::move(E);
|
[COFF] Add a ResourceSectionRef method for getting resource contents
This allows llvm-readobj to print the contents of each resource
when printing resources from an object file or executable, like it
already does for plain .res files.
This requires providing the whole COFFObjectFile to ResourceSectionRef.
This supports both object files and executables. For executables,
the DataRVA field is used as is to look up the right section.
For object files, ideally we would need to complete linking of them
and fix up all relocations to know what the DataRVA field would end up
being. In practice, the only thing that makes sense for an RVA field
is an ADDR32NB relocation. Thus, find a relocation pointing at this
field, verify that it has the expected type, locate the symbol it
points at, look up the section the symbol points at, and read from the
right offset in that section.
This works both for GNU windres object files (which use one single
.rsrc section, with all relocations against the base of the .rsrc
section, with the original value of the DataRVA field being the
offset of the data from the beginning of the .rsrc section) and
cvtres object files (with two separate .rsrc$01 and .rsrc$02 sections,
and one symbol per data entry, with the original pre-relocated DataRVA
field being set to zero).
Differential Revision: https://reviews.llvm.org/D66820
llvm-svn: 370433
2019-08-30 08:55:49 +02:00
|
|
|
if (Offset + Entry.DataSize > Contents.size())
|
|
|
|
return createStringError(object_error::parse_failed,
|
|
|
|
"data outside of section");
|
|
|
|
// Return a reference to the data inside the section.
|
|
|
|
return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,
|
|
|
|
Entry.DataSize);
|
|
|
|
} else {
|
|
|
|
// Relocatable objects need a relocation for the DataRVA field.
|
|
|
|
if (Obj->isRelocatableObject())
|
|
|
|
return createStringError(object_error::parse_failed,
|
|
|
|
"no relocation found for DataRVA");
|
|
|
|
|
|
|
|
// Locate the section that contains the address that DataRVA points at.
|
|
|
|
uint64_t VA = Entry.DataRVA + Obj->getImageBase();
|
|
|
|
for (const SectionRef &S : Obj->sections()) {
|
|
|
|
if (VA >= S.getAddress() &&
|
|
|
|
VA + Entry.DataSize <= S.getAddress() + S.getSize()) {
|
|
|
|
uint64_t Offset = VA - S.getAddress();
|
|
|
|
Expected<StringRef> Contents = S.getContents();
|
|
|
|
if (!Contents)
|
|
|
|
return Contents.takeError();
|
|
|
|
return Contents->slice(Offset, Offset + Entry.DataSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return createStringError(object_error::parse_failed,
|
|
|
|
"address not found in image");
|
|
|
|
}
|
|
|
|
}
|