llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp
Qiu Chaofan b16372c5fc [PowerPC][MC] Set 'future' as default CPU type of XCOFF
For Power on Linux (both LE and BE), ELFObjectFile returns 'future' as
default CPU type if mcpu is not specified, so that all necessary
features will be enabled in MC.

While for XCOFF, the default CPU type is always null, which makes tools
like llvm-objdump not able to recognize prefixed instructions, unless
specifying --mcpu=pwr10 or --mattr=+prefix-instrs manually.

Reviewed By: nemanjai

Differential Revision: https://reviews.llvm.org/D155089
2023-07-13 10:15:34 +08:00

1617 lines
56 KiB
C++

//===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This file defines the XCOFFObjectFile class.
//
//===----------------------------------------------------------------------===//
#include "llvm/Object/XCOFFObjectFile.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/DataExtractor.h"
#include "llvm/TargetParser/SubtargetFeature.h"
#include <cstddef>
#include <cstring>
namespace llvm {
using namespace XCOFF;
namespace object {
static const uint8_t FunctionSym = 0x20;
static const uint16_t NoRelMask = 0x0001;
static const size_t SymbolAuxTypeOffset = 17;
// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer
// 'M'. Returns a pointer to the underlying object on success.
template <typename T>
static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr,
const uint64_t Size = sizeof(T)) {
uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);
if (Error E = Binary::checkOffset(M, Addr, Size))
return std::move(E);
return reinterpret_cast<const T *>(Addr);
}
static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {
return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +
Offset);
}
template <typename T> static const T *viewAs(uintptr_t in) {
return reinterpret_cast<const T *>(in);
}
static StringRef generateXCOFFFixedNameStringRef(const char *Name) {
auto NulCharPtr =
static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize));
return NulCharPtr ? StringRef(Name, NulCharPtr - Name)
: StringRef(Name, XCOFF::NameSize);
}
template <typename T> StringRef XCOFFSectionHeader<T>::getName() const {
const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name);
}
template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const {
const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask;
}
template <typename T>
bool XCOFFSectionHeader<T>::isReservedSectionType() const {
return getSectionType() & SectionFlagsReservedMask;
}
template <typename AddressType>
bool XCOFFRelocation<AddressType>::isRelocationSigned() const {
return Info & XR_SIGN_INDICATOR_MASK;
}
template <typename AddressType>
bool XCOFFRelocation<AddressType>::isFixupIndicated() const {
return Info & XR_FIXUP_INDICATOR_MASK;
}
template <typename AddressType>
uint8_t XCOFFRelocation<AddressType>::getRelocatedLength() const {
// The relocation encodes the bit length being relocated minus 1. Add back
// the 1 to get the actual length being relocated.
return (Info & XR_BIASED_LENGTH_MASK) + 1;
}
template struct ExceptionSectionEntry<support::ubig32_t>;
template struct ExceptionSectionEntry<support::ubig64_t>;
template <typename T>
Expected<StringRef> getLoaderSecSymNameInStrTbl(const T *LoaderSecHeader,
uint64_t Offset) {
if (LoaderSecHeader->LengthOfStrTbl > Offset)
return (reinterpret_cast<const char *>(LoaderSecHeader) +
LoaderSecHeader->OffsetToStrTbl + Offset);
return createError("entry with offset 0x" + Twine::utohexstr(Offset) +
" in the loader section's string table with size 0x" +
Twine::utohexstr(LoaderSecHeader->LengthOfStrTbl) +
" is invalid");
}
Expected<StringRef> LoaderSectionSymbolEntry32::getSymbolName(
const LoaderSectionHeader32 *LoaderSecHeader32) const {
const NameOffsetInStrTbl *NameInStrTbl =
reinterpret_cast<const NameOffsetInStrTbl *>(SymbolName);
if (NameInStrTbl->IsNameInStrTbl != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)
return generateXCOFFFixedNameStringRef(SymbolName);
return getLoaderSecSymNameInStrTbl(LoaderSecHeader32, NameInStrTbl->Offset);
}
Expected<StringRef> LoaderSectionSymbolEntry64::getSymbolName(
const LoaderSectionHeader64 *LoaderSecHeader64) const {
return getLoaderSecSymNameInStrTbl(LoaderSecHeader64, Offset);
}
uintptr_t
XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress,
uint32_t Distance) {
return getWithOffset(CurrentAddress, Distance * XCOFF::SymbolTableEntrySize);
}
const XCOFF::SymbolAuxType *
XCOFFObjectFile::getSymbolAuxType(uintptr_t AuxEntryAddress) const {
assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
return viewAs<XCOFF::SymbolAuxType>(
getWithOffset(AuxEntryAddress, SymbolAuxTypeOffset));
}
void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,
uintptr_t TableAddress) const {
if (Addr < TableAddress)
report_fatal_error("Section header outside of section header table.");
uintptr_t Offset = Addr - TableAddress;
if (Offset >= getSectionHeaderSize() * getNumberOfSections())
report_fatal_error("Section header outside of section header table.");
if (Offset % getSectionHeaderSize() != 0)
report_fatal_error(
"Section header pointer does not point to a valid section header.");
}
const XCOFFSectionHeader32 *
XCOFFObjectFile::toSection32(DataRefImpl Ref) const {
assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
#ifndef NDEBUG
checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
#endif
return viewAs<XCOFFSectionHeader32>(Ref.p);
}
const XCOFFSectionHeader64 *
XCOFFObjectFile::toSection64(DataRefImpl Ref) const {
assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
#ifndef NDEBUG
checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
#endif
return viewAs<XCOFFSectionHeader64>(Ref.p);
}
XCOFFSymbolRef XCOFFObjectFile::toSymbolRef(DataRefImpl Ref) const {
assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!");
#ifndef NDEBUG
checkSymbolEntryPointer(Ref.p);
#endif
return XCOFFSymbolRef(Ref, this);
}
const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const {
assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
return static_cast<const XCOFFFileHeader32 *>(FileHeader);
}
const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {
assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
return static_cast<const XCOFFFileHeader64 *>(FileHeader);
}
const XCOFFAuxiliaryHeader32 *XCOFFObjectFile::auxiliaryHeader32() const {
assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
return static_cast<const XCOFFAuxiliaryHeader32 *>(AuxiliaryHeader);
}
const XCOFFAuxiliaryHeader64 *XCOFFObjectFile::auxiliaryHeader64() const {
assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
return static_cast<const XCOFFAuxiliaryHeader64 *>(AuxiliaryHeader);
}
template <typename T> const T *XCOFFObjectFile::sectionHeaderTable() const {
return static_cast<const T *>(SectionHeaderTable);
}
const XCOFFSectionHeader32 *
XCOFFObjectFile::sectionHeaderTable32() const {
assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable);
}
const XCOFFSectionHeader64 *
XCOFFObjectFile::sectionHeaderTable64() const {
assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);
}
void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
uintptr_t NextSymbolAddr = getAdvancedSymbolEntryAddress(
Symb.p, toSymbolRef(Symb).getNumberOfAuxEntries() + 1);
#ifndef NDEBUG
// This function is used by basic_symbol_iterator, which allows to
// point to the end-of-symbol-table address.
if (NextSymbolAddr != getEndOfSymbolTableAddress())
checkSymbolEntryPointer(NextSymbolAddr);
#endif
Symb.p = NextSymbolAddr;
}
Expected<StringRef>
XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const {
// The byte offset is relative to the start of the string table.
// A byte offset value of 0 is a null or zero-length symbol
// name. A byte offset in the range 1 to 3 (inclusive) points into the length
// field; as a soft-error recovery mechanism, we treat such cases as having an
// offset of 0.
if (Offset < 4)
return StringRef(nullptr, 0);
if (StringTable.Data != nullptr && StringTable.Size > Offset)
return (StringTable.Data + Offset);
return createError("entry with offset 0x" + Twine::utohexstr(Offset) +
" in a string table with size 0x" +
Twine::utohexstr(StringTable.Size) + " is invalid");
}
StringRef XCOFFObjectFile::getStringTable() const {
// If the size is less than or equal to 4, then the string table contains no
// string data.
return StringRef(StringTable.Data,
StringTable.Size <= 4 ? 0 : StringTable.Size);
}
Expected<StringRef>
XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const {
if (CFileEntPtr->NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)
return generateXCOFFFixedNameStringRef(CFileEntPtr->Name);
return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset);
}
Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
return toSymbolRef(Symb).getName();
}
Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
return toSymbolRef(Symb).getValue();
}
uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
return toSymbolRef(Symb).getValue();
}
uint32_t XCOFFObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
uint64_t Result = 0;
XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);
if (XCOFFSym.isCsectSymbol()) {
Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =
XCOFFSym.getXCOFFCsectAuxRef();
if (!CsectAuxRefOrError)
// TODO: report the error up the stack.
consumeError(CsectAuxRefOrError.takeError());
else
Result = 1ULL << CsectAuxRefOrError.get().getAlignmentLog2();
}
return Result;
}
uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
uint64_t Result = 0;
XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);
if (XCOFFSym.isCsectSymbol()) {
Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =
XCOFFSym.getXCOFFCsectAuxRef();
if (!CsectAuxRefOrError)
// TODO: report the error up the stack.
consumeError(CsectAuxRefOrError.takeError());
else {
XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get();
assert(CsectAuxRef.getSymbolType() == XCOFF::XTY_CM);
Result = CsectAuxRef.getSectionOrLength();
}
}
return Result;
}
Expected<SymbolRef::Type>
XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);
if (XCOFFSym.isFunction())
return SymbolRef::ST_Function;
if (XCOFF::C_FILE == XCOFFSym.getStorageClass())
return SymbolRef::ST_File;
int16_t SecNum = XCOFFSym.getSectionNumber();
if (SecNum <= 0)
return SymbolRef::ST_Other;
Expected<DataRefImpl> SecDRIOrErr =
getSectionByNum(XCOFFSym.getSectionNumber());
if (!SecDRIOrErr)
return SecDRIOrErr.takeError();
DataRefImpl SecDRI = SecDRIOrErr.get();
Expected<StringRef> SymNameOrError = XCOFFSym.getName();
if (SymNameOrError) {
// The "TOC" symbol is treated as SymbolRef::ST_Other.
if (SymNameOrError.get() == "TOC")
return SymbolRef::ST_Other;
// The symbol for a section name is treated as SymbolRef::ST_Other.
StringRef SecName;
if (is64Bit())
SecName = XCOFFObjectFile::toSection64(SecDRIOrErr.get())->getName();
else
SecName = XCOFFObjectFile::toSection32(SecDRIOrErr.get())->getName();
if (SecName == SymNameOrError.get())
return SymbolRef::ST_Other;
} else
return SymNameOrError.takeError();
if (isSectionData(SecDRI) || isSectionBSS(SecDRI))
return SymbolRef::ST_Data;
if (isDebugSection(SecDRI))
return SymbolRef::ST_Debug;
return SymbolRef::ST_Other;
}
Expected<section_iterator>
XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
const int16_t SectNum = toSymbolRef(Symb).getSectionNumber();
if (isReservedSectionNumber(SectNum))
return section_end();
Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum);
if (!ExpSec)
return ExpSec.takeError();
return section_iterator(SectionRef(ExpSec.get(), this));
}
void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
const char *Ptr = reinterpret_cast<const char *>(Sec.p);
Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());
}
Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));
}
uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
// Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
// with MSVC.
if (is64Bit())
return toSection64(Sec)->VirtualAddress;
return toSection32(Sec)->VirtualAddress;
}
uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
// Section numbers in XCOFF are numbered beginning at 1. A section number of
// zero is used to indicate that a symbol is being imported or is undefined.
if (is64Bit())
return toSection64(Sec) - sectionHeaderTable64() + 1;
else
return toSection32(Sec) - sectionHeaderTable32() + 1;
}
uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
// Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
// with MSVC.
if (is64Bit())
return toSection64(Sec)->SectionSize;
return toSection32(Sec)->SectionSize;
}
Expected<ArrayRef<uint8_t>>
XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
if (isSectionVirtual(Sec))
return ArrayRef<uint8_t>();
uint64_t OffsetToRaw;
if (is64Bit())
OffsetToRaw = toSection64(Sec)->FileOffsetToRawData;
else
OffsetToRaw = toSection32(Sec)->FileOffsetToRawData;
const uint8_t * ContentStart = base() + OffsetToRaw;
uint64_t SectionSize = getSectionSize(Sec);
if (Error E = Binary::checkOffset(
Data, reinterpret_cast<uintptr_t>(ContentStart), SectionSize))
return createError(
toString(std::move(E)) + ": section data with offset 0x" +
Twine::utohexstr(OffsetToRaw) + " and size 0x" +
Twine::utohexstr(SectionSize) + " goes past the end of the file");
return ArrayRef(ContentStart, SectionSize);
}
uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
uint64_t Result = 0;
llvm_unreachable("Not yet implemented!");
return Result;
}
uint64_t XCOFFObjectFile::getSectionFileOffsetToRawData(DataRefImpl Sec) const {
if (is64Bit())
return toSection64(Sec)->FileOffsetToRawData;
return toSection32(Sec)->FileOffsetToRawData;
}
Expected<uintptr_t> XCOFFObjectFile::getSectionFileOffsetToRawData(
XCOFF::SectionTypeFlags SectType) const {
DataRefImpl DRI = getSectionByType(SectType);
if (DRI.p == 0) // No section is not an error.
return 0;
uint64_t SectionOffset = getSectionFileOffsetToRawData(DRI);
uint64_t SizeOfSection = getSectionSize(DRI);
uintptr_t SectionStart = reinterpret_cast<uintptr_t>(base() + SectionOffset);
if (Error E = Binary::checkOffset(Data, SectionStart, SizeOfSection)) {
SmallString<32> UnknownType;
Twine(("<Unknown:") + Twine::utohexstr(SectType) + ">")
.toVector(UnknownType);
const char *SectionName = UnknownType.c_str();
switch (SectType) {
#define ECASE(Value, String) \
case XCOFF::Value: \
SectionName = String; \
break
ECASE(STYP_PAD, "pad");
ECASE(STYP_DWARF, "dwarf");
ECASE(STYP_TEXT, "text");
ECASE(STYP_DATA, "data");
ECASE(STYP_BSS, "bss");
ECASE(STYP_EXCEPT, "expect");
ECASE(STYP_INFO, "info");
ECASE(STYP_TDATA, "tdata");
ECASE(STYP_TBSS, "tbss");
ECASE(STYP_LOADER, "loader");
ECASE(STYP_DEBUG, "debug");
ECASE(STYP_TYPCHK, "typchk");
ECASE(STYP_OVRFLO, "ovrflo");
#undef ECASE
}
return createError(toString(std::move(E)) + ": " + SectionName +
" section with offset 0x" +
Twine::utohexstr(SectionOffset) + " and size 0x" +
Twine::utohexstr(SizeOfSection) +
" goes past the end of the file");
}
return SectionStart;
}
bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
return false;
}
bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
return getSectionFlags(Sec) & XCOFF::STYP_TEXT;
}
bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
uint32_t Flags = getSectionFlags(Sec);
return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
}
bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
uint32_t Flags = getSectionFlags(Sec);
return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
}
bool XCOFFObjectFile::isDebugSection(DataRefImpl Sec) const {
uint32_t Flags = getSectionFlags(Sec);
return Flags & (XCOFF::STYP_DEBUG | XCOFF::STYP_DWARF);
}
bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0
: toSection32(Sec)->FileOffsetToRawData == 0;
}
relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
DataRefImpl Ret;
if (is64Bit()) {
const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec);
auto RelocationsOrErr =
relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr);
if (Error E = RelocationsOrErr.takeError()) {
// TODO: report the error up the stack.
consumeError(std::move(E));
return relocation_iterator(RelocationRef());
}
Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());
} else {
const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);
auto RelocationsOrErr =
relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr);
if (Error E = RelocationsOrErr.takeError()) {
// TODO: report the error up the stack.
consumeError(std::move(E));
return relocation_iterator(RelocationRef());
}
Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());
}
return relocation_iterator(RelocationRef(Ret, this));
}
relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
DataRefImpl Ret;
if (is64Bit()) {
const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec);
auto RelocationsOrErr =
relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr);
if (Error E = RelocationsOrErr.takeError()) {
// TODO: report the error up the stack.
consumeError(std::move(E));
return relocation_iterator(RelocationRef());
}
Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());
} else {
const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);
auto RelocationsOrErr =
relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr);
if (Error E = RelocationsOrErr.takeError()) {
// TODO: report the error up the stack.
consumeError(std::move(E));
return relocation_iterator(RelocationRef());
}
Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());
}
return relocation_iterator(RelocationRef(Ret, this));
}
void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
if (is64Bit())
Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation64>(Rel.p) + 1);
else
Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1);
}
uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
if (is64Bit()) {
const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);
const XCOFFSectionHeader64 *Sec64 = sectionHeaderTable64();
const uint64_t RelocAddress = Reloc->VirtualAddress;
const uint16_t NumberOfSections = getNumberOfSections();
for (uint16_t I = 0; I < NumberOfSections; ++I) {
// Find which section this relocation belongs to, and get the
// relocation offset relative to the start of the section.
if (Sec64->VirtualAddress <= RelocAddress &&
RelocAddress < Sec64->VirtualAddress + Sec64->SectionSize) {
return RelocAddress - Sec64->VirtualAddress;
}
++Sec64;
}
} else {
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32();
const uint32_t RelocAddress = Reloc->VirtualAddress;
const uint16_t NumberOfSections = getNumberOfSections();
for (uint16_t I = 0; I < NumberOfSections; ++I) {
// Find which section this relocation belongs to, and get the
// relocation offset relative to the start of the section.
if (Sec32->VirtualAddress <= RelocAddress &&
RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) {
return RelocAddress - Sec32->VirtualAddress;
}
++Sec32;
}
}
return InvalidRelocOffset;
}
symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
uint32_t Index;
if (is64Bit()) {
const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);
Index = Reloc->SymbolIndex;
if (Index >= getNumberOfSymbolTableEntries64())
return symbol_end();
} else {
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
Index = Reloc->SymbolIndex;
if (Index >= getLogicalNumberOfSymbolTableEntries32())
return symbol_end();
}
DataRefImpl SymDRI;
SymDRI.p = getSymbolEntryAddressByIndex(Index);
return symbol_iterator(SymbolRef(SymDRI, this));
}
uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
if (is64Bit())
return viewAs<XCOFFRelocation64>(Rel.p)->Type;
return viewAs<XCOFFRelocation32>(Rel.p)->Type;
}
void XCOFFObjectFile::getRelocationTypeName(
DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
StringRef Res;
if (is64Bit()) {
const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);
Res = XCOFF::getRelocationTypeString(Reloc->Type);
} else {
const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
Res = XCOFF::getRelocationTypeString(Reloc->Type);
}
Result.append(Res.begin(), Res.end());
}
Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);
uint32_t Result = SymbolRef::SF_None;
if (XCOFFSym.getSectionNumber() == XCOFF::N_ABS)
Result |= SymbolRef::SF_Absolute;
XCOFF::StorageClass SC = XCOFFSym.getStorageClass();
if (XCOFF::C_EXT == SC || XCOFF::C_WEAKEXT == SC)
Result |= SymbolRef::SF_Global;
if (XCOFF::C_WEAKEXT == SC)
Result |= SymbolRef::SF_Weak;
if (XCOFFSym.isCsectSymbol()) {
Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr =
XCOFFSym.getXCOFFCsectAuxRef();
if (CsectAuxEntOrErr) {
if (CsectAuxEntOrErr.get().getSymbolType() == XCOFF::XTY_CM)
Result |= SymbolRef::SF_Common;
} else
return CsectAuxEntOrErr.takeError();
}
if (XCOFFSym.getSectionNumber() == XCOFF::N_UNDEF)
Result |= SymbolRef::SF_Undefined;
// There is no visibility in old 32 bit XCOFF object file interpret.
if (is64Bit() || (auxiliaryHeader32() && (auxiliaryHeader32()->getVersion() ==
NEW_XCOFF_INTERPRET))) {
uint16_t SymType = XCOFFSym.getSymbolType();
if ((SymType & VISIBILITY_MASK) == SYM_V_HIDDEN)
Result |= SymbolRef::SF_Hidden;
if ((SymType & VISIBILITY_MASK) == SYM_V_EXPORTED)
Result |= SymbolRef::SF_Exported;
}
return Result;
}
basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {
DataRefImpl SymDRI;
SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr);
return basic_symbol_iterator(SymbolRef(SymDRI, this));
}
basic_symbol_iterator XCOFFObjectFile::symbol_end() const {
DataRefImpl SymDRI;
const uint32_t NumberOfSymbolTableEntries = getNumberOfSymbolTableEntries();
SymDRI.p = getSymbolEntryAddressByIndex(NumberOfSymbolTableEntries);
return basic_symbol_iterator(SymbolRef(SymDRI, this));
}
section_iterator XCOFFObjectFile::section_begin() const {
DataRefImpl DRI;
DRI.p = getSectionHeaderTableAddress();
return section_iterator(SectionRef(DRI, this));
}
section_iterator XCOFFObjectFile::section_end() const {
DataRefImpl DRI;
DRI.p = getWithOffset(getSectionHeaderTableAddress(),
getNumberOfSections() * getSectionHeaderSize());
return section_iterator(SectionRef(DRI, this));
}
uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }
StringRef XCOFFObjectFile::getFileFormatName() const {
return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";
}
Triple::ArchType XCOFFObjectFile::getArch() const {
return is64Bit() ? Triple::ppc64 : Triple::ppc;
}
Expected<SubtargetFeatures> XCOFFObjectFile::getFeatures() const {
return SubtargetFeatures();
}
bool XCOFFObjectFile::isRelocatableObject() const {
if (is64Bit())
return !(fileHeader64()->Flags & NoRelMask);
return !(fileHeader32()->Flags & NoRelMask);
}
Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {
// TODO FIXME Should get from auxiliary_header->o_entry when support for the
// auxiliary_header is added.
return 0;
}
StringRef XCOFFObjectFile::mapDebugSectionName(StringRef Name) const {
return StringSwitch<StringRef>(Name)
.Case("dwinfo", "debug_info")
.Case("dwline", "debug_line")
.Case("dwpbnms", "debug_pubnames")
.Case("dwpbtyp", "debug_pubtypes")
.Case("dwarnge", "debug_aranges")
.Case("dwabrev", "debug_abbrev")
.Case("dwstr", "debug_str")
.Case("dwrnges", "debug_ranges")
.Case("dwloc", "debug_loc")
.Case("dwframe", "debug_frame")
.Case("dwmac", "debug_macinfo")
.Default(Name);
}
size_t XCOFFObjectFile::getFileHeaderSize() const {
return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);
}
size_t XCOFFObjectFile::getSectionHeaderSize() const {
return is64Bit() ? sizeof(XCOFFSectionHeader64) :
sizeof(XCOFFSectionHeader32);
}
bool XCOFFObjectFile::is64Bit() const {
return Binary::ID_XCOFF64 == getType();
}
Expected<StringRef> XCOFFObjectFile::getRawData(const char *Start,
uint64_t Size,
StringRef Name) const {
uintptr_t StartPtr = reinterpret_cast<uintptr_t>(Start);
// TODO: this path is untested.
if (Error E = Binary::checkOffset(Data, StartPtr, Size))
return createError(toString(std::move(E)) + ": " + Name.data() +
" data with offset 0x" + Twine::utohexstr(StartPtr) +
" and size 0x" + Twine::utohexstr(Size) +
" goes past the end of the file");
return StringRef(Start, Size);
}
uint16_t XCOFFObjectFile::getMagic() const {
return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;
}
Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {
if (Num <= 0 || Num > getNumberOfSections())
return createStringError(object_error::invalid_section_index,
"the section index (" + Twine(Num) +
") is invalid");
DataRefImpl DRI;
DRI.p = getWithOffset(getSectionHeaderTableAddress(),
getSectionHeaderSize() * (Num - 1));
return DRI;
}
DataRefImpl
XCOFFObjectFile::getSectionByType(XCOFF::SectionTypeFlags SectType) const {
DataRefImpl DRI;
auto GetSectionAddr = [&](const auto &Sections) -> uintptr_t {
for (const auto &Sec : Sections)
if (Sec.getSectionType() == SectType)
return reinterpret_cast<uintptr_t>(&Sec);
return uintptr_t(0);
};
if (is64Bit())
DRI.p = GetSectionAddr(sections64());
else
DRI.p = GetSectionAddr(sections32());
return DRI;
}
Expected<StringRef>
XCOFFObjectFile::getSymbolSectionName(XCOFFSymbolRef SymEntPtr) const {
const int16_t SectionNum = SymEntPtr.getSectionNumber();
switch (SectionNum) {
case XCOFF::N_DEBUG:
return "N_DEBUG";
case XCOFF::N_ABS:
return "N_ABS";
case XCOFF::N_UNDEF:
return "N_UNDEF";
default:
Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum);
if (SecRef)
return generateXCOFFFixedNameStringRef(
getSectionNameInternal(SecRef.get()));
return SecRef.takeError();
}
}
unsigned XCOFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {
XCOFFSymbolRef XCOFFSymRef(Sym.getRawDataRefImpl(), this);
return XCOFFSymRef.getSectionNumber();
}
bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {
return (SectionNumber <= 0 && SectionNumber >= -2);
}
uint16_t XCOFFObjectFile::getNumberOfSections() const {
return is64Bit() ? fileHeader64()->NumberOfSections
: fileHeader32()->NumberOfSections;
}
int32_t XCOFFObjectFile::getTimeStamp() const {
return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;
}
uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
return is64Bit() ? fileHeader64()->AuxHeaderSize
: fileHeader32()->AuxHeaderSize;
}
uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {
return fileHeader32()->SymbolTableOffset;
}
int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const {
// As far as symbol table size is concerned, if this field is negative it is
// to be treated as a 0. However since this field is also used for printing we
// don't want to truncate any negative values.
return fileHeader32()->NumberOfSymTableEntries;
}
uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {
return (fileHeader32()->NumberOfSymTableEntries >= 0
? fileHeader32()->NumberOfSymTableEntries
: 0);
}
uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {
return fileHeader64()->SymbolTableOffset;
}
uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
return fileHeader64()->NumberOfSymTableEntries;
}
uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const {
return is64Bit() ? getNumberOfSymbolTableEntries64()
: getLogicalNumberOfSymbolTableEntries32();
}
uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {
const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries();
return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),
XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);
}
void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const {
if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr))
report_fatal_error("Symbol table entry is outside of symbol table.");
if (SymbolEntPtr >= getEndOfSymbolTableAddress())
report_fatal_error("Symbol table entry is outside of symbol table.");
ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) -
reinterpret_cast<const char *>(SymbolTblPtr);
if (Offset % XCOFF::SymbolTableEntrySize != 0)
report_fatal_error(
"Symbol table entry position is not valid inside of symbol table.");
}
uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {
return (reinterpret_cast<const char *>(SymbolEntPtr) -
reinterpret_cast<const char *>(SymbolTblPtr)) /
XCOFF::SymbolTableEntrySize;
}
uint64_t XCOFFObjectFile::getSymbolSize(DataRefImpl Symb) const {
uint64_t Result = 0;
XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);
if (XCOFFSym.isCsectSymbol()) {
Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =
XCOFFSym.getXCOFFCsectAuxRef();
if (!CsectAuxRefOrError)
// TODO: report the error up the stack.
consumeError(CsectAuxRefOrError.takeError());
else {
XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get();
uint8_t SymType = CsectAuxRef.getSymbolType();
if (SymType == XCOFF::XTY_SD || SymType == XCOFF::XTY_CM)
Result = CsectAuxRef.getSectionOrLength();
}
}
return Result;
}
uintptr_t XCOFFObjectFile::getSymbolEntryAddressByIndex(uint32_t Index) const {
return getAdvancedSymbolEntryAddress(
reinterpret_cast<uintptr_t>(getPointerToSymbolTable()), Index);
}
Expected<StringRef>
XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const {
const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries();
if (Index >= NumberOfSymTableEntries)
return createError("symbol index " + Twine(Index) +
" exceeds symbol count " +
Twine(NumberOfSymTableEntries));
DataRefImpl SymDRI;
SymDRI.p = getSymbolEntryAddressByIndex(Index);
return getSymbolName(SymDRI);
}
uint16_t XCOFFObjectFile::getFlags() const {
return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
}
const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {
return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;
}
uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {
return reinterpret_cast<uintptr_t>(SectionHeaderTable);
}
int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {
return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;
}
XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)
: ObjectFile(Type, Object) {
assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64);
}
ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {
assert(is64Bit() && "64-bit interface called for non 64-bit file.");
const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();
return ArrayRef<XCOFFSectionHeader64>(TablePtr,
TablePtr + getNumberOfSections());
}
ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
assert(!is64Bit() && "32-bit interface called for non 32-bit file.");
const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32();
return ArrayRef<XCOFFSectionHeader32>(TablePtr,
TablePtr + getNumberOfSections());
}
// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO
// section header contains the actual count of relocation entries in the s_paddr
// field. STYP_OVRFLO headers contain the section index of their corresponding
// sections as their raw "NumberOfRelocations" field value.
template <typename T>
Expected<uint32_t> XCOFFObjectFile::getNumberOfRelocationEntries(
const XCOFFSectionHeader<T> &Sec) const {
const T &Section = static_cast<const T &>(Sec);
if (is64Bit())
return Section.NumberOfRelocations;
uint16_t SectionIndex = &Section - sectionHeaderTable<T>() + 1;
if (Section.NumberOfRelocations < XCOFF::RelocOverflow)
return Section.NumberOfRelocations;
for (const auto &Sec : sections32()) {
if (Sec.Flags == XCOFF::STYP_OVRFLO &&
Sec.NumberOfRelocations == SectionIndex)
return Sec.PhysicalAddress;
}
return errorCodeToError(object_error::parse_failed);
}
template <typename Shdr, typename Reloc>
Expected<ArrayRef<Reloc>> XCOFFObjectFile::relocations(const Shdr &Sec) const {
uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),
Sec.FileOffsetToRelocationInfo);
auto NumRelocEntriesOrErr = getNumberOfRelocationEntries(Sec);
if (Error E = NumRelocEntriesOrErr.takeError())
return std::move(E);
uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();
static_assert((sizeof(Reloc) == XCOFF::RelocationSerializationSize64 ||
sizeof(Reloc) == XCOFF::RelocationSerializationSize32),
"Relocation structure is incorrect");
auto RelocationOrErr =
getObject<Reloc>(Data, reinterpret_cast<void *>(RelocAddr),
NumRelocEntries * sizeof(Reloc));
if (!RelocationOrErr)
return createError(
toString(RelocationOrErr.takeError()) + ": relocations with offset 0x" +
Twine::utohexstr(Sec.FileOffsetToRelocationInfo) + " and size 0x" +
Twine::utohexstr(NumRelocEntries * sizeof(Reloc)) +
" go past the end of the file");
const Reloc *StartReloc = RelocationOrErr.get();
return ArrayRef<Reloc>(StartReloc, StartReloc + NumRelocEntries);
}
template <typename ExceptEnt>
Expected<ArrayRef<ExceptEnt>> XCOFFObjectFile::getExceptionEntries() const {
assert((is64Bit() && sizeof(ExceptEnt) == sizeof(ExceptionSectionEntry64)) ||
(!is64Bit() && sizeof(ExceptEnt) == sizeof(ExceptionSectionEntry32)));
Expected<uintptr_t> ExceptionSectOrErr =
getSectionFileOffsetToRawData(XCOFF::STYP_EXCEPT);
if (!ExceptionSectOrErr)
return ExceptionSectOrErr.takeError();
DataRefImpl DRI = getSectionByType(XCOFF::STYP_EXCEPT);
if (DRI.p == 0)
return ArrayRef<ExceptEnt>();
ExceptEnt *ExceptEntStart =
reinterpret_cast<ExceptEnt *>(*ExceptionSectOrErr);
return ArrayRef<ExceptEnt>(
ExceptEntStart, ExceptEntStart + getSectionSize(DRI) / sizeof(ExceptEnt));
}
template Expected<ArrayRef<ExceptionSectionEntry32>>
XCOFFObjectFile::getExceptionEntries() const;
template Expected<ArrayRef<ExceptionSectionEntry64>>
XCOFFObjectFile::getExceptionEntries() const;
Expected<XCOFFStringTable>
XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
// If there is a string table, then the buffer must contain at least 4 bytes
// for the string table's size. Not having a string table is not an error.
if (Error E = Binary::checkOffset(
Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) {
consumeError(std::move(E));
return XCOFFStringTable{0, nullptr};
}
// Read the size out of the buffer.
uint32_t Size = support::endian::read32be(Obj->base() + Offset);
// If the size is less then 4, then the string table is just a size and no
// string data.
if (Size <= 4)
return XCOFFStringTable{4, nullptr};
auto StringTableOrErr =
getObject<char>(Obj->Data, Obj->base() + Offset, Size);
if (!StringTableOrErr)
return createError(toString(StringTableOrErr.takeError()) +
": string table with offset 0x" +
Twine::utohexstr(Offset) + " and size 0x" +
Twine::utohexstr(Size) +
" goes past the end of the file");
const char *StringTablePtr = StringTableOrErr.get();
if (StringTablePtr[Size - 1] != '\0')
return errorCodeToError(object_error::string_table_non_null_end);
return XCOFFStringTable{Size, StringTablePtr};
}
// This function returns the import file table. Each entry in the import file
// table consists of: "path_name\0base_name\0archive_member_name\0".
Expected<StringRef> XCOFFObjectFile::getImportFileTable() const {
Expected<uintptr_t> LoaderSectionAddrOrError =
getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);
if (!LoaderSectionAddrOrError)
return LoaderSectionAddrOrError.takeError();
uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();
if (!LoaderSectionAddr)
return StringRef();
uint64_t OffsetToImportFileTable = 0;
uint64_t LengthOfImportFileTable = 0;
if (is64Bit()) {
const LoaderSectionHeader64 *LoaderSec64 =
viewAs<LoaderSectionHeader64>(LoaderSectionAddr);
OffsetToImportFileTable = LoaderSec64->OffsetToImpid;
LengthOfImportFileTable = LoaderSec64->LengthOfImpidStrTbl;
} else {
const LoaderSectionHeader32 *LoaderSec32 =
viewAs<LoaderSectionHeader32>(LoaderSectionAddr);
OffsetToImportFileTable = LoaderSec32->OffsetToImpid;
LengthOfImportFileTable = LoaderSec32->LengthOfImpidStrTbl;
}
auto ImportTableOrErr = getObject<char>(
Data,
reinterpret_cast<void *>(LoaderSectionAddr + OffsetToImportFileTable),
LengthOfImportFileTable);
if (!ImportTableOrErr)
return createError(
toString(ImportTableOrErr.takeError()) +
": import file table with offset 0x" +
Twine::utohexstr(LoaderSectionAddr + OffsetToImportFileTable) +
" and size 0x" + Twine::utohexstr(LengthOfImportFileTable) +
" goes past the end of the file");
const char *ImportTablePtr = ImportTableOrErr.get();
if (ImportTablePtr[LengthOfImportFileTable - 1] != '\0')
return createError(
": import file name table with offset 0x" +
Twine::utohexstr(LoaderSectionAddr + OffsetToImportFileTable) +
" and size 0x" + Twine::utohexstr(LengthOfImportFileTable) +
" must end with a null terminator");
return StringRef(ImportTablePtr, LengthOfImportFileTable);
}
Expected<std::unique_ptr<XCOFFObjectFile>>
XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
// Can't use std::make_unique because of the private constructor.
std::unique_ptr<XCOFFObjectFile> Obj;
Obj.reset(new XCOFFObjectFile(Type, MBR));
uint64_t CurOffset = 0;
const auto *Base = Obj->base();
MemoryBufferRef Data = Obj->Data;
// Parse file header.
auto FileHeaderOrErr =
getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize());
if (Error E = FileHeaderOrErr.takeError())
return std::move(E);
Obj->FileHeader = FileHeaderOrErr.get();
CurOffset += Obj->getFileHeaderSize();
if (Obj->getOptionalHeaderSize()) {
auto AuxiliaryHeaderOrErr =
getObject<void>(Data, Base + CurOffset, Obj->getOptionalHeaderSize());
if (Error E = AuxiliaryHeaderOrErr.takeError())
return std::move(E);
Obj->AuxiliaryHeader = AuxiliaryHeaderOrErr.get();
}
CurOffset += Obj->getOptionalHeaderSize();
// Parse the section header table if it is present.
if (Obj->getNumberOfSections()) {
uint64_t SectionHeadersSize =
Obj->getNumberOfSections() * Obj->getSectionHeaderSize();
auto SecHeadersOrErr =
getObject<void>(Data, Base + CurOffset, SectionHeadersSize);
if (!SecHeadersOrErr)
return createError(toString(SecHeadersOrErr.takeError()) +
": section headers with offset 0x" +
Twine::utohexstr(CurOffset) + " and size 0x" +
Twine::utohexstr(SectionHeadersSize) +
" go past the end of the file");
Obj->SectionHeaderTable = SecHeadersOrErr.get();
}
const uint32_t NumberOfSymbolTableEntries =
Obj->getNumberOfSymbolTableEntries();
// If there is no symbol table we are done parsing the memory buffer.
if (NumberOfSymbolTableEntries == 0)
return std::move(Obj);
// Parse symbol table.
CurOffset = Obj->is64Bit() ? Obj->getSymbolTableOffset64()
: Obj->getSymbolTableOffset32();
const uint64_t SymbolTableSize =
static_cast<uint64_t>(XCOFF::SymbolTableEntrySize) *
NumberOfSymbolTableEntries;
auto SymTableOrErr =
getObject<void *>(Data, Base + CurOffset, SymbolTableSize);
if (!SymTableOrErr)
return createError(
toString(SymTableOrErr.takeError()) + ": symbol table with offset 0x" +
Twine::utohexstr(CurOffset) + " and size 0x" +
Twine::utohexstr(SymbolTableSize) + " goes past the end of the file");
Obj->SymbolTblPtr = SymTableOrErr.get();
CurOffset += SymbolTableSize;
// Parse String table.
Expected<XCOFFStringTable> StringTableOrErr =
parseStringTable(Obj.get(), CurOffset);
if (Error E = StringTableOrErr.takeError())
return std::move(E);
Obj->StringTable = StringTableOrErr.get();
return std::move(Obj);
}
Expected<std::unique_ptr<ObjectFile>>
ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
unsigned FileType) {
return XCOFFObjectFile::create(FileType, MemBufRef);
}
std::optional<StringRef> XCOFFObjectFile::tryGetCPUName() const {
return StringRef("future");
}
bool XCOFFSymbolRef::isFunction() const {
if (!isCsectSymbol())
return false;
if (getSymbolType() & FunctionSym)
return true;
Expected<XCOFFCsectAuxRef> ExpCsectAuxEnt = getXCOFFCsectAuxRef();
if (!ExpCsectAuxEnt) {
// If we could not get the CSECT auxiliary entry, then treat this symbol as
// if it isn't a function. Consume the error and return `false` to move on.
consumeError(ExpCsectAuxEnt.takeError());
return false;
}
const XCOFFCsectAuxRef CsectAuxRef = ExpCsectAuxEnt.get();
// A function definition should be a label definition.
// FIXME: This is not necessarily the case when -ffunction-sections is
// enabled.
if (!CsectAuxRef.isLabel())
return false;
if (CsectAuxRef.getStorageMappingClass() != XCOFF::XMC_PR)
return false;
const int16_t SectNum = getSectionNumber();
Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum);
if (!SI) {
// If we could not get the section, then this symbol should not be
// a function. So consume the error and return `false` to move on.
consumeError(SI.takeError());
return false;
}
return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT);
}
bool XCOFFSymbolRef::isCsectSymbol() const {
XCOFF::StorageClass SC = getStorageClass();
return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT ||
SC == XCOFF::C_HIDEXT);
}
Expected<XCOFFCsectAuxRef> XCOFFSymbolRef::getXCOFFCsectAuxRef() const {
assert(isCsectSymbol() &&
"Calling csect symbol interface with a non-csect symbol.");
uint8_t NumberOfAuxEntries = getNumberOfAuxEntries();
Expected<StringRef> NameOrErr = getName();
if (auto Err = NameOrErr.takeError())
return std::move(Err);
uint32_t SymbolIdx = OwningObjectPtr->getSymbolIndex(getEntryAddress());
if (!NumberOfAuxEntries) {
return createError("csect symbol \"" + *NameOrErr + "\" with index " +
Twine(SymbolIdx) + " contains no auxiliary entry");
}
if (!OwningObjectPtr->is64Bit()) {
// In XCOFF32, the csect auxilliary entry is always the last auxiliary
// entry for the symbol.
uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
getEntryAddress(), NumberOfAuxEntries);
return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt32>(AuxAddr));
}
// XCOFF64 uses SymbolAuxType to identify the auxiliary entry type.
// We need to iterate through all the auxiliary entries to find it.
for (uint8_t Index = NumberOfAuxEntries; Index > 0; --Index) {
uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
getEntryAddress(), Index);
if (*OwningObjectPtr->getSymbolAuxType(AuxAddr) ==
XCOFF::SymbolAuxType::AUX_CSECT) {
#ifndef NDEBUG
OwningObjectPtr->checkSymbolEntryPointer(AuxAddr);
#endif
return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt64>(AuxAddr));
}
}
return createError(
"a csect auxiliary entry has not been found for symbol \"" + *NameOrErr +
"\" with index " + Twine(SymbolIdx));
}
Expected<StringRef> XCOFFSymbolRef::getName() const {
// A storage class value with the high-order bit on indicates that the name is
// a symbolic debugger stabstring.
if (getStorageClass() & 0x80)
return StringRef("Unimplemented Debug Name");
if (Entry32) {
if (Entry32->NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)
return generateXCOFFFixedNameStringRef(Entry32->SymbolName);
return OwningObjectPtr->getStringTableEntry(Entry32->NameInStrTbl.Offset);
}
return OwningObjectPtr->getStringTableEntry(Entry64->Offset);
}
// Explictly instantiate template classes.
template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
template struct XCOFFRelocation<llvm::support::ubig32_t>;
template struct XCOFFRelocation<llvm::support::ubig64_t>;
template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation64>>
llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader64,
llvm::object::XCOFFRelocation64>(
llvm::object::XCOFFSectionHeader64 const &) const;
template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation32>>
llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader32,
llvm::object::XCOFFRelocation32>(
llvm::object::XCOFFSectionHeader32 const &) const;
bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) {
if (Bytes.size() < 4)
return false;
return support::endian::read32be(Bytes.data()) == 0;
}
#define GETVALUEWITHMASK(X) (Data & (TracebackTable::X))
#define GETVALUEWITHMASKSHIFT(X, S) \
((Data & (TracebackTable::X)) >> (TracebackTable::S))
Expected<TBVectorExt> TBVectorExt::create(StringRef TBvectorStrRef) {
Error Err = Error::success();
TBVectorExt TBTVecExt(TBvectorStrRef, Err);
if (Err)
return std::move(Err);
return TBTVecExt;
}
TBVectorExt::TBVectorExt(StringRef TBvectorStrRef, Error &Err) {
const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(TBvectorStrRef.data());
Data = support::endian::read16be(Ptr);
uint32_t VecParmsTypeValue = support::endian::read32be(Ptr + 2);
unsigned ParmsNum =
GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask, NumberOfVectorParmsShift);
ErrorAsOutParameter EAO(&Err);
Expected<SmallString<32>> VecParmsTypeOrError =
parseVectorParmsType(VecParmsTypeValue, ParmsNum);
if (!VecParmsTypeOrError)
Err = VecParmsTypeOrError.takeError();
else
VecParmsInfo = VecParmsTypeOrError.get();
}
uint8_t TBVectorExt::getNumberOfVRSaved() const {
return GETVALUEWITHMASKSHIFT(NumberOfVRSavedMask, NumberOfVRSavedShift);
}
bool TBVectorExt::isVRSavedOnStack() const {
return GETVALUEWITHMASK(IsVRSavedOnStackMask);
}
bool TBVectorExt::hasVarArgs() const {
return GETVALUEWITHMASK(HasVarArgsMask);
}
uint8_t TBVectorExt::getNumberOfVectorParms() const {
return GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask,
NumberOfVectorParmsShift);
}
bool TBVectorExt::hasVMXInstruction() const {
return GETVALUEWITHMASK(HasVMXInstructionMask);
}
#undef GETVALUEWITHMASK
#undef GETVALUEWITHMASKSHIFT
Expected<XCOFFTracebackTable>
XCOFFTracebackTable::create(const uint8_t *Ptr, uint64_t &Size, bool Is64Bit) {
Error Err = Error::success();
XCOFFTracebackTable TBT(Ptr, Size, Err, Is64Bit);
if (Err)
return std::move(Err);
return TBT;
}
XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size,
Error &Err, bool Is64Bit)
: TBPtr(Ptr), Is64BitObj(Is64Bit) {
ErrorAsOutParameter EAO(&Err);
DataExtractor DE(ArrayRef<uint8_t>(Ptr, Size), /*IsLittleEndian=*/false,
/*AddressSize=*/0);
DataExtractor::Cursor Cur(/*Offset=*/0);
// Skip 8 bytes of mandatory fields.
DE.getU64(Cur);
unsigned FixedParmsNum = getNumberOfFixedParms();
unsigned FloatingParmsNum = getNumberOfFPParms();
uint32_t ParamsTypeValue = 0;
// Begin to parse optional fields.
if (Cur && (FixedParmsNum + FloatingParmsNum) > 0)
ParamsTypeValue = DE.getU32(Cur);
if (Cur && hasTraceBackTableOffset())
TraceBackTableOffset = DE.getU32(Cur);
if (Cur && isInterruptHandler())
HandlerMask = DE.getU32(Cur);
if (Cur && hasControlledStorage()) {
NumOfCtlAnchors = DE.getU32(Cur);
if (Cur && NumOfCtlAnchors) {
SmallVector<uint32_t, 8> Disp;
Disp.reserve(*NumOfCtlAnchors);
for (uint32_t I = 0; I < NumOfCtlAnchors && Cur; ++I)
Disp.push_back(DE.getU32(Cur));
if (Cur)
ControlledStorageInfoDisp = std::move(Disp);
}
}
if (Cur && isFuncNamePresent()) {
uint16_t FunctionNameLen = DE.getU16(Cur);
if (Cur)
FunctionName = DE.getBytes(Cur, FunctionNameLen);
}
if (Cur && isAllocaUsed())
AllocaRegister = DE.getU8(Cur);
unsigned VectorParmsNum = 0;
if (Cur && hasVectorInfo()) {
StringRef VectorExtRef = DE.getBytes(Cur, 6);
if (Cur) {
Expected<TBVectorExt> TBVecExtOrErr = TBVectorExt::create(VectorExtRef);
if (!TBVecExtOrErr) {
Err = TBVecExtOrErr.takeError();
return;
}
VecExt = TBVecExtOrErr.get();
VectorParmsNum = VecExt->getNumberOfVectorParms();
// Skip two bytes of padding after vector info.
DE.skip(Cur, 2);
}
}
// As long as there is no fixed-point or floating-point parameter, this
// field remains not present even when hasVectorInfo gives true and
// indicates the presence of vector parameters.
if (Cur && (FixedParmsNum + FloatingParmsNum) > 0) {
Expected<SmallString<32>> ParmsTypeOrError =
hasVectorInfo()
? parseParmsTypeWithVecInfo(ParamsTypeValue, FixedParmsNum,
FloatingParmsNum, VectorParmsNum)
: parseParmsType(ParamsTypeValue, FixedParmsNum, FloatingParmsNum);
if (!ParmsTypeOrError) {
Err = ParmsTypeOrError.takeError();
return;
}
ParmsType = ParmsTypeOrError.get();
}
if (Cur && hasExtensionTable()) {
ExtensionTable = DE.getU8(Cur);
if (*ExtensionTable & ExtendedTBTableFlag::TB_EH_INFO) {
// eh_info displacement must be 4-byte aligned.
Cur.seek(alignTo(Cur.tell(), 4));
EhInfoDisp = Is64BitObj ? DE.getU64(Cur) : DE.getU32(Cur);
}
}
if (!Cur)
Err = Cur.takeError();
Size = Cur.tell();
}
#define GETBITWITHMASK(P, X) \
(support::endian::read32be(TBPtr + (P)) & (TracebackTable::X))
#define GETBITWITHMASKSHIFT(P, X, S) \
((support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) >> \
(TracebackTable::S))
uint8_t XCOFFTracebackTable::getVersion() const {
return GETBITWITHMASKSHIFT(0, VersionMask, VersionShift);
}
uint8_t XCOFFTracebackTable::getLanguageID() const {
return GETBITWITHMASKSHIFT(0, LanguageIdMask, LanguageIdShift);
}
bool XCOFFTracebackTable::isGlobalLinkage() const {
return GETBITWITHMASK(0, IsGlobaLinkageMask);
}
bool XCOFFTracebackTable::isOutOfLineEpilogOrPrologue() const {
return GETBITWITHMASK(0, IsOutOfLineEpilogOrPrologueMask);
}
bool XCOFFTracebackTable::hasTraceBackTableOffset() const {
return GETBITWITHMASK(0, HasTraceBackTableOffsetMask);
}
bool XCOFFTracebackTable::isInternalProcedure() const {
return GETBITWITHMASK(0, IsInternalProcedureMask);
}
bool XCOFFTracebackTable::hasControlledStorage() const {
return GETBITWITHMASK(0, HasControlledStorageMask);
}
bool XCOFFTracebackTable::isTOCless() const {
return GETBITWITHMASK(0, IsTOClessMask);
}
bool XCOFFTracebackTable::isFloatingPointPresent() const {
return GETBITWITHMASK(0, IsFloatingPointPresentMask);
}
bool XCOFFTracebackTable::isFloatingPointOperationLogOrAbortEnabled() const {
return GETBITWITHMASK(0, IsFloatingPointOperationLogOrAbortEnabledMask);
}
bool XCOFFTracebackTable::isInterruptHandler() const {
return GETBITWITHMASK(0, IsInterruptHandlerMask);
}
bool XCOFFTracebackTable::isFuncNamePresent() const {
return GETBITWITHMASK(0, IsFunctionNamePresentMask);
}
bool XCOFFTracebackTable::isAllocaUsed() const {
return GETBITWITHMASK(0, IsAllocaUsedMask);
}
uint8_t XCOFFTracebackTable::getOnConditionDirective() const {
return GETBITWITHMASKSHIFT(0, OnConditionDirectiveMask,
OnConditionDirectiveShift);
}
bool XCOFFTracebackTable::isCRSaved() const {
return GETBITWITHMASK(0, IsCRSavedMask);
}
bool XCOFFTracebackTable::isLRSaved() const {
return GETBITWITHMASK(0, IsLRSavedMask);
}
bool XCOFFTracebackTable::isBackChainStored() const {
return GETBITWITHMASK(4, IsBackChainStoredMask);
}
bool XCOFFTracebackTable::isFixup() const {
return GETBITWITHMASK(4, IsFixupMask);
}
uint8_t XCOFFTracebackTable::getNumOfFPRsSaved() const {
return GETBITWITHMASKSHIFT(4, FPRSavedMask, FPRSavedShift);
}
bool XCOFFTracebackTable::hasExtensionTable() const {
return GETBITWITHMASK(4, HasExtensionTableMask);
}
bool XCOFFTracebackTable::hasVectorInfo() const {
return GETBITWITHMASK(4, HasVectorInfoMask);
}
uint8_t XCOFFTracebackTable::getNumOfGPRsSaved() const {
return GETBITWITHMASKSHIFT(4, GPRSavedMask, GPRSavedShift);
}
uint8_t XCOFFTracebackTable::getNumberOfFixedParms() const {
return GETBITWITHMASKSHIFT(4, NumberOfFixedParmsMask,
NumberOfFixedParmsShift);
}
uint8_t XCOFFTracebackTable::getNumberOfFPParms() const {
return GETBITWITHMASKSHIFT(4, NumberOfFloatingPointParmsMask,
NumberOfFloatingPointParmsShift);
}
bool XCOFFTracebackTable::hasParmsOnStack() const {
return GETBITWITHMASK(4, HasParmsOnStackMask);
}
#undef GETBITWITHMASK
#undef GETBITWITHMASKSHIFT
} // namespace object
} // namespace llvm