llvm-project/llvm/tools/obj2yaml/xcoff2yaml.cpp
stephenpeckham 5aeabf2df9
[XCOFF][obj2yaml] Support SymbolAlignmentAndType as 2 separate fields in YAML. (#76828)
XCOFF encodes a symbol type and alignment in a single 8-bit field. It is
easier to read and write YAML files if the fields can be specified
separately. This PR causes obj2yaml to write the fields separately and
allows yaml2obj to read either the single combined field or the separate
fields.
2024-02-08 10:44:19 -06:00

409 lines
15 KiB
C++

//===------ 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.SymbolAlignment = AuxEntPtr.getAlignmentLog2();
CsectAuxSym.SymbolType =
static_cast<XCOFF::SymbolType>(AuxEntPtr.getSymbolType());
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();
}