1 //===------ xcoff2yaml.cpp - XCOFF YAMLIO implementation --------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 #include "llvm/Object/XCOFFObjectFile.h"
11 #include "llvm/ObjectYAML/XCOFFYAML.h"
12 #include "llvm/Support/Errc.h"
13 #include "llvm/Support/YAMLTraits.h"
16 using namespace llvm::object
;
20 const object::XCOFFObjectFile
&Obj
;
21 XCOFFYAML::Object YAMLObj
;
25 template <typename Shdr
, typename Reloc
>
26 Error
dumpSections(ArrayRef
<Shdr
> Sections
);
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 dumpCscetAuxSym(XCOFFYAML::Symbol
&Sym
,
41 const object::XCOFFCsectAuxRef
&AuxEntPtr
);
44 XCOFFDumper(const object::XCOFFObjectFile
&obj
) : Obj(obj
) {}
46 XCOFFYAML::Object
&getYAMLObj() { return YAMLObj
; }
48 template <typename T
> const T
*getAuxEntPtr(uintptr_t AuxAddress
) {
49 Obj
.checkSymbolEntryPointer(AuxAddress
);
50 return reinterpret_cast<const T
*>(AuxAddress
);
55 Error
XCOFFDumper::dump() {
57 if (Error E
= dumpSections())
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();
76 Error
XCOFFDumper::dumpSections() {
78 return dumpSections
<XCOFFSectionHeader64
, XCOFFRelocation64
>(
80 return dumpSections
<XCOFFSectionHeader32
, XCOFFRelocation32
>(
84 template <typename Shdr
, typename Reloc
>
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
;
100 if (S
.FileOffsetToRawData
) {
101 DataRefImpl SectionDRI
;
102 SectionDRI
.p
= reinterpret_cast<uintptr_t>(&S
);
103 Expected
<ArrayRef
<uint8_t>> SecDataRefOrErr
=
104 Obj
.getSectionContents(SectionDRI
);
105 if (!SecDataRefOrErr
)
106 return SecDataRefOrErr
.takeError();
107 YamlSec
.SectionData
= SecDataRefOrErr
.get();
111 if (S
.NumberOfRelocations
) {
112 auto RelRefOrErr
= Obj
.relocations
<Shdr
, Reloc
>(S
);
114 return RelRefOrErr
.takeError();
115 for (const Reloc
&R
: RelRefOrErr
.get()) {
116 XCOFFYAML::Relocation YamlRel
;
117 YamlRel
.Type
= R
.Type
;
118 YamlRel
.Info
= R
.Info
;
119 YamlRel
.SymbolIndex
= R
.SymbolIndex
;
120 YamlRel
.VirtualAddress
= R
.VirtualAddress
;
121 YamlSec
.Relocations
.push_back(YamlRel
);
124 YamlSections
.push_back(YamlSec
);
126 return Error::success();
129 Error
XCOFFDumper::dumpFileAuxSym(XCOFFYAML::Symbol
&Sym
,
130 const XCOFFSymbolRef
&SymbolEntRef
) {
131 for (uint8_t I
= 1; I
<= Sym
.NumberOfAuxEntries
; ++I
) {
132 uintptr_t AuxAddress
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
133 SymbolEntRef
.getEntryAddress(), I
);
134 const XCOFFFileAuxEnt
*FileAuxEntPtr
=
135 getAuxEntPtr
<XCOFFFileAuxEnt
>(AuxAddress
);
136 auto FileNameOrError
= Obj
.getCFileName(FileAuxEntPtr
);
137 if (!FileNameOrError
)
138 return FileNameOrError
.takeError();
140 XCOFFYAML::FileAuxEnt FileAuxSym
;
141 FileAuxSym
.FileNameOrString
= FileNameOrError
.get();
142 FileAuxSym
.FileStringType
= FileAuxEntPtr
->Type
;
143 Sym
.AuxEntries
.push_back(
144 std::make_unique
<XCOFFYAML::FileAuxEnt
>(FileAuxSym
));
146 return Error::success();
149 Error
XCOFFDumper::dumpStatAuxSym(XCOFFYAML::Symbol
&Sym
,
150 const XCOFFSymbolRef
&SymbolEntRef
) {
151 if (Sym
.NumberOfAuxEntries
!= 1) {
152 uint32_t SymbolIndex
= Obj
.getSymbolIndex(SymbolEntRef
.getEntryAddress());
153 return createError("failed to parse symbol \"" + Sym
.SymbolName
+
154 "\" with index of " + Twine(SymbolIndex
) +
155 ": expected 1 aux symbol for C_STAT, while got " +
156 Twine(static_cast<uint32_t>(*Sym
.NumberOfAuxEntries
)));
159 const XCOFFSectAuxEntForStat
*AuxEntPtr
=
160 getAuxEntPtr
<XCOFFSectAuxEntForStat
>(
161 XCOFFObjectFile::getAdvancedSymbolEntryAddress(
162 SymbolEntRef
.getEntryAddress(), 1));
163 XCOFFYAML::SectAuxEntForStat StatAuxSym
;
164 StatAuxSym
.SectionLength
= AuxEntPtr
->SectionLength
;
165 StatAuxSym
.NumberOfLineNum
= AuxEntPtr
->NumberOfLineNum
;
166 StatAuxSym
.NumberOfRelocEnt
= AuxEntPtr
->NumberOfRelocEnt
;
167 Sym
.AuxEntries
.push_back(
168 std::make_unique
<XCOFFYAML::SectAuxEntForStat
>(StatAuxSym
));
169 return Error::success();
172 void XCOFFDumper::dumpFuncAuxSym(XCOFFYAML::Symbol
&Sym
,
173 const uintptr_t AuxAddress
) {
174 XCOFFYAML::FunctionAuxEnt FunAuxSym
;
177 const XCOFFFunctionAuxEnt64
*AuxEntPtr
=
178 getAuxEntPtr
<XCOFFFunctionAuxEnt64
>(AuxAddress
);
179 FunAuxSym
.PtrToLineNum
= AuxEntPtr
->PtrToLineNum
;
180 FunAuxSym
.SizeOfFunction
= AuxEntPtr
->SizeOfFunction
;
181 FunAuxSym
.SymIdxOfNextBeyond
= AuxEntPtr
->SymIdxOfNextBeyond
;
183 const XCOFFFunctionAuxEnt32
*AuxEntPtr
=
184 getAuxEntPtr
<XCOFFFunctionAuxEnt32
>(AuxAddress
);
185 FunAuxSym
.OffsetToExceptionTbl
= AuxEntPtr
->OffsetToExceptionTbl
;
186 FunAuxSym
.PtrToLineNum
= AuxEntPtr
->PtrToLineNum
;
187 FunAuxSym
.SizeOfFunction
= AuxEntPtr
->SizeOfFunction
;
188 FunAuxSym
.SymIdxOfNextBeyond
= AuxEntPtr
->SymIdxOfNextBeyond
;
191 Sym
.AuxEntries
.push_back(
192 std::make_unique
<XCOFFYAML::FunctionAuxEnt
>(FunAuxSym
));
195 void XCOFFDumper::dumpExpAuxSym(XCOFFYAML::Symbol
&Sym
,
196 const uintptr_t AuxAddress
) {
197 const XCOFFExceptionAuxEnt
*AuxEntPtr
=
198 getAuxEntPtr
<XCOFFExceptionAuxEnt
>(AuxAddress
);
199 XCOFFYAML::ExcpetionAuxEnt ExceptAuxSym
;
200 ExceptAuxSym
.OffsetToExceptionTbl
= AuxEntPtr
->OffsetToExceptionTbl
;
201 ExceptAuxSym
.SizeOfFunction
= AuxEntPtr
->SizeOfFunction
;
202 ExceptAuxSym
.SymIdxOfNextBeyond
= AuxEntPtr
->SymIdxOfNextBeyond
;
203 Sym
.AuxEntries
.push_back(
204 std::make_unique
<XCOFFYAML::ExcpetionAuxEnt
>(ExceptAuxSym
));
207 void XCOFFDumper::dumpCscetAuxSym(XCOFFYAML::Symbol
&Sym
,
208 const object::XCOFFCsectAuxRef
&AuxEntPtr
) {
209 XCOFFYAML::CsectAuxEnt CsectAuxSym
;
210 CsectAuxSym
.ParameterHashIndex
= AuxEntPtr
.getParameterHashIndex();
211 CsectAuxSym
.TypeChkSectNum
= AuxEntPtr
.getTypeChkSectNum();
212 CsectAuxSym
.SymbolAlignmentAndType
= AuxEntPtr
.getSymbolAlignmentAndType();
213 CsectAuxSym
.StorageMappingClass
= AuxEntPtr
.getStorageMappingClass();
216 CsectAuxSym
.SectionOrLengthLo
=
217 static_cast<uint32_t>(AuxEntPtr
.getSectionOrLength64());
218 CsectAuxSym
.SectionOrLengthHi
=
219 static_cast<uint32_t>(AuxEntPtr
.getSectionOrLength64() >> 32);
221 CsectAuxSym
.SectionOrLength
= AuxEntPtr
.getSectionOrLength32();
222 CsectAuxSym
.StabInfoIndex
= AuxEntPtr
.getStabInfoIndex32();
223 CsectAuxSym
.StabSectNum
= AuxEntPtr
.getStabSectNum32();
226 Sym
.AuxEntries
.push_back(
227 std::make_unique
<XCOFFYAML::CsectAuxEnt
>(CsectAuxSym
));
230 Error
XCOFFDumper::dumpAuxSyms(XCOFFYAML::Symbol
&Sym
,
231 const XCOFFSymbolRef
&SymbolEntRef
) {
232 auto ErrOrCsectAuxRef
= SymbolEntRef
.getXCOFFCsectAuxRef();
233 if (!ErrOrCsectAuxRef
)
234 return ErrOrCsectAuxRef
.takeError();
235 XCOFFCsectAuxRef CsectAuxRef
= ErrOrCsectAuxRef
.get();
237 for (uint8_t I
= 1; I
<= Sym
.NumberOfAuxEntries
; ++I
) {
239 if (I
== Sym
.NumberOfAuxEntries
&& !Obj
.is64Bit()) {
240 dumpCscetAuxSym(Sym
, CsectAuxRef
);
241 return Error::success();
244 uintptr_t AuxAddress
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
245 SymbolEntRef
.getEntryAddress(), I
);
248 XCOFF::SymbolAuxType Type
= *Obj
.getSymbolAuxType(AuxAddress
);
249 if (Type
== XCOFF::SymbolAuxType::AUX_CSECT
)
250 dumpCscetAuxSym(Sym
, CsectAuxRef
);
251 else if (Type
== XCOFF::SymbolAuxType::AUX_FCN
)
252 dumpFuncAuxSym(Sym
, AuxAddress
);
253 else if (Type
== XCOFF::SymbolAuxType::AUX_EXCEPT
)
254 dumpExpAuxSym(Sym
, AuxAddress
);
256 uint32_t SymbolIndex
=
257 Obj
.getSymbolIndex(SymbolEntRef
.getEntryAddress());
258 return createError("failed to parse symbol \"" + Sym
.SymbolName
+
259 "\" with index of " + Twine(SymbolIndex
) +
260 ": invalid auxiliary symbol type: " +
261 Twine(static_cast<uint32_t>(Type
)));
265 dumpFuncAuxSym(Sym
, AuxAddress
);
268 return Error::success();
271 Error
XCOFFDumper::dumpBlockAuxSym(XCOFFYAML::Symbol
&Sym
,
272 const XCOFFSymbolRef
&SymbolEntRef
) {
273 if (Sym
.NumberOfAuxEntries
!= 1) {
274 uint32_t SymbolIndex
= Obj
.getSymbolIndex(SymbolEntRef
.getEntryAddress());
276 "failed to parse symbol \"" + Sym
.SymbolName
+ "\" with index of " +
278 ": expected 1 aux symbol for C_BLOCK or C_FCN, while got " +
279 Twine(static_cast<uint32_t>(*Sym
.NumberOfAuxEntries
)));
282 uintptr_t AuxAddress
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
283 SymbolEntRef
.getEntryAddress(), 1);
284 XCOFFYAML::BlockAuxEnt BlockAuxSym
;
287 const XCOFFBlockAuxEnt64
*AuxEntPtr
=
288 getAuxEntPtr
<XCOFFBlockAuxEnt64
>(AuxAddress
);
289 BlockAuxSym
.LineNum
= AuxEntPtr
->LineNum
;
291 const XCOFFBlockAuxEnt32
*AuxEntPtr
=
292 getAuxEntPtr
<XCOFFBlockAuxEnt32
>(AuxAddress
);
293 BlockAuxSym
.LineNumLo
= AuxEntPtr
->LineNumLo
;
294 BlockAuxSym
.LineNumHi
= AuxEntPtr
->LineNumHi
;
297 Sym
.AuxEntries
.push_back(
298 std::make_unique
<XCOFFYAML::BlockAuxEnt
>(BlockAuxSym
));
299 return Error::success();
302 Error
XCOFFDumper::dumpDwarfAuxSym(XCOFFYAML::Symbol
&Sym
,
303 const XCOFFSymbolRef
&SymbolEntRef
) {
304 if (Sym
.NumberOfAuxEntries
!= 1) {
305 uint32_t SymbolIndex
= Obj
.getSymbolIndex(SymbolEntRef
.getEntryAddress());
306 return createError("failed to parse symbol \"" + Sym
.SymbolName
+
307 "\" with index of " + Twine(SymbolIndex
) +
308 ": expected 1 aux symbol for C_DWARF, while got " +
309 Twine(static_cast<uint32_t>(*Sym
.NumberOfAuxEntries
)));
312 uintptr_t AuxAddress
= XCOFFObjectFile::getAdvancedSymbolEntryAddress(
313 SymbolEntRef
.getEntryAddress(), 1);
314 XCOFFYAML::SectAuxEntForDWARF DwarfAuxSym
;
317 const XCOFFSectAuxEntForDWARF64
*AuxEntPtr
=
318 getAuxEntPtr
<XCOFFSectAuxEntForDWARF64
>(AuxAddress
);
319 DwarfAuxSym
.LengthOfSectionPortion
= AuxEntPtr
->LengthOfSectionPortion
;
320 DwarfAuxSym
.NumberOfRelocEnt
= AuxEntPtr
->NumberOfRelocEnt
;
322 const XCOFFSectAuxEntForDWARF32
*AuxEntPtr
=
323 getAuxEntPtr
<XCOFFSectAuxEntForDWARF32
>(AuxAddress
);
324 DwarfAuxSym
.LengthOfSectionPortion
= AuxEntPtr
->LengthOfSectionPortion
;
325 DwarfAuxSym
.NumberOfRelocEnt
= AuxEntPtr
->NumberOfRelocEnt
;
328 Sym
.AuxEntries
.push_back(
329 std::make_unique
<XCOFFYAML::SectAuxEntForDWARF
>(DwarfAuxSym
));
330 return Error::success();
333 Error
XCOFFDumper::dumpSymbols() {
334 std::vector
<XCOFFYAML::Symbol
> &Symbols
= YAMLObj
.Symbols
;
336 for (const SymbolRef
&S
: Obj
.symbols()) {
337 DataRefImpl SymbolDRI
= S
.getRawDataRefImpl();
338 const XCOFFSymbolRef SymbolEntRef
= Obj
.toSymbolRef(SymbolDRI
);
339 XCOFFYAML::Symbol Sym
;
341 Expected
<StringRef
> SymNameRefOrErr
= Obj
.getSymbolName(SymbolDRI
);
342 if (!SymNameRefOrErr
) {
343 return SymNameRefOrErr
.takeError();
345 Sym
.SymbolName
= SymNameRefOrErr
.get();
347 Sym
.Value
= SymbolEntRef
.getValue();
349 Expected
<StringRef
> SectionNameRefOrErr
=
350 Obj
.getSymbolSectionName(SymbolEntRef
);
351 if (!SectionNameRefOrErr
)
352 return SectionNameRefOrErr
.takeError();
354 Sym
.SectionName
= SectionNameRefOrErr
.get();
356 Sym
.Type
= SymbolEntRef
.getSymbolType();
357 Sym
.StorageClass
= SymbolEntRef
.getStorageClass();
358 Sym
.NumberOfAuxEntries
= SymbolEntRef
.getNumberOfAuxEntries();
360 if (Sym
.NumberOfAuxEntries
) {
361 switch (Sym
.StorageClass
) {
363 if (Error E
= dumpFileAuxSym(Sym
, SymbolEntRef
))
367 if (Error E
= dumpStatAuxSym(Sym
, SymbolEntRef
))
371 case XCOFF::C_WEAKEXT
:
372 case XCOFF::C_HIDEXT
:
373 if (Error E
= dumpAuxSyms(Sym
, SymbolEntRef
))
378 if (Error E
= dumpBlockAuxSym(Sym
, SymbolEntRef
))
382 if (Error E
= dumpDwarfAuxSym(Sym
, SymbolEntRef
))
390 Symbols
.push_back(std::move(Sym
));
393 return Error::success();
396 Error
xcoff2yaml(raw_ostream
&Out
, const object::XCOFFObjectFile
&Obj
) {
397 XCOFFDumper
Dumper(Obj
);
399 if (Error E
= Dumper
.dump())
402 yaml::Output
Yout(Out
);
403 Yout
<< Dumper
.getYAMLObj();
405 return Error::success();