1 //===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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/CodeViewYAMLSymbols.h"
17 #include "llvm/ObjectYAML/CodeViewYAMLTypes.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/YAMLTraits.h"
26 const object::COFFObjectFile
&Obj
;
27 COFFYAML::Object YAMLObj
;
29 void dumpOptionalHeader(T OptionalHeader
);
31 void dumpSections(unsigned numSections
);
32 void dumpSymbols(unsigned numSymbols
);
35 COFFDumper(const object::COFFObjectFile
&Obj
);
36 COFFYAML::Object
&getYAMLObj();
41 COFFDumper::COFFDumper(const object::COFFObjectFile
&Obj
) : Obj(Obj
) {
42 const object::pe32_header
*PE32Header
= nullptr;
43 Obj
.getPE32Header(PE32Header
);
45 dumpOptionalHeader(PE32Header
);
47 const object::pe32plus_header
*PE32PlusHeader
= nullptr;
48 Obj
.getPE32PlusHeader(PE32PlusHeader
);
50 dumpOptionalHeader(PE32PlusHeader
);
54 dumpSections(Obj
.getNumberOfSections());
55 dumpSymbols(Obj
.getNumberOfSymbols());
58 template <typename T
> void COFFDumper::dumpOptionalHeader(T OptionalHeader
) {
59 YAMLObj
.OptionalHeader
= COFFYAML::PEHeader();
60 YAMLObj
.OptionalHeader
->Header
.AddressOfEntryPoint
=
61 OptionalHeader
->AddressOfEntryPoint
;
62 YAMLObj
.OptionalHeader
->Header
.AddressOfEntryPoint
=
63 OptionalHeader
->AddressOfEntryPoint
;
64 YAMLObj
.OptionalHeader
->Header
.ImageBase
= OptionalHeader
->ImageBase
;
65 YAMLObj
.OptionalHeader
->Header
.SectionAlignment
=
66 OptionalHeader
->SectionAlignment
;
67 YAMLObj
.OptionalHeader
->Header
.FileAlignment
= OptionalHeader
->FileAlignment
;
68 YAMLObj
.OptionalHeader
->Header
.MajorOperatingSystemVersion
=
69 OptionalHeader
->MajorOperatingSystemVersion
;
70 YAMLObj
.OptionalHeader
->Header
.MinorOperatingSystemVersion
=
71 OptionalHeader
->MinorOperatingSystemVersion
;
72 YAMLObj
.OptionalHeader
->Header
.MajorImageVersion
=
73 OptionalHeader
->MajorImageVersion
;
74 YAMLObj
.OptionalHeader
->Header
.MinorImageVersion
=
75 OptionalHeader
->MinorImageVersion
;
76 YAMLObj
.OptionalHeader
->Header
.MajorSubsystemVersion
=
77 OptionalHeader
->MajorSubsystemVersion
;
78 YAMLObj
.OptionalHeader
->Header
.MinorSubsystemVersion
=
79 OptionalHeader
->MinorSubsystemVersion
;
80 YAMLObj
.OptionalHeader
->Header
.Subsystem
= OptionalHeader
->Subsystem
;
81 YAMLObj
.OptionalHeader
->Header
.DLLCharacteristics
=
82 OptionalHeader
->DLLCharacteristics
;
83 YAMLObj
.OptionalHeader
->Header
.SizeOfStackReserve
=
84 OptionalHeader
->SizeOfStackReserve
;
85 YAMLObj
.OptionalHeader
->Header
.SizeOfStackCommit
=
86 OptionalHeader
->SizeOfStackCommit
;
87 YAMLObj
.OptionalHeader
->Header
.SizeOfHeapReserve
=
88 OptionalHeader
->SizeOfHeapReserve
;
89 YAMLObj
.OptionalHeader
->Header
.SizeOfHeapCommit
=
90 OptionalHeader
->SizeOfHeapCommit
;
92 for (auto &DestDD
: YAMLObj
.OptionalHeader
->DataDirectories
) {
93 const object::data_directory
*DD
;
94 if (Obj
.getDataDirectory(I
++, DD
))
96 DestDD
= COFF::DataDirectory();
97 DestDD
->RelativeVirtualAddress
= DD
->RelativeVirtualAddress
;
98 DestDD
->Size
= DD
->Size
;
102 void COFFDumper::dumpHeader() {
103 YAMLObj
.Header
.Machine
= Obj
.getMachine();
104 YAMLObj
.Header
.Characteristics
= Obj
.getCharacteristics();
108 initializeFileAndStringTable(const llvm::object::COFFObjectFile
&Obj
,
109 codeview::StringsAndChecksumsRef
&SC
) {
111 ExitOnError
Err("Invalid .debug$S section!");
112 // Iterate all .debug$S sections looking for the checksums and string table.
113 // Exit as soon as both sections are found.
114 for (const auto &S
: Obj
.sections()) {
115 if (SC
.hasStrings() && SC
.hasChecksums())
118 StringRef SectionName
;
119 S
.getName(SectionName
);
120 ArrayRef
<uint8_t> sectionData
;
121 if (SectionName
!= ".debug$S")
124 const object::coff_section
*COFFSection
= Obj
.getCOFFSection(S
);
126 Obj
.getSectionContents(COFFSection
, sectionData
);
128 BinaryStreamReader
Reader(sectionData
, support::little
);
131 Err(Reader
.readInteger(Magic
));
132 assert(Magic
== COFF::DEBUG_SECTION_MAGIC
&& "Invalid .debug$S section!");
134 codeview::DebugSubsectionArray Subsections
;
135 Err(Reader
.readArray(Subsections
, Reader
.bytesRemaining()));
137 SC
.initialize(Subsections
);
141 void COFFDumper::dumpSections(unsigned NumSections
) {
142 std::vector
<COFFYAML::Section
> &YAMLSections
= YAMLObj
.Sections
;
143 codeview::StringsAndChecksumsRef SC
;
144 initializeFileAndStringTable(Obj
, SC
);
146 for (const auto &ObjSection
: Obj
.sections()) {
147 const object::coff_section
*COFFSection
= Obj
.getCOFFSection(ObjSection
);
148 COFFYAML::Section NewYAMLSection
;
149 ObjSection
.getName(NewYAMLSection
.Name
);
150 NewYAMLSection
.Header
.Characteristics
= COFFSection
->Characteristics
;
151 NewYAMLSection
.Header
.VirtualAddress
= ObjSection
.getAddress();
152 NewYAMLSection
.Header
.VirtualSize
= COFFSection
->VirtualSize
;
153 NewYAMLSection
.Header
.NumberOfLineNumbers
=
154 COFFSection
->NumberOfLinenumbers
;
155 NewYAMLSection
.Header
.NumberOfRelocations
=
156 COFFSection
->NumberOfRelocations
;
157 NewYAMLSection
.Header
.PointerToLineNumbers
=
158 COFFSection
->PointerToLinenumbers
;
159 NewYAMLSection
.Header
.PointerToRawData
= COFFSection
->PointerToRawData
;
160 NewYAMLSection
.Header
.PointerToRelocations
=
161 COFFSection
->PointerToRelocations
;
162 NewYAMLSection
.Header
.SizeOfRawData
= COFFSection
->SizeOfRawData
;
163 NewYAMLSection
.Alignment
= ObjSection
.getAlignment();
164 assert(NewYAMLSection
.Alignment
<= 8192);
166 ArrayRef
<uint8_t> sectionData
;
167 if (!ObjSection
.isBSS())
168 Obj
.getSectionContents(COFFSection
, sectionData
);
169 NewYAMLSection
.SectionData
= yaml::BinaryRef(sectionData
);
171 if (NewYAMLSection
.Name
== ".debug$S")
172 NewYAMLSection
.DebugS
= CodeViewYAML::fromDebugS(sectionData
, SC
);
173 else if (NewYAMLSection
.Name
== ".debug$T")
174 NewYAMLSection
.DebugT
= CodeViewYAML::fromDebugT(sectionData
);
176 std::vector
<COFFYAML::Relocation
> Relocations
;
177 for (const auto &Reloc
: ObjSection
.relocations()) {
178 const object::coff_relocation
*reloc
= Obj
.getCOFFRelocation(Reloc
);
179 COFFYAML::Relocation Rel
;
180 object::symbol_iterator Sym
= Reloc
.getSymbol();
181 Expected
<StringRef
> SymbolNameOrErr
= Sym
->getName();
182 if (!SymbolNameOrErr
) {
184 raw_string_ostream
OS(Buf
);
185 logAllUnhandledErrors(SymbolNameOrErr
.takeError(), OS
, "");
187 report_fatal_error(Buf
);
189 Rel
.SymbolName
= *SymbolNameOrErr
;
190 Rel
.VirtualAddress
= reloc
->VirtualAddress
;
191 Rel
.Type
= reloc
->Type
;
192 Relocations
.push_back(Rel
);
194 NewYAMLSection
.Relocations
= Relocations
;
195 YAMLSections
.push_back(NewYAMLSection
);
200 dumpFunctionDefinition(COFFYAML::Symbol
*Sym
,
201 const object::coff_aux_function_definition
*ObjFD
) {
202 COFF::AuxiliaryFunctionDefinition YAMLFD
;
203 YAMLFD
.TagIndex
= ObjFD
->TagIndex
;
204 YAMLFD
.TotalSize
= ObjFD
->TotalSize
;
205 YAMLFD
.PointerToLinenumber
= ObjFD
->PointerToLinenumber
;
206 YAMLFD
.PointerToNextFunction
= ObjFD
->PointerToNextFunction
;
208 Sym
->FunctionDefinition
= YAMLFD
;
212 dumpbfAndEfLineInfo(COFFYAML::Symbol
*Sym
,
213 const object::coff_aux_bf_and_ef_symbol
*ObjBES
) {
214 COFF::AuxiliarybfAndefSymbol YAMLAAS
;
215 YAMLAAS
.Linenumber
= ObjBES
->Linenumber
;
216 YAMLAAS
.PointerToNextFunction
= ObjBES
->PointerToNextFunction
;
218 Sym
->bfAndefSymbol
= YAMLAAS
;
221 static void dumpWeakExternal(COFFYAML::Symbol
*Sym
,
222 const object::coff_aux_weak_external
*ObjWE
) {
223 COFF::AuxiliaryWeakExternal YAMLWE
;
224 YAMLWE
.TagIndex
= ObjWE
->TagIndex
;
225 YAMLWE
.Characteristics
= ObjWE
->Characteristics
;
227 Sym
->WeakExternal
= YAMLWE
;
231 dumpSectionDefinition(COFFYAML::Symbol
*Sym
,
232 const object::coff_aux_section_definition
*ObjSD
,
234 COFF::AuxiliarySectionDefinition YAMLASD
;
235 int32_t AuxNumber
= ObjSD
->getNumber(IsBigObj
);
236 YAMLASD
.Length
= ObjSD
->Length
;
237 YAMLASD
.NumberOfRelocations
= ObjSD
->NumberOfRelocations
;
238 YAMLASD
.NumberOfLinenumbers
= ObjSD
->NumberOfLinenumbers
;
239 YAMLASD
.CheckSum
= ObjSD
->CheckSum
;
240 YAMLASD
.Number
= AuxNumber
;
241 YAMLASD
.Selection
= ObjSD
->Selection
;
243 Sym
->SectionDefinition
= YAMLASD
;
247 dumpCLRTokenDefinition(COFFYAML::Symbol
*Sym
,
248 const object::coff_aux_clr_token
*ObjCLRToken
) {
249 COFF::AuxiliaryCLRToken YAMLCLRToken
;
250 YAMLCLRToken
.AuxType
= ObjCLRToken
->AuxType
;
251 YAMLCLRToken
.SymbolTableIndex
= ObjCLRToken
->SymbolTableIndex
;
253 Sym
->CLRToken
= YAMLCLRToken
;
256 void COFFDumper::dumpSymbols(unsigned NumSymbols
) {
257 std::vector
<COFFYAML::Symbol
> &Symbols
= YAMLObj
.Symbols
;
258 for (const auto &S
: Obj
.symbols()) {
259 object::COFFSymbolRef Symbol
= Obj
.getCOFFSymbol(S
);
260 COFFYAML::Symbol Sym
;
261 Obj
.getSymbolName(Symbol
, Sym
.Name
);
262 Sym
.SimpleType
= COFF::SymbolBaseType(Symbol
.getBaseType());
263 Sym
.ComplexType
= COFF::SymbolComplexType(Symbol
.getComplexType());
264 Sym
.Header
.StorageClass
= Symbol
.getStorageClass();
265 Sym
.Header
.Value
= Symbol
.getValue();
266 Sym
.Header
.SectionNumber
= Symbol
.getSectionNumber();
267 Sym
.Header
.NumberOfAuxSymbols
= Symbol
.getNumberOfAuxSymbols();
269 if (Symbol
.getNumberOfAuxSymbols() > 0) {
270 ArrayRef
<uint8_t> AuxData
= Obj
.getSymbolAuxData(Symbol
);
271 if (Symbol
.isFunctionDefinition()) {
272 // This symbol represents a function definition.
273 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
274 "Expected a single aux symbol to describe this function!");
276 const object::coff_aux_function_definition
*ObjFD
=
277 reinterpret_cast<const object::coff_aux_function_definition
*>(
279 dumpFunctionDefinition(&Sym
, ObjFD
);
280 } else if (Symbol
.isFunctionLineInfo()) {
281 // This symbol describes function line number information.
282 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
283 "Expected a single aux symbol to describe this function!");
285 const object::coff_aux_bf_and_ef_symbol
*ObjBES
=
286 reinterpret_cast<const object::coff_aux_bf_and_ef_symbol
*>(
288 dumpbfAndEfLineInfo(&Sym
, ObjBES
);
289 } else if (Symbol
.isAnyUndefined()) {
290 // This symbol represents a weak external definition.
291 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
292 "Expected a single aux symbol to describe this weak symbol!");
294 const object::coff_aux_weak_external
*ObjWE
=
295 reinterpret_cast<const object::coff_aux_weak_external
*>(
297 dumpWeakExternal(&Sym
, ObjWE
);
298 } else if (Symbol
.isFileRecord()) {
299 // This symbol represents a file record.
300 Sym
.File
= StringRef(reinterpret_cast<const char *>(AuxData
.data()),
301 Symbol
.getNumberOfAuxSymbols() *
302 Obj
.getSymbolTableEntrySize())
303 .rtrim(StringRef("\0", /*length=*/1));
304 } else if (Symbol
.isSectionDefinition()) {
305 // This symbol represents a section definition.
306 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
307 "Expected a single aux symbol to describe this section!");
309 const object::coff_aux_section_definition
*ObjSD
=
310 reinterpret_cast<const object::coff_aux_section_definition
*>(
312 dumpSectionDefinition(&Sym
, ObjSD
, Symbol
.isBigObj());
313 } else if (Symbol
.isCLRToken()) {
314 // This symbol represents a CLR token definition.
315 assert(Symbol
.getNumberOfAuxSymbols() == 1 &&
316 "Expected a single aux symbol to describe this CLR Token!");
318 const object::coff_aux_clr_token
*ObjCLRToken
=
319 reinterpret_cast<const object::coff_aux_clr_token
*>(
321 dumpCLRTokenDefinition(&Sym
, ObjCLRToken
);
323 llvm_unreachable("Unhandled auxiliary symbol!");
326 Symbols
.push_back(Sym
);
330 COFFYAML::Object
&COFFDumper::getYAMLObj() {
334 std::error_code
coff2yaml(raw_ostream
&Out
, const object::COFFObjectFile
&Obj
) {
335 COFFDumper
Dumper(Obj
);
337 yaml::Output
Yout(Out
);
338 Yout
<< Dumper
.getYAMLObj();
340 return std::error_code();