1 //===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- 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/ADT/StringMap.h"
11 #include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
12 #include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
13 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
14 #include "llvm/Object/COFF.h"
15 #include "llvm/ObjectYAML/COFFYAML.h"
16 #include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
17 #include "llvm/Support/ErrorHandling.h"
18 #include "llvm/Support/YAMLTraits.h"
25 const object::COFFObjectFile
&Obj
;
26 COFFYAML::Object YAMLObj
;
28 void dumpOptionalHeader(T OptionalHeader
);
30 void dumpSections(unsigned numSections
);
31 void dumpSymbols(unsigned numSymbols
);
34 COFFDumper(const object::COFFObjectFile
&Obj
);
35 COFFYAML::Object
&getYAMLObj();
40 COFFDumper::COFFDumper(const object::COFFObjectFile
&Obj
) : Obj(Obj
) {
41 if (const object::pe32_header
*PE32Header
= Obj
.getPE32Header())
42 dumpOptionalHeader(PE32Header
);
43 else if (const object::pe32plus_header
*PE32PlusHeader
=
44 Obj
.getPE32PlusHeader())
45 dumpOptionalHeader(PE32PlusHeader
);
48 dumpSections(Obj
.getNumberOfSections());
49 dumpSymbols(Obj
.getNumberOfSymbols());
52 template <typename T
> void COFFDumper::dumpOptionalHeader(T OptionalHeader
) {
53 YAMLObj
.OptionalHeader
= COFFYAML::PEHeader();
54 YAMLObj
.OptionalHeader
->Header
.AddressOfEntryPoint
=
55 OptionalHeader
->AddressOfEntryPoint
;
56 YAMLObj
.OptionalHeader
->Header
.ImageBase
= OptionalHeader
->ImageBase
;
57 YAMLObj
.OptionalHeader
->Header
.SectionAlignment
=
58 OptionalHeader
->SectionAlignment
;
59 YAMLObj
.OptionalHeader
->Header
.FileAlignment
= OptionalHeader
->FileAlignment
;
60 YAMLObj
.OptionalHeader
->Header
.MajorOperatingSystemVersion
=
61 OptionalHeader
->MajorOperatingSystemVersion
;
62 YAMLObj
.OptionalHeader
->Header
.MinorOperatingSystemVersion
=
63 OptionalHeader
->MinorOperatingSystemVersion
;
64 YAMLObj
.OptionalHeader
->Header
.MajorImageVersion
=
65 OptionalHeader
->MajorImageVersion
;
66 YAMLObj
.OptionalHeader
->Header
.MinorImageVersion
=
67 OptionalHeader
->MinorImageVersion
;
68 YAMLObj
.OptionalHeader
->Header
.MajorSubsystemVersion
=
69 OptionalHeader
->MajorSubsystemVersion
;
70 YAMLObj
.OptionalHeader
->Header
.MinorSubsystemVersion
=
71 OptionalHeader
->MinorSubsystemVersion
;
72 YAMLObj
.OptionalHeader
->Header
.Subsystem
= OptionalHeader
->Subsystem
;
73 YAMLObj
.OptionalHeader
->Header
.DLLCharacteristics
=
74 OptionalHeader
->DLLCharacteristics
;
75 YAMLObj
.OptionalHeader
->Header
.SizeOfStackReserve
=
76 OptionalHeader
->SizeOfStackReserve
;
77 YAMLObj
.OptionalHeader
->Header
.SizeOfStackCommit
=
78 OptionalHeader
->SizeOfStackCommit
;
79 YAMLObj
.OptionalHeader
->Header
.SizeOfHeapReserve
=
80 OptionalHeader
->SizeOfHeapReserve
;
81 YAMLObj
.OptionalHeader
->Header
.SizeOfHeapCommit
=
82 OptionalHeader
->SizeOfHeapCommit
;
83 YAMLObj
.OptionalHeader
->Header
.NumberOfRvaAndSize
=
84 OptionalHeader
->NumberOfRvaAndSize
;
86 for (auto &DestDD
: YAMLObj
.OptionalHeader
->DataDirectories
) {
87 const object::data_directory
*DD
= Obj
.getDataDirectory(I
++);
90 DestDD
= COFF::DataDirectory();
91 DestDD
->RelativeVirtualAddress
= DD
->RelativeVirtualAddress
;
92 DestDD
->Size
= DD
->Size
;
96 void COFFDumper::dumpHeader() {
97 YAMLObj
.Header
.Machine
= Obj
.getMachine();
98 YAMLObj
.Header
.Characteristics
= Obj
.getCharacteristics();
102 initializeFileAndStringTable(const llvm::object::COFFObjectFile
&Obj
,
103 codeview::StringsAndChecksumsRef
&SC
) {
105 ExitOnError
Err("invalid .debug$S section");
106 // Iterate all .debug$S sections looking for the checksums and string table.
107 // Exit as soon as both sections are found.
108 for (const auto &S
: Obj
.sections()) {
109 if (SC
.hasStrings() && SC
.hasChecksums())
112 Expected
<StringRef
> SectionNameOrErr
= S
.getName();
113 if (!SectionNameOrErr
) {
114 consumeError(SectionNameOrErr
.takeError());
118 ArrayRef
<uint8_t> sectionData
;
119 if ((*SectionNameOrErr
) != ".debug$S")
122 const object::coff_section
*COFFSection
= Obj
.getCOFFSection(S
);
124 cantFail(Obj
.getSectionContents(COFFSection
, sectionData
));
126 BinaryStreamReader
Reader(sectionData
, llvm::endianness::little
);
129 Err(Reader
.readInteger(Magic
));
130 assert(Magic
== COFF::DEBUG_SECTION_MAGIC
&& "Invalid .debug$S section!");
132 codeview::DebugSubsectionArray Subsections
;
133 Err(Reader
.readArray(Subsections
, Reader
.bytesRemaining()));
135 SC
.initialize(Subsections
);
139 void COFFDumper::dumpSections(unsigned NumSections
) {
140 std::vector
<COFFYAML::Section
> &YAMLSections
= YAMLObj
.Sections
;
141 codeview::StringsAndChecksumsRef SC
;
142 initializeFileAndStringTable(Obj
, SC
);
144 ExitOnError
Err("invalid section table");
145 StringMap
<bool> SymbolUnique
;
146 for (const auto &S
: Obj
.symbols()) {
147 StringRef Name
= Err(Obj
.getSymbolName(Obj
.getCOFFSymbol(S
)));
148 StringMap
<bool>::iterator It
;
150 std::tie(It
, Inserted
) = SymbolUnique
.insert(std::make_pair(Name
, true));
155 for (const auto &ObjSection
: Obj
.sections()) {
156 const object::coff_section
*COFFSection
= Obj
.getCOFFSection(ObjSection
);
157 COFFYAML::Section NewYAMLSection
;
159 if (Expected
<StringRef
> NameOrErr
= ObjSection
.getName())
160 NewYAMLSection
.Name
= *NameOrErr
;
162 consumeError(NameOrErr
.takeError());
164 NewYAMLSection
.Header
.Characteristics
= COFFSection
->Characteristics
;
165 NewYAMLSection
.Header
.VirtualAddress
= COFFSection
->VirtualAddress
;
166 NewYAMLSection
.Header
.VirtualSize
= COFFSection
->VirtualSize
;
167 NewYAMLSection
.Header
.NumberOfLineNumbers
=
168 COFFSection
->NumberOfLinenumbers
;
169 NewYAMLSection
.Header
.NumberOfRelocations
=
170 COFFSection
->NumberOfRelocations
;
171 NewYAMLSection
.Header
.PointerToLineNumbers
=
172 COFFSection
->PointerToLinenumbers
;
173 NewYAMLSection
.Header
.PointerToRawData
= COFFSection
->PointerToRawData
;
174 NewYAMLSection
.Header
.PointerToRelocations
=
175 COFFSection
->PointerToRelocations
;
176 NewYAMLSection
.Header
.SizeOfRawData
= COFFSection
->SizeOfRawData
;
177 uint32_t Shift
= (COFFSection
->Characteristics
>> 20) & 0xF;
178 NewYAMLSection
.Alignment
= (1U << Shift
) >> 1;
179 assert(NewYAMLSection
.Alignment
<= 8192);
181 ArrayRef
<uint8_t> sectionData
;
182 if (!ObjSection
.isBSS())
183 cantFail(Obj
.getSectionContents(COFFSection
, sectionData
));
184 NewYAMLSection
.SectionData
= yaml::BinaryRef(sectionData
);
186 if (NewYAMLSection
.Name
== ".debug$S")
187 NewYAMLSection
.DebugS
= CodeViewYAML::fromDebugS(sectionData
, SC
);
188 else if (NewYAMLSection
.Name
== ".debug$T")
189 NewYAMLSection
.DebugT
= CodeViewYAML::fromDebugT(sectionData
,
190 NewYAMLSection
.Name
);
191 else if (NewYAMLSection
.Name
== ".debug$P")
192 NewYAMLSection
.DebugP
= CodeViewYAML::fromDebugT(sectionData
,
193 NewYAMLSection
.Name
);
194 else if (NewYAMLSection
.Name
== ".debug$H")
195 NewYAMLSection
.DebugH
= CodeViewYAML::fromDebugH(sectionData
);
197 std::vector
<COFFYAML::Relocation
> Relocations
;
198 for (const auto &Reloc
: ObjSection
.relocations()) {
199 const object::coff_relocation
*reloc
= Obj
.getCOFFRelocation(Reloc
);
200 COFFYAML::Relocation Rel
;
201 object::symbol_iterator Sym
= Reloc
.getSymbol();
202 Expected
<StringRef
> SymbolNameOrErr
= Sym
->getName();
203 if (!SymbolNameOrErr
) {
205 raw_string_ostream
OS(Buf
);
206 logAllUnhandledErrors(SymbolNameOrErr
.takeError(), OS
);
207 report_fatal_error(Twine(OS
.str()));
209 if (SymbolUnique
.lookup(*SymbolNameOrErr
))
210 Rel
.SymbolName
= *SymbolNameOrErr
;
212 Rel
.SymbolTableIndex
= reloc
->SymbolTableIndex
;
213 Rel
.VirtualAddress
= reloc
->VirtualAddress
;
214 Rel
.Type
= reloc
->Type
;
215 Relocations
.push_back(Rel
);
217 NewYAMLSection
.Relocations
= Relocations
;
218 YAMLSections
.push_back(NewYAMLSection
);
223 dumpFunctionDefinition(COFFYAML::Symbol
*Sym
,
224 const object::coff_aux_function_definition
*ObjFD
) {
225 COFF::AuxiliaryFunctionDefinition YAMLFD
;
226 YAMLFD
.TagIndex
= ObjFD
->TagIndex
;
227 YAMLFD
.TotalSize
= ObjFD
->TotalSize
;
228 YAMLFD
.PointerToLinenumber
= ObjFD
->PointerToLinenumber
;
229 YAMLFD
.PointerToNextFunction
= ObjFD
->PointerToNextFunction
;
231 Sym
->FunctionDefinition
= YAMLFD
;
235 dumpbfAndEfLineInfo(COFFYAML::Symbol
*Sym
,
236 const object::coff_aux_bf_and_ef_symbol
*ObjBES
) {
237 COFF::AuxiliarybfAndefSymbol YAMLAAS
;
238 YAMLAAS
.Linenumber
= ObjBES
->Linenumber
;
239 YAMLAAS
.PointerToNextFunction
= ObjBES
->PointerToNextFunction
;
241 Sym
->bfAndefSymbol
= YAMLAAS
;
244 static void dumpWeakExternal(COFFYAML::Symbol
*Sym
,
245 const object::coff_aux_weak_external
*ObjWE
) {
246 COFF::AuxiliaryWeakExternal YAMLWE
;
247 YAMLWE
.TagIndex
= ObjWE
->TagIndex
;
248 YAMLWE
.Characteristics
= ObjWE
->Characteristics
;
250 Sym
->WeakExternal
= YAMLWE
;
254 dumpSectionDefinition(COFFYAML::Symbol
*Sym
,
255 const object::coff_aux_section_definition
*ObjSD
,
257 COFF::AuxiliarySectionDefinition YAMLASD
;
258 int32_t AuxNumber
= ObjSD
->getNumber(IsBigObj
);
259 YAMLASD
.Length
= ObjSD
->Length
;
260 YAMLASD
.NumberOfRelocations
= ObjSD
->NumberOfRelocations
;
261 YAMLASD
.NumberOfLinenumbers
= ObjSD
->NumberOfLinenumbers
;
262 YAMLASD
.CheckSum
= ObjSD
->CheckSum
;
263 YAMLASD
.Number
= AuxNumber
;
264 YAMLASD
.Selection
= ObjSD
->Selection
;
266 Sym
->SectionDefinition
= YAMLASD
;
270 dumpCLRTokenDefinition(COFFYAML::Symbol
*Sym
,
271 const object::coff_aux_clr_token
*ObjCLRToken
) {
272 COFF::AuxiliaryCLRToken YAMLCLRToken
;
273 YAMLCLRToken
.AuxType
= ObjCLRToken
->AuxType
;
274 YAMLCLRToken
.SymbolTableIndex
= ObjCLRToken
->SymbolTableIndex
;
276 Sym
->CLRToken
= YAMLCLRToken
;
279 void COFFDumper::dumpSymbols(unsigned NumSymbols
) {
280 ExitOnError
Err("invalid symbol table");
282 std::vector
<COFFYAML::Symbol
> &Symbols
= YAMLObj
.Symbols
;
283 for (const auto &S
: Obj
.symbols()) {
284 object::COFFSymbolRef Symbol
= Obj
.getCOFFSymbol(S
);
285 COFFYAML::Symbol Sym
;
286 Sym
.Name
= Err(Obj
.getSymbolName(Symbol
));
287 Sym
.SimpleType
= COFF::SymbolBaseType(Symbol
.getBaseType());
288 Sym
.ComplexType
= COFF::SymbolComplexType(Symbol
.getComplexType());
289 Sym
.Header
.StorageClass
= Symbol
.getStorageClass();
290 Sym
.Header
.Value
= Symbol
.getValue();
291 Sym
.Header
.SectionNumber
= Symbol
.getSectionNumber();
292 Sym
.Header
.NumberOfAuxSymbols
= Symbol
.getNumberOfAuxSymbols();
294 if (Symbol
.getNumberOfAuxSymbols() > 0) {
295 ArrayRef
<uint8_t> AuxData
= Obj
.getSymbolAuxData(Symbol
);
296 if (Symbol
.isFunctionDefinition()) {
297 // This symbol represents a function definition.
298 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
299 "Expected a single aux symbol to describe this function!");
301 const object::coff_aux_function_definition
*ObjFD
=
302 reinterpret_cast<const object::coff_aux_function_definition
*>(
304 dumpFunctionDefinition(&Sym
, ObjFD
);
305 } else if (Symbol
.isFunctionLineInfo()) {
306 // This symbol describes function line number information.
307 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
308 "Expected a single aux symbol to describe this function!");
310 const object::coff_aux_bf_and_ef_symbol
*ObjBES
=
311 reinterpret_cast<const object::coff_aux_bf_and_ef_symbol
*>(
313 dumpbfAndEfLineInfo(&Sym
, ObjBES
);
314 } else if (Symbol
.isAnyUndefined()) {
315 // This symbol represents a weak external definition.
316 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
317 "Expected a single aux symbol to describe this weak symbol!");
319 const object::coff_aux_weak_external
*ObjWE
=
320 reinterpret_cast<const object::coff_aux_weak_external
*>(
322 dumpWeakExternal(&Sym
, ObjWE
);
323 } else if (Symbol
.isFileRecord()) {
324 // This symbol represents a file record.
325 Sym
.File
= StringRef(reinterpret_cast<const char *>(AuxData
.data()),
326 Symbol
.getNumberOfAuxSymbols() *
327 Obj
.getSymbolTableEntrySize())
328 .rtrim(StringRef("\0", /*length=*/1));
329 } else if (Symbol
.isSectionDefinition()) {
330 // This symbol represents a section definition.
331 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
332 "Expected a single aux symbol to describe this section!");
334 const object::coff_aux_section_definition
*ObjSD
=
335 reinterpret_cast<const object::coff_aux_section_definition
*>(
337 dumpSectionDefinition(&Sym
, ObjSD
, Symbol
.isBigObj());
338 } else if (Symbol
.isCLRToken()) {
339 // This symbol represents a CLR token definition.
340 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
341 "Expected a single aux symbol to describe this CLR Token!");
343 const object::coff_aux_clr_token
*ObjCLRToken
=
344 reinterpret_cast<const object::coff_aux_clr_token
*>(
346 dumpCLRTokenDefinition(&Sym
, ObjCLRToken
);
348 llvm_unreachable("Unhandled auxiliary symbol!");
351 Symbols
.push_back(Sym
);
355 COFFYAML::Object
&COFFDumper::getYAMLObj() {
359 std::error_code
coff2yaml(raw_ostream
&Out
, const object::COFFObjectFile
&Obj
) {
360 COFFDumper
Dumper(Obj
);
362 yaml::Output
Yout(Out
);
363 Yout
<< Dumper
.getYAMLObj();
365 return std::error_code();