| //===------ 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 <typename Shdr, typename Reloc> | 
 |   Error dumpSections(ArrayRef<Shdr> 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 <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress) { | 
 |     Obj.checkSymbolEntryPointer(AuxAddress); | 
 |     return reinterpret_cast<const T *>(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<XCOFFSectionHeader64, XCOFFRelocation64>( | 
 |         Obj.sections64()); | 
 |   return dumpSections<XCOFFSectionHeader32, XCOFFRelocation32>( | 
 |       Obj.sections32()); | 
 | } | 
 |  | 
 | template <typename Shdr, typename Reloc> | 
 | Error XCOFFDumper::dumpSections(ArrayRef<Shdr> Sections) { | 
 |   std::vector<XCOFFYAML::Section> &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; | 
 |  | 
 |     // Dump section data. | 
 |     if (S.FileOffsetToRawData) { | 
 |       DataRefImpl SectionDRI; | 
 |       SectionDRI.p = reinterpret_cast<uintptr_t>(&S); | 
 |       Expected<ArrayRef<uint8_t>> SecDataRefOrErr = | 
 |           Obj.getSectionContents(SectionDRI); | 
 |       if (!SecDataRefOrErr) | 
 |         return SecDataRefOrErr.takeError(); | 
 |       YamlSec.SectionData = SecDataRefOrErr.get(); | 
 |     } | 
 |  | 
 |     // Dump relocations. | 
 |     if (S.NumberOfRelocations) { | 
 |       auto RelRefOrErr = Obj.relocations<Shdr, Reloc>(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<XCOFFFileAuxEnt>(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<XCOFFYAML::FileAuxEnt>(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<uint32_t>(*Sym.NumberOfAuxEntries))); | 
 |   } | 
 |  | 
 |   const XCOFFSectAuxEntForStat *AuxEntPtr = | 
 |       getAuxEntPtr<XCOFFSectAuxEntForStat>( | 
 |           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<XCOFFYAML::SectAuxEntForStat>(StatAuxSym)); | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | void XCOFFDumper::dumpFuncAuxSym(XCOFFYAML::Symbol &Sym, | 
 |                                  const uintptr_t AuxAddress) { | 
 |   XCOFFYAML::FunctionAuxEnt FunAuxSym; | 
 |  | 
 |   if (Obj.is64Bit()) { | 
 |     const XCOFFFunctionAuxEnt64 *AuxEntPtr = | 
 |         getAuxEntPtr<XCOFFFunctionAuxEnt64>(AuxAddress); | 
 |     FunAuxSym.PtrToLineNum = AuxEntPtr->PtrToLineNum; | 
 |     FunAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction; | 
 |     FunAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond; | 
 |   } else { | 
 |     const XCOFFFunctionAuxEnt32 *AuxEntPtr = | 
 |         getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress); | 
 |     FunAuxSym.OffsetToExceptionTbl = AuxEntPtr->OffsetToExceptionTbl; | 
 |     FunAuxSym.PtrToLineNum = AuxEntPtr->PtrToLineNum; | 
 |     FunAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction; | 
 |     FunAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond; | 
 |   } | 
 |  | 
 |   Sym.AuxEntries.push_back( | 
 |       std::make_unique<XCOFFYAML::FunctionAuxEnt>(FunAuxSym)); | 
 | } | 
 |  | 
 | void XCOFFDumper::dumpExpAuxSym(XCOFFYAML::Symbol &Sym, | 
 |                                 const uintptr_t AuxAddress) { | 
 |   const XCOFFExceptionAuxEnt *AuxEntPtr = | 
 |       getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress); | 
 |   XCOFFYAML::ExcpetionAuxEnt ExceptAuxSym; | 
 |   ExceptAuxSym.OffsetToExceptionTbl = AuxEntPtr->OffsetToExceptionTbl; | 
 |   ExceptAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction; | 
 |   ExceptAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond; | 
 |   Sym.AuxEntries.push_back( | 
 |       std::make_unique<XCOFFYAML::ExcpetionAuxEnt>(ExceptAuxSym)); | 
 | } | 
 |  | 
 | void XCOFFDumper::dumpCsectAuxSym(XCOFFYAML::Symbol &Sym, | 
 |                                   const object::XCOFFCsectAuxRef &AuxEntPtr) { | 
 |   XCOFFYAML::CsectAuxEnt CsectAuxSym; | 
 |   CsectAuxSym.ParameterHashIndex = AuxEntPtr.getParameterHashIndex(); | 
 |   CsectAuxSym.TypeChkSectNum = AuxEntPtr.getTypeChkSectNum(); | 
 |   CsectAuxSym.SymbolAlignmentAndType = AuxEntPtr.getSymbolAlignmentAndType(); | 
 |   CsectAuxSym.StorageMappingClass = AuxEntPtr.getStorageMappingClass(); | 
 |  | 
 |   if (Obj.is64Bit()) { | 
 |     CsectAuxSym.SectionOrLengthLo = | 
 |         static_cast<uint32_t>(AuxEntPtr.getSectionOrLength64()); | 
 |     CsectAuxSym.SectionOrLengthHi = | 
 |         static_cast<uint32_t>(AuxEntPtr.getSectionOrLength64() >> 32); | 
 |   } else { | 
 |     CsectAuxSym.SectionOrLength = AuxEntPtr.getSectionOrLength32(); | 
 |     CsectAuxSym.StabInfoIndex = AuxEntPtr.getStabInfoIndex32(); | 
 |     CsectAuxSym.StabSectNum = AuxEntPtr.getStabSectNum32(); | 
 |   } | 
 |  | 
 |   Sym.AuxEntries.push_back( | 
 |       std::make_unique<XCOFFYAML::CsectAuxEnt>(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<uint32_t>(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<uint32_t>(*Sym.NumberOfAuxEntries))); | 
 |   } | 
 |  | 
 |   uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( | 
 |       SymbolEntRef.getEntryAddress(), 1); | 
 |   XCOFFYAML::BlockAuxEnt BlockAuxSym; | 
 |  | 
 |   if (Obj.is64Bit()) { | 
 |     const XCOFFBlockAuxEnt64 *AuxEntPtr = | 
 |         getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress); | 
 |     BlockAuxSym.LineNum = AuxEntPtr->LineNum; | 
 |   } else { | 
 |     const XCOFFBlockAuxEnt32 *AuxEntPtr = | 
 |         getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress); | 
 |     BlockAuxSym.LineNumLo = AuxEntPtr->LineNumLo; | 
 |     BlockAuxSym.LineNumHi = AuxEntPtr->LineNumHi; | 
 |   } | 
 |  | 
 |   Sym.AuxEntries.push_back( | 
 |       std::make_unique<XCOFFYAML::BlockAuxEnt>(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<uint32_t>(*Sym.NumberOfAuxEntries))); | 
 |   } | 
 |  | 
 |   uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( | 
 |       SymbolEntRef.getEntryAddress(), 1); | 
 |   XCOFFYAML::SectAuxEntForDWARF DwarfAuxSym; | 
 |  | 
 |   if (Obj.is64Bit()) { | 
 |     const XCOFFSectAuxEntForDWARF64 *AuxEntPtr = | 
 |         getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress); | 
 |     DwarfAuxSym.LengthOfSectionPortion = AuxEntPtr->LengthOfSectionPortion; | 
 |     DwarfAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt; | 
 |   } else { | 
 |     const XCOFFSectAuxEntForDWARF32 *AuxEntPtr = | 
 |         getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress); | 
 |     DwarfAuxSym.LengthOfSectionPortion = AuxEntPtr->LengthOfSectionPortion; | 
 |     DwarfAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt; | 
 |   } | 
 |  | 
 |   Sym.AuxEntries.push_back( | 
 |       std::make_unique<XCOFFYAML::SectAuxEntForDWARF>(DwarfAuxSym)); | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | Error XCOFFDumper::dumpSymbols() { | 
 |   std::vector<XCOFFYAML::Symbol> &Symbols = YAMLObj.Symbols; | 
 |  | 
 |   for (const SymbolRef &S : Obj.symbols()) { | 
 |     DataRefImpl SymbolDRI = S.getRawDataRefImpl(); | 
 |     const XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI); | 
 |     XCOFFYAML::Symbol Sym; | 
 |  | 
 |     Expected<StringRef> SymNameRefOrErr = Obj.getSymbolName(SymbolDRI); | 
 |     if (!SymNameRefOrErr) { | 
 |       return SymNameRefOrErr.takeError(); | 
 |     } | 
 |     Sym.SymbolName = SymNameRefOrErr.get(); | 
 |  | 
 |     Sym.Value = SymbolEntRef.getValue(); | 
 |  | 
 |     Expected<StringRef> 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(); | 
 | } |