[Alignment][NFC] Value::getPointerAlignment returns MaybeAlign
[llvm-core.git] / tools / llvm-readobj / XCOFFDumper.cpp
blobc48d7ed78e0c44cfaadc34d638e44d4153f74a44
1 //===-- XCOFFDumper.cpp - XCOFF dumping utility -----------------*- 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 // This file implements an XCOFF specific dumper for llvm-readobj.
11 //===----------------------------------------------------------------------===//
13 #include "Error.h"
14 #include "ObjDumper.h"
15 #include "llvm-readobj.h"
16 #include "llvm/Object/XCOFFObjectFile.h"
17 #include "llvm/Support/ScopedPrinter.h"
19 using namespace llvm;
20 using namespace object;
22 namespace {
24 class XCOFFDumper : public ObjDumper {
25 enum {
26 SymbolTypeMask = 0x07,
27 SymbolAlignmentMask = 0xF8,
28 SymbolAlignmentBitOffset = 3
31 public:
32 XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
33 : ObjDumper(Writer), Obj(Obj) {}
35 void printFileHeaders() override;
36 void printSectionHeaders() override;
37 void printRelocations() override;
38 void printSymbols() override;
39 void printDynamicSymbols() override;
40 void printUnwindInfo() override;
41 void printStackMap() const override;
42 void printNeededLibraries() override;
44 private:
45 template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
46 void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr);
47 void printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr);
48 void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr);
49 void printSymbol(const SymbolRef &);
51 // Least significant 3 bits are reserved.
52 static constexpr unsigned SectionFlagsReservedMask = 0x7;
53 const XCOFFObjectFile &Obj;
55 } // anonymous namespace
57 void XCOFFDumper::printFileHeaders() {
58 DictScope DS(W, "FileHeader");
59 W.printHex("Magic", Obj.getMagic());
60 W.printNumber("NumberOfSections", Obj.getNumberOfSections());
62 // Negative timestamp values are reserved for future use.
63 int32_t TimeStamp = Obj.getTimeStamp();
64 if (TimeStamp > 0) {
65 // This handling of the time stamp assumes that the host system's time_t is
66 // compatible with AIX time_t. If a platform is not compatible, the lit
67 // tests will let us know.
68 time_t TimeDate = TimeStamp;
70 char FormattedTime[21] = {};
71 size_t BytesWritten =
72 strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate));
73 if (BytesWritten)
74 W.printHex("TimeStamp", FormattedTime, TimeStamp);
75 else
76 W.printHex("Timestamp", TimeStamp);
77 } else {
78 W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
79 TimeStamp);
82 // The number of symbol table entries is an unsigned value in 64-bit objects
83 // and a signed value (with negative values being 'reserved') in 32-bit
84 // objects.
85 if (Obj.is64Bit()) {
86 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
87 W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
88 } else {
89 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
90 int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
91 if (SymTabEntries >= 0)
92 W.printNumber("SymbolTableEntries", SymTabEntries);
93 else
94 W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
97 W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
98 W.printHex("Flags", Obj.getFlags());
100 // TODO FIXME Add support for the auxiliary header (if any) once
101 // XCOFFObjectFile has the necessary support.
104 void XCOFFDumper::printSectionHeaders() {
105 if (Obj.is64Bit())
106 printSectionHeaders(Obj.sections64());
107 else
108 printSectionHeaders(Obj.sections32());
111 void XCOFFDumper::printRelocations() {
112 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
115 static const EnumEntry<XCOFF::CFileStringType> FileStringType[] = {
116 #define ECase(X) \
117 { #X, XCOFF::X }
118 ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD)
119 #undef ECase
122 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) {
123 if (Obj.is64Bit())
124 report_fatal_error(
125 "Printing for File Auxiliary Entry in 64-bit is unimplemented.");
126 StringRef FileName =
127 unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr));
128 DictScope SymDs(W, "File Auxiliary Entry");
129 W.printNumber("Index",
130 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
131 W.printString("Name", FileName);
132 W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type),
133 makeArrayRef(FileStringType));
136 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] =
138 #define ECase(X) \
139 { #X, XCOFF::X }
140 ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB),
141 ECase(XMC_GL), ECase(XMC_XO), ECase(XMC_SV),
142 ECase(XMC_SV64), ECase(XMC_SV3264), ECase(XMC_TI),
143 ECase(XMC_TB), ECase(XMC_RW), ECase(XMC_TC0),
144 ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS),
145 ECase(XMC_UA), ECase(XMC_BS), ECase(XMC_UC),
146 ECase(XMC_TL), ECase(XMC_TE)
147 #undef ECase
150 static const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = {
151 #define ECase(X) \
152 { #X, XCOFF::X }
153 ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM)
154 #undef ECase
157 void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr) {
158 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
160 DictScope SymDs(W, "CSECT Auxiliary Entry");
161 W.printNumber("Index",
162 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
163 if ((AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask) == XCOFF::XTY_LD)
164 W.printNumber("ContainingCsectSymbolIndex", AuxEntPtr->SectionOrLength);
165 else
166 W.printNumber("SectionLen", AuxEntPtr->SectionOrLength);
167 W.printHex("ParameterHashIndex", AuxEntPtr->ParameterHashIndex);
168 W.printHex("TypeChkSectNum", AuxEntPtr->TypeChkSectNum);
169 // Print out symbol alignment and type.
170 W.printNumber("SymbolAlignmentLog2",
171 (AuxEntPtr->SymbolAlignmentAndType & SymbolAlignmentMask) >>
172 SymbolAlignmentBitOffset);
173 W.printEnum("SymbolType", AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask,
174 makeArrayRef(CsectSymbolTypeClass));
175 W.printEnum("StorageMappingClass",
176 static_cast<uint8_t>(AuxEntPtr->StorageMappingClass),
177 makeArrayRef(CsectStorageMappingClass));
178 W.printHex("StabInfoIndex", AuxEntPtr->StabInfoIndex);
179 W.printHex("StabSectNum", AuxEntPtr->StabSectNum);
182 void XCOFFDumper::printSectAuxEntForStat(
183 const XCOFFSectAuxEntForStat *AuxEntPtr) {
184 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file.");
186 DictScope SymDs(W, "Sect Auxiliary Entry For Stat");
187 W.printNumber("Index",
188 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
189 W.printNumber("SectionLength", AuxEntPtr->SectionLength);
191 // Unlike the corresponding fields in the section header, NumberOfRelocEnt
192 // and NumberOfLineNum do not handle values greater than 65535.
193 W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt);
194 W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum);
197 static const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = {
198 #define ECase(X) \
199 { #X, XCOFF::X }
200 ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT),
201 ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL),
202 ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU),
203 ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG),
204 ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK),
205 ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE),
206 ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL),
207 ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF),
208 ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM),
209 ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM),
210 ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY),
211 ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS),
212 ECase(C_STTLS), ECase(C_EFCN)
213 #undef ECase
216 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) {
217 switch (SC) {
218 case XCOFF::C_EXT:
219 case XCOFF::C_WEAKEXT:
220 case XCOFF::C_HIDEXT:
221 case XCOFF::C_STAT:
222 return "Value (RelocatableAddress)";
223 case XCOFF::C_FILE:
224 return "Value (SymbolTableIndex)";
225 case XCOFF::C_FCN:
226 case XCOFF::C_BLOCK:
227 case XCOFF::C_FUN:
228 case XCOFF::C_STSYM:
229 case XCOFF::C_BINCL:
230 case XCOFF::C_EINCL:
231 case XCOFF::C_INFO:
232 case XCOFF::C_BSTAT:
233 case XCOFF::C_LSYM:
234 case XCOFF::C_PSYM:
235 case XCOFF::C_RPSYM:
236 case XCOFF::C_RSYM:
237 case XCOFF::C_ECOML:
238 case XCOFF::C_DWARF:
239 assert(false && "This StorageClass for the symbol is not yet implemented.");
240 return "";
241 default:
242 return "Value";
246 static const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = {
247 #define ECase(X) \
248 { #X, XCOFF::X }
249 ECase(TB_C), ECase(TB_CPLUSPLUS)
250 #undef ECase
253 static const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = {
254 #define ECase(X) \
255 { #X, XCOFF::X }
256 ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970)
257 #undef ECase
260 void XCOFFDumper::printSymbol(const SymbolRef &S) {
261 if (Obj.is64Bit())
262 report_fatal_error("64-bit support is unimplemented.");
264 DataRefImpl SymbolDRI = S.getRawDataRefImpl();
265 const XCOFFSymbolEntry *SymbolEntPtr = Obj.toSymbolEntry(SymbolDRI);
267 XCOFFSymbolRef XCOFFSymRef(SymbolDRI, &Obj);
268 uint8_t NumberOfAuxEntries = XCOFFSymRef.getNumberOfAuxEntries();
270 DictScope SymDs(W, "Symbol");
272 StringRef SymbolName =
273 unwrapOrError(Obj.getFileName(), Obj.getSymbolName(SymbolDRI));
275 W.printNumber("Index",
276 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(SymbolEntPtr)));
277 W.printString("Name", SymbolName);
278 W.printHex(GetSymbolValueName(SymbolEntPtr->StorageClass),
279 SymbolEntPtr->Value);
281 StringRef SectionName =
282 unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntPtr));
284 W.printString("Section", SectionName);
285 if (XCOFFSymRef.getStorageClass() == XCOFF::C_FILE) {
286 W.printEnum("Source Language ID",
287 SymbolEntPtr->CFileLanguageIdAndTypeId.LanguageId,
288 makeArrayRef(CFileLangIdClass));
289 W.printEnum("CPU Version ID",
290 SymbolEntPtr->CFileLanguageIdAndTypeId.CpuTypeId,
291 makeArrayRef(CFileCpuIdClass));
292 } else
293 W.printHex("Type", SymbolEntPtr->SymbolType);
295 W.printEnum("StorageClass", static_cast<uint8_t>(SymbolEntPtr->StorageClass),
296 makeArrayRef(SymStorageClass));
297 W.printNumber("NumberOfAuxEntries", SymbolEntPtr->NumberOfAuxEntries);
299 if (NumberOfAuxEntries == 0)
300 return;
302 switch (XCOFFSymRef.getStorageClass()) {
303 case XCOFF::C_FILE:
304 // If the symbol is C_FILE and has auxiliary entries...
305 for (int i = 1; i <= NumberOfAuxEntries; i++) {
306 const XCOFFFileAuxEnt *FileAuxEntPtr =
307 reinterpret_cast<const XCOFFFileAuxEnt *>(SymbolEntPtr + i);
308 #ifndef NDEBUG
309 Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr));
310 #endif
311 printFileAuxEnt(FileAuxEntPtr);
313 break;
314 case XCOFF::C_EXT:
315 case XCOFF::C_WEAKEXT:
316 case XCOFF::C_HIDEXT:
317 // If the symbol is for a function, and it has more than 1 auxiliary entry,
318 // then one of them must be function auxiliary entry which we do not
319 // support yet.
320 if (XCOFFSymRef.isFunction() && NumberOfAuxEntries >= 2)
321 report_fatal_error("Function auxiliary entry printing is unimplemented.");
323 // If there is more than 1 auxiliary entry, instead of printing out
324 // error information, print out the raw Auxiliary entry from 1st till
325 // the last - 1. The last one must be a CSECT Auxiliary Entry.
326 for (int i = 1; i < NumberOfAuxEntries; i++) {
327 W.startLine() << "!Unexpected raw auxiliary entry data:\n";
328 W.startLine() << format_bytes(
329 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i),
330 XCOFF::SymbolTableEntrySize));
333 // The symbol's last auxiliary entry is a CSECT Auxiliary Entry.
334 printCsectAuxEnt32(XCOFFSymRef.getXCOFFCsectAuxEnt32());
335 break;
336 case XCOFF::C_STAT:
337 if (NumberOfAuxEntries > 1)
338 report_fatal_error(
339 "C_STAT symbol should not have more than 1 auxiliary entry.");
341 const XCOFFSectAuxEntForStat *StatAuxEntPtr;
342 StatAuxEntPtr =
343 reinterpret_cast<const XCOFFSectAuxEntForStat *>(SymbolEntPtr + 1);
344 #ifndef NDEBUG
345 Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr));
346 #endif
347 printSectAuxEntForStat(StatAuxEntPtr);
348 break;
349 case XCOFF::C_DWARF:
350 case XCOFF::C_BLOCK:
351 case XCOFF::C_FCN:
352 report_fatal_error("Symbol table entry printing for this storage class "
353 "type is unimplemented.");
354 break;
355 default:
356 for (int i = 1; i <= NumberOfAuxEntries; i++) {
357 W.startLine() << "!Unexpected raw auxiliary entry data:\n";
358 W.startLine() << format_bytes(
359 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i),
360 XCOFF::SymbolTableEntrySize));
362 break;
366 void XCOFFDumper::printSymbols() {
367 ListScope Group(W, "Symbols");
368 for (const SymbolRef &S : Obj.symbols())
369 printSymbol(S);
372 void XCOFFDumper::printDynamicSymbols() {
373 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
376 void XCOFFDumper::printUnwindInfo() {
377 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
380 void XCOFFDumper::printStackMap() const {
381 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
384 void XCOFFDumper::printNeededLibraries() {
385 llvm_unreachable("Unimplemented functionality for XCOFFDumper");
388 static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
389 #define ECase(X) \
390 { #X, XCOFF::X }
391 ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT),
392 ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT),
393 ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS),
394 ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
395 ECase(STYP_OVRFLO)
396 #undef ECase
399 template <typename T>
400 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
401 ListScope Group(W, "Sections");
403 uint16_t Index = 1;
404 for (const T &Sec : Sections) {
405 DictScope SecDS(W, "Section");
407 W.printNumber("Index", Index++);
408 W.printString("Name", Sec.getName());
410 W.printHex("PhysicalAddress", Sec.PhysicalAddress);
411 W.printHex("VirtualAddress", Sec.VirtualAddress);
412 W.printHex("Size", Sec.SectionSize);
413 W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
414 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
415 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
417 // TODO Need to add overflow handling when NumberOfX == _OVERFLOW_MARKER
418 // in 32-bit object files.
419 W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
420 W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
422 // The most significant 16-bits represent the DWARF section subtype. For
423 // now we just dump the section type flags.
424 uint16_t Flags = Sec.Flags & 0xffffu;
425 if (Flags & SectionFlagsReservedMask)
426 W.printHex("Flags", "Reserved", Flags);
427 else
428 W.printEnum("Type", Flags, makeArrayRef(SectionTypeFlagsNames));
431 if (opts::SectionRelocations)
432 report_fatal_error("Dumping section relocations is unimplemented");
434 if (opts::SectionSymbols)
435 report_fatal_error("Dumping symbols is unimplemented");
437 if (opts::SectionData)
438 report_fatal_error("Dumping section data is unimplemented");
441 namespace llvm {
442 std::error_code createXCOFFDumper(const object::ObjectFile *Obj,
443 ScopedPrinter &Writer,
444 std::unique_ptr<ObjDumper> &Result) {
445 const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(Obj);
446 if (!XObj)
447 return readobj_error::unsupported_obj_file_format;
449 Result.reset(new XCOFFDumper(*XObj, Writer));
450 return readobj_error::success;
452 } // namespace llvm