diff options
Diffstat (limited to 'lib/Object/XCOFFObjectFile.cpp')
-rw-r--r-- | lib/Object/XCOFFObjectFile.cpp | 240 |
1 files changed, 211 insertions, 29 deletions
diff --git a/lib/Object/XCOFFObjectFile.cpp b/lib/Object/XCOFFObjectFile.cpp index 602b7357986a..98782c2701c1 100644 --- a/lib/Object/XCOFFObjectFile.cpp +++ b/lib/Object/XCOFFObjectFile.cpp @@ -11,17 +11,14 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/XCOFFObjectFile.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/BinaryStreamReader.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/MathExtras.h" #include <cstddef> #include <cstring> namespace llvm { namespace object { +enum { FUNCTION_SYM = 0x20, SYM_TYPE_MASK = 0x07, RELOC_OVERFLOW = 65535 }; + // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer // 'M'. Returns a pointer to the underlying object on success. template <typename T> @@ -42,10 +39,25 @@ template <typename T> static const T *viewAs(uintptr_t in) { return reinterpret_cast<const T *>(in); } -static StringRef generateStringRef(const char *Name, uint64_t Size) { - auto NulCharPtr = static_cast<const char *>(memchr(Name, '\0', Size)); +static StringRef generateXCOFFFixedNameStringRef(const char *Name) { + auto NulCharPtr = + static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize)); return NulCharPtr ? StringRef(Name, NulCharPtr - Name) - : StringRef(Name, Size); + : StringRef(Name, XCOFF::NameSize); +} + +bool XCOFFRelocation32::isRelocationSigned() const { + return Info & XR_SIGN_INDICATOR_MASK; +} + +bool XCOFFRelocation32::isFixupIndicated() const { + return Info & XR_FIXUP_INDICATOR_MASK; +} + +uint8_t XCOFFRelocation32::getRelocatedLength() const { + // The relocation encodes the bit length being relocated minus 1. Add back + // the 1 to get the actual length being relocated. + return (Info & XR_BIASED_LENGTH_MASK) + 1; } void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr, @@ -83,6 +95,9 @@ XCOFFObjectFile::toSection64(DataRefImpl Ref) const { const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const { assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!"); +#ifndef NDEBUG + checkSymbolEntryPointer(Ref.p); +#endif auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p); return SymEntPtr; } @@ -112,23 +127,19 @@ XCOFFObjectFile::sectionHeaderTable64() const { void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1; +#ifndef NDEBUG + // This function is used by basic_symbol_iterator, which allows to + // point to the end-of-symbol-table address. + if (reinterpret_cast<uintptr_t>(SymEntPtr) != getEndOfSymbolTableAddress()) + checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(SymEntPtr)); +#endif Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr); } -Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { - const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); - - if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) - return generateStringRef(SymEntPtr->SymbolName, XCOFF::SymbolNameSize); - - // A storage class value with the high-order bit on indicates that the name is - // a symbolic debugger stabstring. - if (SymEntPtr->StorageClass & 0x80) - return StringRef("Unimplemented Debug Name"); - - uint32_t Offset = SymEntPtr->NameInStrTbl.Offset; - // The byte offset is relative to the start of the string table - // or .debug section. A byte offset value of 0 is a null or zero-length symbol +Expected<StringRef> +XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const { + // The byte offset is relative to the start of the string table. + // A byte offset value of 0 is a null or zero-length symbol // name. A byte offset in the range 1 to 3 (inclusive) points into the length // field; as a soft-error recovery mechanism, we treat such cases as having an // offset of 0. @@ -138,10 +149,32 @@ Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { if (StringTable.Data != nullptr && StringTable.Size > Offset) return (StringTable.Data + Offset); - return make_error<GenericBinaryError>("Symbol Name parse failed", + return make_error<GenericBinaryError>("Bad offset for string table entry", object_error::parse_failed); } +Expected<StringRef> +XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const { + if (CFileEntPtr->NameInStrTbl.Magic != + XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) + return generateXCOFFFixedNameStringRef(CFileEntPtr->Name); + return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset); +} + +Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { + const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); + + // A storage class value with the high-order bit on indicates that the name is + // a symbolic debugger stabstring. + if (SymEntPtr->StorageClass & 0x80) + return StringRef("Unimplemented Debug Name"); + + if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) + return generateXCOFFFixedNameStringRef(SymEntPtr->SymbolName); + + return getStringTableEntry(SymEntPtr->NameInStrTbl.Offset); +} + Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { uint64_t Result = 0; llvm_unreachable("Not yet implemented!"); @@ -149,6 +182,7 @@ Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { } uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); return toSymbolEntry(Symb)->Value; } @@ -185,7 +219,7 @@ void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { } Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { - return generateStringRef(getSectionNameInternal(Sec), XCOFF::SectionNameSize); + return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec)); } uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { @@ -393,8 +427,8 @@ XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const { default: Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum); if (SecRef) - return generateStringRef(getSectionNameInternal(SecRef.get()), - XCOFF::SectionNameSize); + return generateXCOFFFixedNameStringRef( + getSectionNameInternal(SecRef.get())); return SecRef.takeError(); } } @@ -442,6 +476,48 @@ uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { return fileHeader64()->NumberOfSymTableEntries; } +uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const { + uint32_t NumberOfSymTableEntries = + is64Bit() ? getNumberOfSymbolTableEntries64() + : getLogicalNumberOfSymbolTableEntries32(); + return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr), + XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries); +} + +void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const { + if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr)) + report_fatal_error("Symbol table entry is outside of symbol table."); + + if (SymbolEntPtr >= getEndOfSymbolTableAddress()) + report_fatal_error("Symbol table entry is outside of symbol table."); + + ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) - + reinterpret_cast<const char *>(SymbolTblPtr); + + if (Offset % XCOFF::SymbolTableEntrySize != 0) + report_fatal_error( + "Symbol table entry position is not valid inside of symbol table."); +} + +uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const { + return (reinterpret_cast<const char *>(SymbolEntPtr) - + reinterpret_cast<const char *>(SymbolTblPtr)) / + XCOFF::SymbolTableEntrySize; +} + +Expected<StringRef> +XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const { + if (is64Bit()) + report_fatal_error("64-bit symbol table support not implemented yet."); + + if (Index >= getLogicalNumberOfSymbolTableEntries32()) + return errorCodeToError(object_error::invalid_symbol_index); + + DataRefImpl SymDRI; + SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index); + return getSymbolName(SymDRI); +} + uint16_t XCOFFObjectFile::getFlags() const { return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; } @@ -477,6 +553,46 @@ ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const { TablePtr + getNumberOfSections()); } +// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO +// section header contains the actual count of relocation entries in the s_paddr +// field. STYP_OVRFLO headers contain the section index of their corresponding +// sections as their raw "NumberOfRelocations" field value. +Expected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries( + const XCOFFSectionHeader32 &Sec) const { + + uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1; + + if (Sec.NumberOfRelocations < RELOC_OVERFLOW) + return Sec.NumberOfRelocations; + for (const auto &Sec : sections32()) { + if (Sec.Flags == XCOFF::STYP_OVRFLO && + Sec.NumberOfRelocations == SectionIndex) + return Sec.PhysicalAddress; + } + return errorCodeToError(object_error::parse_failed); +} + +Expected<ArrayRef<XCOFFRelocation32>> +XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const { + uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader), + Sec.FileOffsetToRelocationInfo); + auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec); + if (Error E = NumRelocEntriesOrErr.takeError()) + return std::move(E); + + uint32_t NumRelocEntries = NumRelocEntriesOrErr.get(); + + auto RelocationOrErr = + getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr), + NumRelocEntries * sizeof(XCOFFRelocation32)); + if (Error E = RelocationOrErr.takeError()) + return std::move(E); + + const XCOFFRelocation32 *StartReloc = RelocationOrErr.get(); + + return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries); +} + Expected<XCOFFStringTable> XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { // If there is a string table, then the buffer must contain at least 4 bytes @@ -507,7 +623,7 @@ XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { Expected<std::unique_ptr<XCOFFObjectFile>> XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { - // Can't use make_unique because of the private constructor. + // Can't use std::make_unique because of the private constructor. std::unique_ptr<XCOFFObjectFile> Obj; Obj.reset(new XCOFFObjectFile(Type, MBR)); @@ -573,11 +689,77 @@ ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef, } StringRef XCOFFSectionHeader32::getName() const { - return generateStringRef(Name, XCOFF::SectionNameSize); + return generateXCOFFFixedNameStringRef(Name); } StringRef XCOFFSectionHeader64::getName() const { - return generateStringRef(Name, XCOFF::SectionNameSize); + return generateXCOFFFixedNameStringRef(Name); +} + +XCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const { + return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass; +} + +uint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const { + return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries; +} + +const XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const { + assert(!OwningObjectPtr->is64Bit() && + "32-bit interface called on 64-bit object file."); + assert(hasCsectAuxEnt() && "No Csect Auxiliary Entry is found."); + + // In XCOFF32, the csect auxilliary entry is always the last auxiliary + // entry for the symbol. + uintptr_t AuxAddr = getWithOffset( + SymEntDataRef.p, XCOFF::SymbolTableEntrySize * getNumberOfAuxEntries()); + +#ifndef NDEBUG + OwningObjectPtr->checkSymbolEntryPointer(AuxAddr); +#endif + + return reinterpret_cast<const XCOFFCsectAuxEnt32 *>(AuxAddr); +} + +uint16_t XCOFFSymbolRef::getType() const { + return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType; +} + +int16_t XCOFFSymbolRef::getSectionNumber() const { + return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber; +} + +bool XCOFFSymbolRef::hasCsectAuxEnt() const { + XCOFF::StorageClass SC = getStorageClass(); + return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT || + SC == XCOFF::C_HIDEXT); +} + +bool XCOFFSymbolRef::isFunction() const { + if (OwningObjectPtr->is64Bit()) + report_fatal_error("64-bit support is unimplemented yet."); + + if (getType() & FUNCTION_SYM) + return true; + + if (!hasCsectAuxEnt()) + return false; + + const XCOFFCsectAuxEnt32 *CsectAuxEnt = getXCOFFCsectAuxEnt32(); + + // A function definition should be a label definition. + if ((CsectAuxEnt->SymbolAlignmentAndType & SYM_TYPE_MASK) != XCOFF::XTY_LD) + return false; + + if (CsectAuxEnt->StorageMappingClass != XCOFF::XMC_PR) + return false; + + int16_t SectNum = getSectionNumber(); + Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum); + if (!SI) + return false; + + return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT); } } // namespace object |