1351278Sdim//===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===// 2351278Sdim// 3351278Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4351278Sdim// See https://llvm.org/LICENSE.txt for license information. 5351278Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6351278Sdim// 7351278Sdim//===----------------------------------------------------------------------===// 8351278Sdim// 9351278Sdim// This file defines the XCOFFObjectFile class. 10351278Sdim// 11351278Sdim//===----------------------------------------------------------------------===// 12351278Sdim 13351278Sdim#include "llvm/Object/XCOFFObjectFile.h" 14351278Sdim#include <cstddef> 15351278Sdim#include <cstring> 16351278Sdim 17351278Sdimnamespace llvm { 18351278Sdimnamespace object { 19351278Sdim 20360784Sdimenum { FUNCTION_SYM = 0x20, SYM_TYPE_MASK = 0x07, RELOC_OVERFLOW = 65535 }; 21360784Sdim 22351278Sdim// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer 23351278Sdim// 'M'. Returns a pointer to the underlying object on success. 24351278Sdimtemplate <typename T> 25351278Sdimstatic Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr, 26351278Sdim const uint64_t Size = sizeof(T)) { 27351278Sdim uintptr_t Addr = uintptr_t(Ptr); 28351278Sdim if (std::error_code EC = Binary::checkOffset(M, Addr, Size)) 29351278Sdim return errorCodeToError(EC); 30351278Sdim return reinterpret_cast<const T *>(Addr); 31351278Sdim} 32351278Sdim 33351278Sdimstatic uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) { 34351278Sdim return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) + 35351278Sdim Offset); 36351278Sdim} 37351278Sdim 38351278Sdimtemplate <typename T> static const T *viewAs(uintptr_t in) { 39351278Sdim return reinterpret_cast<const T *>(in); 40351278Sdim} 41351278Sdim 42360784Sdimstatic StringRef generateXCOFFFixedNameStringRef(const char *Name) { 43360784Sdim auto NulCharPtr = 44360784Sdim static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize)); 45351278Sdim return NulCharPtr ? StringRef(Name, NulCharPtr - Name) 46360784Sdim : StringRef(Name, XCOFF::NameSize); 47351278Sdim} 48351278Sdim 49360784Sdimtemplate <typename T> StringRef XCOFFSectionHeader<T>::getName() const { 50360784Sdim const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); 51360784Sdim return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name); 52360784Sdim} 53360784Sdim 54360784Sdimtemplate <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const { 55360784Sdim const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); 56360784Sdim return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask; 57360784Sdim} 58360784Sdim 59360784Sdimtemplate <typename T> 60360784Sdimbool XCOFFSectionHeader<T>::isReservedSectionType() const { 61360784Sdim return getSectionType() & SectionFlagsReservedMask; 62360784Sdim} 63360784Sdim 64360784Sdimbool XCOFFRelocation32::isRelocationSigned() const { 65360784Sdim return Info & XR_SIGN_INDICATOR_MASK; 66360784Sdim} 67360784Sdim 68360784Sdimbool XCOFFRelocation32::isFixupIndicated() const { 69360784Sdim return Info & XR_FIXUP_INDICATOR_MASK; 70360784Sdim} 71360784Sdim 72360784Sdimuint8_t XCOFFRelocation32::getRelocatedLength() const { 73360784Sdim // The relocation encodes the bit length being relocated minus 1. Add back 74360784Sdim // the 1 to get the actual length being relocated. 75360784Sdim return (Info & XR_BIASED_LENGTH_MASK) + 1; 76360784Sdim} 77360784Sdim 78351278Sdimvoid XCOFFObjectFile::checkSectionAddress(uintptr_t Addr, 79351278Sdim uintptr_t TableAddress) const { 80351278Sdim if (Addr < TableAddress) 81351278Sdim report_fatal_error("Section header outside of section header table."); 82351278Sdim 83351278Sdim uintptr_t Offset = Addr - TableAddress; 84351278Sdim if (Offset >= getSectionHeaderSize() * getNumberOfSections()) 85351278Sdim report_fatal_error("Section header outside of section header table."); 86351278Sdim 87351278Sdim if (Offset % getSectionHeaderSize() != 0) 88351278Sdim report_fatal_error( 89351278Sdim "Section header pointer does not point to a valid section header."); 90351278Sdim} 91351278Sdim 92351278Sdimconst XCOFFSectionHeader32 * 93351278SdimXCOFFObjectFile::toSection32(DataRefImpl Ref) const { 94351278Sdim assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 95351278Sdim#ifndef NDEBUG 96351278Sdim checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); 97351278Sdim#endif 98351278Sdim return viewAs<XCOFFSectionHeader32>(Ref.p); 99351278Sdim} 100351278Sdim 101351278Sdimconst XCOFFSectionHeader64 * 102351278SdimXCOFFObjectFile::toSection64(DataRefImpl Ref) const { 103351278Sdim assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 104351278Sdim#ifndef NDEBUG 105351278Sdim checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); 106351278Sdim#endif 107351278Sdim return viewAs<XCOFFSectionHeader64>(Ref.p); 108351278Sdim} 109351278Sdim 110351278Sdimconst XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const { 111351278Sdim assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 112351278Sdim assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!"); 113360784Sdim#ifndef NDEBUG 114360784Sdim checkSymbolEntryPointer(Ref.p); 115360784Sdim#endif 116351278Sdim auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p); 117351278Sdim return SymEntPtr; 118351278Sdim} 119351278Sdim 120351278Sdimconst XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const { 121351278Sdim assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 122351278Sdim return static_cast<const XCOFFFileHeader32 *>(FileHeader); 123351278Sdim} 124351278Sdim 125351278Sdimconst XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const { 126351278Sdim assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 127351278Sdim return static_cast<const XCOFFFileHeader64 *>(FileHeader); 128351278Sdim} 129351278Sdim 130351278Sdimconst XCOFFSectionHeader32 * 131351278SdimXCOFFObjectFile::sectionHeaderTable32() const { 132351278Sdim assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 133351278Sdim return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable); 134351278Sdim} 135351278Sdim 136351278Sdimconst XCOFFSectionHeader64 * 137351278SdimXCOFFObjectFile::sectionHeaderTable64() const { 138351278Sdim assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 139351278Sdim return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable); 140351278Sdim} 141351278Sdim 142351278Sdimvoid XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { 143351278Sdim const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); 144351278Sdim SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1; 145360784Sdim#ifndef NDEBUG 146360784Sdim // This function is used by basic_symbol_iterator, which allows to 147360784Sdim // point to the end-of-symbol-table address. 148360784Sdim if (reinterpret_cast<uintptr_t>(SymEntPtr) != getEndOfSymbolTableAddress()) 149360784Sdim checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(SymEntPtr)); 150360784Sdim#endif 151351278Sdim Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr); 152351278Sdim} 153351278Sdim 154360784SdimExpected<StringRef> 155360784SdimXCOFFObjectFile::getStringTableEntry(uint32_t Offset) const { 156360784Sdim // The byte offset is relative to the start of the string table. 157360784Sdim // A byte offset value of 0 is a null or zero-length symbol 158351278Sdim // name. A byte offset in the range 1 to 3 (inclusive) points into the length 159351278Sdim // field; as a soft-error recovery mechanism, we treat such cases as having an 160351278Sdim // offset of 0. 161351278Sdim if (Offset < 4) 162351278Sdim return StringRef(nullptr, 0); 163351278Sdim 164351278Sdim if (StringTable.Data != nullptr && StringTable.Size > Offset) 165351278Sdim return (StringTable.Data + Offset); 166351278Sdim 167360784Sdim return make_error<GenericBinaryError>("Bad offset for string table entry", 168351278Sdim object_error::parse_failed); 169351278Sdim} 170351278Sdim 171360784SdimExpected<StringRef> 172360784SdimXCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const { 173360784Sdim if (CFileEntPtr->NameInStrTbl.Magic != 174360784Sdim XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) 175360784Sdim return generateXCOFFFixedNameStringRef(CFileEntPtr->Name); 176360784Sdim return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset); 177360784Sdim} 178360784Sdim 179360784SdimExpected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { 180360784Sdim const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); 181360784Sdim 182360784Sdim // A storage class value with the high-order bit on indicates that the name is 183360784Sdim // a symbolic debugger stabstring. 184360784Sdim if (SymEntPtr->StorageClass & 0x80) 185360784Sdim return StringRef("Unimplemented Debug Name"); 186360784Sdim 187360784Sdim if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) 188360784Sdim return generateXCOFFFixedNameStringRef(SymEntPtr->SymbolName); 189360784Sdim 190360784Sdim return getStringTableEntry(SymEntPtr->NameInStrTbl.Offset); 191360784Sdim} 192360784Sdim 193351278SdimExpected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { 194360784Sdim assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 195360784Sdim return toSymbolEntry(Symb)->Value; 196351278Sdim} 197351278Sdim 198351278Sdimuint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { 199360784Sdim assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 200351278Sdim return toSymbolEntry(Symb)->Value; 201351278Sdim} 202351278Sdim 203351278Sdimuint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { 204351278Sdim uint64_t Result = 0; 205351278Sdim llvm_unreachable("Not yet implemented!"); 206351278Sdim return Result; 207351278Sdim} 208351278Sdim 209351278SdimExpected<SymbolRef::Type> 210351278SdimXCOFFObjectFile::getSymbolType(DataRefImpl Symb) const { 211351278Sdim llvm_unreachable("Not yet implemented!"); 212351278Sdim return SymbolRef::ST_Other; 213351278Sdim} 214351278Sdim 215351278SdimExpected<section_iterator> 216351278SdimXCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { 217351278Sdim const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); 218351278Sdim int16_t SectNum = SymEntPtr->SectionNumber; 219351278Sdim 220351278Sdim if (isReservedSectionNumber(SectNum)) 221351278Sdim return section_end(); 222351278Sdim 223351278Sdim Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum); 224351278Sdim if (!ExpSec) 225351278Sdim return ExpSec.takeError(); 226351278Sdim 227351278Sdim return section_iterator(SectionRef(ExpSec.get(), this)); 228351278Sdim} 229351278Sdim 230351278Sdimvoid XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { 231351278Sdim const char *Ptr = reinterpret_cast<const char *>(Sec.p); 232351278Sdim Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize()); 233351278Sdim} 234351278Sdim 235351278SdimExpected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { 236360784Sdim return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec)); 237351278Sdim} 238351278Sdim 239351278Sdimuint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { 240351278Sdim // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t 241351278Sdim // with MSVC. 242351278Sdim if (is64Bit()) 243351278Sdim return toSection64(Sec)->VirtualAddress; 244351278Sdim 245351278Sdim return toSection32(Sec)->VirtualAddress; 246351278Sdim} 247351278Sdim 248351278Sdimuint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { 249351278Sdim // Section numbers in XCOFF are numbered beginning at 1. A section number of 250351278Sdim // zero is used to indicate that a symbol is being imported or is undefined. 251351278Sdim if (is64Bit()) 252351278Sdim return toSection64(Sec) - sectionHeaderTable64() + 1; 253351278Sdim else 254351278Sdim return toSection32(Sec) - sectionHeaderTable32() + 1; 255351278Sdim} 256351278Sdim 257351278Sdimuint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const { 258351278Sdim // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t 259351278Sdim // with MSVC. 260351278Sdim if (is64Bit()) 261351278Sdim return toSection64(Sec)->SectionSize; 262351278Sdim 263351278Sdim return toSection32(Sec)->SectionSize; 264351278Sdim} 265351278Sdim 266351278SdimExpected<ArrayRef<uint8_t>> 267351278SdimXCOFFObjectFile::getSectionContents(DataRefImpl Sec) const { 268360784Sdim if (isSectionVirtual(Sec)) 269360784Sdim return ArrayRef<uint8_t>(); 270360784Sdim 271360784Sdim uint64_t OffsetToRaw; 272360784Sdim if (is64Bit()) 273360784Sdim OffsetToRaw = toSection64(Sec)->FileOffsetToRawData; 274360784Sdim else 275360784Sdim OffsetToRaw = toSection32(Sec)->FileOffsetToRawData; 276360784Sdim 277360784Sdim const uint8_t * ContentStart = base() + OffsetToRaw; 278360784Sdim uint64_t SectionSize = getSectionSize(Sec); 279360784Sdim if (checkOffset(Data, uintptr_t(ContentStart), SectionSize)) 280360784Sdim return make_error<BinaryError>(); 281360784Sdim 282360784Sdim return makeArrayRef(ContentStart,SectionSize); 283351278Sdim} 284351278Sdim 285351278Sdimuint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { 286351278Sdim uint64_t Result = 0; 287351278Sdim llvm_unreachable("Not yet implemented!"); 288351278Sdim return Result; 289351278Sdim} 290351278Sdim 291351278Sdimbool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { 292351278Sdim bool Result = false; 293351278Sdim llvm_unreachable("Not yet implemented!"); 294351278Sdim return Result; 295351278Sdim} 296351278Sdim 297351278Sdimbool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { 298351278Sdim return getSectionFlags(Sec) & XCOFF::STYP_TEXT; 299351278Sdim} 300351278Sdim 301351278Sdimbool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { 302351278Sdim uint32_t Flags = getSectionFlags(Sec); 303351278Sdim return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); 304351278Sdim} 305351278Sdim 306351278Sdimbool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { 307351278Sdim uint32_t Flags = getSectionFlags(Sec); 308351278Sdim return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); 309351278Sdim} 310351278Sdim 311351278Sdimbool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const { 312360784Sdim return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0 313360784Sdim : toSection32(Sec)->FileOffsetToRawData == 0; 314351278Sdim} 315351278Sdim 316351278Sdimrelocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { 317351278Sdim llvm_unreachable("Not yet implemented!"); 318351278Sdim return relocation_iterator(RelocationRef()); 319351278Sdim} 320351278Sdim 321351278Sdimrelocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const { 322351278Sdim llvm_unreachable("Not yet implemented!"); 323351278Sdim return relocation_iterator(RelocationRef()); 324351278Sdim} 325351278Sdim 326351278Sdimvoid XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { 327351278Sdim llvm_unreachable("Not yet implemented!"); 328351278Sdim return; 329351278Sdim} 330351278Sdim 331351278Sdimuint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { 332351278Sdim llvm_unreachable("Not yet implemented!"); 333351278Sdim uint64_t Result = 0; 334351278Sdim return Result; 335351278Sdim} 336351278Sdim 337351278Sdimsymbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { 338351278Sdim llvm_unreachable("Not yet implemented!"); 339351278Sdim return symbol_iterator(SymbolRef()); 340351278Sdim} 341351278Sdim 342351278Sdimuint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const { 343351278Sdim llvm_unreachable("Not yet implemented!"); 344351278Sdim uint64_t Result = 0; 345351278Sdim return Result; 346351278Sdim} 347351278Sdim 348351278Sdimvoid XCOFFObjectFile::getRelocationTypeName( 349351278Sdim DataRefImpl Rel, SmallVectorImpl<char> &Result) const { 350351278Sdim llvm_unreachable("Not yet implemented!"); 351351278Sdim return; 352351278Sdim} 353351278Sdim 354351278Sdimuint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { 355351278Sdim uint32_t Result = 0; 356351278Sdim llvm_unreachable("Not yet implemented!"); 357351278Sdim return Result; 358351278Sdim} 359351278Sdim 360351278Sdimbasic_symbol_iterator XCOFFObjectFile::symbol_begin() const { 361351278Sdim assert(!is64Bit() && "64-bit support not implemented yet."); 362351278Sdim DataRefImpl SymDRI; 363351278Sdim SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr); 364351278Sdim return basic_symbol_iterator(SymbolRef(SymDRI, this)); 365351278Sdim} 366351278Sdim 367351278Sdimbasic_symbol_iterator XCOFFObjectFile::symbol_end() const { 368351278Sdim assert(!is64Bit() && "64-bit support not implemented yet."); 369351278Sdim DataRefImpl SymDRI; 370351278Sdim SymDRI.p = reinterpret_cast<uintptr_t>( 371351278Sdim SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32()); 372351278Sdim return basic_symbol_iterator(SymbolRef(SymDRI, this)); 373351278Sdim} 374351278Sdim 375351278Sdimsection_iterator XCOFFObjectFile::section_begin() const { 376351278Sdim DataRefImpl DRI; 377351278Sdim DRI.p = getSectionHeaderTableAddress(); 378351278Sdim return section_iterator(SectionRef(DRI, this)); 379351278Sdim} 380351278Sdim 381351278Sdimsection_iterator XCOFFObjectFile::section_end() const { 382351278Sdim DataRefImpl DRI; 383351278Sdim DRI.p = getWithOffset(getSectionHeaderTableAddress(), 384351278Sdim getNumberOfSections() * getSectionHeaderSize()); 385351278Sdim return section_iterator(SectionRef(DRI, this)); 386351278Sdim} 387351278Sdim 388351278Sdimuint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } 389351278Sdim 390351278SdimStringRef XCOFFObjectFile::getFileFormatName() const { 391351278Sdim return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000"; 392351278Sdim} 393351278Sdim 394351278SdimTriple::ArchType XCOFFObjectFile::getArch() const { 395351278Sdim return is64Bit() ? Triple::ppc64 : Triple::ppc; 396351278Sdim} 397351278Sdim 398351278SdimSubtargetFeatures XCOFFObjectFile::getFeatures() const { 399351278Sdim return SubtargetFeatures(); 400351278Sdim} 401351278Sdim 402351278Sdimbool XCOFFObjectFile::isRelocatableObject() const { 403351278Sdim bool Result = false; 404351278Sdim llvm_unreachable("Not yet implemented!"); 405351278Sdim return Result; 406351278Sdim} 407351278Sdim 408351278SdimExpected<uint64_t> XCOFFObjectFile::getStartAddress() const { 409351278Sdim // TODO FIXME Should get from auxiliary_header->o_entry when support for the 410351278Sdim // auxiliary_header is added. 411351278Sdim return 0; 412351278Sdim} 413351278Sdim 414351278Sdimsize_t XCOFFObjectFile::getFileHeaderSize() const { 415351278Sdim return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32); 416351278Sdim} 417351278Sdim 418351278Sdimsize_t XCOFFObjectFile::getSectionHeaderSize() const { 419351278Sdim return is64Bit() ? sizeof(XCOFFSectionHeader64) : 420351278Sdim sizeof(XCOFFSectionHeader32); 421351278Sdim} 422351278Sdim 423351278Sdimbool XCOFFObjectFile::is64Bit() const { 424351278Sdim return Binary::ID_XCOFF64 == getType(); 425351278Sdim} 426351278Sdim 427351278Sdimuint16_t XCOFFObjectFile::getMagic() const { 428351278Sdim return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; 429351278Sdim} 430351278Sdim 431351278SdimExpected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const { 432351278Sdim if (Num <= 0 || Num > getNumberOfSections()) 433351278Sdim return errorCodeToError(object_error::invalid_section_index); 434351278Sdim 435351278Sdim DataRefImpl DRI; 436351278Sdim DRI.p = getWithOffset(getSectionHeaderTableAddress(), 437351278Sdim getSectionHeaderSize() * (Num - 1)); 438351278Sdim return DRI; 439351278Sdim} 440351278Sdim 441351278SdimExpected<StringRef> 442351278SdimXCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const { 443351278Sdim assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 444351278Sdim int16_t SectionNum = SymEntPtr->SectionNumber; 445351278Sdim 446351278Sdim switch (SectionNum) { 447351278Sdim case XCOFF::N_DEBUG: 448351278Sdim return "N_DEBUG"; 449351278Sdim case XCOFF::N_ABS: 450351278Sdim return "N_ABS"; 451351278Sdim case XCOFF::N_UNDEF: 452351278Sdim return "N_UNDEF"; 453351278Sdim default: 454351278Sdim Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum); 455351278Sdim if (SecRef) 456360784Sdim return generateXCOFFFixedNameStringRef( 457360784Sdim getSectionNameInternal(SecRef.get())); 458351278Sdim return SecRef.takeError(); 459351278Sdim } 460351278Sdim} 461351278Sdim 462351278Sdimbool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) { 463351278Sdim return (SectionNumber <= 0 && SectionNumber >= -2); 464351278Sdim} 465351278Sdim 466351278Sdimuint16_t XCOFFObjectFile::getNumberOfSections() const { 467351278Sdim return is64Bit() ? fileHeader64()->NumberOfSections 468351278Sdim : fileHeader32()->NumberOfSections; 469351278Sdim} 470351278Sdim 471351278Sdimint32_t XCOFFObjectFile::getTimeStamp() const { 472351278Sdim return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp; 473351278Sdim} 474351278Sdim 475351278Sdimuint16_t XCOFFObjectFile::getOptionalHeaderSize() const { 476351278Sdim return is64Bit() ? fileHeader64()->AuxHeaderSize 477351278Sdim : fileHeader32()->AuxHeaderSize; 478351278Sdim} 479351278Sdim 480351278Sdimuint32_t XCOFFObjectFile::getSymbolTableOffset32() const { 481351278Sdim return fileHeader32()->SymbolTableOffset; 482351278Sdim} 483351278Sdim 484351278Sdimint32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const { 485351278Sdim // As far as symbol table size is concerned, if this field is negative it is 486351278Sdim // to be treated as a 0. However since this field is also used for printing we 487351278Sdim // don't want to truncate any negative values. 488351278Sdim return fileHeader32()->NumberOfSymTableEntries; 489351278Sdim} 490351278Sdim 491351278Sdimuint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const { 492351278Sdim return (fileHeader32()->NumberOfSymTableEntries >= 0 493351278Sdim ? fileHeader32()->NumberOfSymTableEntries 494351278Sdim : 0); 495351278Sdim} 496351278Sdim 497351278Sdimuint64_t XCOFFObjectFile::getSymbolTableOffset64() const { 498351278Sdim return fileHeader64()->SymbolTableOffset; 499351278Sdim} 500351278Sdim 501351278Sdimuint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { 502351278Sdim return fileHeader64()->NumberOfSymTableEntries; 503351278Sdim} 504351278Sdim 505360784Sdimuintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const { 506360784Sdim uint32_t NumberOfSymTableEntries = 507360784Sdim is64Bit() ? getNumberOfSymbolTableEntries64() 508360784Sdim : getLogicalNumberOfSymbolTableEntries32(); 509360784Sdim return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr), 510360784Sdim XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries); 511360784Sdim} 512360784Sdim 513360784Sdimvoid XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const { 514360784Sdim if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr)) 515360784Sdim report_fatal_error("Symbol table entry is outside of symbol table."); 516360784Sdim 517360784Sdim if (SymbolEntPtr >= getEndOfSymbolTableAddress()) 518360784Sdim report_fatal_error("Symbol table entry is outside of symbol table."); 519360784Sdim 520360784Sdim ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) - 521360784Sdim reinterpret_cast<const char *>(SymbolTblPtr); 522360784Sdim 523360784Sdim if (Offset % XCOFF::SymbolTableEntrySize != 0) 524360784Sdim report_fatal_error( 525360784Sdim "Symbol table entry position is not valid inside of symbol table."); 526360784Sdim} 527360784Sdim 528360784Sdimuint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const { 529360784Sdim return (reinterpret_cast<const char *>(SymbolEntPtr) - 530360784Sdim reinterpret_cast<const char *>(SymbolTblPtr)) / 531360784Sdim XCOFF::SymbolTableEntrySize; 532360784Sdim} 533360784Sdim 534360784SdimExpected<StringRef> 535360784SdimXCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const { 536360784Sdim if (is64Bit()) 537360784Sdim report_fatal_error("64-bit symbol table support not implemented yet."); 538360784Sdim 539360784Sdim if (Index >= getLogicalNumberOfSymbolTableEntries32()) 540360784Sdim return errorCodeToError(object_error::invalid_symbol_index); 541360784Sdim 542360784Sdim DataRefImpl SymDRI; 543360784Sdim SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index); 544360784Sdim return getSymbolName(SymDRI); 545360784Sdim} 546360784Sdim 547351278Sdimuint16_t XCOFFObjectFile::getFlags() const { 548351278Sdim return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; 549351278Sdim} 550351278Sdim 551351278Sdimconst char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const { 552351278Sdim return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name; 553351278Sdim} 554351278Sdim 555351278Sdimuintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const { 556351278Sdim return reinterpret_cast<uintptr_t>(SectionHeaderTable); 557351278Sdim} 558351278Sdim 559351278Sdimint32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const { 560351278Sdim return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags; 561351278Sdim} 562351278Sdim 563351278SdimXCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object) 564351278Sdim : ObjectFile(Type, Object) { 565351278Sdim assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64); 566351278Sdim} 567351278Sdim 568351278SdimArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const { 569351278Sdim assert(is64Bit() && "64-bit interface called for non 64-bit file."); 570351278Sdim const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64(); 571351278Sdim return ArrayRef<XCOFFSectionHeader64>(TablePtr, 572351278Sdim TablePtr + getNumberOfSections()); 573351278Sdim} 574351278Sdim 575351278SdimArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const { 576351278Sdim assert(!is64Bit() && "32-bit interface called for non 32-bit file."); 577351278Sdim const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32(); 578351278Sdim return ArrayRef<XCOFFSectionHeader32>(TablePtr, 579351278Sdim TablePtr + getNumberOfSections()); 580351278Sdim} 581351278Sdim 582360784Sdim// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO 583360784Sdim// section header contains the actual count of relocation entries in the s_paddr 584360784Sdim// field. STYP_OVRFLO headers contain the section index of their corresponding 585360784Sdim// sections as their raw "NumberOfRelocations" field value. 586360784SdimExpected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries( 587360784Sdim const XCOFFSectionHeader32 &Sec) const { 588360784Sdim 589360784Sdim uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1; 590360784Sdim 591360784Sdim if (Sec.NumberOfRelocations < RELOC_OVERFLOW) 592360784Sdim return Sec.NumberOfRelocations; 593360784Sdim for (const auto &Sec : sections32()) { 594360784Sdim if (Sec.Flags == XCOFF::STYP_OVRFLO && 595360784Sdim Sec.NumberOfRelocations == SectionIndex) 596360784Sdim return Sec.PhysicalAddress; 597360784Sdim } 598360784Sdim return errorCodeToError(object_error::parse_failed); 599360784Sdim} 600360784Sdim 601360784SdimExpected<ArrayRef<XCOFFRelocation32>> 602360784SdimXCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const { 603360784Sdim uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader), 604360784Sdim Sec.FileOffsetToRelocationInfo); 605360784Sdim auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec); 606360784Sdim if (Error E = NumRelocEntriesOrErr.takeError()) 607360784Sdim return std::move(E); 608360784Sdim 609360784Sdim uint32_t NumRelocEntries = NumRelocEntriesOrErr.get(); 610360784Sdim 611360784Sdim auto RelocationOrErr = 612360784Sdim getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr), 613360784Sdim NumRelocEntries * sizeof(XCOFFRelocation32)); 614360784Sdim if (Error E = RelocationOrErr.takeError()) 615360784Sdim return std::move(E); 616360784Sdim 617360784Sdim const XCOFFRelocation32 *StartReloc = RelocationOrErr.get(); 618360784Sdim 619360784Sdim return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries); 620360784Sdim} 621360784Sdim 622351278SdimExpected<XCOFFStringTable> 623351278SdimXCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { 624351278Sdim // If there is a string table, then the buffer must contain at least 4 bytes 625351278Sdim // for the string table's size. Not having a string table is not an error. 626351278Sdim if (auto EC = Binary::checkOffset( 627351278Sdim Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) 628351278Sdim return XCOFFStringTable{0, nullptr}; 629351278Sdim 630351278Sdim // Read the size out of the buffer. 631351278Sdim uint32_t Size = support::endian::read32be(Obj->base() + Offset); 632351278Sdim 633351278Sdim // If the size is less then 4, then the string table is just a size and no 634351278Sdim // string data. 635351278Sdim if (Size <= 4) 636351278Sdim return XCOFFStringTable{4, nullptr}; 637351278Sdim 638351278Sdim auto StringTableOrErr = 639351278Sdim getObject<char>(Obj->Data, Obj->base() + Offset, Size); 640351278Sdim if (Error E = StringTableOrErr.takeError()) 641351278Sdim return std::move(E); 642351278Sdim 643351278Sdim const char *StringTablePtr = StringTableOrErr.get(); 644351278Sdim if (StringTablePtr[Size - 1] != '\0') 645351278Sdim return errorCodeToError(object_error::string_table_non_null_end); 646351278Sdim 647351278Sdim return XCOFFStringTable{Size, StringTablePtr}; 648351278Sdim} 649351278Sdim 650351278SdimExpected<std::unique_ptr<XCOFFObjectFile>> 651351278SdimXCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { 652360784Sdim // Can't use std::make_unique because of the private constructor. 653351278Sdim std::unique_ptr<XCOFFObjectFile> Obj; 654351278Sdim Obj.reset(new XCOFFObjectFile(Type, MBR)); 655351278Sdim 656351278Sdim uint64_t CurOffset = 0; 657351278Sdim const auto *Base = Obj->base(); 658351278Sdim MemoryBufferRef Data = Obj->Data; 659351278Sdim 660351278Sdim // Parse file header. 661351278Sdim auto FileHeaderOrErr = 662351278Sdim getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize()); 663351278Sdim if (Error E = FileHeaderOrErr.takeError()) 664351278Sdim return std::move(E); 665351278Sdim Obj->FileHeader = FileHeaderOrErr.get(); 666351278Sdim 667351278Sdim CurOffset += Obj->getFileHeaderSize(); 668351278Sdim // TODO FIXME we don't have support for an optional header yet, so just skip 669351278Sdim // past it. 670351278Sdim CurOffset += Obj->getOptionalHeaderSize(); 671351278Sdim 672351278Sdim // Parse the section header table if it is present. 673351278Sdim if (Obj->getNumberOfSections()) { 674351278Sdim auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset, 675351278Sdim Obj->getNumberOfSections() * 676351278Sdim Obj->getSectionHeaderSize()); 677351278Sdim if (Error E = SecHeadersOrErr.takeError()) 678351278Sdim return std::move(E); 679351278Sdim Obj->SectionHeaderTable = SecHeadersOrErr.get(); 680351278Sdim } 681351278Sdim 682351278Sdim // 64-bit object supports only file header and section headers for now. 683351278Sdim if (Obj->is64Bit()) 684351278Sdim return std::move(Obj); 685351278Sdim 686351278Sdim // If there is no symbol table we are done parsing the memory buffer. 687351278Sdim if (Obj->getLogicalNumberOfSymbolTableEntries32() == 0) 688351278Sdim return std::move(Obj); 689351278Sdim 690351278Sdim // Parse symbol table. 691351278Sdim CurOffset = Obj->fileHeader32()->SymbolTableOffset; 692351278Sdim uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) * 693351278Sdim Obj->getLogicalNumberOfSymbolTableEntries32(); 694351278Sdim auto SymTableOrErr = 695351278Sdim getObject<XCOFFSymbolEntry>(Data, Base + CurOffset, SymbolTableSize); 696351278Sdim if (Error E = SymTableOrErr.takeError()) 697351278Sdim return std::move(E); 698351278Sdim Obj->SymbolTblPtr = SymTableOrErr.get(); 699351278Sdim CurOffset += SymbolTableSize; 700351278Sdim 701351278Sdim // Parse String table. 702351278Sdim Expected<XCOFFStringTable> StringTableOrErr = 703351278Sdim parseStringTable(Obj.get(), CurOffset); 704351278Sdim if (Error E = StringTableOrErr.takeError()) 705351278Sdim return std::move(E); 706351278Sdim Obj->StringTable = StringTableOrErr.get(); 707351278Sdim 708351278Sdim return std::move(Obj); 709351278Sdim} 710351278Sdim 711351278SdimExpected<std::unique_ptr<ObjectFile>> 712351278SdimObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef, 713351278Sdim unsigned FileType) { 714351278Sdim return XCOFFObjectFile::create(FileType, MemBufRef); 715351278Sdim} 716351278Sdim 717360784SdimXCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const { 718360784Sdim return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass; 719351278Sdim} 720351278Sdim 721360784Sdimuint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const { 722360784Sdim return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries; 723351278Sdim} 724351278Sdim 725360784Sdimconst XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const { 726360784Sdim assert(!OwningObjectPtr->is64Bit() && 727360784Sdim "32-bit interface called on 64-bit object file."); 728360784Sdim assert(hasCsectAuxEnt() && "No Csect Auxiliary Entry is found."); 729360784Sdim 730360784Sdim // In XCOFF32, the csect auxilliary entry is always the last auxiliary 731360784Sdim // entry for the symbol. 732360784Sdim uintptr_t AuxAddr = getWithOffset( 733360784Sdim SymEntDataRef.p, XCOFF::SymbolTableEntrySize * getNumberOfAuxEntries()); 734360784Sdim 735360784Sdim#ifndef NDEBUG 736360784Sdim OwningObjectPtr->checkSymbolEntryPointer(AuxAddr); 737360784Sdim#endif 738360784Sdim 739360784Sdim return reinterpret_cast<const XCOFFCsectAuxEnt32 *>(AuxAddr); 740360784Sdim} 741360784Sdim 742360784Sdimuint16_t XCOFFSymbolRef::getType() const { 743360784Sdim return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType; 744360784Sdim} 745360784Sdim 746360784Sdimint16_t XCOFFSymbolRef::getSectionNumber() const { 747360784Sdim return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber; 748360784Sdim} 749360784Sdim 750360784Sdimbool XCOFFSymbolRef::hasCsectAuxEnt() const { 751360784Sdim XCOFF::StorageClass SC = getStorageClass(); 752360784Sdim return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT || 753360784Sdim SC == XCOFF::C_HIDEXT); 754360784Sdim} 755360784Sdim 756360784Sdimbool XCOFFSymbolRef::isFunction() const { 757360784Sdim if (OwningObjectPtr->is64Bit()) 758360784Sdim report_fatal_error("64-bit support is unimplemented yet."); 759360784Sdim 760360784Sdim if (getType() & FUNCTION_SYM) 761360784Sdim return true; 762360784Sdim 763360784Sdim if (!hasCsectAuxEnt()) 764360784Sdim return false; 765360784Sdim 766360784Sdim const XCOFFCsectAuxEnt32 *CsectAuxEnt = getXCOFFCsectAuxEnt32(); 767360784Sdim 768360784Sdim // A function definition should be a label definition. 769360784Sdim if ((CsectAuxEnt->SymbolAlignmentAndType & SYM_TYPE_MASK) != XCOFF::XTY_LD) 770360784Sdim return false; 771360784Sdim 772360784Sdim if (CsectAuxEnt->StorageMappingClass != XCOFF::XMC_PR) 773360784Sdim return false; 774360784Sdim 775360784Sdim int16_t SectNum = getSectionNumber(); 776360784Sdim Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum); 777360784Sdim if (!SI) 778360784Sdim return false; 779360784Sdim 780360784Sdim return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT); 781360784Sdim} 782360784Sdim 783360784Sdim// Explictly instantiate template classes. 784360784Sdimtemplate struct XCOFFSectionHeader<XCOFFSectionHeader32>; 785360784Sdimtemplate struct XCOFFSectionHeader<XCOFFSectionHeader64>; 786360784Sdim 787351278Sdim} // namespace object 788351278Sdim} // namespace llvm 789