diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -19,12 +19,13 @@ namespace XCOFF { // Constants used in the XCOFF definition. -enum { NameSize = 8 }; +enum { FileNamePadSize = 6, NameSize = 8, SymbolTableEntrySize = 18 }; + enum ReservedSectionNum { N_DEBUG = -2, N_ABS = -1, N_UNDEF = 0 }; // x_smclas field of x_csect from system header: /usr/include/syms.h /// Storage Mapping Class definitions. -enum StorageMappingClass { +enum StorageMappingClass : uint8_t { // READ ONLY CLASSES XMC_PR = 0, ///< Program Code XMC_RO = 1, ///< Read Only Constant @@ -170,6 +171,24 @@ int32_t Flags; }; +enum CFileStringType : uint8_t { + XFT_FN = 0, ///< Specifies the source-file name. + XFT_CT = 1, ///< Specifies the compiler time stamp. + XFT_CV = 2, ///< Specifies the compiler version number. + XFT_CD = 128 ///< Specifies compiler-defined information. +}; + +enum CFileLangId : uint8_t { + TB_C = 0, ///< C language. + TB_CPLUSPLUS = 9 ///< C++ language. +}; + +enum CFileCpuId : uint8_t { + TCPU_PPC64 = 2, ///< PowerPC common architecture 64-bit mode. + TCPU_COM = 3, ///< POWER and PowerPC architecture common. + TCPU_970 = 19 ///< PPC970 - PowerPC 64-bit architecture. +}; + } // end namespace XCOFF } // end namespace llvm diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -112,6 +112,38 @@ const char *Data; }; +struct XCOFFCsectAuxEnt32 { + support::ubig32_t SectionLen; + support::ubig32_t ParameterHashIndex; + support::ubig16_t TypeChkSectNum; + uint8_t SymbolAlignmentAndType; + XCOFF::StorageMappingClass StorageMappingClass; + support::ubig32_t StabInfoIndex; + support::ubig16_t StabSectNum; +}; + +struct XCOFFFileAuxEnt { + typedef struct { + support::big32_t Magic; // Zero indicates name in string table. + support::ubig32_t Offset; + char NamePad[XCOFF::FileNamePadSize]; + } NameInStrTblType; + union { + char Name[XCOFF::NameSize + XCOFF::FileNamePadSize]; + NameInStrTblType NameInStrTbl; + }; + XCOFF::CFileStringType Type; + uint8_t ReservedZeros[2]; + uint8_t AuxType; // 64-bit XCOFF file only. +}; + +struct XCOFFSectAuxEntForStat { + support::ubig32_t SectionLength; + support::ubig16_t NumberOfRelocEnt; + support::ubig16_t NumberOfLineNum; + uint8_t Pad[10]; +}; + class XCOFFObjectFile : public ObjectFile { private: const void *FileHeader = nullptr; @@ -131,18 +163,18 @@ const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; - void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; uintptr_t getSectionHeaderTableAddress() const; + uintptr_t getEndOfSymbolTableAddress() const; // This returns a pointer to the start of the storage for the name field of // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily // null-terminated. const char *getSectionNameInternal(DataRefImpl Sec) const; - int32_t getSectionFlags(DataRefImpl Sec) const; + // This function returns string table entry. + Expected getStringTableEntry(uint32_t Offset) const; static bool isReservedSectionNumber(int16_t SectionNumber); - Expected getSectionByNum(int16_t Num) const; // Constructor and "create" factory function. The constructor is only a thin // wrapper around the base constructor. The "create" function fills out the @@ -160,6 +192,8 @@ friend Expected> ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); + void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; + public: // Interface inherited from base classes. void moveSymbolNext(DataRefImpl &Symb) const override; @@ -238,15 +272,41 @@ uint32_t getLogicalNumberOfSymbolTableEntries32() const; uint32_t getNumberOfSymbolTableEntries64() const; + uint32_t getSymbolIndex(uintptr_t SymEntPtr) const; + Expected getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const; uint16_t getOptionalHeaderSize() const; uint16_t getFlags() const; // Section header table related interfaces. ArrayRef sections32() const; ArrayRef sections64() const; + + int32_t getSectionFlags(DataRefImpl Sec) const; + Expected getSectionByNum(int16_t Num) const; + + void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const; }; // XCOFFObjectFile +class XCOFFSymbolRef { + const DataRefImpl SymEntDataRef; + const XCOFFObjectFile *const OwningObjectPtr; + +public: + XCOFFSymbolRef(DataRefImpl SymEntDataRef, + const XCOFFObjectFile *OwningObjectPtr) + : SymEntDataRef(SymEntDataRef), OwningObjectPtr(OwningObjectPtr){}; + + XCOFF::StorageClass getStorageClass() const; + uint8_t getNumberOfAuxEntries() const; + const XCOFFCsectAuxEnt32 *getXCOFFCsectAuxEnt32() const; + uint16_t getType() const; + int16_t getSectionNumber() const; + + bool hasCsectAuxEnt() const; + bool isFunction() const; +}; + } // namespace object } // namespace llvm diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -17,6 +17,11 @@ namespace llvm { namespace object { +enum { + FUNCTION_SYM = 0x20, + SYM_TYPE_MASK = 0x07 +}; + // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer // 'M'. Returns a pointer to the underlying object on success. template @@ -37,7 +42,7 @@ return reinterpret_cast(in); } -static StringRef generateStringRef(const char *Name) { +static StringRef generateXCOFFFixedNameStringRef(const char *Name) { auto NulCharPtr = static_cast(memchr(Name, '\0', XCOFF::NameSize)); return NulCharPtr ? StringRef(Name, NulCharPtr - Name) @@ -79,6 +84,9 @@ 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(Ref.p); return SymEntPtr; } @@ -108,23 +116,19 @@ 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(SymEntPtr) != getEndOfSymbolTableAddress()) + checkSymbolEntryPointer(reinterpret_cast(SymEntPtr)); +#endif Symb.p = reinterpret_cast(SymEntPtr); } -Expected XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { - const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); - - if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) - return generateStringRef(SymEntPtr->SymbolName); - - // 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 +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. @@ -134,10 +138,32 @@ if (StringTable.Data != nullptr && StringTable.Size > Offset) return (StringTable.Data + Offset); - return make_error("Symbol Name parse failed", + return make_error("Bad offset for string table entry", object_error::parse_failed); } +Expected +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 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 XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { uint64_t Result = 0; llvm_unreachable("Not yet implemented!"); @@ -145,6 +171,7 @@ } uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); return toSymbolEntry(Symb)->Value; } @@ -181,7 +208,7 @@ } Expected XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { - return generateStringRef(getSectionNameInternal(Sec)); + return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec)); } uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { @@ -389,7 +416,8 @@ default: Expected SecRef = getSectionByNum(SectionNum); if (SecRef) - return generateStringRef(getSectionNameInternal(SecRef.get())); + return generateXCOFFFixedNameStringRef( + getSectionNameInternal(SecRef.get())); return SecRef.takeError(); } } @@ -437,6 +465,35 @@ return fileHeader64()->NumberOfSymTableEntries; } +uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const { + uint32_t NumberOfSymTableEntries = + is64Bit() ? getNumberOfSymbolTableEntries64() + : getLogicalNumberOfSymbolTableEntries32(); + return getWithOffset(reinterpret_cast(SymbolTblPtr), + XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries); +} + +void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const { + if (SymbolEntPtr < reinterpret_cast(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(SymbolEntPtr) - + reinterpret_cast(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(SymbolEntPtr) - + reinterpret_cast(SymbolTblPtr)) / + XCOFF::SymbolTableEntrySize; +} + uint16_t XCOFFObjectFile::getFlags() const { return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; } @@ -568,11 +625,77 @@ } StringRef XCOFFSectionHeader32::getName() const { - return generateStringRef(Name); + return generateXCOFFFixedNameStringRef(Name); } StringRef XCOFFSectionHeader64::getName() const { - return generateStringRef(Name); + 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(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 SI = OwningObjectPtr->getSectionByNum(SectNum); + if (!SI) + return false; + + return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT); } } // namespace object diff --git a/llvm/test/tools/llvm-readobj/Inputs/aix_xcoff_xlc_test8.o b/llvm/test/tools/llvm-readobj/Inputs/aix_xcoff_xlc_test8.o new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@ cat test8.c +# +# extern int i; +# extern int TestforXcoff; +# extern int fun(int i); +# static int static_i; +# char* p="abcd"; +# int fun1(int j) { +# static_i++; +# j++; +# j=j+*p; +# return j; +# } +# +# int main() { +# i++; +# fun(i); +# return fun1(i); +# } +# +# > xlc -c test8.c -o aix_xcoff_xlc_test8.o diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -22,6 +22,12 @@ namespace { class XCOFFDumper : public ObjDumper { + enum { + SymbolTypeMask = 0x07, + SymbolAlignmentMask = 0xF8, + SymbolAlignmentBitOffset = 3 + }; + public: XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) : ObjDumper(Writer), Obj(Obj) {} @@ -37,11 +43,14 @@ private: template void printSectionHeaders(ArrayRef Sections); - - const XCOFFObjectFile &Obj; + void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr); + void printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr); + void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); + void printSymbol(const SymbolRef &); // Least significant 3 bits are reserved. static constexpr unsigned SectionFlagsReservedMask = 0x7; + const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -103,8 +112,260 @@ llvm_unreachable("Unimplemented functionality for XCOFFDumper"); } +static const EnumEntry FileStringType[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD) +#undef ECase +}; + +void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) { + if (Obj.is64Bit()) + report_fatal_error( + "Printing for File Auxiliary Entry in 64-bit is unimplemented."); + StringRef FileName = + unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr)); + DictScope SymDs(W, "File Auxiliary Entry"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); + W.printString("Name", FileName); + W.printEnum("Type", static_cast(AuxEntPtr->Type), + makeArrayRef(FileStringType)); +} + +static const EnumEntry CsectStorageMappingClass[] = + { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB), + ECase(XMC_GL), ECase(XMC_XO), ECase(XMC_SV), + ECase(XMC_SV64), ECase(XMC_SV3264), ECase(XMC_TI), + ECase(XMC_TB), ECase(XMC_RW), ECase(XMC_TC0), + ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS), + ECase(XMC_UA), ECase(XMC_BS), ECase(XMC_UC), + ECase(XMC_TL), ECase(XMC_TE) +#undef ECase +}; + +static const EnumEntry CsectSymbolTypeClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM) +#undef ECase +}; + +void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr) { + assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); + + DictScope SymDs(W, "CSECT Auxiliary Entry"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); + if ((AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask) == XCOFF::XTY_LD) + W.printNumber("ContainingCsectSymbolIndex", AuxEntPtr->SectionLen); + else + W.printNumber("SectionLen", AuxEntPtr->SectionLen); + W.printHex("ParameterHashIndex", AuxEntPtr->ParameterHashIndex); + W.printHex("TypeChkSectNum", AuxEntPtr->TypeChkSectNum); + // Print out symbol alignment and type. + W.printNumber("SymbolAlignmentLog2", + (AuxEntPtr->SymbolAlignmentAndType & SymbolAlignmentMask) >> + SymbolAlignmentBitOffset); + W.printEnum("SymbolType", AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask, + makeArrayRef(CsectSymbolTypeClass)); + W.printEnum("StorageMappingClass", + static_cast(AuxEntPtr->StorageMappingClass), + makeArrayRef(CsectStorageMappingClass)); + W.printHex("StabInfoIndex", AuxEntPtr->StabInfoIndex); + W.printHex("StabSectNum", AuxEntPtr->StabSectNum); +} + +void XCOFFDumper::printSectAuxEntForStat( + const XCOFFSectAuxEntForStat *AuxEntPtr) { + assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); + + DictScope SymDs(W, "Sect Auxiliary Entry For Stat"); + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast(AuxEntPtr))); + W.printNumber("SectionLength", AuxEntPtr->SectionLength); + + // Unlike the corresponding fields in the section header, NumberOfRelocEnt + // and NumberOfLineNum do not handle values greater than 65535. + W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt); + W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum); +} + +static const EnumEntry SymStorageClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT), + ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL), + ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU), + ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG), + ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK), + ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE), + ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL), + ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF), + ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM), + ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM), + ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY), + ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS), + ECase(C_STTLS), ECase(C_EFCN) +#undef ECase +}; + +static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { + switch (SC) { + case XCOFF::C_EXT: + case XCOFF::C_WEAKEXT: + case XCOFF::C_HIDEXT: + case XCOFF::C_STAT: + return "Value (RelocatableAddress)"; + case XCOFF::C_FILE: + return "Value (SymbolTableIndex)"; + case XCOFF::C_FCN: + case XCOFF::C_BLOCK: + case XCOFF::C_FUN: + case XCOFF::C_STSYM: + case XCOFF::C_BINCL: + case XCOFF::C_EINCL: + case XCOFF::C_INFO: + case XCOFF::C_BSTAT: + case XCOFF::C_LSYM: + case XCOFF::C_PSYM: + case XCOFF::C_RPSYM: + case XCOFF::C_RSYM: + case XCOFF::C_ECOML: + case XCOFF::C_DWARF: + assert(false && "This StorageClass for the symbol is not yet implemented."); + default: + return "Value"; + } +} + +static const EnumEntry CFileLangIdClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(TB_C), ECase(TB_CPLUSPLUS) +#undef ECase +}; + +static const EnumEntry CFileCpuIdClass[] = { +#define ECase(X) \ + { #X, XCOFF::X } + ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970) +#undef ECase +}; + +void XCOFFDumper::printSymbol(const SymbolRef &S) { + if (Obj.is64Bit()) + report_fatal_error("64-bit support is unimplemented."); + + DataRefImpl SymbolDRI = S.getRawDataRefImpl(); + const XCOFFSymbolEntry *SymbolEntPtr = Obj.toSymbolEntry(SymbolDRI); + + XCOFFSymbolRef XCOFFSymRef(SymbolDRI, &Obj); + uint8_t NumberOfAuxEntries = XCOFFSymRef.getNumberOfAuxEntries(); + + DictScope SymDs(W, "Symbol"); + + StringRef SymbolName = + unwrapOrError(Obj.getFileName(), Obj.getSymbolName(SymbolDRI)); + + W.printNumber("Index", + Obj.getSymbolIndex(reinterpret_cast(SymbolEntPtr))); + W.printString("Name", SymbolName); + W.printHex(GetSymbolValueName(SymbolEntPtr->StorageClass), + SymbolEntPtr->Value); + + StringRef SectionName = + unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntPtr)); + + W.printString("Section", SectionName); + if (XCOFFSymRef.getStorageClass() == XCOFF::C_FILE) { + W.printEnum("Source Language ID", + SymbolEntPtr->CFileLanguageIdAndTypeId.LanguageId, + makeArrayRef(CFileLangIdClass)); + W.printEnum("CPU Version ID", + SymbolEntPtr->CFileLanguageIdAndTypeId.CpuTypeId, + makeArrayRef(CFileCpuIdClass)); + } else + W.printHex("Type", SymbolEntPtr->SymbolType); + + W.printEnum("StorageClass", static_cast(SymbolEntPtr->StorageClass), + makeArrayRef(SymStorageClass)); + W.printNumber("NumberOfAuxEntries", SymbolEntPtr->NumberOfAuxEntries); + + if (NumberOfAuxEntries == 0) + return; + + switch (XCOFFSymRef.getStorageClass()) { + case XCOFF::C_FILE: + // If the symbol is C_FILE and has auxiliary entries... + for (int i = 1; i <= NumberOfAuxEntries; i++) { + const XCOFFFileAuxEnt *FileAuxEntPtr = + reinterpret_cast(SymbolEntPtr + i); +#ifndef NDEBUG + Obj.checkSymbolEntryPointer(reinterpret_cast(FileAuxEntPtr)); +#endif + printFileAuxEnt(FileAuxEntPtr); + } + break; + case XCOFF::C_EXT: + case XCOFF::C_WEAKEXT: + case XCOFF::C_HIDEXT: + // If the symbol is for a function, and it has more than 1 auxiliary entry, + // then one of them must be function auxiliary entry which we do not + // support yet. + if (XCOFFSymRef.isFunction() && NumberOfAuxEntries >= 2) + report_fatal_error("Function auxiliary entry printing is unimplemented."); + + // If there is more than 1 auxiliary entry, instead of printing out + // error information, print out the raw Auxiliary entry from 1st till + // the last - 1. The last one must be a CSECT Auxiliary Entry. + for (int i = 1; i < NumberOfAuxEntries; i++) { + W.startLine() << "!Unexpected raw auxiliary entry data:\n"; + W.startLine() << format_bytes( + ArrayRef(reinterpret_cast(SymbolEntPtr + i), + XCOFF::SymbolTableEntrySize)); + } + + // The symbol's last auxiliary entry is a CSECT Auxiliary Entry. + printCsectAuxEnt32(XCOFFSymRef.getXCOFFCsectAuxEnt32()); + break; + case XCOFF::C_STAT: + if (NumberOfAuxEntries > 1) + report_fatal_error( + "C_STAT symbol should not have more than 1 auxiliary entry."); + + const XCOFFSectAuxEntForStat *StatAuxEntPtr; + StatAuxEntPtr = + reinterpret_cast(SymbolEntPtr + 1); +#ifndef NDEBUG + Obj.checkSymbolEntryPointer(reinterpret_cast(StatAuxEntPtr)); +#endif + printSectAuxEntForStat(StatAuxEntPtr); + break; + case XCOFF::C_DWARF: + case XCOFF::C_BLOCK: + case XCOFF::C_FCN: + report_fatal_error("Symbol table entry printing for this storage class " + "type is unimplemented."); + break; + default: + for (int i = 1; i <= NumberOfAuxEntries; i++) { + W.startLine() << "!Unexpected raw auxiliary entry data:\n"; + W.startLine() << format_bytes( + ArrayRef(reinterpret_cast(SymbolEntPtr + i), + XCOFF::SymbolTableEntrySize)); + } + break; + } +} + void XCOFFDumper::printSymbols() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + ListScope Group(W, "Symbols"); + for (const SymbolRef &S : Obj.symbols()) + printSymbol(S); } void XCOFFDumper::printDynamicSymbols() {