Path: blob/main/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp
35232 views
//===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines the XCOFFObjectFile class.9//10//===----------------------------------------------------------------------===//1112#include "llvm/Object/XCOFFObjectFile.h"13#include "llvm/ADT/StringSwitch.h"14#include "llvm/Support/DataExtractor.h"15#include "llvm/TargetParser/SubtargetFeature.h"16#include <cstddef>17#include <cstring>1819namespace llvm {2021using namespace XCOFF;2223namespace object {2425static const uint8_t FunctionSym = 0x20;26static const uint16_t NoRelMask = 0x0001;27static const size_t SymbolAuxTypeOffset = 17;2829// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer30// 'M'. Returns a pointer to the underlying object on success.31template <typename T>32static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr,33const uint64_t Size = sizeof(T)) {34uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);35if (Error E = Binary::checkOffset(M, Addr, Size))36return std::move(E);37return reinterpret_cast<const T *>(Addr);38}3940static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {41return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +42Offset);43}4445template <typename T> static const T *viewAs(uintptr_t in) {46return reinterpret_cast<const T *>(in);47}4849static StringRef generateXCOFFFixedNameStringRef(const char *Name) {50auto NulCharPtr =51static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize));52return NulCharPtr ? StringRef(Name, NulCharPtr - Name)53: StringRef(Name, XCOFF::NameSize);54}5556template <typename T> StringRef XCOFFSectionHeader<T>::getName() const {57const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);58return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name);59}6061template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const {62const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);63return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask;64}6566template <typename T>67uint32_t XCOFFSectionHeader<T>::getSectionSubtype() const {68const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);69return DerivedXCOFFSectionHeader.Flags & ~SectionFlagsTypeMask;70}7172template <typename T>73bool XCOFFSectionHeader<T>::isReservedSectionType() const {74return getSectionType() & SectionFlagsReservedMask;75}7677template <typename AddressType>78bool XCOFFRelocation<AddressType>::isRelocationSigned() const {79return Info & XR_SIGN_INDICATOR_MASK;80}8182template <typename AddressType>83bool XCOFFRelocation<AddressType>::isFixupIndicated() const {84return Info & XR_FIXUP_INDICATOR_MASK;85}8687template <typename AddressType>88uint8_t XCOFFRelocation<AddressType>::getRelocatedLength() const {89// The relocation encodes the bit length being relocated minus 1. Add back90// the 1 to get the actual length being relocated.91return (Info & XR_BIASED_LENGTH_MASK) + 1;92}9394template struct ExceptionSectionEntry<support::ubig32_t>;95template struct ExceptionSectionEntry<support::ubig64_t>;9697template <typename T>98Expected<StringRef> getLoaderSecSymNameInStrTbl(const T *LoaderSecHeader,99uint64_t Offset) {100if (LoaderSecHeader->LengthOfStrTbl > Offset)101return (reinterpret_cast<const char *>(LoaderSecHeader) +102LoaderSecHeader->OffsetToStrTbl + Offset);103104return createError("entry with offset 0x" + Twine::utohexstr(Offset) +105" in the loader section's string table with size 0x" +106Twine::utohexstr(LoaderSecHeader->LengthOfStrTbl) +107" is invalid");108}109110Expected<StringRef> LoaderSectionSymbolEntry32::getSymbolName(111const LoaderSectionHeader32 *LoaderSecHeader32) const {112const NameOffsetInStrTbl *NameInStrTbl =113reinterpret_cast<const NameOffsetInStrTbl *>(SymbolName);114if (NameInStrTbl->IsNameInStrTbl != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)115return generateXCOFFFixedNameStringRef(SymbolName);116117return getLoaderSecSymNameInStrTbl(LoaderSecHeader32, NameInStrTbl->Offset);118}119120Expected<StringRef> LoaderSectionSymbolEntry64::getSymbolName(121const LoaderSectionHeader64 *LoaderSecHeader64) const {122return getLoaderSecSymNameInStrTbl(LoaderSecHeader64, Offset);123}124125uintptr_t126XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress,127uint32_t Distance) {128return getWithOffset(CurrentAddress, Distance * XCOFF::SymbolTableEntrySize);129}130131const XCOFF::SymbolAuxType *132XCOFFObjectFile::getSymbolAuxType(uintptr_t AuxEntryAddress) const {133assert(is64Bit() && "64-bit interface called on a 32-bit object file.");134return viewAs<XCOFF::SymbolAuxType>(135getWithOffset(AuxEntryAddress, SymbolAuxTypeOffset));136}137138void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,139uintptr_t TableAddress) const {140if (Addr < TableAddress)141report_fatal_error("Section header outside of section header table.");142143uintptr_t Offset = Addr - TableAddress;144if (Offset >= getSectionHeaderSize() * getNumberOfSections())145report_fatal_error("Section header outside of section header table.");146147if (Offset % getSectionHeaderSize() != 0)148report_fatal_error(149"Section header pointer does not point to a valid section header.");150}151152const XCOFFSectionHeader32 *153XCOFFObjectFile::toSection32(DataRefImpl Ref) const {154assert(!is64Bit() && "32-bit interface called on 64-bit object file.");155#ifndef NDEBUG156checkSectionAddress(Ref.p, getSectionHeaderTableAddress());157#endif158return viewAs<XCOFFSectionHeader32>(Ref.p);159}160161const XCOFFSectionHeader64 *162XCOFFObjectFile::toSection64(DataRefImpl Ref) const {163assert(is64Bit() && "64-bit interface called on a 32-bit object file.");164#ifndef NDEBUG165checkSectionAddress(Ref.p, getSectionHeaderTableAddress());166#endif167return viewAs<XCOFFSectionHeader64>(Ref.p);168}169170XCOFFSymbolRef XCOFFObjectFile::toSymbolRef(DataRefImpl Ref) const {171assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!");172#ifndef NDEBUG173checkSymbolEntryPointer(Ref.p);174#endif175return XCOFFSymbolRef(Ref, this);176}177178const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const {179assert(!is64Bit() && "32-bit interface called on 64-bit object file.");180return static_cast<const XCOFFFileHeader32 *>(FileHeader);181}182183const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {184assert(is64Bit() && "64-bit interface called on a 32-bit object file.");185return static_cast<const XCOFFFileHeader64 *>(FileHeader);186}187188const XCOFFAuxiliaryHeader32 *XCOFFObjectFile::auxiliaryHeader32() const {189assert(!is64Bit() && "32-bit interface called on 64-bit object file.");190return static_cast<const XCOFFAuxiliaryHeader32 *>(AuxiliaryHeader);191}192193const XCOFFAuxiliaryHeader64 *XCOFFObjectFile::auxiliaryHeader64() const {194assert(is64Bit() && "64-bit interface called on a 32-bit object file.");195return static_cast<const XCOFFAuxiliaryHeader64 *>(AuxiliaryHeader);196}197198template <typename T> const T *XCOFFObjectFile::sectionHeaderTable() const {199return static_cast<const T *>(SectionHeaderTable);200}201202const XCOFFSectionHeader32 *203XCOFFObjectFile::sectionHeaderTable32() const {204assert(!is64Bit() && "32-bit interface called on 64-bit object file.");205return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable);206}207208const XCOFFSectionHeader64 *209XCOFFObjectFile::sectionHeaderTable64() const {210assert(is64Bit() && "64-bit interface called on a 32-bit object file.");211return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);212}213214void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {215uintptr_t NextSymbolAddr = getAdvancedSymbolEntryAddress(216Symb.p, toSymbolRef(Symb).getNumberOfAuxEntries() + 1);217#ifndef NDEBUG218// This function is used by basic_symbol_iterator, which allows to219// point to the end-of-symbol-table address.220if (NextSymbolAddr != getEndOfSymbolTableAddress())221checkSymbolEntryPointer(NextSymbolAddr);222#endif223Symb.p = NextSymbolAddr;224}225226Expected<StringRef>227XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const {228// The byte offset is relative to the start of the string table.229// A byte offset value of 0 is a null or zero-length symbol230// name. A byte offset in the range 1 to 3 (inclusive) points into the length231// field; as a soft-error recovery mechanism, we treat such cases as having an232// offset of 0.233if (Offset < 4)234return StringRef(nullptr, 0);235236if (StringTable.Data != nullptr && StringTable.Size > Offset)237return (StringTable.Data + Offset);238239return createError("entry with offset 0x" + Twine::utohexstr(Offset) +240" in a string table with size 0x" +241Twine::utohexstr(StringTable.Size) + " is invalid");242}243244StringRef XCOFFObjectFile::getStringTable() const {245// If the size is less than or equal to 4, then the string table contains no246// string data.247return StringRef(StringTable.Data,248StringTable.Size <= 4 ? 0 : StringTable.Size);249}250251Expected<StringRef>252XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const {253if (CFileEntPtr->NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)254return generateXCOFFFixedNameStringRef(CFileEntPtr->Name);255return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset);256}257258Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {259return toSymbolRef(Symb).getName();260}261262Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {263return toSymbolRef(Symb).getValue();264}265266uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {267return toSymbolRef(Symb).getValue();268}269270uint32_t XCOFFObjectFile::getSymbolAlignment(DataRefImpl Symb) const {271uint64_t Result = 0;272XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);273if (XCOFFSym.isCsectSymbol()) {274Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =275XCOFFSym.getXCOFFCsectAuxRef();276if (!CsectAuxRefOrError)277// TODO: report the error up the stack.278consumeError(CsectAuxRefOrError.takeError());279else280Result = 1ULL << CsectAuxRefOrError.get().getAlignmentLog2();281}282return Result;283}284285uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {286uint64_t Result = 0;287XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);288if (XCOFFSym.isCsectSymbol()) {289Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =290XCOFFSym.getXCOFFCsectAuxRef();291if (!CsectAuxRefOrError)292// TODO: report the error up the stack.293consumeError(CsectAuxRefOrError.takeError());294else {295XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get();296assert(CsectAuxRef.getSymbolType() == XCOFF::XTY_CM);297Result = CsectAuxRef.getSectionOrLength();298}299}300return Result;301}302303Expected<SymbolRef::Type>304XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {305XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);306307Expected<bool> IsFunction = XCOFFSym.isFunction();308if (!IsFunction)309return IsFunction.takeError();310311if (*IsFunction)312return SymbolRef::ST_Function;313314if (XCOFF::C_FILE == XCOFFSym.getStorageClass())315return SymbolRef::ST_File;316317int16_t SecNum = XCOFFSym.getSectionNumber();318if (SecNum <= 0)319return SymbolRef::ST_Other;320321Expected<DataRefImpl> SecDRIOrErr =322getSectionByNum(XCOFFSym.getSectionNumber());323324if (!SecDRIOrErr)325return SecDRIOrErr.takeError();326327DataRefImpl SecDRI = SecDRIOrErr.get();328329Expected<StringRef> SymNameOrError = XCOFFSym.getName();330if (SymNameOrError) {331// The "TOC" symbol is treated as SymbolRef::ST_Other.332if (SymNameOrError.get() == "TOC")333return SymbolRef::ST_Other;334335// The symbol for a section name is treated as SymbolRef::ST_Other.336StringRef SecName;337if (is64Bit())338SecName = XCOFFObjectFile::toSection64(SecDRIOrErr.get())->getName();339else340SecName = XCOFFObjectFile::toSection32(SecDRIOrErr.get())->getName();341342if (SecName == SymNameOrError.get())343return SymbolRef::ST_Other;344} else345return SymNameOrError.takeError();346347if (isSectionData(SecDRI) || isSectionBSS(SecDRI))348return SymbolRef::ST_Data;349350if (isDebugSection(SecDRI))351return SymbolRef::ST_Debug;352353return SymbolRef::ST_Other;354}355356Expected<section_iterator>357XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {358const int16_t SectNum = toSymbolRef(Symb).getSectionNumber();359360if (isReservedSectionNumber(SectNum))361return section_end();362363Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum);364if (!ExpSec)365return ExpSec.takeError();366367return section_iterator(SectionRef(ExpSec.get(), this));368}369370void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {371const char *Ptr = reinterpret_cast<const char *>(Sec.p);372Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());373}374375Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {376return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));377}378379uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {380// Avoid ternary due to failure to convert the ubig32_t value to a unit64_t381// with MSVC.382if (is64Bit())383return toSection64(Sec)->VirtualAddress;384385return toSection32(Sec)->VirtualAddress;386}387388uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {389// Section numbers in XCOFF are numbered beginning at 1. A section number of390// zero is used to indicate that a symbol is being imported or is undefined.391if (is64Bit())392return toSection64(Sec) - sectionHeaderTable64() + 1;393else394return toSection32(Sec) - sectionHeaderTable32() + 1;395}396397uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {398// Avoid ternary due to failure to convert the ubig32_t value to a unit64_t399// with MSVC.400if (is64Bit())401return toSection64(Sec)->SectionSize;402403return toSection32(Sec)->SectionSize;404}405406Expected<ArrayRef<uint8_t>>407XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const {408if (isSectionVirtual(Sec))409return ArrayRef<uint8_t>();410411uint64_t OffsetToRaw;412if (is64Bit())413OffsetToRaw = toSection64(Sec)->FileOffsetToRawData;414else415OffsetToRaw = toSection32(Sec)->FileOffsetToRawData;416417const uint8_t * ContentStart = base() + OffsetToRaw;418uint64_t SectionSize = getSectionSize(Sec);419if (Error E = Binary::checkOffset(420Data, reinterpret_cast<uintptr_t>(ContentStart), SectionSize))421return createError(422toString(std::move(E)) + ": section data with offset 0x" +423Twine::utohexstr(OffsetToRaw) + " and size 0x" +424Twine::utohexstr(SectionSize) + " goes past the end of the file");425426return ArrayRef(ContentStart, SectionSize);427}428429uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {430uint64_t Result = 0;431llvm_unreachable("Not yet implemented!");432return Result;433}434435uint64_t XCOFFObjectFile::getSectionFileOffsetToRawData(DataRefImpl Sec) const {436if (is64Bit())437return toSection64(Sec)->FileOffsetToRawData;438439return toSection32(Sec)->FileOffsetToRawData;440}441442Expected<uintptr_t> XCOFFObjectFile::getSectionFileOffsetToRawData(443XCOFF::SectionTypeFlags SectType) const {444DataRefImpl DRI = getSectionByType(SectType);445446if (DRI.p == 0) // No section is not an error.447return 0;448449uint64_t SectionOffset = getSectionFileOffsetToRawData(DRI);450uint64_t SizeOfSection = getSectionSize(DRI);451452uintptr_t SectionStart = reinterpret_cast<uintptr_t>(base() + SectionOffset);453if (Error E = Binary::checkOffset(Data, SectionStart, SizeOfSection)) {454SmallString<32> UnknownType;455Twine(("<Unknown:") + Twine::utohexstr(SectType) + ">")456.toVector(UnknownType);457const char *SectionName = UnknownType.c_str();458459switch (SectType) {460#define ECASE(Value, String) \461case XCOFF::Value: \462SectionName = String; \463break464465ECASE(STYP_PAD, "pad");466ECASE(STYP_DWARF, "dwarf");467ECASE(STYP_TEXT, "text");468ECASE(STYP_DATA, "data");469ECASE(STYP_BSS, "bss");470ECASE(STYP_EXCEPT, "expect");471ECASE(STYP_INFO, "info");472ECASE(STYP_TDATA, "tdata");473ECASE(STYP_TBSS, "tbss");474ECASE(STYP_LOADER, "loader");475ECASE(STYP_DEBUG, "debug");476ECASE(STYP_TYPCHK, "typchk");477ECASE(STYP_OVRFLO, "ovrflo");478#undef ECASE479}480return createError(toString(std::move(E)) + ": " + SectionName +481" section with offset 0x" +482Twine::utohexstr(SectionOffset) + " and size 0x" +483Twine::utohexstr(SizeOfSection) +484" goes past the end of the file");485}486return SectionStart;487}488489bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {490return false;491}492493bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {494return getSectionFlags(Sec) & XCOFF::STYP_TEXT;495}496497bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {498uint32_t Flags = getSectionFlags(Sec);499return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);500}501502bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {503uint32_t Flags = getSectionFlags(Sec);504return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);505}506507bool XCOFFObjectFile::isDebugSection(DataRefImpl Sec) const {508uint32_t Flags = getSectionFlags(Sec);509return Flags & (XCOFF::STYP_DEBUG | XCOFF::STYP_DWARF);510}511512bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {513return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0514: toSection32(Sec)->FileOffsetToRawData == 0;515}516517relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {518DataRefImpl Ret;519if (is64Bit()) {520const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec);521auto RelocationsOrErr =522relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr);523if (Error E = RelocationsOrErr.takeError()) {524// TODO: report the error up the stack.525consumeError(std::move(E));526return relocation_iterator(RelocationRef());527}528Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());529} else {530const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);531auto RelocationsOrErr =532relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr);533if (Error E = RelocationsOrErr.takeError()) {534// TODO: report the error up the stack.535consumeError(std::move(E));536return relocation_iterator(RelocationRef());537}538Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());539}540return relocation_iterator(RelocationRef(Ret, this));541}542543relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {544DataRefImpl Ret;545if (is64Bit()) {546const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec);547auto RelocationsOrErr =548relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr);549if (Error E = RelocationsOrErr.takeError()) {550// TODO: report the error up the stack.551consumeError(std::move(E));552return relocation_iterator(RelocationRef());553}554Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());555} else {556const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);557auto RelocationsOrErr =558relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr);559if (Error E = RelocationsOrErr.takeError()) {560// TODO: report the error up the stack.561consumeError(std::move(E));562return relocation_iterator(RelocationRef());563}564Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());565}566return relocation_iterator(RelocationRef(Ret, this));567}568569void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {570if (is64Bit())571Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation64>(Rel.p) + 1);572else573Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1);574}575576uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {577if (is64Bit()) {578const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);579const XCOFFSectionHeader64 *Sec64 = sectionHeaderTable64();580const uint64_t RelocAddress = Reloc->VirtualAddress;581const uint16_t NumberOfSections = getNumberOfSections();582for (uint16_t I = 0; I < NumberOfSections; ++I) {583// Find which section this relocation belongs to, and get the584// relocation offset relative to the start of the section.585if (Sec64->VirtualAddress <= RelocAddress &&586RelocAddress < Sec64->VirtualAddress + Sec64->SectionSize) {587return RelocAddress - Sec64->VirtualAddress;588}589++Sec64;590}591} else {592const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);593const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32();594const uint32_t RelocAddress = Reloc->VirtualAddress;595const uint16_t NumberOfSections = getNumberOfSections();596for (uint16_t I = 0; I < NumberOfSections; ++I) {597// Find which section this relocation belongs to, and get the598// relocation offset relative to the start of the section.599if (Sec32->VirtualAddress <= RelocAddress &&600RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) {601return RelocAddress - Sec32->VirtualAddress;602}603++Sec32;604}605}606return InvalidRelocOffset;607}608609symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {610uint32_t Index;611if (is64Bit()) {612const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);613Index = Reloc->SymbolIndex;614615if (Index >= getNumberOfSymbolTableEntries64())616return symbol_end();617} else {618const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);619Index = Reloc->SymbolIndex;620621if (Index >= getLogicalNumberOfSymbolTableEntries32())622return symbol_end();623}624DataRefImpl SymDRI;625SymDRI.p = getSymbolEntryAddressByIndex(Index);626return symbol_iterator(SymbolRef(SymDRI, this));627}628629uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {630if (is64Bit())631return viewAs<XCOFFRelocation64>(Rel.p)->Type;632return viewAs<XCOFFRelocation32>(Rel.p)->Type;633}634635void XCOFFObjectFile::getRelocationTypeName(636DataRefImpl Rel, SmallVectorImpl<char> &Result) const {637StringRef Res;638if (is64Bit()) {639const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);640Res = XCOFF::getRelocationTypeString(Reloc->Type);641} else {642const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);643Res = XCOFF::getRelocationTypeString(Reloc->Type);644}645Result.append(Res.begin(), Res.end());646}647648Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {649XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);650uint32_t Result = SymbolRef::SF_None;651652if (XCOFFSym.getSectionNumber() == XCOFF::N_ABS)653Result |= SymbolRef::SF_Absolute;654655XCOFF::StorageClass SC = XCOFFSym.getStorageClass();656if (XCOFF::C_EXT == SC || XCOFF::C_WEAKEXT == SC)657Result |= SymbolRef::SF_Global;658659if (XCOFF::C_WEAKEXT == SC)660Result |= SymbolRef::SF_Weak;661662if (XCOFFSym.isCsectSymbol()) {663Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr =664XCOFFSym.getXCOFFCsectAuxRef();665if (CsectAuxEntOrErr) {666if (CsectAuxEntOrErr.get().getSymbolType() == XCOFF::XTY_CM)667Result |= SymbolRef::SF_Common;668} else669return CsectAuxEntOrErr.takeError();670}671672if (XCOFFSym.getSectionNumber() == XCOFF::N_UNDEF)673Result |= SymbolRef::SF_Undefined;674675// There is no visibility in old 32 bit XCOFF object file interpret.676if (is64Bit() || (auxiliaryHeader32() && (auxiliaryHeader32()->getVersion() ==677NEW_XCOFF_INTERPRET))) {678uint16_t SymType = XCOFFSym.getSymbolType();679if ((SymType & VISIBILITY_MASK) == SYM_V_HIDDEN)680Result |= SymbolRef::SF_Hidden;681682if ((SymType & VISIBILITY_MASK) == SYM_V_EXPORTED)683Result |= SymbolRef::SF_Exported;684}685return Result;686}687688basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {689DataRefImpl SymDRI;690SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr);691return basic_symbol_iterator(SymbolRef(SymDRI, this));692}693694basic_symbol_iterator XCOFFObjectFile::symbol_end() const {695DataRefImpl SymDRI;696const uint32_t NumberOfSymbolTableEntries = getNumberOfSymbolTableEntries();697SymDRI.p = getSymbolEntryAddressByIndex(NumberOfSymbolTableEntries);698return basic_symbol_iterator(SymbolRef(SymDRI, this));699}700701XCOFFObjectFile::xcoff_symbol_iterator_range XCOFFObjectFile::symbols() const {702return xcoff_symbol_iterator_range(symbol_begin(), symbol_end());703}704705section_iterator XCOFFObjectFile::section_begin() const {706DataRefImpl DRI;707DRI.p = getSectionHeaderTableAddress();708return section_iterator(SectionRef(DRI, this));709}710711section_iterator XCOFFObjectFile::section_end() const {712DataRefImpl DRI;713DRI.p = getWithOffset(getSectionHeaderTableAddress(),714getNumberOfSections() * getSectionHeaderSize());715return section_iterator(SectionRef(DRI, this));716}717718uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }719720StringRef XCOFFObjectFile::getFileFormatName() const {721return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";722}723724Triple::ArchType XCOFFObjectFile::getArch() const {725return is64Bit() ? Triple::ppc64 : Triple::ppc;726}727728Expected<SubtargetFeatures> XCOFFObjectFile::getFeatures() const {729return SubtargetFeatures();730}731732bool XCOFFObjectFile::isRelocatableObject() const {733if (is64Bit())734return !(fileHeader64()->Flags & NoRelMask);735return !(fileHeader32()->Flags & NoRelMask);736}737738Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {739if (AuxiliaryHeader == nullptr)740return 0;741742return is64Bit() ? auxiliaryHeader64()->getEntryPointAddr()743: auxiliaryHeader32()->getEntryPointAddr();744}745746StringRef XCOFFObjectFile::mapDebugSectionName(StringRef Name) const {747return StringSwitch<StringRef>(Name)748.Case("dwinfo", "debug_info")749.Case("dwline", "debug_line")750.Case("dwpbnms", "debug_pubnames")751.Case("dwpbtyp", "debug_pubtypes")752.Case("dwarnge", "debug_aranges")753.Case("dwabrev", "debug_abbrev")754.Case("dwstr", "debug_str")755.Case("dwrnges", "debug_ranges")756.Case("dwloc", "debug_loc")757.Case("dwframe", "debug_frame")758.Case("dwmac", "debug_macinfo")759.Default(Name);760}761762size_t XCOFFObjectFile::getFileHeaderSize() const {763return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);764}765766size_t XCOFFObjectFile::getSectionHeaderSize() const {767return is64Bit() ? sizeof(XCOFFSectionHeader64) :768sizeof(XCOFFSectionHeader32);769}770771bool XCOFFObjectFile::is64Bit() const {772return Binary::ID_XCOFF64 == getType();773}774775Expected<StringRef> XCOFFObjectFile::getRawData(const char *Start,776uint64_t Size,777StringRef Name) const {778uintptr_t StartPtr = reinterpret_cast<uintptr_t>(Start);779// TODO: this path is untested.780if (Error E = Binary::checkOffset(Data, StartPtr, Size))781return createError(toString(std::move(E)) + ": " + Name.data() +782" data with offset 0x" + Twine::utohexstr(StartPtr) +783" and size 0x" + Twine::utohexstr(Size) +784" goes past the end of the file");785return StringRef(Start, Size);786}787788uint16_t XCOFFObjectFile::getMagic() const {789return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;790}791792Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {793if (Num <= 0 || Num > getNumberOfSections())794return createStringError(object_error::invalid_section_index,795"the section index (" + Twine(Num) +796") is invalid");797798DataRefImpl DRI;799DRI.p = getWithOffset(getSectionHeaderTableAddress(),800getSectionHeaderSize() * (Num - 1));801return DRI;802}803804DataRefImpl805XCOFFObjectFile::getSectionByType(XCOFF::SectionTypeFlags SectType) const {806DataRefImpl DRI;807auto GetSectionAddr = [&](const auto &Sections) -> uintptr_t {808for (const auto &Sec : Sections)809if (Sec.getSectionType() == SectType)810return reinterpret_cast<uintptr_t>(&Sec);811return uintptr_t(0);812};813if (is64Bit())814DRI.p = GetSectionAddr(sections64());815else816DRI.p = GetSectionAddr(sections32());817return DRI;818}819820Expected<StringRef>821XCOFFObjectFile::getSymbolSectionName(XCOFFSymbolRef SymEntPtr) const {822const int16_t SectionNum = SymEntPtr.getSectionNumber();823824switch (SectionNum) {825case XCOFF::N_DEBUG:826return "N_DEBUG";827case XCOFF::N_ABS:828return "N_ABS";829case XCOFF::N_UNDEF:830return "N_UNDEF";831default:832Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum);833if (SecRef)834return generateXCOFFFixedNameStringRef(835getSectionNameInternal(SecRef.get()));836return SecRef.takeError();837}838}839840unsigned XCOFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {841XCOFFSymbolRef XCOFFSymRef(Sym.getRawDataRefImpl(), this);842return XCOFFSymRef.getSectionNumber();843}844845bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {846return (SectionNumber <= 0 && SectionNumber >= -2);847}848849uint16_t XCOFFObjectFile::getNumberOfSections() const {850return is64Bit() ? fileHeader64()->NumberOfSections851: fileHeader32()->NumberOfSections;852}853854int32_t XCOFFObjectFile::getTimeStamp() const {855return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;856}857858uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {859return is64Bit() ? fileHeader64()->AuxHeaderSize860: fileHeader32()->AuxHeaderSize;861}862863uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {864return fileHeader32()->SymbolTableOffset;865}866867int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const {868// As far as symbol table size is concerned, if this field is negative it is869// to be treated as a 0. However since this field is also used for printing we870// don't want to truncate any negative values.871return fileHeader32()->NumberOfSymTableEntries;872}873874uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {875return (fileHeader32()->NumberOfSymTableEntries >= 0876? fileHeader32()->NumberOfSymTableEntries877: 0);878}879880uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {881return fileHeader64()->SymbolTableOffset;882}883884uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {885return fileHeader64()->NumberOfSymTableEntries;886}887888uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const {889return is64Bit() ? getNumberOfSymbolTableEntries64()890: getLogicalNumberOfSymbolTableEntries32();891}892893uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {894const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries();895return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),896XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);897}898899void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const {900if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr))901report_fatal_error("Symbol table entry is outside of symbol table.");902903if (SymbolEntPtr >= getEndOfSymbolTableAddress())904report_fatal_error("Symbol table entry is outside of symbol table.");905906ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) -907reinterpret_cast<const char *>(SymbolTblPtr);908909if (Offset % XCOFF::SymbolTableEntrySize != 0)910report_fatal_error(911"Symbol table entry position is not valid inside of symbol table.");912}913914uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {915return (reinterpret_cast<const char *>(SymbolEntPtr) -916reinterpret_cast<const char *>(SymbolTblPtr)) /917XCOFF::SymbolTableEntrySize;918}919920uint64_t XCOFFObjectFile::getSymbolSize(DataRefImpl Symb) const {921uint64_t Result = 0;922XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);923if (XCOFFSym.isCsectSymbol()) {924Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =925XCOFFSym.getXCOFFCsectAuxRef();926if (!CsectAuxRefOrError)927// TODO: report the error up the stack.928consumeError(CsectAuxRefOrError.takeError());929else {930XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get();931uint8_t SymType = CsectAuxRef.getSymbolType();932if (SymType == XCOFF::XTY_SD || SymType == XCOFF::XTY_CM)933Result = CsectAuxRef.getSectionOrLength();934}935}936return Result;937}938939uintptr_t XCOFFObjectFile::getSymbolEntryAddressByIndex(uint32_t Index) const {940return getAdvancedSymbolEntryAddress(941reinterpret_cast<uintptr_t>(getPointerToSymbolTable()), Index);942}943944Expected<StringRef>945XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const {946const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries();947948if (Index >= NumberOfSymTableEntries)949return createError("symbol index " + Twine(Index) +950" exceeds symbol count " +951Twine(NumberOfSymTableEntries));952953DataRefImpl SymDRI;954SymDRI.p = getSymbolEntryAddressByIndex(Index);955return getSymbolName(SymDRI);956}957958uint16_t XCOFFObjectFile::getFlags() const {959return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;960}961962const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {963return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;964}965966uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {967return reinterpret_cast<uintptr_t>(SectionHeaderTable);968}969970int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {971return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;972}973974XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)975: ObjectFile(Type, Object) {976assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64);977}978979ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {980assert(is64Bit() && "64-bit interface called for non 64-bit file.");981const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();982return ArrayRef<XCOFFSectionHeader64>(TablePtr,983TablePtr + getNumberOfSections());984}985986ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {987assert(!is64Bit() && "32-bit interface called for non 32-bit file.");988const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32();989return ArrayRef<XCOFFSectionHeader32>(TablePtr,990TablePtr + getNumberOfSections());991}992993// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO994// section header contains the actual count of relocation entries in the s_paddr995// field. STYP_OVRFLO headers contain the section index of their corresponding996// sections as their raw "NumberOfRelocations" field value.997template <typename T>998Expected<uint32_t> XCOFFObjectFile::getNumberOfRelocationEntries(999const XCOFFSectionHeader<T> &Sec) const {1000const T &Section = static_cast<const T &>(Sec);1001if (is64Bit())1002return Section.NumberOfRelocations;10031004uint16_t SectionIndex = &Section - sectionHeaderTable<T>() + 1;1005if (Section.NumberOfRelocations < XCOFF::RelocOverflow)1006return Section.NumberOfRelocations;1007for (const auto &Sec : sections32()) {1008if (Sec.Flags == XCOFF::STYP_OVRFLO &&1009Sec.NumberOfRelocations == SectionIndex)1010return Sec.PhysicalAddress;1011}1012return errorCodeToError(object_error::parse_failed);1013}10141015template <typename Shdr, typename Reloc>1016Expected<ArrayRef<Reloc>> XCOFFObjectFile::relocations(const Shdr &Sec) const {1017uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),1018Sec.FileOffsetToRelocationInfo);1019auto NumRelocEntriesOrErr = getNumberOfRelocationEntries(Sec);1020if (Error E = NumRelocEntriesOrErr.takeError())1021return std::move(E);10221023uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();1024static_assert((sizeof(Reloc) == XCOFF::RelocationSerializationSize64 ||1025sizeof(Reloc) == XCOFF::RelocationSerializationSize32),1026"Relocation structure is incorrect");1027auto RelocationOrErr =1028getObject<Reloc>(Data, reinterpret_cast<void *>(RelocAddr),1029NumRelocEntries * sizeof(Reloc));1030if (!RelocationOrErr)1031return createError(1032toString(RelocationOrErr.takeError()) + ": relocations with offset 0x" +1033Twine::utohexstr(Sec.FileOffsetToRelocationInfo) + " and size 0x" +1034Twine::utohexstr(NumRelocEntries * sizeof(Reloc)) +1035" go past the end of the file");10361037const Reloc *StartReloc = RelocationOrErr.get();10381039return ArrayRef<Reloc>(StartReloc, StartReloc + NumRelocEntries);1040}10411042template <typename ExceptEnt>1043Expected<ArrayRef<ExceptEnt>> XCOFFObjectFile::getExceptionEntries() const {1044assert((is64Bit() && sizeof(ExceptEnt) == sizeof(ExceptionSectionEntry64)) ||1045(!is64Bit() && sizeof(ExceptEnt) == sizeof(ExceptionSectionEntry32)));10461047Expected<uintptr_t> ExceptionSectOrErr =1048getSectionFileOffsetToRawData(XCOFF::STYP_EXCEPT);1049if (!ExceptionSectOrErr)1050return ExceptionSectOrErr.takeError();10511052DataRefImpl DRI = getSectionByType(XCOFF::STYP_EXCEPT);1053if (DRI.p == 0)1054return ArrayRef<ExceptEnt>();10551056ExceptEnt *ExceptEntStart =1057reinterpret_cast<ExceptEnt *>(*ExceptionSectOrErr);1058return ArrayRef<ExceptEnt>(1059ExceptEntStart, ExceptEntStart + getSectionSize(DRI) / sizeof(ExceptEnt));1060}10611062template Expected<ArrayRef<ExceptionSectionEntry32>>1063XCOFFObjectFile::getExceptionEntries() const;1064template Expected<ArrayRef<ExceptionSectionEntry64>>1065XCOFFObjectFile::getExceptionEntries() const;10661067Expected<XCOFFStringTable>1068XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {1069// If there is a string table, then the buffer must contain at least 4 bytes1070// for the string table's size. Not having a string table is not an error.1071if (Error E = Binary::checkOffset(1072Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) {1073consumeError(std::move(E));1074return XCOFFStringTable{0, nullptr};1075}10761077// Read the size out of the buffer.1078uint32_t Size = support::endian::read32be(Obj->base() + Offset);10791080// If the size is less then 4, then the string table is just a size and no1081// string data.1082if (Size <= 4)1083return XCOFFStringTable{4, nullptr};10841085auto StringTableOrErr =1086getObject<char>(Obj->Data, Obj->base() + Offset, Size);1087if (!StringTableOrErr)1088return createError(toString(StringTableOrErr.takeError()) +1089": string table with offset 0x" +1090Twine::utohexstr(Offset) + " and size 0x" +1091Twine::utohexstr(Size) +1092" goes past the end of the file");10931094const char *StringTablePtr = StringTableOrErr.get();1095if (StringTablePtr[Size - 1] != '\0')1096return errorCodeToError(object_error::string_table_non_null_end);10971098return XCOFFStringTable{Size, StringTablePtr};1099}11001101// This function returns the import file table. Each entry in the import file1102// table consists of: "path_name\0base_name\0archive_member_name\0".1103Expected<StringRef> XCOFFObjectFile::getImportFileTable() const {1104Expected<uintptr_t> LoaderSectionAddrOrError =1105getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);1106if (!LoaderSectionAddrOrError)1107return LoaderSectionAddrOrError.takeError();11081109uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();1110if (!LoaderSectionAddr)1111return StringRef();11121113uint64_t OffsetToImportFileTable = 0;1114uint64_t LengthOfImportFileTable = 0;1115if (is64Bit()) {1116const LoaderSectionHeader64 *LoaderSec64 =1117viewAs<LoaderSectionHeader64>(LoaderSectionAddr);1118OffsetToImportFileTable = LoaderSec64->OffsetToImpid;1119LengthOfImportFileTable = LoaderSec64->LengthOfImpidStrTbl;1120} else {1121const LoaderSectionHeader32 *LoaderSec32 =1122viewAs<LoaderSectionHeader32>(LoaderSectionAddr);1123OffsetToImportFileTable = LoaderSec32->OffsetToImpid;1124LengthOfImportFileTable = LoaderSec32->LengthOfImpidStrTbl;1125}11261127auto ImportTableOrErr = getObject<char>(1128Data,1129reinterpret_cast<void *>(LoaderSectionAddr + OffsetToImportFileTable),1130LengthOfImportFileTable);1131if (!ImportTableOrErr)1132return createError(1133toString(ImportTableOrErr.takeError()) +1134": import file table with offset 0x" +1135Twine::utohexstr(LoaderSectionAddr + OffsetToImportFileTable) +1136" and size 0x" + Twine::utohexstr(LengthOfImportFileTable) +1137" goes past the end of the file");11381139const char *ImportTablePtr = ImportTableOrErr.get();1140if (ImportTablePtr[LengthOfImportFileTable - 1] != '\0')1141return createError(1142": import file name table with offset 0x" +1143Twine::utohexstr(LoaderSectionAddr + OffsetToImportFileTable) +1144" and size 0x" + Twine::utohexstr(LengthOfImportFileTable) +1145" must end with a null terminator");11461147return StringRef(ImportTablePtr, LengthOfImportFileTable);1148}11491150Expected<std::unique_ptr<XCOFFObjectFile>>1151XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {1152// Can't use std::make_unique because of the private constructor.1153std::unique_ptr<XCOFFObjectFile> Obj;1154Obj.reset(new XCOFFObjectFile(Type, MBR));11551156uint64_t CurOffset = 0;1157const auto *Base = Obj->base();1158MemoryBufferRef Data = Obj->Data;11591160// Parse file header.1161auto FileHeaderOrErr =1162getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize());1163if (Error E = FileHeaderOrErr.takeError())1164return std::move(E);1165Obj->FileHeader = FileHeaderOrErr.get();11661167CurOffset += Obj->getFileHeaderSize();11681169if (Obj->getOptionalHeaderSize()) {1170auto AuxiliaryHeaderOrErr =1171getObject<void>(Data, Base + CurOffset, Obj->getOptionalHeaderSize());1172if (Error E = AuxiliaryHeaderOrErr.takeError())1173return std::move(E);1174Obj->AuxiliaryHeader = AuxiliaryHeaderOrErr.get();1175}11761177CurOffset += Obj->getOptionalHeaderSize();11781179// Parse the section header table if it is present.1180if (Obj->getNumberOfSections()) {1181uint64_t SectionHeadersSize =1182Obj->getNumberOfSections() * Obj->getSectionHeaderSize();1183auto SecHeadersOrErr =1184getObject<void>(Data, Base + CurOffset, SectionHeadersSize);1185if (!SecHeadersOrErr)1186return createError(toString(SecHeadersOrErr.takeError()) +1187": section headers with offset 0x" +1188Twine::utohexstr(CurOffset) + " and size 0x" +1189Twine::utohexstr(SectionHeadersSize) +1190" go past the end of the file");11911192Obj->SectionHeaderTable = SecHeadersOrErr.get();1193}11941195const uint32_t NumberOfSymbolTableEntries =1196Obj->getNumberOfSymbolTableEntries();11971198// If there is no symbol table we are done parsing the memory buffer.1199if (NumberOfSymbolTableEntries == 0)1200return std::move(Obj);12011202// Parse symbol table.1203CurOffset = Obj->is64Bit() ? Obj->getSymbolTableOffset64()1204: Obj->getSymbolTableOffset32();1205const uint64_t SymbolTableSize =1206static_cast<uint64_t>(XCOFF::SymbolTableEntrySize) *1207NumberOfSymbolTableEntries;1208auto SymTableOrErr =1209getObject<void *>(Data, Base + CurOffset, SymbolTableSize);1210if (!SymTableOrErr)1211return createError(1212toString(SymTableOrErr.takeError()) + ": symbol table with offset 0x" +1213Twine::utohexstr(CurOffset) + " and size 0x" +1214Twine::utohexstr(SymbolTableSize) + " goes past the end of the file");12151216Obj->SymbolTblPtr = SymTableOrErr.get();1217CurOffset += SymbolTableSize;12181219// Parse String table.1220Expected<XCOFFStringTable> StringTableOrErr =1221parseStringTable(Obj.get(), CurOffset);1222if (Error E = StringTableOrErr.takeError())1223return std::move(E);1224Obj->StringTable = StringTableOrErr.get();12251226return std::move(Obj);1227}12281229Expected<std::unique_ptr<ObjectFile>>1230ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,1231unsigned FileType) {1232return XCOFFObjectFile::create(FileType, MemBufRef);1233}12341235std::optional<StringRef> XCOFFObjectFile::tryGetCPUName() const {1236return StringRef("future");1237}12381239Expected<bool> XCOFFSymbolRef::isFunction() const {1240if (!isCsectSymbol())1241return false;12421243if (getSymbolType() & FunctionSym)1244return true;12451246Expected<XCOFFCsectAuxRef> ExpCsectAuxEnt = getXCOFFCsectAuxRef();1247if (!ExpCsectAuxEnt)1248return ExpCsectAuxEnt.takeError();12491250const XCOFFCsectAuxRef CsectAuxRef = ExpCsectAuxEnt.get();12511252if (CsectAuxRef.getStorageMappingClass() != XCOFF::XMC_PR &&1253CsectAuxRef.getStorageMappingClass() != XCOFF::XMC_GL)1254return false;12551256// A function definition should not be a common type symbol or an external1257// symbol.1258if (CsectAuxRef.getSymbolType() == XCOFF::XTY_CM ||1259CsectAuxRef.getSymbolType() == XCOFF::XTY_ER)1260return false;12611262// If the next symbol is an XTY_LD type symbol with the same address, this1263// XTY_SD symbol is not a function. Otherwise this is a function symbol for1264// -ffunction-sections.1265if (CsectAuxRef.getSymbolType() == XCOFF::XTY_SD) {1266// If this is a csect with size 0, it won't be a function definition.1267// This is used to work around the fact that LLVM always generates below1268// symbol for -ffunction-sections:1269// m 0x00000000 .text 1 unamex **No Symbol**1270// a4 0x00000000 0 0 SD PR 0 01271// FIXME: remove or replace this meaningless symbol.1272if (getSize() == 0)1273return false;12741275xcoff_symbol_iterator NextIt(this);1276// If this is the last main symbol table entry, there won't be an XTY_LD1277// type symbol below.1278if (++NextIt == getObject()->symbol_end())1279return true;12801281if (cantFail(getAddress()) != cantFail(NextIt->getAddress()))1282return true;12831284// Check next symbol is XTY_LD. If so, this symbol is not a function.1285Expected<XCOFFCsectAuxRef> NextCsectAuxEnt = NextIt->getXCOFFCsectAuxRef();1286if (!NextCsectAuxEnt)1287return NextCsectAuxEnt.takeError();12881289if (NextCsectAuxEnt.get().getSymbolType() == XCOFF::XTY_LD)1290return false;12911292return true;1293}12941295if (CsectAuxRef.getSymbolType() == XCOFF::XTY_LD)1296return true;12971298return createError(1299"symbol csect aux entry with index " +1300Twine(getObject()->getSymbolIndex(CsectAuxRef.getEntryAddress())) +1301" has invalid symbol type " +1302Twine::utohexstr(CsectAuxRef.getSymbolType()));1303}13041305bool XCOFFSymbolRef::isCsectSymbol() const {1306XCOFF::StorageClass SC = getStorageClass();1307return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT ||1308SC == XCOFF::C_HIDEXT);1309}13101311Expected<XCOFFCsectAuxRef> XCOFFSymbolRef::getXCOFFCsectAuxRef() const {1312assert(isCsectSymbol() &&1313"Calling csect symbol interface with a non-csect symbol.");13141315uint8_t NumberOfAuxEntries = getNumberOfAuxEntries();13161317Expected<StringRef> NameOrErr = getName();1318if (auto Err = NameOrErr.takeError())1319return std::move(Err);13201321uint32_t SymbolIdx = getObject()->getSymbolIndex(getEntryAddress());1322if (!NumberOfAuxEntries) {1323return createError("csect symbol \"" + *NameOrErr + "\" with index " +1324Twine(SymbolIdx) + " contains no auxiliary entry");1325}13261327if (!getObject()->is64Bit()) {1328// In XCOFF32, the csect auxilliary entry is always the last auxiliary1329// entry for the symbol.1330uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress(1331getEntryAddress(), NumberOfAuxEntries);1332return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt32>(AuxAddr));1333}13341335// XCOFF64 uses SymbolAuxType to identify the auxiliary entry type.1336// We need to iterate through all the auxiliary entries to find it.1337for (uint8_t Index = NumberOfAuxEntries; Index > 0; --Index) {1338uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress(1339getEntryAddress(), Index);1340if (*getObject()->getSymbolAuxType(AuxAddr) ==1341XCOFF::SymbolAuxType::AUX_CSECT) {1342#ifndef NDEBUG1343getObject()->checkSymbolEntryPointer(AuxAddr);1344#endif1345return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt64>(AuxAddr));1346}1347}13481349return createError(1350"a csect auxiliary entry has not been found for symbol \"" + *NameOrErr +1351"\" with index " + Twine(SymbolIdx));1352}13531354Expected<StringRef> XCOFFSymbolRef::getName() const {1355// A storage class value with the high-order bit on indicates that the name is1356// a symbolic debugger stabstring.1357if (getStorageClass() & 0x80)1358return StringRef("Unimplemented Debug Name");13591360if (!getObject()->is64Bit()) {1361if (getSymbol32()->NameInStrTbl.Magic !=1362XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)1363return generateXCOFFFixedNameStringRef(getSymbol32()->SymbolName);13641365return getObject()->getStringTableEntry(getSymbol32()->NameInStrTbl.Offset);1366}13671368return getObject()->getStringTableEntry(getSymbol64()->Offset);1369}13701371// Explicitly instantiate template classes.1372template struct XCOFFSectionHeader<XCOFFSectionHeader32>;1373template struct XCOFFSectionHeader<XCOFFSectionHeader64>;13741375template struct XCOFFRelocation<llvm::support::ubig32_t>;1376template struct XCOFFRelocation<llvm::support::ubig64_t>;13771378template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation64>>1379llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader64,1380llvm::object::XCOFFRelocation64>(1381llvm::object::XCOFFSectionHeader64 const &) const;1382template llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation32>>1383llvm::object::XCOFFObjectFile::relocations<llvm::object::XCOFFSectionHeader32,1384llvm::object::XCOFFRelocation32>(1385llvm::object::XCOFFSectionHeader32 const &) const;13861387bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) {1388if (Bytes.size() < 4)1389return false;13901391return support::endian::read32be(Bytes.data()) == 0;1392}13931394#define GETVALUEWITHMASK(X) (Data & (TracebackTable::X))1395#define GETVALUEWITHMASKSHIFT(X, S) \1396((Data & (TracebackTable::X)) >> (TracebackTable::S))13971398Expected<TBVectorExt> TBVectorExt::create(StringRef TBvectorStrRef) {1399Error Err = Error::success();1400TBVectorExt TBTVecExt(TBvectorStrRef, Err);1401if (Err)1402return std::move(Err);1403return TBTVecExt;1404}14051406TBVectorExt::TBVectorExt(StringRef TBvectorStrRef, Error &Err) {1407const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(TBvectorStrRef.data());1408Data = support::endian::read16be(Ptr);1409uint32_t VecParmsTypeValue = support::endian::read32be(Ptr + 2);1410unsigned ParmsNum =1411GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask, NumberOfVectorParmsShift);14121413ErrorAsOutParameter EAO(&Err);1414Expected<SmallString<32>> VecParmsTypeOrError =1415parseVectorParmsType(VecParmsTypeValue, ParmsNum);1416if (!VecParmsTypeOrError)1417Err = VecParmsTypeOrError.takeError();1418else1419VecParmsInfo = VecParmsTypeOrError.get();1420}14211422uint8_t TBVectorExt::getNumberOfVRSaved() const {1423return GETVALUEWITHMASKSHIFT(NumberOfVRSavedMask, NumberOfVRSavedShift);1424}14251426bool TBVectorExt::isVRSavedOnStack() const {1427return GETVALUEWITHMASK(IsVRSavedOnStackMask);1428}14291430bool TBVectorExt::hasVarArgs() const {1431return GETVALUEWITHMASK(HasVarArgsMask);1432}14331434uint8_t TBVectorExt::getNumberOfVectorParms() const {1435return GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask,1436NumberOfVectorParmsShift);1437}14381439bool TBVectorExt::hasVMXInstruction() const {1440return GETVALUEWITHMASK(HasVMXInstructionMask);1441}1442#undef GETVALUEWITHMASK1443#undef GETVALUEWITHMASKSHIFT14441445Expected<XCOFFTracebackTable>1446XCOFFTracebackTable::create(const uint8_t *Ptr, uint64_t &Size, bool Is64Bit) {1447Error Err = Error::success();1448XCOFFTracebackTable TBT(Ptr, Size, Err, Is64Bit);1449if (Err)1450return std::move(Err);1451return TBT;1452}14531454XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size,1455Error &Err, bool Is64Bit)1456: TBPtr(Ptr), Is64BitObj(Is64Bit) {1457ErrorAsOutParameter EAO(&Err);1458DataExtractor DE(ArrayRef<uint8_t>(Ptr, Size), /*IsLittleEndian=*/false,1459/*AddressSize=*/0);1460DataExtractor::Cursor Cur(/*Offset=*/0);14611462// Skip 8 bytes of mandatory fields.1463DE.getU64(Cur);14641465unsigned FixedParmsNum = getNumberOfFixedParms();1466unsigned FloatingParmsNum = getNumberOfFPParms();1467uint32_t ParamsTypeValue = 0;14681469// Begin to parse optional fields.1470if (Cur && (FixedParmsNum + FloatingParmsNum) > 0)1471ParamsTypeValue = DE.getU32(Cur);14721473if (Cur && hasTraceBackTableOffset())1474TraceBackTableOffset = DE.getU32(Cur);14751476if (Cur && isInterruptHandler())1477HandlerMask = DE.getU32(Cur);14781479if (Cur && hasControlledStorage()) {1480NumOfCtlAnchors = DE.getU32(Cur);1481if (Cur && NumOfCtlAnchors) {1482SmallVector<uint32_t, 8> Disp;1483Disp.reserve(*NumOfCtlAnchors);1484for (uint32_t I = 0; I < NumOfCtlAnchors && Cur; ++I)1485Disp.push_back(DE.getU32(Cur));1486if (Cur)1487ControlledStorageInfoDisp = std::move(Disp);1488}1489}14901491if (Cur && isFuncNamePresent()) {1492uint16_t FunctionNameLen = DE.getU16(Cur);1493if (Cur)1494FunctionName = DE.getBytes(Cur, FunctionNameLen);1495}14961497if (Cur && isAllocaUsed())1498AllocaRegister = DE.getU8(Cur);14991500unsigned VectorParmsNum = 0;1501if (Cur && hasVectorInfo()) {1502StringRef VectorExtRef = DE.getBytes(Cur, 6);1503if (Cur) {1504Expected<TBVectorExt> TBVecExtOrErr = TBVectorExt::create(VectorExtRef);1505if (!TBVecExtOrErr) {1506Err = TBVecExtOrErr.takeError();1507return;1508}1509VecExt = TBVecExtOrErr.get();1510VectorParmsNum = VecExt->getNumberOfVectorParms();1511// Skip two bytes of padding after vector info.1512DE.skip(Cur, 2);1513}1514}15151516// As long as there is no fixed-point or floating-point parameter, this1517// field remains not present even when hasVectorInfo gives true and1518// indicates the presence of vector parameters.1519if (Cur && (FixedParmsNum + FloatingParmsNum) > 0) {1520Expected<SmallString<32>> ParmsTypeOrError =1521hasVectorInfo()1522? parseParmsTypeWithVecInfo(ParamsTypeValue, FixedParmsNum,1523FloatingParmsNum, VectorParmsNum)1524: parseParmsType(ParamsTypeValue, FixedParmsNum, FloatingParmsNum);15251526if (!ParmsTypeOrError) {1527Err = ParmsTypeOrError.takeError();1528return;1529}1530ParmsType = ParmsTypeOrError.get();1531}15321533if (Cur && hasExtensionTable()) {1534ExtensionTable = DE.getU8(Cur);15351536if (*ExtensionTable & ExtendedTBTableFlag::TB_EH_INFO) {1537// eh_info displacement must be 4-byte aligned.1538Cur.seek(alignTo(Cur.tell(), 4));1539EhInfoDisp = Is64BitObj ? DE.getU64(Cur) : DE.getU32(Cur);1540}1541}1542if (!Cur)1543Err = Cur.takeError();15441545Size = Cur.tell();1546}15471548#define GETBITWITHMASK(P, X) \1549(support::endian::read32be(TBPtr + (P)) & (TracebackTable::X))1550#define GETBITWITHMASKSHIFT(P, X, S) \1551((support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) >> \1552(TracebackTable::S))15531554uint8_t XCOFFTracebackTable::getVersion() const {1555return GETBITWITHMASKSHIFT(0, VersionMask, VersionShift);1556}15571558uint8_t XCOFFTracebackTable::getLanguageID() const {1559return GETBITWITHMASKSHIFT(0, LanguageIdMask, LanguageIdShift);1560}15611562bool XCOFFTracebackTable::isGlobalLinkage() const {1563return GETBITWITHMASK(0, IsGlobaLinkageMask);1564}15651566bool XCOFFTracebackTable::isOutOfLineEpilogOrPrologue() const {1567return GETBITWITHMASK(0, IsOutOfLineEpilogOrPrologueMask);1568}15691570bool XCOFFTracebackTable::hasTraceBackTableOffset() const {1571return GETBITWITHMASK(0, HasTraceBackTableOffsetMask);1572}15731574bool XCOFFTracebackTable::isInternalProcedure() const {1575return GETBITWITHMASK(0, IsInternalProcedureMask);1576}15771578bool XCOFFTracebackTable::hasControlledStorage() const {1579return GETBITWITHMASK(0, HasControlledStorageMask);1580}15811582bool XCOFFTracebackTable::isTOCless() const {1583return GETBITWITHMASK(0, IsTOClessMask);1584}15851586bool XCOFFTracebackTable::isFloatingPointPresent() const {1587return GETBITWITHMASK(0, IsFloatingPointPresentMask);1588}15891590bool XCOFFTracebackTable::isFloatingPointOperationLogOrAbortEnabled() const {1591return GETBITWITHMASK(0, IsFloatingPointOperationLogOrAbortEnabledMask);1592}15931594bool XCOFFTracebackTable::isInterruptHandler() const {1595return GETBITWITHMASK(0, IsInterruptHandlerMask);1596}15971598bool XCOFFTracebackTable::isFuncNamePresent() const {1599return GETBITWITHMASK(0, IsFunctionNamePresentMask);1600}16011602bool XCOFFTracebackTable::isAllocaUsed() const {1603return GETBITWITHMASK(0, IsAllocaUsedMask);1604}16051606uint8_t XCOFFTracebackTable::getOnConditionDirective() const {1607return GETBITWITHMASKSHIFT(0, OnConditionDirectiveMask,1608OnConditionDirectiveShift);1609}16101611bool XCOFFTracebackTable::isCRSaved() const {1612return GETBITWITHMASK(0, IsCRSavedMask);1613}16141615bool XCOFFTracebackTable::isLRSaved() const {1616return GETBITWITHMASK(0, IsLRSavedMask);1617}16181619bool XCOFFTracebackTable::isBackChainStored() const {1620return GETBITWITHMASK(4, IsBackChainStoredMask);1621}16221623bool XCOFFTracebackTable::isFixup() const {1624return GETBITWITHMASK(4, IsFixupMask);1625}16261627uint8_t XCOFFTracebackTable::getNumOfFPRsSaved() const {1628return GETBITWITHMASKSHIFT(4, FPRSavedMask, FPRSavedShift);1629}16301631bool XCOFFTracebackTable::hasExtensionTable() const {1632return GETBITWITHMASK(4, HasExtensionTableMask);1633}16341635bool XCOFFTracebackTable::hasVectorInfo() const {1636return GETBITWITHMASK(4, HasVectorInfoMask);1637}16381639uint8_t XCOFFTracebackTable::getNumOfGPRsSaved() const {1640return GETBITWITHMASKSHIFT(4, GPRSavedMask, GPRSavedShift);1641}16421643uint8_t XCOFFTracebackTable::getNumberOfFixedParms() const {1644return GETBITWITHMASKSHIFT(4, NumberOfFixedParmsMask,1645NumberOfFixedParmsShift);1646}16471648uint8_t XCOFFTracebackTable::getNumberOfFPParms() const {1649return GETBITWITHMASKSHIFT(4, NumberOfFloatingPointParmsMask,1650NumberOfFloatingPointParmsShift);1651}16521653bool XCOFFTracebackTable::hasParmsOnStack() const {1654return GETBITWITHMASK(4, HasParmsOnStackMask);1655}16561657#undef GETBITWITHMASK1658#undef GETBITWITHMASKSHIFT1659} // namespace object1660} // namespace llvm166116621663