xref: /llvm-project/llvm/tools/obj2yaml/xcoff2yaml.cpp (revision 26db845536aa4ada6231873a01252c75637fcbae)
1 //===------ xcoff2yaml.cpp - XCOFF YAMLIO implementation --------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "obj2yaml.h"
10 #include "llvm/Object/XCOFFObjectFile.h"
11 #include "llvm/ObjectYAML/XCOFFYAML.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/YAMLTraits.h"
14 
15 using namespace llvm;
16 using namespace llvm::object;
17 namespace {
18 
19 class XCOFFDumper {
20   const object::XCOFFObjectFile &Obj;
21   XCOFFYAML::Object YAMLObj;
22   void dumpHeader();
23   Error dumpSections();
24   Error dumpSymbols();
25   template <typename Shdr, typename Reloc>
26   Error dumpSections(ArrayRef<Shdr> Sections);
27 
28   // Dump auxiliary symbols.
29   Error dumpFileAuxSym(XCOFFYAML::Symbol &Sym,
30                        const XCOFFSymbolRef &SymbolEntRef);
31   Error dumpStatAuxSym(XCOFFYAML::Symbol &Sym,
32                        const XCOFFSymbolRef &SymbolEntRef);
33   Error dumpBlockAuxSym(XCOFFYAML::Symbol &Sym,
34                         const XCOFFSymbolRef &SymbolEntRef);
35   Error dumpDwarfAuxSym(XCOFFYAML::Symbol &Sym,
36                         const XCOFFSymbolRef &SymbolEntRef);
37   Error dumpAuxSyms(XCOFFYAML::Symbol &Sym, const XCOFFSymbolRef &SymbolEntRef);
38   void dumpFuncAuxSym(XCOFFYAML::Symbol &Sym, const uintptr_t AuxAddress);
39   void dumpExpAuxSym(XCOFFYAML::Symbol &Sym, const uintptr_t AuxAddress);
40   void dumpCsectAuxSym(XCOFFYAML::Symbol &Sym,
41                        const object::XCOFFCsectAuxRef &AuxEntPtr);
42 
43 public:
XCOFFDumper(const object::XCOFFObjectFile & obj)44   XCOFFDumper(const object::XCOFFObjectFile &obj) : Obj(obj) {}
45   Error dump();
getYAMLObj()46   XCOFFYAML::Object &getYAMLObj() { return YAMLObj; }
47 
getAuxEntPtr(uintptr_t AuxAddress)48   template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress) {
49     Obj.checkSymbolEntryPointer(AuxAddress);
50     return reinterpret_cast<const T *>(AuxAddress);
51   }
52 };
53 } // namespace
54 
dump()55 Error XCOFFDumper::dump() {
56   dumpHeader();
57   if (Error E = dumpSections())
58     return E;
59   return dumpSymbols();
60 }
61 
dumpHeader()62 void XCOFFDumper::dumpHeader() {
63   YAMLObj.Header.Magic = Obj.getMagic();
64   YAMLObj.Header.NumberOfSections = Obj.getNumberOfSections();
65   YAMLObj.Header.TimeStamp = Obj.getTimeStamp();
66   YAMLObj.Header.SymbolTableOffset = Obj.is64Bit()
67                                          ? Obj.getSymbolTableOffset64()
68                                          : Obj.getSymbolTableOffset32();
69   YAMLObj.Header.NumberOfSymTableEntries =
70       Obj.is64Bit() ? Obj.getNumberOfSymbolTableEntries64()
71                     : Obj.getRawNumberOfSymbolTableEntries32();
72   YAMLObj.Header.AuxHeaderSize = Obj.getOptionalHeaderSize();
73   YAMLObj.Header.Flags = Obj.getFlags();
74 }
75 
dumpSections()76 Error XCOFFDumper::dumpSections() {
77   if (Obj.is64Bit())
78     return dumpSections<XCOFFSectionHeader64, XCOFFRelocation64>(
79         Obj.sections64());
80   return dumpSections<XCOFFSectionHeader32, XCOFFRelocation32>(
81       Obj.sections32());
82 }
83 
84 template <typename Shdr, typename Reloc>
dumpSections(ArrayRef<Shdr> Sections)85 Error XCOFFDumper::dumpSections(ArrayRef<Shdr> Sections) {
86   std::vector<XCOFFYAML::Section> &YamlSections = YAMLObj.Sections;
87   for (const Shdr &S : Sections) {
88     XCOFFYAML::Section YamlSec;
89     YamlSec.SectionName = S.getName();
90     YamlSec.Address = S.PhysicalAddress;
91     YamlSec.Size = S.SectionSize;
92     YamlSec.NumberOfRelocations = S.NumberOfRelocations;
93     YamlSec.NumberOfLineNumbers = S.NumberOfLineNumbers;
94     YamlSec.FileOffsetToData = S.FileOffsetToRawData;
95     YamlSec.FileOffsetToRelocations = S.FileOffsetToRelocationInfo;
96     YamlSec.FileOffsetToLineNumbers = S.FileOffsetToLineNumberInfo;
97     YamlSec.Flags = S.Flags;
98     if (YamlSec.Flags & XCOFF::STYP_DWARF) {
99       unsigned Mask = Obj.is64Bit()
100                           ? XCOFFSectionHeader64::SectionFlagsTypeMask
101                           : XCOFFSectionHeader32::SectionFlagsTypeMask;
102       YamlSec.SectionSubtype =
103           static_cast<XCOFF::DwarfSectionSubtypeFlags>(S.Flags & ~Mask);
104     }
105 
106     // Dump section data.
107     if (S.FileOffsetToRawData) {
108       DataRefImpl SectionDRI;
109       SectionDRI.p = reinterpret_cast<uintptr_t>(&S);
110       Expected<ArrayRef<uint8_t>> SecDataRefOrErr =
111           Obj.getSectionContents(SectionDRI);
112       if (!SecDataRefOrErr)
113         return SecDataRefOrErr.takeError();
114       YamlSec.SectionData = SecDataRefOrErr.get();
115     }
116 
117     // Dump relocations.
118     if (S.NumberOfRelocations) {
119       auto RelRefOrErr = Obj.relocations<Shdr, Reloc>(S);
120       if (!RelRefOrErr)
121         return RelRefOrErr.takeError();
122       for (const Reloc &R : RelRefOrErr.get()) {
123         XCOFFYAML::Relocation YamlRel;
124         YamlRel.Type = R.Type;
125         YamlRel.Info = R.Info;
126         YamlRel.SymbolIndex = R.SymbolIndex;
127         YamlRel.VirtualAddress = R.VirtualAddress;
128         YamlSec.Relocations.push_back(YamlRel);
129       }
130     }
131     YamlSections.push_back(YamlSec);
132   }
133   return Error::success();
134 }
135 
dumpFileAuxSym(XCOFFYAML::Symbol & Sym,const XCOFFSymbolRef & SymbolEntRef)136 Error XCOFFDumper::dumpFileAuxSym(XCOFFYAML::Symbol &Sym,
137                                   const XCOFFSymbolRef &SymbolEntRef) {
138   for (uint8_t I = 1; I <= Sym.NumberOfAuxEntries; ++I) {
139     uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
140         SymbolEntRef.getEntryAddress(), I);
141     const XCOFFFileAuxEnt *FileAuxEntPtr =
142         getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
143     auto FileNameOrError = Obj.getCFileName(FileAuxEntPtr);
144     if (!FileNameOrError)
145       return FileNameOrError.takeError();
146 
147     XCOFFYAML::FileAuxEnt FileAuxSym;
148     FileAuxSym.FileNameOrString = FileNameOrError.get();
149     FileAuxSym.FileStringType = FileAuxEntPtr->Type;
150     Sym.AuxEntries.push_back(
151         std::make_unique<XCOFFYAML::FileAuxEnt>(FileAuxSym));
152   }
153   return Error::success();
154 }
155 
dumpStatAuxSym(XCOFFYAML::Symbol & Sym,const XCOFFSymbolRef & SymbolEntRef)156 Error XCOFFDumper::dumpStatAuxSym(XCOFFYAML::Symbol &Sym,
157                                   const XCOFFSymbolRef &SymbolEntRef) {
158   if (Sym.NumberOfAuxEntries != 1) {
159     uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
160     return createError("failed to parse symbol \"" + Sym.SymbolName +
161                        "\" with index of " + Twine(SymbolIndex) +
162                        ": expected 1 aux symbol for C_STAT, while got " +
163                        Twine(static_cast<uint32_t>(*Sym.NumberOfAuxEntries)));
164   }
165 
166   const XCOFFSectAuxEntForStat *AuxEntPtr =
167       getAuxEntPtr<XCOFFSectAuxEntForStat>(
168           XCOFFObjectFile::getAdvancedSymbolEntryAddress(
169               SymbolEntRef.getEntryAddress(), 1));
170   XCOFFYAML::SectAuxEntForStat StatAuxSym;
171   StatAuxSym.SectionLength = AuxEntPtr->SectionLength;
172   StatAuxSym.NumberOfLineNum = AuxEntPtr->NumberOfLineNum;
173   StatAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt;
174   Sym.AuxEntries.push_back(
175       std::make_unique<XCOFFYAML::SectAuxEntForStat>(StatAuxSym));
176   return Error::success();
177 }
178 
dumpFuncAuxSym(XCOFFYAML::Symbol & Sym,const uintptr_t AuxAddress)179 void XCOFFDumper::dumpFuncAuxSym(XCOFFYAML::Symbol &Sym,
180                                  const uintptr_t AuxAddress) {
181   XCOFFYAML::FunctionAuxEnt FunAuxSym;
182 
183   if (Obj.is64Bit()) {
184     const XCOFFFunctionAuxEnt64 *AuxEntPtr =
185         getAuxEntPtr<XCOFFFunctionAuxEnt64>(AuxAddress);
186     FunAuxSym.PtrToLineNum = AuxEntPtr->PtrToLineNum;
187     FunAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction;
188     FunAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond;
189   } else {
190     const XCOFFFunctionAuxEnt32 *AuxEntPtr =
191         getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress);
192     FunAuxSym.OffsetToExceptionTbl = AuxEntPtr->OffsetToExceptionTbl;
193     FunAuxSym.PtrToLineNum = AuxEntPtr->PtrToLineNum;
194     FunAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction;
195     FunAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond;
196   }
197 
198   Sym.AuxEntries.push_back(
199       std::make_unique<XCOFFYAML::FunctionAuxEnt>(FunAuxSym));
200 }
201 
dumpExpAuxSym(XCOFFYAML::Symbol & Sym,const uintptr_t AuxAddress)202 void XCOFFDumper::dumpExpAuxSym(XCOFFYAML::Symbol &Sym,
203                                 const uintptr_t AuxAddress) {
204   const XCOFFExceptionAuxEnt *AuxEntPtr =
205       getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress);
206   XCOFFYAML::ExcpetionAuxEnt ExceptAuxSym;
207   ExceptAuxSym.OffsetToExceptionTbl = AuxEntPtr->OffsetToExceptionTbl;
208   ExceptAuxSym.SizeOfFunction = AuxEntPtr->SizeOfFunction;
209   ExceptAuxSym.SymIdxOfNextBeyond = AuxEntPtr->SymIdxOfNextBeyond;
210   Sym.AuxEntries.push_back(
211       std::make_unique<XCOFFYAML::ExcpetionAuxEnt>(ExceptAuxSym));
212 }
213 
dumpCsectAuxSym(XCOFFYAML::Symbol & Sym,const object::XCOFFCsectAuxRef & AuxEntPtr)214 void XCOFFDumper::dumpCsectAuxSym(XCOFFYAML::Symbol &Sym,
215                                   const object::XCOFFCsectAuxRef &AuxEntPtr) {
216   XCOFFYAML::CsectAuxEnt CsectAuxSym;
217   CsectAuxSym.ParameterHashIndex = AuxEntPtr.getParameterHashIndex();
218   CsectAuxSym.TypeChkSectNum = AuxEntPtr.getTypeChkSectNum();
219   CsectAuxSym.SymbolAlignment = AuxEntPtr.getAlignmentLog2();
220   CsectAuxSym.SymbolType =
221       static_cast<XCOFF::SymbolType>(AuxEntPtr.getSymbolType());
222   CsectAuxSym.StorageMappingClass = AuxEntPtr.getStorageMappingClass();
223 
224   if (Obj.is64Bit()) {
225     CsectAuxSym.SectionOrLengthLo =
226         static_cast<uint32_t>(AuxEntPtr.getSectionOrLength64());
227     CsectAuxSym.SectionOrLengthHi =
228         static_cast<uint32_t>(AuxEntPtr.getSectionOrLength64() >> 32);
229   } else {
230     CsectAuxSym.SectionOrLength = AuxEntPtr.getSectionOrLength32();
231     CsectAuxSym.StabInfoIndex = AuxEntPtr.getStabInfoIndex32();
232     CsectAuxSym.StabSectNum = AuxEntPtr.getStabSectNum32();
233   }
234 
235   Sym.AuxEntries.push_back(
236       std::make_unique<XCOFFYAML::CsectAuxEnt>(CsectAuxSym));
237 }
238 
dumpAuxSyms(XCOFFYAML::Symbol & Sym,const XCOFFSymbolRef & SymbolEntRef)239 Error XCOFFDumper::dumpAuxSyms(XCOFFYAML::Symbol &Sym,
240                                const XCOFFSymbolRef &SymbolEntRef) {
241   auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef();
242   if (!ErrOrCsectAuxRef)
243     return ErrOrCsectAuxRef.takeError();
244   XCOFFCsectAuxRef CsectAuxRef = ErrOrCsectAuxRef.get();
245 
246   for (uint8_t I = 1; I <= Sym.NumberOfAuxEntries; ++I) {
247 
248     if (I == Sym.NumberOfAuxEntries && !Obj.is64Bit()) {
249       dumpCsectAuxSym(Sym, CsectAuxRef);
250       return Error::success();
251     }
252 
253     uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
254         SymbolEntRef.getEntryAddress(), I);
255 
256     if (Obj.is64Bit()) {
257       XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress);
258       if (Type == XCOFF::SymbolAuxType::AUX_CSECT)
259         dumpCsectAuxSym(Sym, CsectAuxRef);
260       else if (Type == XCOFF::SymbolAuxType::AUX_FCN)
261         dumpFuncAuxSym(Sym, AuxAddress);
262       else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT)
263         dumpExpAuxSym(Sym, AuxAddress);
264       else {
265         uint32_t SymbolIndex =
266             Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
267         return createError("failed to parse symbol \"" + Sym.SymbolName +
268                            "\" with index of " + Twine(SymbolIndex) +
269                            ": invalid auxiliary symbol type: " +
270                            Twine(static_cast<uint32_t>(Type)));
271       }
272 
273     } else
274       dumpFuncAuxSym(Sym, AuxAddress);
275   }
276 
277   return Error::success();
278 }
279 
dumpBlockAuxSym(XCOFFYAML::Symbol & Sym,const XCOFFSymbolRef & SymbolEntRef)280 Error XCOFFDumper::dumpBlockAuxSym(XCOFFYAML::Symbol &Sym,
281                                    const XCOFFSymbolRef &SymbolEntRef) {
282   if (Sym.NumberOfAuxEntries != 1) {
283     uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
284     return createError(
285         "failed to parse symbol \"" + Sym.SymbolName + "\" with index of " +
286         Twine(SymbolIndex) +
287         ": expected 1 aux symbol for C_BLOCK or C_FCN, while got " +
288         Twine(static_cast<uint32_t>(*Sym.NumberOfAuxEntries)));
289   }
290 
291   uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
292       SymbolEntRef.getEntryAddress(), 1);
293   XCOFFYAML::BlockAuxEnt BlockAuxSym;
294 
295   if (Obj.is64Bit()) {
296     const XCOFFBlockAuxEnt64 *AuxEntPtr =
297         getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress);
298     BlockAuxSym.LineNum = AuxEntPtr->LineNum;
299   } else {
300     const XCOFFBlockAuxEnt32 *AuxEntPtr =
301         getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress);
302     BlockAuxSym.LineNumLo = AuxEntPtr->LineNumLo;
303     BlockAuxSym.LineNumHi = AuxEntPtr->LineNumHi;
304   }
305 
306   Sym.AuxEntries.push_back(
307       std::make_unique<XCOFFYAML::BlockAuxEnt>(BlockAuxSym));
308   return Error::success();
309 }
310 
dumpDwarfAuxSym(XCOFFYAML::Symbol & Sym,const XCOFFSymbolRef & SymbolEntRef)311 Error XCOFFDumper::dumpDwarfAuxSym(XCOFFYAML::Symbol &Sym,
312                                    const XCOFFSymbolRef &SymbolEntRef) {
313   if (Sym.NumberOfAuxEntries != 1) {
314     uint32_t SymbolIndex = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress());
315     return createError("failed to parse symbol \"" + Sym.SymbolName +
316                        "\" with index of " + Twine(SymbolIndex) +
317                        ": expected 1 aux symbol for C_DWARF, while got " +
318                        Twine(static_cast<uint32_t>(*Sym.NumberOfAuxEntries)));
319   }
320 
321   uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
322       SymbolEntRef.getEntryAddress(), 1);
323   XCOFFYAML::SectAuxEntForDWARF DwarfAuxSym;
324 
325   if (Obj.is64Bit()) {
326     const XCOFFSectAuxEntForDWARF64 *AuxEntPtr =
327         getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress);
328     DwarfAuxSym.LengthOfSectionPortion = AuxEntPtr->LengthOfSectionPortion;
329     DwarfAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt;
330   } else {
331     const XCOFFSectAuxEntForDWARF32 *AuxEntPtr =
332         getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress);
333     DwarfAuxSym.LengthOfSectionPortion = AuxEntPtr->LengthOfSectionPortion;
334     DwarfAuxSym.NumberOfRelocEnt = AuxEntPtr->NumberOfRelocEnt;
335   }
336 
337   Sym.AuxEntries.push_back(
338       std::make_unique<XCOFFYAML::SectAuxEntForDWARF>(DwarfAuxSym));
339   return Error::success();
340 }
341 
dumpSymbols()342 Error XCOFFDumper::dumpSymbols() {
343   std::vector<XCOFFYAML::Symbol> &Symbols = YAMLObj.Symbols;
344 
345   for (const SymbolRef &S : Obj.symbols()) {
346     DataRefImpl SymbolDRI = S.getRawDataRefImpl();
347     const XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI);
348     XCOFFYAML::Symbol Sym;
349 
350     Expected<StringRef> SymNameRefOrErr = Obj.getSymbolName(SymbolDRI);
351     if (!SymNameRefOrErr) {
352       return SymNameRefOrErr.takeError();
353     }
354     Sym.SymbolName = SymNameRefOrErr.get();
355 
356     Sym.Value = SymbolEntRef.getValue();
357 
358     Expected<StringRef> SectionNameRefOrErr =
359         Obj.getSymbolSectionName(SymbolEntRef);
360     if (!SectionNameRefOrErr)
361       return SectionNameRefOrErr.takeError();
362 
363     Sym.SectionName = SectionNameRefOrErr.get();
364 
365     Sym.Type = SymbolEntRef.getSymbolType();
366     Sym.StorageClass = SymbolEntRef.getStorageClass();
367     Sym.NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries();
368 
369     if (Sym.NumberOfAuxEntries) {
370       switch (Sym.StorageClass) {
371       case XCOFF::C_FILE:
372         if (Error E = dumpFileAuxSym(Sym, SymbolEntRef))
373           return E;
374         break;
375       case XCOFF::C_STAT:
376         if (Error E = dumpStatAuxSym(Sym, SymbolEntRef))
377           return E;
378         break;
379       case XCOFF::C_EXT:
380       case XCOFF::C_WEAKEXT:
381       case XCOFF::C_HIDEXT:
382         if (Error E = dumpAuxSyms(Sym, SymbolEntRef))
383           return E;
384         break;
385       case XCOFF::C_BLOCK:
386       case XCOFF::C_FCN:
387         if (Error E = dumpBlockAuxSym(Sym, SymbolEntRef))
388           return E;
389         break;
390       case XCOFF::C_DWARF:
391         if (Error E = dumpDwarfAuxSym(Sym, SymbolEntRef))
392           return E;
393         break;
394       default:
395         break;
396       }
397     }
398 
399     Symbols.push_back(std::move(Sym));
400   }
401 
402   return Error::success();
403 }
404 
xcoff2yaml(raw_ostream & Out,const object::XCOFFObjectFile & Obj)405 Error xcoff2yaml(raw_ostream &Out, const object::XCOFFObjectFile &Obj) {
406   XCOFFDumper Dumper(Obj);
407 
408   if (Error E = Dumper.dump())
409     return E;
410 
411   yaml::Output Yout(Out);
412   Yout << Dumper.getYAMLObj();
413 
414   return Error::success();
415 }
416