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
15using namespace llvm;
16using namespace llvm::object;
17namespace {
18
19class 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
43public:
44 XCOFFDumper(const object::XCOFFObjectFile &obj) : Obj(obj) {}
45 Error dump();
46 XCOFFYAML::Object &getYAMLObj() { return YAMLObj; }
47
48 template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress) {
49 Obj.checkSymbolEntryPointer(SymbolEntPtr: AuxAddress);
50 return reinterpret_cast<const T *>(AuxAddress);
51 }
52};
53} // namespace
54
55Error XCOFFDumper::dump() {
56 dumpHeader();
57 if (Error E = dumpSections())
58 return E;
59 return dumpSymbols();
60}
61
62void 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
76Error XCOFFDumper::dumpSections() {
77 if (Obj.is64Bit())
78 return dumpSections<XCOFFSectionHeader64, XCOFFRelocation64>(
79 Sections: Obj.sections64());
80 return dumpSections<XCOFFSectionHeader32, XCOFFRelocation32>(
81 Sections: Obj.sections32());
82}
83
84template <typename Shdr, typename Reloc>
85Error 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(Sec: 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(x: YamlRel);
129 }
130 }
131 YamlSections.push_back(x: YamlSec);
132 }
133 return Error::success();
134}
135
136Error 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 CurrentAddress: SymbolEntRef.getEntryAddress(), Distance: I);
141 const XCOFFFileAuxEnt *FileAuxEntPtr =
142 getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress);
143 auto FileNameOrError = Obj.getCFileName(CFileEntPtr: 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 x: std::make_unique<XCOFFYAML::FileAuxEnt>(args&: FileAuxSym));
152 }
153 return Error::success();
154}
155
156Error XCOFFDumper::dumpStatAuxSym(XCOFFYAML::Symbol &Sym,
157 const XCOFFSymbolRef &SymbolEntRef) {
158 if (Sym.NumberOfAuxEntries != 1) {
159 uint32_t SymbolIndex = Obj.getSymbolIndex(SymEntPtr: SymbolEntRef.getEntryAddress());
160 return createError(Err: "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 AuxAddress: XCOFFObjectFile::getAdvancedSymbolEntryAddress(
169 CurrentAddress: SymbolEntRef.getEntryAddress(), Distance: 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 x: std::make_unique<XCOFFYAML::SectAuxEntForStat>(args&: StatAuxSym));
176 return Error::success();
177}
178
179void 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 x: std::make_unique<XCOFFYAML::FunctionAuxEnt>(args&: FunAuxSym));
200}
201
202void 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 x: std::make_unique<XCOFFYAML::ExcpetionAuxEnt>(args&: ExceptAuxSym));
212}
213
214void 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 x: std::make_unique<XCOFFYAML::CsectAuxEnt>(args&: CsectAuxSym));
237}
238
239Error 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, AuxEntPtr: CsectAuxRef);
250 return Error::success();
251 }
252
253 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress(
254 CurrentAddress: SymbolEntRef.getEntryAddress(), Distance: I);
255
256 if (Obj.is64Bit()) {
257 XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxEntryAddress: AuxAddress);
258 if (Type == XCOFF::SymbolAuxType::AUX_CSECT)
259 dumpCsectAuxSym(Sym, AuxEntPtr: 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(SymEntPtr: SymbolEntRef.getEntryAddress());
267 return createError(Err: "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
280Error XCOFFDumper::dumpBlockAuxSym(XCOFFYAML::Symbol &Sym,
281 const XCOFFSymbolRef &SymbolEntRef) {
282 if (Sym.NumberOfAuxEntries != 1) {
283 uint32_t SymbolIndex = Obj.getSymbolIndex(SymEntPtr: SymbolEntRef.getEntryAddress());
284 return createError(
285 Err: "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 CurrentAddress: SymbolEntRef.getEntryAddress(), Distance: 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 x: std::make_unique<XCOFFYAML::BlockAuxEnt>(args&: BlockAuxSym));
308 return Error::success();
309}
310
311Error XCOFFDumper::dumpDwarfAuxSym(XCOFFYAML::Symbol &Sym,
312 const XCOFFSymbolRef &SymbolEntRef) {
313 if (Sym.NumberOfAuxEntries != 1) {
314 uint32_t SymbolIndex = Obj.getSymbolIndex(SymEntPtr: SymbolEntRef.getEntryAddress());
315 return createError(Err: "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 CurrentAddress: SymbolEntRef.getEntryAddress(), Distance: 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 x: std::make_unique<XCOFFYAML::SectAuxEntForDWARF>(args&: DwarfAuxSym));
339 return Error::success();
340}
341
342Error 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(Ref: SymbolDRI);
348 XCOFFYAML::Symbol Sym;
349
350 Expected<StringRef> SymNameRefOrErr = Obj.getSymbolName(Symb: 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(Ref: 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(x: std::move(Sym));
400 }
401
402 return Error::success();
403}
404
405Error 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