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 | |
15 | using namespace llvm; |
16 | using namespace llvm::object; |
17 | namespace { |
18 | |
19 | class 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 | |
43 | public: |
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 | |
55 | Error XCOFFDumper::dump() { |
56 | dumpHeader(); |
57 | if (Error E = dumpSections()) |
58 | return E; |
59 | return dumpSymbols(); |
60 | } |
61 | |
62 | void XCOFFDumper::() { |
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 | |
76 | Error 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 | |
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; |
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 | |
136 | Error 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 | |
156 | Error 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 | |
179 | void 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 | |
202 | void 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 | |
214 | void 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 | |
239 | Error 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 | |
280 | Error 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 | |
311 | Error 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 | |
342 | Error 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 | |
405 | Error 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 | |