1669 lines · cpp
1//===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file defines the XCOFFObjectFile class.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/Object/XCOFFObjectFile.h"14#include "llvm/ADT/StringSwitch.h"15#include "llvm/Support/Compiler.h"16#include "llvm/Support/DataExtractor.h"17#include "llvm/TargetParser/SubtargetFeature.h"18#include <cstddef>19#include <cstring>20 21namespace llvm {22 23using namespace XCOFF;24 25namespace object {26 27static const uint8_t FunctionSym = 0x20;28static const uint16_t NoRelMask = 0x0001;29static const size_t SymbolAuxTypeOffset = 17;30 31// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer32// 'M'. Returns a pointer to the underlying object on success.33template <typename T>34static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr,35 const uint64_t Size = sizeof(T)) {36 uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);37 if (Error E = Binary::checkOffset(M, Addr, Size))38 return std::move(E);39 return reinterpret_cast<const T *>(Addr);40}41 42static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {43 return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +44 Offset);45}46 47template <typename T> static const T *viewAs(uintptr_t in) {48 return reinterpret_cast<const T *>(in);49}50 51static StringRef generateXCOFFFixedNameStringRef(const char *Name) {52 auto NulCharPtr =53 static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize));54 return NulCharPtr ? StringRef(Name, NulCharPtr - Name)55 : StringRef(Name, XCOFF::NameSize);56}57 58template <typename T> StringRef XCOFFSectionHeader<T>::getName() const {59 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);60 return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name);61}62 63template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const {64 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);65 return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask;66}67 68template <typename T>69uint32_t XCOFFSectionHeader<T>::getSectionSubtype() const {70 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);71 return DerivedXCOFFSectionHeader.Flags & ~SectionFlagsTypeMask;72}73 74template <typename T>75bool XCOFFSectionHeader<T>::isReservedSectionType() const {76 return getSectionType() & SectionFlagsReservedMask;77}78 79template <typename AddressType>80bool XCOFFRelocation<AddressType>::isRelocationSigned() const {81 return Info & XR_SIGN_INDICATOR_MASK;82}83 84template <typename AddressType>85bool XCOFFRelocation<AddressType>::isFixupIndicated() const {86 return Info & XR_FIXUP_INDICATOR_MASK;87}88 89template <typename AddressType>90uint8_t XCOFFRelocation<AddressType>::getRelocatedLength() const {91 // The relocation encodes the bit length being relocated minus 1. Add back92 // the 1 to get the actual length being relocated.93 return (Info & XR_BIASED_LENGTH_MASK) + 1;94}95 96template struct LLVM_EXPORT_TEMPLATE ExceptionSectionEntry<support::ubig32_t>;97template struct LLVM_EXPORT_TEMPLATE ExceptionSectionEntry<support::ubig64_t>;98 99template <typename T>100Expected<StringRef> getLoaderSecSymNameInStrTbl(const T *LoaderSecHeader,101 uint64_t Offset) {102 if (LoaderSecHeader->LengthOfStrTbl > Offset)103 return (reinterpret_cast<const char *>(LoaderSecHeader) +104 LoaderSecHeader->OffsetToStrTbl + Offset);105 106 return createError("entry with offset 0x" + Twine::utohexstr(Offset) +107 " in the loader section's string table with size 0x" +108 Twine::utohexstr(LoaderSecHeader->LengthOfStrTbl) +109 " is invalid");110}111 112Expected<StringRef> LoaderSectionSymbolEntry32::getSymbolName(113 const LoaderSectionHeader32 *LoaderSecHeader32) const {114 const NameOffsetInStrTbl *NameInStrTbl =115 reinterpret_cast<const NameOffsetInStrTbl *>(SymbolName);116 if (NameInStrTbl->IsNameInStrTbl != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)117 return generateXCOFFFixedNameStringRef(SymbolName);118 119 return getLoaderSecSymNameInStrTbl(LoaderSecHeader32, NameInStrTbl->Offset);120}121 122Expected<StringRef> LoaderSectionSymbolEntry64::getSymbolName(123 const LoaderSectionHeader64 *LoaderSecHeader64) const {124 return getLoaderSecSymNameInStrTbl(LoaderSecHeader64, Offset);125}126 127uintptr_t128XCOFFObjectFile::getAdvancedSymbolEntryAddress(uintptr_t CurrentAddress,129 uint32_t Distance) {130 return getWithOffset(CurrentAddress, Distance * XCOFF::SymbolTableEntrySize);131}132 133const XCOFF::SymbolAuxType *134XCOFFObjectFile::getSymbolAuxType(uintptr_t AuxEntryAddress) const {135 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");136 return viewAs<XCOFF::SymbolAuxType>(137 getWithOffset(AuxEntryAddress, SymbolAuxTypeOffset));138}139 140void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,141 uintptr_t TableAddress) const {142 if (Addr < TableAddress)143 report_fatal_error("Section header outside of section header table.");144 145 uintptr_t Offset = Addr - TableAddress;146 if (Offset >= getSectionHeaderSize() * getNumberOfSections())147 report_fatal_error("Section header outside of section header table.");148 149 if (Offset % getSectionHeaderSize() != 0)150 report_fatal_error(151 "Section header pointer does not point to a valid section header.");152}153 154const XCOFFSectionHeader32 *155XCOFFObjectFile::toSection32(DataRefImpl Ref) const {156 assert(!is64Bit() && "32-bit interface called on 64-bit object file.");157#ifndef NDEBUG158 checkSectionAddress(Ref.p, getSectionHeaderTableAddress());159#endif160 return viewAs<XCOFFSectionHeader32>(Ref.p);161}162 163const XCOFFSectionHeader64 *164XCOFFObjectFile::toSection64(DataRefImpl Ref) const {165 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");166#ifndef NDEBUG167 checkSectionAddress(Ref.p, getSectionHeaderTableAddress());168#endif169 return viewAs<XCOFFSectionHeader64>(Ref.p);170}171 172XCOFFSymbolRef XCOFFObjectFile::toSymbolRef(DataRefImpl Ref) const {173 assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!");174#ifndef NDEBUG175 checkSymbolEntryPointer(Ref.p);176#endif177 return XCOFFSymbolRef(Ref, this);178}179 180const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const {181 assert(!is64Bit() && "32-bit interface called on 64-bit object file.");182 return static_cast<const XCOFFFileHeader32 *>(FileHeader);183}184 185const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {186 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");187 return static_cast<const XCOFFFileHeader64 *>(FileHeader);188}189 190const XCOFFAuxiliaryHeader32 *XCOFFObjectFile::auxiliaryHeader32() const {191 assert(!is64Bit() && "32-bit interface called on 64-bit object file.");192 return static_cast<const XCOFFAuxiliaryHeader32 *>(AuxiliaryHeader);193}194 195const XCOFFAuxiliaryHeader64 *XCOFFObjectFile::auxiliaryHeader64() const {196 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");197 return static_cast<const XCOFFAuxiliaryHeader64 *>(AuxiliaryHeader);198}199 200template <typename T> const T *XCOFFObjectFile::sectionHeaderTable() const {201 return static_cast<const T *>(SectionHeaderTable);202}203 204const XCOFFSectionHeader32 *205XCOFFObjectFile::sectionHeaderTable32() const {206 assert(!is64Bit() && "32-bit interface called on 64-bit object file.");207 return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable);208}209 210const XCOFFSectionHeader64 *211XCOFFObjectFile::sectionHeaderTable64() const {212 assert(is64Bit() && "64-bit interface called on a 32-bit object file.");213 return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);214}215 216void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {217 uintptr_t NextSymbolAddr = getAdvancedSymbolEntryAddress(218 Symb.p, toSymbolRef(Symb).getNumberOfAuxEntries() + 1);219#ifndef NDEBUG220 // This function is used by basic_symbol_iterator, which allows to221 // point to the end-of-symbol-table address.222 if (NextSymbolAddr != getEndOfSymbolTableAddress())223 checkSymbolEntryPointer(NextSymbolAddr);224#endif225 Symb.p = NextSymbolAddr;226}227 228Expected<StringRef>229XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const {230 // The byte offset is relative to the start of the string table.231 // A byte offset value of 0 is a null or zero-length symbol232 // name. A byte offset in the range 1 to 3 (inclusive) points into the length233 // field; as a soft-error recovery mechanism, we treat such cases as having an234 // offset of 0.235 if (Offset < 4)236 return StringRef(nullptr, 0);237 238 if (StringTable.Data != nullptr && StringTable.Size > Offset)239 return (StringTable.Data + Offset);240 241 return createError("entry with offset 0x" + Twine::utohexstr(Offset) +242 " in a string table with size 0x" +243 Twine::utohexstr(StringTable.Size) + " is invalid");244}245 246StringRef XCOFFObjectFile::getStringTable() const {247 // If the size is less than or equal to 4, then the string table contains no248 // string data.249 return StringRef(StringTable.Data,250 StringTable.Size <= 4 ? 0 : StringTable.Size);251}252 253Expected<StringRef>254XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const {255 if (CFileEntPtr->NameInStrTbl.Magic != XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)256 return generateXCOFFFixedNameStringRef(CFileEntPtr->Name);257 return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset);258}259 260Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {261 return toSymbolRef(Symb).getName();262}263 264Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {265 return toSymbolRef(Symb).getValue();266}267 268uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {269 return toSymbolRef(Symb).getValue();270}271 272uint32_t XCOFFObjectFile::getSymbolAlignment(DataRefImpl Symb) const {273 uint64_t Result = 0;274 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);275 if (XCOFFSym.isCsectSymbol()) {276 Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =277 XCOFFSym.getXCOFFCsectAuxRef();278 if (!CsectAuxRefOrError)279 // TODO: report the error up the stack.280 consumeError(CsectAuxRefOrError.takeError());281 else282 Result = 1ULL << CsectAuxRefOrError.get().getAlignmentLog2();283 }284 return Result;285}286 287uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {288 uint64_t Result = 0;289 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);290 if (XCOFFSym.isCsectSymbol()) {291 Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =292 XCOFFSym.getXCOFFCsectAuxRef();293 if (!CsectAuxRefOrError)294 // TODO: report the error up the stack.295 consumeError(CsectAuxRefOrError.takeError());296 else {297 XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get();298 assert(CsectAuxRef.getSymbolType() == XCOFF::XTY_CM);299 Result = CsectAuxRef.getSectionOrLength();300 }301 }302 return Result;303}304 305Expected<SymbolRef::Type>306XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {307 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);308 309 Expected<bool> IsFunction = XCOFFSym.isFunction();310 if (!IsFunction)311 return IsFunction.takeError();312 313 if (*IsFunction)314 return SymbolRef::ST_Function;315 316 if (XCOFF::C_FILE == XCOFFSym.getStorageClass())317 return SymbolRef::ST_File;318 319 int16_t SecNum = XCOFFSym.getSectionNumber();320 if (SecNum <= 0)321 return SymbolRef::ST_Other;322 323 Expected<DataRefImpl> SecDRIOrErr =324 getSectionByNum(XCOFFSym.getSectionNumber());325 326 if (!SecDRIOrErr)327 return SecDRIOrErr.takeError();328 329 DataRefImpl SecDRI = SecDRIOrErr.get();330 331 Expected<StringRef> SymNameOrError = XCOFFSym.getName();332 if (SymNameOrError) {333 // The "TOC" symbol is treated as SymbolRef::ST_Other.334 if (SymNameOrError.get() == "TOC")335 return SymbolRef::ST_Other;336 337 // The symbol for a section name is treated as SymbolRef::ST_Other.338 StringRef SecName;339 if (is64Bit())340 SecName = XCOFFObjectFile::toSection64(SecDRIOrErr.get())->getName();341 else342 SecName = XCOFFObjectFile::toSection32(SecDRIOrErr.get())->getName();343 344 if (SecName == SymNameOrError.get())345 return SymbolRef::ST_Other;346 } else347 return SymNameOrError.takeError();348 349 if (isSectionData(SecDRI) || isSectionBSS(SecDRI))350 return SymbolRef::ST_Data;351 352 if (isDebugSection(SecDRI))353 return SymbolRef::ST_Debug;354 355 return SymbolRef::ST_Other;356}357 358Expected<section_iterator>359XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {360 const int16_t SectNum = toSymbolRef(Symb).getSectionNumber();361 362 if (isReservedSectionNumber(SectNum))363 return section_end();364 365 Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum);366 if (!ExpSec)367 return ExpSec.takeError();368 369 return section_iterator(SectionRef(ExpSec.get(), this));370}371 372void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {373 const char *Ptr = reinterpret_cast<const char *>(Sec.p);374 Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());375}376 377Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {378 return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));379}380 381uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {382 // Avoid ternary due to failure to convert the ubig32_t value to a uint64_t383 // with MSVC.384 if (is64Bit())385 return toSection64(Sec)->VirtualAddress;386 387 return toSection32(Sec)->VirtualAddress;388}389 390uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {391 // Section numbers in XCOFF are numbered beginning at 1. A section number of392 // zero is used to indicate that a symbol is being imported or is undefined.393 if (is64Bit())394 return toSection64(Sec) - sectionHeaderTable64() + 1;395 else396 return toSection32(Sec) - sectionHeaderTable32() + 1;397}398 399uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {400 // Avoid ternary due to failure to convert the ubig32_t value to a uint64_t401 // with MSVC.402 if (is64Bit())403 return toSection64(Sec)->SectionSize;404 405 return toSection32(Sec)->SectionSize;406}407 408Expected<ArrayRef<uint8_t>>409XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const {410 if (isSectionVirtual(Sec))411 return ArrayRef<uint8_t>();412 413 uint64_t OffsetToRaw;414 if (is64Bit())415 OffsetToRaw = toSection64(Sec)->FileOffsetToRawData;416 else417 OffsetToRaw = toSection32(Sec)->FileOffsetToRawData;418 419 const uint8_t * ContentStart = base() + OffsetToRaw;420 uint64_t SectionSize = getSectionSize(Sec);421 if (Error E = Binary::checkOffset(422 Data, reinterpret_cast<uintptr_t>(ContentStart), SectionSize))423 return createError(424 toString(std::move(E)) + ": section data with offset 0x" +425 Twine::utohexstr(OffsetToRaw) + " and size 0x" +426 Twine::utohexstr(SectionSize) + " goes past the end of the file");427 428 return ArrayRef(ContentStart, SectionSize);429}430 431uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {432 // TODO: Copied from MC/XCOFFObjectWriter.cpp433 // Sections other than DWARF section use DefaultSectionAlign as the default434 // alignment, while DWARF sections have their own alignments. DWARF section435 // alignment is bigger than DefaultSectionAlign.436 if (isDebugSection(Sec))437 return 8;438 return 4;439}440 441uint64_t XCOFFObjectFile::getSectionFileOffsetToRawData(DataRefImpl Sec) const {442 if (is64Bit())443 return toSection64(Sec)->FileOffsetToRawData;444 445 return toSection32(Sec)->FileOffsetToRawData;446}447 448Expected<uintptr_t> XCOFFObjectFile::getSectionFileOffsetToRawData(449 XCOFF::SectionTypeFlags SectType) const {450 DataRefImpl DRI = getSectionByType(SectType);451 452 if (DRI.p == 0) // No section is not an error.453 return 0;454 455 uint64_t SectionOffset = getSectionFileOffsetToRawData(DRI);456 uint64_t SizeOfSection = getSectionSize(DRI);457 458 uintptr_t SectionStart = reinterpret_cast<uintptr_t>(base() + SectionOffset);459 if (Error E = Binary::checkOffset(Data, SectionStart, SizeOfSection)) {460 SmallString<32> UnknownType;461 Twine(("<Unknown:") + Twine::utohexstr(SectType) + ">")462 .toVector(UnknownType);463 const char *SectionName = UnknownType.c_str();464 465 switch (SectType) {466#define ECASE(Value, String) \467 case XCOFF::Value: \468 SectionName = String; \469 break470 471 ECASE(STYP_PAD, "pad");472 ECASE(STYP_DWARF, "dwarf");473 ECASE(STYP_TEXT, "text");474 ECASE(STYP_DATA, "data");475 ECASE(STYP_BSS, "bss");476 ECASE(STYP_EXCEPT, "expect");477 ECASE(STYP_INFO, "info");478 ECASE(STYP_TDATA, "tdata");479 ECASE(STYP_TBSS, "tbss");480 ECASE(STYP_LOADER, "loader");481 ECASE(STYP_DEBUG, "debug");482 ECASE(STYP_TYPCHK, "typchk");483 ECASE(STYP_OVRFLO, "ovrflo");484#undef ECASE485 }486 return createError(toString(std::move(E)) + ": " + SectionName +487 " section with offset 0x" +488 Twine::utohexstr(SectionOffset) + " and size 0x" +489 Twine::utohexstr(SizeOfSection) +490 " goes past the end of the file");491 }492 return SectionStart;493}494 495bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {496 return false;497}498 499bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {500 return getSectionFlags(Sec) & XCOFF::STYP_TEXT;501}502 503bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {504 uint32_t Flags = getSectionFlags(Sec);505 return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);506}507 508bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {509 uint32_t Flags = getSectionFlags(Sec);510 return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);511}512 513bool XCOFFObjectFile::isDebugSection(DataRefImpl Sec) const {514 uint32_t Flags = getSectionFlags(Sec);515 return Flags & (XCOFF::STYP_DEBUG | XCOFF::STYP_DWARF);516}517 518bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {519 return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0520 : toSection32(Sec)->FileOffsetToRawData == 0;521}522 523relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {524 DataRefImpl Ret;525 if (is64Bit()) {526 const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec);527 auto RelocationsOrErr =528 relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr);529 if (Error E = RelocationsOrErr.takeError()) {530 // TODO: report the error up the stack.531 consumeError(std::move(E));532 return relocation_iterator(RelocationRef());533 }534 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());535 } else {536 const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);537 auto RelocationsOrErr =538 relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr);539 if (Error E = RelocationsOrErr.takeError()) {540 // TODO: report the error up the stack.541 consumeError(std::move(E));542 return relocation_iterator(RelocationRef());543 }544 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());545 }546 return relocation_iterator(RelocationRef(Ret, this));547}548 549relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {550 DataRefImpl Ret;551 if (is64Bit()) {552 const XCOFFSectionHeader64 *SectionEntPtr = toSection64(Sec);553 auto RelocationsOrErr =554 relocations<XCOFFSectionHeader64, XCOFFRelocation64>(*SectionEntPtr);555 if (Error E = RelocationsOrErr.takeError()) {556 // TODO: report the error up the stack.557 consumeError(std::move(E));558 return relocation_iterator(RelocationRef());559 }560 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());561 } else {562 const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);563 auto RelocationsOrErr =564 relocations<XCOFFSectionHeader32, XCOFFRelocation32>(*SectionEntPtr);565 if (Error E = RelocationsOrErr.takeError()) {566 // TODO: report the error up the stack.567 consumeError(std::move(E));568 return relocation_iterator(RelocationRef());569 }570 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());571 }572 return relocation_iterator(RelocationRef(Ret, this));573}574 575void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {576 if (is64Bit())577 Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation64>(Rel.p) + 1);578 else579 Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1);580}581 582uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {583 if (is64Bit()) {584 const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);585 const XCOFFSectionHeader64 *Sec64 = sectionHeaderTable64();586 const uint64_t RelocAddress = Reloc->VirtualAddress;587 const uint16_t NumberOfSections = getNumberOfSections();588 for (uint16_t I = 0; I < NumberOfSections; ++I) {589 // Find which section this relocation belongs to, and get the590 // relocation offset relative to the start of the section.591 if (Sec64->VirtualAddress <= RelocAddress &&592 RelocAddress < Sec64->VirtualAddress + Sec64->SectionSize) {593 return RelocAddress - Sec64->VirtualAddress;594 }595 ++Sec64;596 }597 } else {598 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);599 const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32();600 const uint32_t RelocAddress = Reloc->VirtualAddress;601 const uint16_t NumberOfSections = getNumberOfSections();602 for (uint16_t I = 0; I < NumberOfSections; ++I) {603 // Find which section this relocation belongs to, and get the604 // relocation offset relative to the start of the section.605 if (Sec32->VirtualAddress <= RelocAddress &&606 RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) {607 return RelocAddress - Sec32->VirtualAddress;608 }609 ++Sec32;610 }611 }612 return InvalidRelocOffset;613}614 615symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {616 uint32_t Index;617 if (is64Bit()) {618 const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);619 Index = Reloc->SymbolIndex;620 621 if (Index >= getNumberOfSymbolTableEntries64())622 return symbol_end();623 } else {624 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);625 Index = Reloc->SymbolIndex;626 627 if (Index >= getLogicalNumberOfSymbolTableEntries32())628 return symbol_end();629 }630 DataRefImpl SymDRI;631 SymDRI.p = getSymbolEntryAddressByIndex(Index);632 return symbol_iterator(SymbolRef(SymDRI, this));633}634 635uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {636 if (is64Bit())637 return viewAs<XCOFFRelocation64>(Rel.p)->Type;638 return viewAs<XCOFFRelocation32>(Rel.p)->Type;639}640 641void XCOFFObjectFile::getRelocationTypeName(642 DataRefImpl Rel, SmallVectorImpl<char> &Result) const {643 StringRef Res;644 if (is64Bit()) {645 const XCOFFRelocation64 *Reloc = viewAs<XCOFFRelocation64>(Rel.p);646 Res = XCOFF::getRelocationTypeString(Reloc->Type);647 } else {648 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);649 Res = XCOFF::getRelocationTypeString(Reloc->Type);650 }651 Result.append(Res.begin(), Res.end());652}653 654Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {655 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);656 uint32_t Result = SymbolRef::SF_None;657 658 if (XCOFFSym.getSectionNumber() == XCOFF::N_ABS)659 Result |= SymbolRef::SF_Absolute;660 661 XCOFF::StorageClass SC = XCOFFSym.getStorageClass();662 if (XCOFF::C_EXT == SC || XCOFF::C_WEAKEXT == SC)663 Result |= SymbolRef::SF_Global;664 665 if (XCOFF::C_WEAKEXT == SC)666 Result |= SymbolRef::SF_Weak;667 668 if (XCOFFSym.isCsectSymbol()) {669 Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr =670 XCOFFSym.getXCOFFCsectAuxRef();671 if (CsectAuxEntOrErr) {672 if (CsectAuxEntOrErr.get().getSymbolType() == XCOFF::XTY_CM)673 Result |= SymbolRef::SF_Common;674 } else675 return CsectAuxEntOrErr.takeError();676 }677 678 if (XCOFFSym.getSectionNumber() == XCOFF::N_UNDEF)679 Result |= SymbolRef::SF_Undefined;680 681 // There is no visibility in old 32 bit XCOFF object file interpret.682 if (is64Bit() || (auxiliaryHeader32() && (auxiliaryHeader32()->getVersion() ==683 NEW_XCOFF_INTERPRET))) {684 uint16_t SymType = XCOFFSym.getSymbolType();685 if ((SymType & VISIBILITY_MASK) == SYM_V_HIDDEN)686 Result |= SymbolRef::SF_Hidden;687 688 if ((SymType & VISIBILITY_MASK) == SYM_V_EXPORTED)689 Result |= SymbolRef::SF_Exported;690 }691 return Result;692}693 694basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {695 DataRefImpl SymDRI;696 SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr);697 return basic_symbol_iterator(SymbolRef(SymDRI, this));698}699 700basic_symbol_iterator XCOFFObjectFile::symbol_end() const {701 DataRefImpl SymDRI;702 const uint32_t NumberOfSymbolTableEntries = getNumberOfSymbolTableEntries();703 SymDRI.p = getSymbolEntryAddressByIndex(NumberOfSymbolTableEntries);704 return basic_symbol_iterator(SymbolRef(SymDRI, this));705}706 707XCOFFObjectFile::xcoff_symbol_iterator_range XCOFFObjectFile::symbols() const {708 return xcoff_symbol_iterator_range(symbol_begin(), symbol_end());709}710 711section_iterator XCOFFObjectFile::section_begin() const {712 DataRefImpl DRI;713 DRI.p = getSectionHeaderTableAddress();714 return section_iterator(SectionRef(DRI, this));715}716 717section_iterator XCOFFObjectFile::section_end() const {718 DataRefImpl DRI;719 DRI.p = getWithOffset(getSectionHeaderTableAddress(),720 getNumberOfSections() * getSectionHeaderSize());721 return section_iterator(SectionRef(DRI, this));722}723 724uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }725 726StringRef XCOFFObjectFile::getFileFormatName() const {727 return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";728}729 730Triple::ArchType XCOFFObjectFile::getArch() const {731 return is64Bit() ? Triple::ppc64 : Triple::ppc;732}733 734Expected<SubtargetFeatures> XCOFFObjectFile::getFeatures() const {735 return SubtargetFeatures();736}737 738bool XCOFFObjectFile::isRelocatableObject() const {739 if (is64Bit())740 return !(fileHeader64()->Flags & NoRelMask);741 return !(fileHeader32()->Flags & NoRelMask);742}743 744Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {745 if (AuxiliaryHeader == nullptr)746 return 0;747 748 return is64Bit() ? auxiliaryHeader64()->getEntryPointAddr()749 : auxiliaryHeader32()->getEntryPointAddr();750}751 752StringRef XCOFFObjectFile::mapDebugSectionName(StringRef Name) const {753 return StringSwitch<StringRef>(Name)754 .Case("dwinfo", "debug_info")755 .Case("dwline", "debug_line")756 .Case("dwpbnms", "debug_pubnames")757 .Case("dwpbtyp", "debug_pubtypes")758 .Case("dwarnge", "debug_aranges")759 .Case("dwabrev", "debug_abbrev")760 .Case("dwstr", "debug_str")761 .Case("dwrnges", "debug_ranges")762 .Case("dwloc", "debug_loc")763 .Case("dwframe", "debug_frame")764 .Case("dwmac", "debug_macinfo")765 .Default(Name);766}767 768size_t XCOFFObjectFile::getFileHeaderSize() const {769 return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);770}771 772size_t XCOFFObjectFile::getSectionHeaderSize() const {773 return is64Bit() ? sizeof(XCOFFSectionHeader64) :774 sizeof(XCOFFSectionHeader32);775}776 777bool XCOFFObjectFile::is64Bit() const {778 return Binary::ID_XCOFF64 == getType();779}780 781Expected<StringRef> XCOFFObjectFile::getRawData(const char *Start,782 uint64_t Size,783 StringRef Name) const {784 uintptr_t StartPtr = reinterpret_cast<uintptr_t>(Start);785 // TODO: this path is untested.786 if (Error E = Binary::checkOffset(Data, StartPtr, Size))787 return createError(toString(std::move(E)) + ": " + Name.data() +788 " data with offset 0x" + Twine::utohexstr(StartPtr) +789 " and size 0x" + Twine::utohexstr(Size) +790 " goes past the end of the file");791 return StringRef(Start, Size);792}793 794uint16_t XCOFFObjectFile::getMagic() const {795 return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;796}797 798Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {799 if (Num <= 0 || Num > getNumberOfSections())800 return createStringError(object_error::invalid_section_index,801 "the section index (" + Twine(Num) +802 ") is invalid");803 804 DataRefImpl DRI;805 DRI.p = getWithOffset(getSectionHeaderTableAddress(),806 getSectionHeaderSize() * (Num - 1));807 return DRI;808}809 810DataRefImpl811XCOFFObjectFile::getSectionByType(XCOFF::SectionTypeFlags SectType) const {812 DataRefImpl DRI;813 auto GetSectionAddr = [&](const auto &Sections) -> uintptr_t {814 for (const auto &Sec : Sections)815 if (Sec.getSectionType() == SectType)816 return reinterpret_cast<uintptr_t>(&Sec);817 return uintptr_t(0);818 };819 if (is64Bit())820 DRI.p = GetSectionAddr(sections64());821 else822 DRI.p = GetSectionAddr(sections32());823 return DRI;824}825 826Expected<StringRef>827XCOFFObjectFile::getSymbolSectionName(XCOFFSymbolRef SymEntPtr) const {828 const int16_t SectionNum = SymEntPtr.getSectionNumber();829 830 switch (SectionNum) {831 case XCOFF::N_DEBUG:832 return "N_DEBUG";833 case XCOFF::N_ABS:834 return "N_ABS";835 case XCOFF::N_UNDEF:836 return "N_UNDEF";837 default:838 Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum);839 if (SecRef)840 return generateXCOFFFixedNameStringRef(841 getSectionNameInternal(SecRef.get()));842 return SecRef.takeError();843 }844}845 846unsigned XCOFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {847 XCOFFSymbolRef XCOFFSymRef(Sym.getRawDataRefImpl(), this);848 return XCOFFSymRef.getSectionNumber();849}850 851bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {852 return (SectionNumber <= 0 && SectionNumber >= -2);853}854 855uint16_t XCOFFObjectFile::getNumberOfSections() const {856 return is64Bit() ? fileHeader64()->NumberOfSections857 : fileHeader32()->NumberOfSections;858}859 860int32_t XCOFFObjectFile::getTimeStamp() const {861 return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;862}863 864uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {865 return is64Bit() ? fileHeader64()->AuxHeaderSize866 : fileHeader32()->AuxHeaderSize;867}868 869uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {870 return fileHeader32()->SymbolTableOffset;871}872 873int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const {874 // As far as symbol table size is concerned, if this field is negative it is875 // to be treated as a 0. However since this field is also used for printing we876 // don't want to truncate any negative values.877 return fileHeader32()->NumberOfSymTableEntries;878}879 880uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {881 return (fileHeader32()->NumberOfSymTableEntries >= 0882 ? fileHeader32()->NumberOfSymTableEntries883 : 0);884}885 886uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {887 return fileHeader64()->SymbolTableOffset;888}889 890uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {891 return fileHeader64()->NumberOfSymTableEntries;892}893 894uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries() const {895 return is64Bit() ? getNumberOfSymbolTableEntries64()896 : getLogicalNumberOfSymbolTableEntries32();897}898 899uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {900 const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries();901 return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),902 XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);903}904 905void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const {906 if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr))907 report_fatal_error("Symbol table entry is outside of symbol table.");908 909 if (SymbolEntPtr >= getEndOfSymbolTableAddress())910 report_fatal_error("Symbol table entry is outside of symbol table.");911 912 ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) -913 reinterpret_cast<const char *>(SymbolTblPtr);914 915 if (Offset % XCOFF::SymbolTableEntrySize != 0)916 report_fatal_error(917 "Symbol table entry position is not valid inside of symbol table.");918}919 920uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {921 return (reinterpret_cast<const char *>(SymbolEntPtr) -922 reinterpret_cast<const char *>(SymbolTblPtr)) /923 XCOFF::SymbolTableEntrySize;924}925 926uint64_t XCOFFObjectFile::getSymbolSize(DataRefImpl Symb) const {927 uint64_t Result = 0;928 XCOFFSymbolRef XCOFFSym = toSymbolRef(Symb);929 if (XCOFFSym.isCsectSymbol()) {930 Expected<XCOFFCsectAuxRef> CsectAuxRefOrError =931 XCOFFSym.getXCOFFCsectAuxRef();932 if (!CsectAuxRefOrError)933 // TODO: report the error up the stack.934 consumeError(CsectAuxRefOrError.takeError());935 else {936 XCOFFCsectAuxRef CsectAuxRef = CsectAuxRefOrError.get();937 uint8_t SymType = CsectAuxRef.getSymbolType();938 if (SymType == XCOFF::XTY_SD || SymType == XCOFF::XTY_CM)939 Result = CsectAuxRef.getSectionOrLength();940 }941 }942 return Result;943}944 945uintptr_t XCOFFObjectFile::getSymbolEntryAddressByIndex(uint32_t Index) const {946 return getAdvancedSymbolEntryAddress(947 reinterpret_cast<uintptr_t>(getPointerToSymbolTable()), Index);948}949 950Expected<StringRef>951XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const {952 const uint32_t NumberOfSymTableEntries = getNumberOfSymbolTableEntries();953 954 if (Index >= NumberOfSymTableEntries)955 return createError("symbol index " + Twine(Index) +956 " exceeds symbol count " +957 Twine(NumberOfSymTableEntries));958 959 DataRefImpl SymDRI;960 SymDRI.p = getSymbolEntryAddressByIndex(Index);961 return getSymbolName(SymDRI);962}963 964uint16_t XCOFFObjectFile::getFlags() const {965 return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;966}967 968const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {969 return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;970}971 972uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {973 return reinterpret_cast<uintptr_t>(SectionHeaderTable);974}975 976int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {977 return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;978}979 980XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)981 : ObjectFile(Type, Object) {982 assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64);983}984 985ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {986 assert(is64Bit() && "64-bit interface called for non 64-bit file.");987 const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();988 return ArrayRef<XCOFFSectionHeader64>(TablePtr,989 TablePtr + getNumberOfSections());990}991 992ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {993 assert(!is64Bit() && "32-bit interface called for non 32-bit file.");994 const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32();995 return ArrayRef<XCOFFSectionHeader32>(TablePtr,996 TablePtr + getNumberOfSections());997}998 999// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO1000// section header contains the actual count of relocation entries in the s_paddr1001// field. STYP_OVRFLO headers contain the section index of their corresponding1002// sections as their raw "NumberOfRelocations" field value.1003template <typename T>1004Expected<uint32_t> XCOFFObjectFile::getNumberOfRelocationEntries(1005 const XCOFFSectionHeader<T> &Sec) const {1006 const T &Section = static_cast<const T &>(Sec);1007 if (is64Bit())1008 return Section.NumberOfRelocations;1009 1010 uint16_t SectionIndex = &Section - sectionHeaderTable<T>() + 1;1011 if (Section.NumberOfRelocations < XCOFF::RelocOverflow)1012 return Section.NumberOfRelocations;1013 for (const auto &Sec : sections32()) {1014 if (Sec.Flags == XCOFF::STYP_OVRFLO &&1015 Sec.NumberOfRelocations == SectionIndex)1016 return Sec.PhysicalAddress;1017 }1018 return errorCodeToError(object_error::parse_failed);1019}1020 1021template <typename Shdr, typename Reloc>1022Expected<ArrayRef<Reloc>> XCOFFObjectFile::relocations(const Shdr &Sec) const {1023 uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),1024 Sec.FileOffsetToRelocationInfo);1025 auto NumRelocEntriesOrErr = getNumberOfRelocationEntries(Sec);1026 if (Error E = NumRelocEntriesOrErr.takeError())1027 return std::move(E);1028 1029 uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();1030 static_assert((sizeof(Reloc) == XCOFF::RelocationSerializationSize64 ||1031 sizeof(Reloc) == XCOFF::RelocationSerializationSize32),1032 "Relocation structure is incorrect");1033 auto RelocationOrErr =1034 getObject<Reloc>(Data, reinterpret_cast<void *>(RelocAddr),1035 NumRelocEntries * sizeof(Reloc));1036 if (!RelocationOrErr)1037 return createError(1038 toString(RelocationOrErr.takeError()) + ": relocations with offset 0x" +1039 Twine::utohexstr(Sec.FileOffsetToRelocationInfo) + " and size 0x" +1040 Twine::utohexstr(NumRelocEntries * sizeof(Reloc)) +1041 " go past the end of the file");1042 1043 const Reloc *StartReloc = RelocationOrErr.get();1044 1045 return ArrayRef<Reloc>(StartReloc, StartReloc + NumRelocEntries);1046}1047 1048template <typename ExceptEnt>1049Expected<ArrayRef<ExceptEnt>> XCOFFObjectFile::getExceptionEntries() const {1050 assert((is64Bit() && sizeof(ExceptEnt) == sizeof(ExceptionSectionEntry64)) ||1051 (!is64Bit() && sizeof(ExceptEnt) == sizeof(ExceptionSectionEntry32)));1052 1053 Expected<uintptr_t> ExceptionSectOrErr =1054 getSectionFileOffsetToRawData(XCOFF::STYP_EXCEPT);1055 if (!ExceptionSectOrErr)1056 return ExceptionSectOrErr.takeError();1057 1058 DataRefImpl DRI = getSectionByType(XCOFF::STYP_EXCEPT);1059 if (DRI.p == 0)1060 return ArrayRef<ExceptEnt>();1061 1062 ExceptEnt *ExceptEntStart =1063 reinterpret_cast<ExceptEnt *>(*ExceptionSectOrErr);1064 return ArrayRef<ExceptEnt>(1065 ExceptEntStart, ExceptEntStart + getSectionSize(DRI) / sizeof(ExceptEnt));1066}1067 1068template LLVM_EXPORT_TEMPLATE Expected<ArrayRef<ExceptionSectionEntry32>>1069XCOFFObjectFile::getExceptionEntries() const;1070template LLVM_EXPORT_TEMPLATE Expected<ArrayRef<ExceptionSectionEntry64>>1071XCOFFObjectFile::getExceptionEntries() const;1072 1073Expected<XCOFFStringTable>1074XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {1075 // If there is a string table, then the buffer must contain at least 4 bytes1076 // for the string table's size. Not having a string table is not an error.1077 if (Error E = Binary::checkOffset(1078 Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) {1079 consumeError(std::move(E));1080 return XCOFFStringTable{0, nullptr};1081 }1082 1083 // Read the size out of the buffer.1084 uint32_t Size = support::endian::read32be(Obj->base() + Offset);1085 1086 // If the size is less then 4, then the string table is just a size and no1087 // string data.1088 if (Size <= 4)1089 return XCOFFStringTable{4, nullptr};1090 1091 auto StringTableOrErr =1092 getObject<char>(Obj->Data, Obj->base() + Offset, Size);1093 if (!StringTableOrErr)1094 return createError(toString(StringTableOrErr.takeError()) +1095 ": string table with offset 0x" +1096 Twine::utohexstr(Offset) + " and size 0x" +1097 Twine::utohexstr(Size) +1098 " goes past the end of the file");1099 1100 const char *StringTablePtr = StringTableOrErr.get();1101 if (StringTablePtr[Size - 1] != '\0')1102 return errorCodeToError(object_error::string_table_non_null_end);1103 1104 return XCOFFStringTable{Size, StringTablePtr};1105}1106 1107// This function returns the import file table. Each entry in the import file1108// table consists of: "path_name\0base_name\0archive_member_name\0".1109Expected<StringRef> XCOFFObjectFile::getImportFileTable() const {1110 Expected<uintptr_t> LoaderSectionAddrOrError =1111 getSectionFileOffsetToRawData(XCOFF::STYP_LOADER);1112 if (!LoaderSectionAddrOrError)1113 return LoaderSectionAddrOrError.takeError();1114 1115 uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get();1116 if (!LoaderSectionAddr)1117 return StringRef();1118 1119 uint64_t OffsetToImportFileTable = 0;1120 uint64_t LengthOfImportFileTable = 0;1121 if (is64Bit()) {1122 const LoaderSectionHeader64 *LoaderSec64 =1123 viewAs<LoaderSectionHeader64>(LoaderSectionAddr);1124 OffsetToImportFileTable = LoaderSec64->OffsetToImpid;1125 LengthOfImportFileTable = LoaderSec64->LengthOfImpidStrTbl;1126 } else {1127 const LoaderSectionHeader32 *LoaderSec32 =1128 viewAs<LoaderSectionHeader32>(LoaderSectionAddr);1129 OffsetToImportFileTable = LoaderSec32->OffsetToImpid;1130 LengthOfImportFileTable = LoaderSec32->LengthOfImpidStrTbl;1131 }1132 1133 auto ImportTableOrErr = getObject<char>(1134 Data,1135 reinterpret_cast<void *>(LoaderSectionAddr + OffsetToImportFileTable),1136 LengthOfImportFileTable);1137 if (!ImportTableOrErr)1138 return createError(1139 toString(ImportTableOrErr.takeError()) +1140 ": import file table with offset 0x" +1141 Twine::utohexstr(LoaderSectionAddr + OffsetToImportFileTable) +1142 " and size 0x" + Twine::utohexstr(LengthOfImportFileTable) +1143 " goes past the end of the file");1144 1145 const char *ImportTablePtr = ImportTableOrErr.get();1146 if (ImportTablePtr[LengthOfImportFileTable - 1] != '\0')1147 return createError(1148 ": import file name table with offset 0x" +1149 Twine::utohexstr(LoaderSectionAddr + OffsetToImportFileTable) +1150 " and size 0x" + Twine::utohexstr(LengthOfImportFileTable) +1151 " must end with a null terminator");1152 1153 return StringRef(ImportTablePtr, LengthOfImportFileTable);1154}1155 1156Expected<std::unique_ptr<XCOFFObjectFile>>1157XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {1158 // Can't use std::make_unique because of the private constructor.1159 std::unique_ptr<XCOFFObjectFile> Obj;1160 Obj.reset(new XCOFFObjectFile(Type, MBR));1161 1162 uint64_t CurOffset = 0;1163 const auto *Base = Obj->base();1164 MemoryBufferRef Data = Obj->Data;1165 1166 // Parse file header.1167 auto FileHeaderOrErr =1168 getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize());1169 if (Error E = FileHeaderOrErr.takeError())1170 return std::move(E);1171 Obj->FileHeader = FileHeaderOrErr.get();1172 1173 CurOffset += Obj->getFileHeaderSize();1174 1175 if (Obj->getOptionalHeaderSize()) {1176 auto AuxiliaryHeaderOrErr =1177 getObject<void>(Data, Base + CurOffset, Obj->getOptionalHeaderSize());1178 if (Error E = AuxiliaryHeaderOrErr.takeError())1179 return std::move(E);1180 Obj->AuxiliaryHeader = AuxiliaryHeaderOrErr.get();1181 }1182 1183 CurOffset += Obj->getOptionalHeaderSize();1184 1185 // Parse the section header table if it is present.1186 if (Obj->getNumberOfSections()) {1187 uint64_t SectionHeadersSize =1188 Obj->getNumberOfSections() * Obj->getSectionHeaderSize();1189 auto SecHeadersOrErr =1190 getObject<void>(Data, Base + CurOffset, SectionHeadersSize);1191 if (!SecHeadersOrErr)1192 return createError(toString(SecHeadersOrErr.takeError()) +1193 ": section headers with offset 0x" +1194 Twine::utohexstr(CurOffset) + " and size 0x" +1195 Twine::utohexstr(SectionHeadersSize) +1196 " go past the end of the file");1197 1198 Obj->SectionHeaderTable = SecHeadersOrErr.get();1199 }1200 1201 const uint32_t NumberOfSymbolTableEntries =1202 Obj->getNumberOfSymbolTableEntries();1203 1204 // If there is no symbol table we are done parsing the memory buffer.1205 if (NumberOfSymbolTableEntries == 0)1206 return std::move(Obj);1207 1208 // Parse symbol table.1209 CurOffset = Obj->is64Bit() ? Obj->getSymbolTableOffset64()1210 : Obj->getSymbolTableOffset32();1211 const uint64_t SymbolTableSize =1212 static_cast<uint64_t>(XCOFF::SymbolTableEntrySize) *1213 NumberOfSymbolTableEntries;1214 auto SymTableOrErr =1215 getObject<void *>(Data, Base + CurOffset, SymbolTableSize);1216 if (!SymTableOrErr)1217 return createError(1218 toString(SymTableOrErr.takeError()) + ": symbol table with offset 0x" +1219 Twine::utohexstr(CurOffset) + " and size 0x" +1220 Twine::utohexstr(SymbolTableSize) + " goes past the end of the file");1221 1222 Obj->SymbolTblPtr = SymTableOrErr.get();1223 CurOffset += SymbolTableSize;1224 1225 // Parse String table.1226 Expected<XCOFFStringTable> StringTableOrErr =1227 parseStringTable(Obj.get(), CurOffset);1228 if (Error E = StringTableOrErr.takeError())1229 return std::move(E);1230 Obj->StringTable = StringTableOrErr.get();1231 1232 return std::move(Obj);1233}1234 1235Expected<std::unique_ptr<ObjectFile>>1236ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,1237 unsigned FileType) {1238 return XCOFFObjectFile::create(FileType, MemBufRef);1239}1240 1241std::optional<StringRef> XCOFFObjectFile::tryGetCPUName() const {1242 return StringRef("future");1243}1244 1245Expected<bool> XCOFFSymbolRef::isFunction() const {1246 if (!isCsectSymbol())1247 return false;1248 1249 if (getSymbolType() & FunctionSym)1250 return true;1251 1252 Expected<XCOFFCsectAuxRef> ExpCsectAuxEnt = getXCOFFCsectAuxRef();1253 if (!ExpCsectAuxEnt)1254 return ExpCsectAuxEnt.takeError();1255 1256 const XCOFFCsectAuxRef CsectAuxRef = ExpCsectAuxEnt.get();1257 1258 if (CsectAuxRef.getStorageMappingClass() != XCOFF::XMC_PR &&1259 CsectAuxRef.getStorageMappingClass() != XCOFF::XMC_GL)1260 return false;1261 1262 // A function definition should not be a common type symbol or an external1263 // symbol.1264 if (CsectAuxRef.getSymbolType() == XCOFF::XTY_CM ||1265 CsectAuxRef.getSymbolType() == XCOFF::XTY_ER)1266 return false;1267 1268 // If the next symbol is an XTY_LD type symbol with the same address, this1269 // XTY_SD symbol is not a function. Otherwise this is a function symbol for1270 // -ffunction-sections.1271 if (CsectAuxRef.getSymbolType() == XCOFF::XTY_SD) {1272 // If this is a csect with size 0, it won't be a function definition.1273 // This is used to work around the fact that LLVM always generates below1274 // symbol for -ffunction-sections:1275 // m 0x00000000 .text 1 unamex **No Symbol**1276 // a4 0x00000000 0 0 SD PR 0 01277 // FIXME: remove or replace this meaningless symbol.1278 if (getSize() == 0)1279 return false;1280 1281 xcoff_symbol_iterator NextIt(this);1282 // If this is the last main symbol table entry, there won't be an XTY_LD1283 // type symbol below.1284 if (++NextIt == getObject()->symbol_end())1285 return true;1286 1287 if (cantFail(getAddress()) != cantFail(NextIt->getAddress()))1288 return true;1289 1290 // Check next symbol is XTY_LD. If so, this symbol is not a function.1291 Expected<XCOFFCsectAuxRef> NextCsectAuxEnt = NextIt->getXCOFFCsectAuxRef();1292 if (!NextCsectAuxEnt)1293 return NextCsectAuxEnt.takeError();1294 1295 if (NextCsectAuxEnt.get().getSymbolType() == XCOFF::XTY_LD)1296 return false;1297 1298 return true;1299 }1300 1301 if (CsectAuxRef.getSymbolType() == XCOFF::XTY_LD)1302 return true;1303 1304 return createError(1305 "symbol csect aux entry with index " +1306 Twine(getObject()->getSymbolIndex(CsectAuxRef.getEntryAddress())) +1307 " has invalid symbol type " +1308 Twine::utohexstr(CsectAuxRef.getSymbolType()));1309}1310 1311bool XCOFFSymbolRef::isCsectSymbol() const {1312 XCOFF::StorageClass SC = getStorageClass();1313 return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT ||1314 SC == XCOFF::C_HIDEXT);1315}1316 1317Expected<XCOFFCsectAuxRef> XCOFFSymbolRef::getXCOFFCsectAuxRef() const {1318 assert(isCsectSymbol() &&1319 "Calling csect symbol interface with a non-csect symbol.");1320 1321 uint8_t NumberOfAuxEntries = getNumberOfAuxEntries();1322 1323 Expected<StringRef> NameOrErr = getName();1324 if (auto Err = NameOrErr.takeError())1325 return std::move(Err);1326 1327 uint32_t SymbolIdx = getObject()->getSymbolIndex(getEntryAddress());1328 if (!NumberOfAuxEntries) {1329 return createError("csect symbol \"" + *NameOrErr + "\" with index " +1330 Twine(SymbolIdx) + " contains no auxiliary entry");1331 }1332 1333 if (!getObject()->is64Bit()) {1334 // In XCOFF32, the csect auxilliary entry is always the last auxiliary1335 // entry for the symbol.1336 uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress(1337 getEntryAddress(), NumberOfAuxEntries);1338 return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt32>(AuxAddr));1339 }1340 1341 // XCOFF64 uses SymbolAuxType to identify the auxiliary entry type.1342 // We need to iterate through all the auxiliary entries to find it.1343 for (uint8_t Index = NumberOfAuxEntries; Index > 0; --Index) {1344 uintptr_t AuxAddr = XCOFFObjectFile::getAdvancedSymbolEntryAddress(1345 getEntryAddress(), Index);1346 if (*getObject()->getSymbolAuxType(AuxAddr) ==1347 XCOFF::SymbolAuxType::AUX_CSECT) {1348#ifndef NDEBUG1349 getObject()->checkSymbolEntryPointer(AuxAddr);1350#endif1351 return XCOFFCsectAuxRef(viewAs<XCOFFCsectAuxEnt64>(AuxAddr));1352 }1353 }1354 1355 return createError(1356 "a csect auxiliary entry has not been found for symbol \"" + *NameOrErr +1357 "\" with index " + Twine(SymbolIdx));1358}1359 1360Expected<StringRef> XCOFFSymbolRef::getName() const {1361 // A storage class value with the high-order bit on indicates that the name is1362 // a symbolic debugger stabstring.1363 if (getStorageClass() & 0x80)1364 return StringRef("Unimplemented Debug Name");1365 1366 if (!getObject()->is64Bit()) {1367 if (getSymbol32()->NameInStrTbl.Magic !=1368 XCOFFSymbolRef::NAME_IN_STR_TBL_MAGIC)1369 return generateXCOFFFixedNameStringRef(getSymbol32()->SymbolName);1370 1371 return getObject()->getStringTableEntry(getSymbol32()->NameInStrTbl.Offset);1372 }1373 1374 return getObject()->getStringTableEntry(getSymbol64()->Offset);1375}1376 1377// Explicitly instantiate template classes.1378template struct LLVM_EXPORT_TEMPLATE XCOFFSectionHeader<XCOFFSectionHeader32>;1379template struct LLVM_EXPORT_TEMPLATE XCOFFSectionHeader<XCOFFSectionHeader64>;1380 1381template struct LLVM_EXPORT_TEMPLATE XCOFFRelocation<llvm::support::ubig32_t>;1382template struct LLVM_EXPORT_TEMPLATE XCOFFRelocation<llvm::support::ubig64_t>;1383 1384template LLVM_EXPORT_TEMPLATE1385 llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation64>>1386 llvm::object::XCOFFObjectFile::relocations<1387 llvm::object::XCOFFSectionHeader64, llvm::object::XCOFFRelocation64>(1388 llvm::object::XCOFFSectionHeader64 const &) const;1389template LLVM_EXPORT_TEMPLATE1390 llvm::Expected<llvm::ArrayRef<llvm::object::XCOFFRelocation32>>1391 llvm::object::XCOFFObjectFile::relocations<1392 llvm::object::XCOFFSectionHeader32, llvm::object::XCOFFRelocation32>(1393 llvm::object::XCOFFSectionHeader32 const &) const;1394 1395bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) {1396 if (Bytes.size() < 4)1397 return false;1398 1399 return support::endian::read32be(Bytes.data()) == 0;1400}1401 1402#define GETVALUEWITHMASK(X) (Data & (TracebackTable::X))1403#define GETVALUEWITHMASKSHIFT(X, S) \1404 ((Data & (TracebackTable::X)) >> (TracebackTable::S))1405 1406Expected<TBVectorExt> TBVectorExt::create(StringRef TBvectorStrRef) {1407 Error Err = Error::success();1408 TBVectorExt TBTVecExt(TBvectorStrRef, Err);1409 if (Err)1410 return std::move(Err);1411 return TBTVecExt;1412}1413 1414TBVectorExt::TBVectorExt(StringRef TBvectorStrRef, Error &Err) {1415 const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(TBvectorStrRef.data());1416 Data = support::endian::read16be(Ptr);1417 uint32_t VecParmsTypeValue = support::endian::read32be(Ptr + 2);1418 unsigned ParmsNum =1419 GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask, NumberOfVectorParmsShift);1420 1421 ErrorAsOutParameter EAO(Err);1422 Expected<SmallString<32>> VecParmsTypeOrError =1423 parseVectorParmsType(VecParmsTypeValue, ParmsNum);1424 if (!VecParmsTypeOrError)1425 Err = VecParmsTypeOrError.takeError();1426 else1427 VecParmsInfo = VecParmsTypeOrError.get();1428}1429 1430uint8_t TBVectorExt::getNumberOfVRSaved() const {1431 return GETVALUEWITHMASKSHIFT(NumberOfVRSavedMask, NumberOfVRSavedShift);1432}1433 1434bool TBVectorExt::isVRSavedOnStack() const {1435 return GETVALUEWITHMASK(IsVRSavedOnStackMask);1436}1437 1438bool TBVectorExt::hasVarArgs() const {1439 return GETVALUEWITHMASK(HasVarArgsMask);1440}1441 1442uint8_t TBVectorExt::getNumberOfVectorParms() const {1443 return GETVALUEWITHMASKSHIFT(NumberOfVectorParmsMask,1444 NumberOfVectorParmsShift);1445}1446 1447bool TBVectorExt::hasVMXInstruction() const {1448 return GETVALUEWITHMASK(HasVMXInstructionMask);1449}1450#undef GETVALUEWITHMASK1451#undef GETVALUEWITHMASKSHIFT1452 1453Expected<XCOFFTracebackTable>1454XCOFFTracebackTable::create(const uint8_t *Ptr, uint64_t &Size, bool Is64Bit) {1455 Error Err = Error::success();1456 XCOFFTracebackTable TBT(Ptr, Size, Err, Is64Bit);1457 if (Err)1458 return std::move(Err);1459 return TBT;1460}1461 1462XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size,1463 Error &Err, bool Is64Bit)1464 : TBPtr(Ptr), Is64BitObj(Is64Bit) {1465 ErrorAsOutParameter EAO(Err);1466 DataExtractor DE(ArrayRef<uint8_t>(Ptr, Size), /*IsLittleEndian=*/false,1467 /*AddressSize=*/0);1468 DataExtractor::Cursor Cur(/*Offset=*/0);1469 1470 // Skip 8 bytes of mandatory fields.1471 DE.getU64(Cur);1472 1473 unsigned FixedParmsNum = getNumberOfFixedParms();1474 unsigned FloatingParmsNum = getNumberOfFPParms();1475 uint32_t ParamsTypeValue = 0;1476 1477 // Begin to parse optional fields.1478 if (Cur && (FixedParmsNum + FloatingParmsNum) > 0)1479 ParamsTypeValue = DE.getU32(Cur);1480 1481 if (Cur && hasTraceBackTableOffset())1482 TraceBackTableOffset = DE.getU32(Cur);1483 1484 if (Cur && isInterruptHandler())1485 HandlerMask = DE.getU32(Cur);1486 1487 if (Cur && hasControlledStorage()) {1488 NumOfCtlAnchors = DE.getU32(Cur);1489 if (Cur && NumOfCtlAnchors) {1490 SmallVector<uint32_t, 8> Disp;1491 Disp.reserve(*NumOfCtlAnchors);1492 for (uint32_t I = 0; I < NumOfCtlAnchors && Cur; ++I)1493 Disp.push_back(DE.getU32(Cur));1494 if (Cur)1495 ControlledStorageInfoDisp = std::move(Disp);1496 }1497 }1498 1499 if (Cur && isFuncNamePresent()) {1500 uint16_t FunctionNameLen = DE.getU16(Cur);1501 if (Cur)1502 FunctionName = DE.getBytes(Cur, FunctionNameLen);1503 }1504 1505 if (Cur && isAllocaUsed())1506 AllocaRegister = DE.getU8(Cur);1507 1508 unsigned VectorParmsNum = 0;1509 if (Cur && hasVectorInfo()) {1510 StringRef VectorExtRef = DE.getBytes(Cur, 6);1511 if (Cur) {1512 Expected<TBVectorExt> TBVecExtOrErr = TBVectorExt::create(VectorExtRef);1513 if (!TBVecExtOrErr) {1514 Err = TBVecExtOrErr.takeError();1515 return;1516 }1517 VecExt = TBVecExtOrErr.get();1518 VectorParmsNum = VecExt->getNumberOfVectorParms();1519 // Skip two bytes of padding after vector info.1520 DE.skip(Cur, 2);1521 }1522 }1523 1524 // As long as there is no fixed-point or floating-point parameter, this1525 // field remains not present even when hasVectorInfo gives true and1526 // indicates the presence of vector parameters.1527 if (Cur && (FixedParmsNum + FloatingParmsNum) > 0) {1528 Expected<SmallString<32>> ParmsTypeOrError =1529 hasVectorInfo()1530 ? parseParmsTypeWithVecInfo(ParamsTypeValue, FixedParmsNum,1531 FloatingParmsNum, VectorParmsNum)1532 : parseParmsType(ParamsTypeValue, FixedParmsNum, FloatingParmsNum);1533 1534 if (!ParmsTypeOrError) {1535 Err = ParmsTypeOrError.takeError();1536 return;1537 }1538 ParmsType = ParmsTypeOrError.get();1539 }1540 1541 if (Cur && hasExtensionTable()) {1542 ExtensionTable = DE.getU8(Cur);1543 1544 if (*ExtensionTable & ExtendedTBTableFlag::TB_EH_INFO) {1545 // eh_info displacement must be 4-byte aligned.1546 Cur.seek(alignTo(Cur.tell(), 4));1547 EhInfoDisp = Is64BitObj ? DE.getU64(Cur) : DE.getU32(Cur);1548 }1549 }1550 if (!Cur)1551 Err = Cur.takeError();1552 1553 Size = Cur.tell();1554}1555 1556#define GETBITWITHMASK(P, X) \1557 (support::endian::read32be(TBPtr + (P)) & (TracebackTable::X))1558#define GETBITWITHMASKSHIFT(P, X, S) \1559 ((support::endian::read32be(TBPtr + (P)) & (TracebackTable::X)) >> \1560 (TracebackTable::S))1561 1562uint8_t XCOFFTracebackTable::getVersion() const {1563 return GETBITWITHMASKSHIFT(0, VersionMask, VersionShift);1564}1565 1566uint8_t XCOFFTracebackTable::getLanguageID() const {1567 return GETBITWITHMASKSHIFT(0, LanguageIdMask, LanguageIdShift);1568}1569 1570bool XCOFFTracebackTable::isGlobalLinkage() const {1571 return GETBITWITHMASK(0, IsGlobalLinkageMask);1572}1573 1574bool XCOFFTracebackTable::isOutOfLineEpilogOrPrologue() const {1575 return GETBITWITHMASK(0, IsOutOfLineEpilogOrPrologueMask);1576}1577 1578bool XCOFFTracebackTable::hasTraceBackTableOffset() const {1579 return GETBITWITHMASK(0, HasTraceBackTableOffsetMask);1580}1581 1582bool XCOFFTracebackTable::isInternalProcedure() const {1583 return GETBITWITHMASK(0, IsInternalProcedureMask);1584}1585 1586bool XCOFFTracebackTable::hasControlledStorage() const {1587 return GETBITWITHMASK(0, HasControlledStorageMask);1588}1589 1590bool XCOFFTracebackTable::isTOCless() const {1591 return GETBITWITHMASK(0, IsTOClessMask);1592}1593 1594bool XCOFFTracebackTable::isFloatingPointPresent() const {1595 return GETBITWITHMASK(0, IsFloatingPointPresentMask);1596}1597 1598bool XCOFFTracebackTable::isFloatingPointOperationLogOrAbortEnabled() const {1599 return GETBITWITHMASK(0, IsFloatingPointOperationLogOrAbortEnabledMask);1600}1601 1602bool XCOFFTracebackTable::isInterruptHandler() const {1603 return GETBITWITHMASK(0, IsInterruptHandlerMask);1604}1605 1606bool XCOFFTracebackTable::isFuncNamePresent() const {1607 return GETBITWITHMASK(0, IsFunctionNamePresentMask);1608}1609 1610bool XCOFFTracebackTable::isAllocaUsed() const {1611 return GETBITWITHMASK(0, IsAllocaUsedMask);1612}1613 1614uint8_t XCOFFTracebackTable::getOnConditionDirective() const {1615 return GETBITWITHMASKSHIFT(0, OnConditionDirectiveMask,1616 OnConditionDirectiveShift);1617}1618 1619bool XCOFFTracebackTable::isCRSaved() const {1620 return GETBITWITHMASK(0, IsCRSavedMask);1621}1622 1623bool XCOFFTracebackTable::isLRSaved() const {1624 return GETBITWITHMASK(0, IsLRSavedMask);1625}1626 1627bool XCOFFTracebackTable::isBackChainStored() const {1628 return GETBITWITHMASK(4, IsBackChainStoredMask);1629}1630 1631bool XCOFFTracebackTable::isFixup() const {1632 return GETBITWITHMASK(4, IsFixupMask);1633}1634 1635uint8_t XCOFFTracebackTable::getNumOfFPRsSaved() const {1636 return GETBITWITHMASKSHIFT(4, FPRSavedMask, FPRSavedShift);1637}1638 1639bool XCOFFTracebackTable::hasExtensionTable() const {1640 return GETBITWITHMASK(4, HasExtensionTableMask);1641}1642 1643bool XCOFFTracebackTable::hasVectorInfo() const {1644 return GETBITWITHMASK(4, HasVectorInfoMask);1645}1646 1647uint8_t XCOFFTracebackTable::getNumOfGPRsSaved() const {1648 return GETBITWITHMASKSHIFT(4, GPRSavedMask, GPRSavedShift);1649}1650 1651uint8_t XCOFFTracebackTable::getNumberOfFixedParms() const {1652 return GETBITWITHMASKSHIFT(4, NumberOfFixedParmsMask,1653 NumberOfFixedParmsShift);1654}1655 1656uint8_t XCOFFTracebackTable::getNumberOfFPParms() const {1657 return GETBITWITHMASKSHIFT(4, NumberOfFloatingPointParmsMask,1658 NumberOfFloatingPointParmsShift);1659}1660 1661bool XCOFFTracebackTable::hasParmsOnStack() const {1662 return GETBITWITHMASK(4, HasParmsOnStackMask);1663}1664 1665#undef GETBITWITHMASK1666#undef GETBITWITHMASKSHIFT1667} // namespace object1668} // namespace llvm1669