//===------ xcoff2yaml.cpp - XCOFF YAMLIO implementation --------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "obj2yaml.h" #include "llvm/Object/XCOFFObjectFile.h" #include "llvm/ObjectYAML/XCOFFYAML.h" #include "llvm/Support/Errc.h" #include "llvm/Support/YAMLTraits.h" using namespace llvm; using namespace llvm::object; namespace { class XCOFFDumper { const object::XCOFFObjectFile &Obj; XCOFFYAML::Object YAMLObj; void dumpHeader(); Error dumpSections(); Error dumpSymbols(); template Error dumpSections(ArrayRef Sections); // Dump auxiliary symbols. Error dumpFileAuxSym(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef); Error dumpStatAuxSym(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef); Error dumpBlockAuxSym(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef); Error dumpDwarfAuxSym(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef); Error dumpAuxSyms(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef); void dumpFuncAuxSym(XCOFFYAML::Symbol &Sym, const uintptr_t AuxAddress); void dumpExpAuxSym(XCOFFYAML::Symbol &Sym, const uintptr_t AuxAddress); void dumpCsectAuxSym(XCOFFYAML::Symbol &Sym, const object::XCOFFCsectAuxRef &AuxEntPtr); public: XCOFFDumper(const object::XCOFFObjectFile &obj) : Obj(obj) {} Error dump(); XCOFFYAML::Object &getYAMLObj() { return YAMLObj; } template const T *getAuxEntPtr(uintptr_t AuxAddress) { Obj.checkSymbolEntryPointer(AuxAddress); return reinterpret_cast(AuxAddress); } }; } // namespace Error XCOFFDumper::dump() { dumpHeader(); if (Error E = dumpSections()) return E; return dumpSymbols(); } void XCOFFDumper::dumpHeader() { YAMLObj.Header.Magic = Obj.getMagic(); YAMLObj.Header.NumberOfSections = Obj.getNumberOfSections(); YAMLObj.Header.TimeStamp = Obj.getTimeStamp(); YAMLObj.Header.SymbolTableOffset = Obj.is64Bit() ? Obj.getSymbolTableOffset64() : Obj.getSymbolTableOffset32(); YAMLObj.Header.NumberOfSymTableEntries = Obj.is64Bit() ? Obj.getNumberOfSymbolTableEntries64() : Obj.getRawNumberOfSymbolTableEntries32(); YAMLObj.Header.AuxHeaderSize = Obj.getOptionalHeaderSize(); YAMLObj.Header.Flags = Obj.getFlags(); } Error XCOFFDumper::dumpSections() { if (Obj.is64Bit()) return dumpSections( Obj.sections64()); return dumpSections( Obj.sections32()); } template Error XCOFFDumper::dumpSections(ArrayRef Sections) { std::vector &YamlSections = YAMLObj.Sections; for (const Shdr &S : Sections) { XCOFFYAML::Section YamlSec; YamlSec.SectionName = S.getName(); YamlSec.Address = S.PhysicalAddress; YamlSec.Size = S.SectionSize; YamlSec.NumberOfRelocations = S.NumberOfRelocations; YamlSec.NumberOfLineNumbers = S.NumberOfLineNumbers; YamlSec.FileOffsetToData = S.FileOffsetToRawData; YamlSec.FileOffsetToRelocations = S.FileOffsetToRelocationInfo; YamlSec.FileOffsetToLineNumbers = S.FileOffsetToLineNumberInfo; YamlSec.Flags = S.Flags; if (YamlSec.Flags & XCOFF::STYP_DWARF) { unsigned Mask = Obj.is64Bit() ? XCOFFSectionHeader64::SectionFlagsTypeMask : XCOFFSectionHeader32::SectionFlagsTypeMask; YamlSec.SectionSubtype = static_cast(S.Flags & ~Mask); } // Dump section data. if (S.FileOffsetToRawData) { DataRefImpl SectionDRI; SectionDRI.p = reinterpret_cast(&S); Expected> SecDataRefOrErr = Obj.getSectionContents(SectionDRI); if (!SecDataRefOrErr) return SecDataRefOrErr.takeError(); YamlSec.SectionData = SecDataRefOrErr.get(); } // Dump relocations. if (S.NumberOfRelocations) { auto RelRefOrErr = Obj.relocations(S); if (!RelRefOrErr) return RelRefOrErr.takeError(); for (const Reloc &R : RelRefOrErr.get()) { XCOFFYAML::Relocation YamlRel; YamlRel.Type = R.Type; YamlRel.Info = R.Info; YamlRel.SymbolIndex = R.SymbolIndex; YamlRel.VirtualAddress = R.VirtualAddress; YamlSec.Relocations.push_back(YamlRel); } } YamlSections.push_back(YamlSec); } return Error::success(); } Error XCOFFDumper::dumpFileAuxSym(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef) { for (uint8_t I = 1; I <= Sym.NumberOfAuxEntries; ++I) { uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), I); const XCOFFFileAuxEnt *FileAuxEntPtr = getAuxEntPtr(AuxAddress); auto FileNameOrError = Obj.getCFileName(FileAuxEntPtr); if (!FileNameOrError) return FileNameOrError.takeError(); XCOFFYAML::FileAuxEnt FileAuxSym; FileAuxSym.FileNameOrString = FileNameOrError.get(); FileAuxSym.FileStringType = FileAuxEntPtr->Type; Sym.AuxEntries.push_back( std::make_unique(FileAuxSym)); } return Error::success(); } Error XCOFFDumper::dumpStatAuxSym(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef) { if (Sym.NumberOfAuxEntries != 1) { uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress()); return createError("failed to parse symbol \"" + Sym.SymbolName + "\" with index of " + Twine(SymbolIndex) + ": expected 1 aux symbol for C_STAT, while got " + Twine(static_cast(*Sym.NumberOfAuxEntries))); } const XCOFFSectAuxEntForStat *AuxEntPtr = getAuxEntPtr( XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), 1)); XCOFFYAML::SectAuxEntForStat StatAuxSym; StatAuxSym.SectionLength = AuxEntPtr->SectionLength; StatAuxSym.NumberOfLineNum = AuxEntPtr->NumberOfLineNum; StatAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt; Sym.AuxEntries.push_back( std::make_unique(StatAuxSym)); return Error::success(); } void XCOFFDumper::dumpFuncAuxSym(XCOFFYAML::Symbol &Sym, const uintptr_t AuxAddress) { XCOFFYAML::FunctionAuxEnt FunAuxSym; if (Obj.is64Bit()) { const XCOFFFunctionAuxEnt64 *AuxEntPtr = getAuxEntPtr(AuxAddress); FunAuxSym.PtrToLineNum = AuxEntPtr->PtrToLineNum; FunAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction; FunAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond; } else { const XCOFFFunctionAuxEnt32 *AuxEntPtr = getAuxEntPtr(AuxAddress); FunAuxSym.OffsetToExceptionTbl = AuxEntPtr->OffsetToExceptionTbl; FunAuxSym.PtrToLineNum = AuxEntPtr->PtrToLineNum; FunAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction; FunAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond; } Sym.AuxEntries.push_back( std::make_unique(FunAuxSym)); } void XCOFFDumper::dumpExpAuxSym(XCOFFYAML::Symbol &Sym, const uintptr_t AuxAddress) { const XCOFFExceptionAuxEnt *AuxEntPtr = getAuxEntPtr(AuxAddress); XCOFFYAML::ExcpetionAuxEnt ExceptAuxSym; ExceptAuxSym.OffsetToExceptionTbl = AuxEntPtr->OffsetToExceptionTbl; ExceptAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction; ExceptAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond; Sym.AuxEntries.push_back( std::make_unique(ExceptAuxSym)); } void XCOFFDumper::dumpCsectAuxSym(XCOFFYAML::Symbol &Sym, const object::XCOFFCsectAuxRef &AuxEntPtr) { XCOFFYAML::CsectAuxEnt CsectAuxSym; CsectAuxSym.ParameterHashIndex = AuxEntPtr.getParameterHashIndex(); CsectAuxSym.TypeChkSectNum = AuxEntPtr.getTypeChkSectNum(); CsectAuxSym.SymbolAlignment = AuxEntPtr.getAlignmentLog2(); CsectAuxSym.SymbolType = static_cast(AuxEntPtr.getSymbolType()); CsectAuxSym.StorageMappingClass = AuxEntPtr.getStorageMappingClass(); if (Obj.is64Bit()) { CsectAuxSym.SectionOrLengthLo = static_cast(AuxEntPtr.getSectionOrLength64()); CsectAuxSym.SectionOrLengthHi = static_cast(AuxEntPtr.getSectionOrLength64() >> 32); } else { CsectAuxSym.SectionOrLength = AuxEntPtr.getSectionOrLength32(); CsectAuxSym.StabInfoIndex = AuxEntPtr.getStabInfoIndex32(); CsectAuxSym.StabSectNum = AuxEntPtr.getStabSectNum32(); } Sym.AuxEntries.push_back( std::make_unique(CsectAuxSym)); } Error XCOFFDumper::dumpAuxSyms(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef) { auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef(); if (!ErrOrCsectAuxRef) return ErrOrCsectAuxRef.takeError(); XCOFFCsectAuxRef CsectAuxRef = ErrOrCsectAuxRef.get(); for (uint8_t I = 1; I <= Sym.NumberOfAuxEntries; ++I) { if (I == Sym.NumberOfAuxEntries && !Obj.is64Bit()) { dumpCsectAuxSym(Sym, CsectAuxRef); return Error::success(); } uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), I); if (Obj.is64Bit()) { XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress); if (Type == XCOFF::SymbolAuxType::AUX_CSECT) dumpCsectAuxSym(Sym, CsectAuxRef); else if (Type == XCOFF::SymbolAuxType::AUX_FCN) dumpFuncAuxSym(Sym, AuxAddress); else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT) dumpExpAuxSym(Sym, AuxAddress); else { uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress()); return createError("failed to parse symbol \"" + Sym.SymbolName + "\" with index of " + Twine(SymbolIndex) + ": invalid auxiliary symbol type: " + Twine(static_cast(Type))); } } else dumpFuncAuxSym(Sym, AuxAddress); } return Error::success(); } Error XCOFFDumper::dumpBlockAuxSym(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef) { if (Sym.NumberOfAuxEntries != 1) { uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress()); return createError( "failed to parse symbol \"" + Sym.SymbolName + "\" with index of " + Twine(SymbolIndex) + ": expected 1 aux symbol for C_BLOCK or C_FCN, while got " + Twine(static_cast(*Sym.NumberOfAuxEntries))); } uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), 1); XCOFFYAML::BlockAuxEnt BlockAuxSym; if (Obj.is64Bit()) { const XCOFFBlockAuxEnt64 *AuxEntPtr = getAuxEntPtr(AuxAddress); BlockAuxSym.LineNum = AuxEntPtr->LineNum; } else { const XCOFFBlockAuxEnt32 *AuxEntPtr = getAuxEntPtr(AuxAddress); BlockAuxSym.LineNumLo = AuxEntPtr->LineNumLo; BlockAuxSym.LineNumHi = AuxEntPtr->LineNumHi; } Sym.AuxEntries.push_back( std::make_unique(BlockAuxSym)); return Error::success(); } Error XCOFFDumper::dumpDwarfAuxSym(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef) { if (Sym.NumberOfAuxEntries != 1) { uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress()); return createError("failed to parse symbol \"" + Sym.SymbolName + "\" with index of " + Twine(SymbolIndex) + ": expected 1 aux symbol for C_DWARF, while got " + Twine(static_cast(*Sym.NumberOfAuxEntries))); } uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( SymbolEntRef.getEntryAddress(), 1); XCOFFYAML::SectAuxEntForDWARF DwarfAuxSym; if (Obj.is64Bit()) { const XCOFFSectAuxEntForDWARF64 *AuxEntPtr = getAuxEntPtr(AuxAddress); DwarfAuxSym.LengthOfSectionPortion = AuxEntPtr->LengthOfSectionPortion; DwarfAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt; } else { const XCOFFSectAuxEntForDWARF32 *AuxEntPtr = getAuxEntPtr(AuxAddress); DwarfAuxSym.LengthOfSectionPortion = AuxEntPtr->LengthOfSectionPortion; DwarfAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt; } Sym.AuxEntries.push_back( std::make_unique(DwarfAuxSym)); return Error::success(); } Error XCOFFDumper::dumpSymbols() { std::vector &Symbols = YAMLObj.Symbols; for (const SymbolRef &S : Obj.symbols()) { DataRefImpl SymbolDRI = S.getRawDataRefImpl(); const XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI); XCOFFYAML::Symbol Sym; Expected SymNameRefOrErr = Obj.getSymbolName(SymbolDRI); if (!SymNameRefOrErr) { return SymNameRefOrErr.takeError(); } Sym.SymbolName = SymNameRefOrErr.get(); Sym.Value = SymbolEntRef.getValue(); Expected SectionNameRefOrErr = Obj.getSymbolSectionName(SymbolEntRef); if (!SectionNameRefOrErr) return SectionNameRefOrErr.takeError(); Sym.SectionName = SectionNameRefOrErr.get(); Sym.Type = SymbolEntRef.getSymbolType(); Sym.StorageClass = SymbolEntRef.getStorageClass(); Sym.NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries(); if (Sym.NumberOfAuxEntries) { switch (Sym.StorageClass) { case XCOFF::C_FILE: if (Error E = dumpFileAuxSym(Sym, SymbolEntRef)) return E; break; case XCOFF::C_STAT: if (Error E = dumpStatAuxSym(Sym, SymbolEntRef)) return E; break; case XCOFF::C_EXT: case XCOFF::C_WEAKEXT: case XCOFF::C_HIDEXT: if (Error E = dumpAuxSyms(Sym, SymbolEntRef)) return E; break; case XCOFF::C_BLOCK: case XCOFF::C_FCN: if (Error E = dumpBlockAuxSym(Sym, SymbolEntRef)) return E; break; case XCOFF::C_DWARF: if (Error E = dumpDwarfAuxSym(Sym, SymbolEntRef)) return E; break; default: break; } } Symbols.push_back(std::move(Sym)); } return Error::success(); } Error xcoff2yaml(raw_ostream &Out, const object::XCOFFObjectFile &Obj) { XCOFFDumper Dumper(Obj); if (Error E = Dumper.dump()) return E; yaml::Output Yout(Out); Yout << Dumper.getYAMLObj(); return Error::success(); }