]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | //===------ utils/obj2yaml.cpp - obj2yaml conversion tool -------*- C++ -*-===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | ||
10 | #include "obj2yaml.h" | |
11 | #include "llvm/Object/COFF.h" | |
12 | #include "llvm/Object/COFFYAML.h" | |
13 | #include "llvm/Support/ErrorHandling.h" | |
14 | #include "llvm/Support/YAMLTraits.h" | |
15 | ||
16 | using namespace llvm; | |
17 | ||
18 | namespace { | |
19 | ||
20 | class COFFDumper { | |
21 | const object::COFFObjectFile &Obj; | |
22 | COFFYAML::Object YAMLObj; | |
85aaf69f SL |
23 | template <typename T> |
24 | void dumpOptionalHeader(T OptionalHeader); | |
1a4d82fc JJ |
25 | void dumpHeader(); |
26 | void dumpSections(unsigned numSections); | |
27 | void dumpSymbols(unsigned numSymbols); | |
28 | ||
29 | public: | |
30 | COFFDumper(const object::COFFObjectFile &Obj); | |
31 | COFFYAML::Object &getYAMLObj(); | |
32 | }; | |
33 | ||
34 | } | |
35 | ||
36 | COFFDumper::COFFDumper(const object::COFFObjectFile &Obj) : Obj(Obj) { | |
85aaf69f SL |
37 | const object::pe32_header *PE32Header = nullptr; |
38 | Obj.getPE32Header(PE32Header); | |
39 | if (PE32Header) { | |
40 | dumpOptionalHeader(PE32Header); | |
41 | } else { | |
42 | const object::pe32plus_header *PE32PlusHeader = nullptr; | |
43 | Obj.getPE32PlusHeader(PE32PlusHeader); | |
44 | if (PE32PlusHeader) { | |
45 | dumpOptionalHeader(PE32PlusHeader); | |
46 | } | |
47 | } | |
1a4d82fc JJ |
48 | dumpHeader(); |
49 | dumpSections(Obj.getNumberOfSections()); | |
50 | dumpSymbols(Obj.getNumberOfSymbols()); | |
51 | } | |
52 | ||
85aaf69f SL |
53 | template <typename T> void COFFDumper::dumpOptionalHeader(T OptionalHeader) { |
54 | YAMLObj.OptionalHeader = COFFYAML::PEHeader(); | |
55 | YAMLObj.OptionalHeader->Header.AddressOfEntryPoint = | |
56 | OptionalHeader->AddressOfEntryPoint; | |
57 | YAMLObj.OptionalHeader->Header.AddressOfEntryPoint = | |
58 | OptionalHeader->AddressOfEntryPoint; | |
59 | YAMLObj.OptionalHeader->Header.ImageBase = OptionalHeader->ImageBase; | |
60 | YAMLObj.OptionalHeader->Header.SectionAlignment = | |
61 | OptionalHeader->SectionAlignment; | |
62 | YAMLObj.OptionalHeader->Header.FileAlignment = OptionalHeader->FileAlignment; | |
63 | YAMLObj.OptionalHeader->Header.MajorOperatingSystemVersion = | |
64 | OptionalHeader->MajorOperatingSystemVersion; | |
65 | YAMLObj.OptionalHeader->Header.MinorOperatingSystemVersion = | |
66 | OptionalHeader->MinorOperatingSystemVersion; | |
67 | YAMLObj.OptionalHeader->Header.MajorImageVersion = | |
68 | OptionalHeader->MajorImageVersion; | |
69 | YAMLObj.OptionalHeader->Header.MinorImageVersion = | |
70 | OptionalHeader->MinorImageVersion; | |
71 | YAMLObj.OptionalHeader->Header.MajorSubsystemVersion = | |
72 | OptionalHeader->MajorSubsystemVersion; | |
73 | YAMLObj.OptionalHeader->Header.MinorSubsystemVersion = | |
74 | OptionalHeader->MinorSubsystemVersion; | |
75 | YAMLObj.OptionalHeader->Header.Subsystem = OptionalHeader->Subsystem; | |
76 | YAMLObj.OptionalHeader->Header.DLLCharacteristics = | |
77 | OptionalHeader->DLLCharacteristics; | |
78 | YAMLObj.OptionalHeader->Header.SizeOfStackReserve = | |
79 | OptionalHeader->SizeOfStackReserve; | |
80 | YAMLObj.OptionalHeader->Header.SizeOfStackCommit = | |
81 | OptionalHeader->SizeOfStackCommit; | |
82 | YAMLObj.OptionalHeader->Header.SizeOfHeapReserve = | |
83 | OptionalHeader->SizeOfHeapReserve; | |
84 | YAMLObj.OptionalHeader->Header.SizeOfHeapCommit = | |
85 | OptionalHeader->SizeOfHeapCommit; | |
86 | unsigned I = 0; | |
87 | for (auto &DestDD : YAMLObj.OptionalHeader->DataDirectories) { | |
88 | const object::data_directory *DD; | |
89 | if (Obj.getDataDirectory(I++, DD)) | |
90 | continue; | |
91 | DestDD = COFF::DataDirectory(); | |
92 | DestDD->RelativeVirtualAddress = DD->RelativeVirtualAddress; | |
93 | DestDD->Size = DD->Size; | |
94 | } | |
95 | } | |
96 | ||
1a4d82fc JJ |
97 | void COFFDumper::dumpHeader() { |
98 | YAMLObj.Header.Machine = Obj.getMachine(); | |
99 | YAMLObj.Header.Characteristics = Obj.getCharacteristics(); | |
100 | } | |
101 | ||
102 | void COFFDumper::dumpSections(unsigned NumSections) { | |
85aaf69f SL |
103 | std::vector<COFFYAML::Section> &YAMLSections = YAMLObj.Sections; |
104 | for (const auto &ObjSection : Obj.sections()) { | |
105 | const object::coff_section *COFFSection = Obj.getCOFFSection(ObjSection); | |
106 | COFFYAML::Section NewYAMLSection; | |
107 | ObjSection.getName(NewYAMLSection.Name); | |
108 | NewYAMLSection.Header.Characteristics = COFFSection->Characteristics; | |
109 | NewYAMLSection.Header.VirtualAddress = ObjSection.getAddress(); | |
110 | NewYAMLSection.Header.VirtualSize = COFFSection->VirtualSize; | |
111 | NewYAMLSection.Alignment = ObjSection.getAlignment(); | |
1a4d82fc JJ |
112 | |
113 | ArrayRef<uint8_t> sectionData; | |
85aaf69f SL |
114 | if (!ObjSection.isBSS()) |
115 | Obj.getSectionContents(COFFSection, sectionData); | |
116 | NewYAMLSection.SectionData = yaml::BinaryRef(sectionData); | |
1a4d82fc JJ |
117 | |
118 | std::vector<COFFYAML::Relocation> Relocations; | |
85aaf69f | 119 | for (const auto &Reloc : ObjSection.relocations()) { |
1a4d82fc JJ |
120 | const object::coff_relocation *reloc = Obj.getCOFFRelocation(Reloc); |
121 | COFFYAML::Relocation Rel; | |
122 | object::symbol_iterator Sym = Reloc.getSymbol(); | |
123 | Sym->getName(Rel.SymbolName); | |
124 | Rel.VirtualAddress = reloc->VirtualAddress; | |
125 | Rel.Type = reloc->Type; | |
126 | Relocations.push_back(Rel); | |
127 | } | |
85aaf69f SL |
128 | NewYAMLSection.Relocations = Relocations; |
129 | YAMLSections.push_back(NewYAMLSection); | |
1a4d82fc JJ |
130 | } |
131 | } | |
132 | ||
133 | static void | |
134 | dumpFunctionDefinition(COFFYAML::Symbol *Sym, | |
135 | const object::coff_aux_function_definition *ObjFD) { | |
136 | COFF::AuxiliaryFunctionDefinition YAMLFD; | |
137 | YAMLFD.TagIndex = ObjFD->TagIndex; | |
138 | YAMLFD.TotalSize = ObjFD->TotalSize; | |
139 | YAMLFD.PointerToLinenumber = ObjFD->PointerToLinenumber; | |
140 | YAMLFD.PointerToNextFunction = ObjFD->PointerToNextFunction; | |
141 | ||
142 | Sym->FunctionDefinition = YAMLFD; | |
143 | } | |
144 | ||
145 | static void | |
146 | dumpbfAndEfLineInfo(COFFYAML::Symbol *Sym, | |
147 | const object::coff_aux_bf_and_ef_symbol *ObjBES) { | |
148 | COFF::AuxiliarybfAndefSymbol YAMLAAS; | |
149 | YAMLAAS.Linenumber = ObjBES->Linenumber; | |
150 | YAMLAAS.PointerToNextFunction = ObjBES->PointerToNextFunction; | |
151 | ||
152 | Sym->bfAndefSymbol = YAMLAAS; | |
153 | } | |
154 | ||
155 | static void dumpWeakExternal(COFFYAML::Symbol *Sym, | |
156 | const object::coff_aux_weak_external *ObjWE) { | |
157 | COFF::AuxiliaryWeakExternal YAMLWE; | |
158 | YAMLWE.TagIndex = ObjWE->TagIndex; | |
159 | YAMLWE.Characteristics = ObjWE->Characteristics; | |
160 | ||
161 | Sym->WeakExternal = YAMLWE; | |
162 | } | |
163 | ||
164 | static void | |
165 | dumpSectionDefinition(COFFYAML::Symbol *Sym, | |
166 | const object::coff_aux_section_definition *ObjSD, | |
167 | bool IsBigObj) { | |
168 | COFF::AuxiliarySectionDefinition YAMLASD; | |
169 | int32_t AuxNumber = ObjSD->getNumber(IsBigObj); | |
170 | YAMLASD.Length = ObjSD->Length; | |
171 | YAMLASD.NumberOfRelocations = ObjSD->NumberOfRelocations; | |
172 | YAMLASD.NumberOfLinenumbers = ObjSD->NumberOfLinenumbers; | |
173 | YAMLASD.CheckSum = ObjSD->CheckSum; | |
174 | YAMLASD.Number = AuxNumber; | |
175 | YAMLASD.Selection = ObjSD->Selection; | |
176 | ||
177 | Sym->SectionDefinition = YAMLASD; | |
178 | } | |
179 | ||
180 | static void | |
181 | dumpCLRTokenDefinition(COFFYAML::Symbol *Sym, | |
182 | const object::coff_aux_clr_token *ObjCLRToken) { | |
183 | COFF::AuxiliaryCLRToken YAMLCLRToken; | |
184 | YAMLCLRToken.AuxType = ObjCLRToken->AuxType; | |
185 | YAMLCLRToken.SymbolTableIndex = ObjCLRToken->SymbolTableIndex; | |
186 | ||
187 | Sym->CLRToken = YAMLCLRToken; | |
188 | } | |
189 | ||
190 | void COFFDumper::dumpSymbols(unsigned NumSymbols) { | |
191 | std::vector<COFFYAML::Symbol> &Symbols = YAMLObj.Symbols; | |
192 | for (const auto &S : Obj.symbols()) { | |
193 | object::COFFSymbolRef Symbol = Obj.getCOFFSymbol(S); | |
194 | COFFYAML::Symbol Sym; | |
195 | Obj.getSymbolName(Symbol, Sym.Name); | |
196 | Sym.SimpleType = COFF::SymbolBaseType(Symbol.getBaseType()); | |
197 | Sym.ComplexType = COFF::SymbolComplexType(Symbol.getComplexType()); | |
198 | Sym.Header.StorageClass = Symbol.getStorageClass(); | |
199 | Sym.Header.Value = Symbol.getValue(); | |
200 | Sym.Header.SectionNumber = Symbol.getSectionNumber(); | |
201 | Sym.Header.NumberOfAuxSymbols = Symbol.getNumberOfAuxSymbols(); | |
202 | ||
203 | if (Symbol.getNumberOfAuxSymbols() > 0) { | |
204 | ArrayRef<uint8_t> AuxData = Obj.getSymbolAuxData(Symbol); | |
205 | if (Symbol.isFunctionDefinition()) { | |
206 | // This symbol represents a function definition. | |
207 | assert(Symbol.getNumberOfAuxSymbols() == 1 && | |
208 | "Expected a single aux symbol to describe this function!"); | |
209 | ||
210 | const object::coff_aux_function_definition *ObjFD = | |
211 | reinterpret_cast<const object::coff_aux_function_definition *>( | |
212 | AuxData.data()); | |
213 | dumpFunctionDefinition(&Sym, ObjFD); | |
214 | } else if (Symbol.isFunctionLineInfo()) { | |
215 | // This symbol describes function line number information. | |
216 | assert(Symbol.getNumberOfAuxSymbols() == 1 && | |
217 | "Expected a single aux symbol to describe this function!"); | |
218 | ||
219 | const object::coff_aux_bf_and_ef_symbol *ObjBES = | |
220 | reinterpret_cast<const object::coff_aux_bf_and_ef_symbol *>( | |
221 | AuxData.data()); | |
222 | dumpbfAndEfLineInfo(&Sym, ObjBES); | |
85aaf69f | 223 | } else if (Symbol.isAnyUndefined()) { |
1a4d82fc JJ |
224 | // This symbol represents a weak external definition. |
225 | assert(Symbol.getNumberOfAuxSymbols() == 1 && | |
226 | "Expected a single aux symbol to describe this weak symbol!"); | |
227 | ||
228 | const object::coff_aux_weak_external *ObjWE = | |
229 | reinterpret_cast<const object::coff_aux_weak_external *>( | |
230 | AuxData.data()); | |
231 | dumpWeakExternal(&Sym, ObjWE); | |
232 | } else if (Symbol.isFileRecord()) { | |
233 | // This symbol represents a file record. | |
234 | Sym.File = StringRef(reinterpret_cast<const char *>(AuxData.data()), | |
235 | Symbol.getNumberOfAuxSymbols() * | |
236 | Obj.getSymbolTableEntrySize()) | |
237 | .rtrim(StringRef("\0", /*length=*/1)); | |
238 | } else if (Symbol.isSectionDefinition()) { | |
239 | // This symbol represents a section definition. | |
240 | assert(Symbol.getNumberOfAuxSymbols() == 1 && | |
241 | "Expected a single aux symbol to describe this section!"); | |
242 | ||
243 | const object::coff_aux_section_definition *ObjSD = | |
244 | reinterpret_cast<const object::coff_aux_section_definition *>( | |
245 | AuxData.data()); | |
246 | dumpSectionDefinition(&Sym, ObjSD, Symbol.isBigObj()); | |
247 | } else if (Symbol.isCLRToken()) { | |
248 | // This symbol represents a CLR token definition. | |
249 | assert(Symbol.getNumberOfAuxSymbols() == 1 && | |
250 | "Expected a single aux symbol to describe this CLR Token!"); | |
251 | ||
252 | const object::coff_aux_clr_token *ObjCLRToken = | |
253 | reinterpret_cast<const object::coff_aux_clr_token *>( | |
254 | AuxData.data()); | |
255 | dumpCLRTokenDefinition(&Sym, ObjCLRToken); | |
256 | } else { | |
257 | llvm_unreachable("Unhandled auxiliary symbol!"); | |
258 | } | |
259 | } | |
260 | Symbols.push_back(Sym); | |
261 | } | |
262 | } | |
263 | ||
264 | COFFYAML::Object &COFFDumper::getYAMLObj() { | |
265 | return YAMLObj; | |
266 | } | |
267 | ||
268 | std::error_code coff2yaml(raw_ostream &Out, const object::COFFObjectFile &Obj) { | |
269 | COFFDumper Dumper(Obj); | |
270 | ||
271 | yaml::Output Yout(Out); | |
272 | Yout << Dumper.getYAMLObj(); | |
273 | ||
274 | return object::object_error::success; | |
275 | } |