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. 10// 11//===----------------------------------------------------------------------===// 12 13#include "ObjDumper.h" 14#include "llvm-readobj.h" 15#include "llvm/Object/XCOFFObjectFile.h" 16#include "llvm/Support/ScopedPrinter.h" 17 18using namespace llvm; 19using namespace object; 20 21namespace { 22 23class XCOFFDumper : public ObjDumper { 24 25public: 26 XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) 27 : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {} 28 29 void printFileHeaders() override; 30 void printSectionHeaders() override; 31 void printRelocations() override; 32 void printSymbols() override; 33 void printDynamicSymbols() override; 34 void printUnwindInfo() override; 35 void printStackMap() const override; 36 void printNeededLibraries() override; 37 38private: 39 template <typename T> void printSectionHeaders(ArrayRef<T> Sections); 40 template <typename T> void printGenericSectionHeader(T &Sec) const; 41 template <typename T> void printOverflowSectionHeader(T &Sec) const; 42 void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr); 43 void printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr); 44 void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); 45 void printSymbol(const SymbolRef &); 46 void printRelocations(ArrayRef<XCOFFSectionHeader32> Sections); 47 const XCOFFObjectFile &Obj; 48}; 49} // anonymous namespace 50 51void XCOFFDumper::printFileHeaders() { 52 DictScope DS(W, "FileHeader"); 53 W.printHex("Magic", Obj.getMagic()); 54 W.printNumber("NumberOfSections", Obj.getNumberOfSections()); 55 56 // Negative timestamp values are reserved for future use. 57 int32_t TimeStamp = Obj.getTimeStamp(); 58 if (TimeStamp > 0) { 59 // This handling of the time stamp assumes that the host system's time_t is 60 // compatible with AIX time_t. If a platform is not compatible, the lit 61 // tests will let us know. 62 time_t TimeDate = TimeStamp; 63 64 char FormattedTime[21] = {}; 65 size_t BytesWritten = 66 strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate)); 67 if (BytesWritten) 68 W.printHex("TimeStamp", FormattedTime, TimeStamp); 69 else 70 W.printHex("Timestamp", TimeStamp); 71 } else { 72 W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value", 73 TimeStamp); 74 } 75 76 // The number of symbol table entries is an unsigned value in 64-bit objects 77 // and a signed value (with negative values being 'reserved') in 32-bit 78 // objects. 79 if (Obj.is64Bit()) { 80 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64()); 81 W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64()); 82 } else { 83 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32()); 84 int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32(); 85 if (SymTabEntries >= 0) 86 W.printNumber("SymbolTableEntries", SymTabEntries); 87 else 88 W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries); 89 } 90 91 W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize()); 92 W.printHex("Flags", Obj.getFlags()); 93 94 // TODO FIXME Add support for the auxiliary header (if any) once 95 // XCOFFObjectFile has the necessary support. 96} 97 98void XCOFFDumper::printSectionHeaders() { 99 if (Obj.is64Bit()) 100 printSectionHeaders(Obj.sections64()); 101 else 102 printSectionHeaders(Obj.sections32()); 103} 104 105void XCOFFDumper::printRelocations() { 106 if (Obj.is64Bit()) 107 llvm_unreachable("64-bit relocation output not implemented!"); 108 else 109 printRelocations(Obj.sections32()); 110} 111 112static const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = { 113#define ECase(X) \ 114 { #X, XCOFF::X } 115 ECase(R_POS), ECase(R_RL), ECase(R_RLA), ECase(R_NEG), 116 ECase(R_REL), ECase(R_TOC), ECase(R_TRL), ECase(R_TRLA), 117 ECase(R_GL), ECase(R_TCL), ECase(R_REF), ECase(R_BA), 118 ECase(R_BR), ECase(R_RBA), ECase(R_RBR), ECase(R_TLS), 119 ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM), 120 ECase(R_TLSML), ECase(R_TOCU), ECase(R_TOCL) 121#undef ECase 122}; 123 124void XCOFFDumper::printRelocations(ArrayRef<XCOFFSectionHeader32> Sections) { 125 if (!opts::ExpandRelocs) 126 report_fatal_error("Unexpanded relocation output not implemented."); 127 128 ListScope LS(W, "Relocations"); 129 uint16_t Index = 0; 130 for (const auto &Sec : Sections) { 131 ++Index; 132 // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation. 133 if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA && 134 Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF) 135 continue; 136 auto Relocations = unwrapOrError(Obj.getFileName(), Obj.relocations(Sec)); 137 if (Relocations.empty()) 138 continue; 139 140 W.startLine() << "Section (index: " << Index << ") " << Sec.getName() 141 << " {\n"; 142 for (auto Reloc : Relocations) { 143 StringRef SymbolName = unwrapOrError( 144 Obj.getFileName(), Obj.getSymbolNameByIndex(Reloc.SymbolIndex)); 145 146 DictScope RelocScope(W, "Relocation"); 147 W.printHex("Virtual Address", Reloc.VirtualAddress); 148 W.printNumber("Symbol", SymbolName, Reloc.SymbolIndex); 149 W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No"); 150 W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0); 151 W.printNumber("Length", Reloc.getRelocatedLength()); 152 W.printEnum("Type", (uint8_t)Reloc.Type, 153 makeArrayRef(RelocationTypeNameclass)); 154 } 155 W.unindent(); 156 W.startLine() << "}\n"; 157 } 158} 159 160static const EnumEntry<XCOFF::CFileStringType> FileStringType[] = { 161#define ECase(X) \ 162 { #X, XCOFF::X } 163 ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD) 164#undef ECase 165}; 166 167void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) { 168 if (Obj.is64Bit()) 169 report_fatal_error( 170 "Printing for File Auxiliary Entry in 64-bit is unimplemented."); 171 StringRef FileName = 172 unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr)); 173 DictScope SymDs(W, "File Auxiliary Entry"); 174 W.printNumber("Index", 175 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 176 W.printString("Name", FileName); 177 W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type), 178 makeArrayRef(FileStringType)); 179} 180 181static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] = 182 { 183#define ECase(X) \ 184 { #X, XCOFF::X } 185 ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB), ECase(XMC_GL), 186 ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264), 187 ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW), ECase(XMC_TC0), 188 ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS), ECase(XMC_UA), 189 ECase(XMC_BS), ECase(XMC_UC), ECase(XMC_TL), ECase(XMC_UL), 190 ECase(XMC_TE) 191#undef ECase 192}; 193 194static const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = { 195#define ECase(X) \ 196 { #X, XCOFF::X } 197 ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM) 198#undef ECase 199}; 200 201void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr) { 202 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); 203 204 DictScope SymDs(W, "CSECT Auxiliary Entry"); 205 W.printNumber("Index", 206 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 207 if (AuxEntPtr->isLabel()) 208 W.printNumber("ContainingCsectSymbolIndex", AuxEntPtr->SectionOrLength); 209 else 210 W.printNumber("SectionLen", AuxEntPtr->SectionOrLength); 211 W.printHex("ParameterHashIndex", AuxEntPtr->ParameterHashIndex); 212 W.printHex("TypeChkSectNum", AuxEntPtr->TypeChkSectNum); 213 // Print out symbol alignment and type. 214 W.printNumber("SymbolAlignmentLog2", AuxEntPtr->getAlignmentLog2()); 215 W.printEnum("SymbolType", AuxEntPtr->getSymbolType(), 216 makeArrayRef(CsectSymbolTypeClass)); 217 W.printEnum("StorageMappingClass", 218 static_cast<uint8_t>(AuxEntPtr->StorageMappingClass), 219 makeArrayRef(CsectStorageMappingClass)); 220 W.printHex("StabInfoIndex", AuxEntPtr->StabInfoIndex); 221 W.printHex("StabSectNum", AuxEntPtr->StabSectNum); 222} 223 224void XCOFFDumper::printSectAuxEntForStat( 225 const XCOFFSectAuxEntForStat *AuxEntPtr) { 226 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); 227 228 DictScope SymDs(W, "Sect Auxiliary Entry For Stat"); 229 W.printNumber("Index", 230 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 231 W.printNumber("SectionLength", AuxEntPtr->SectionLength); 232 233 // Unlike the corresponding fields in the section header, NumberOfRelocEnt 234 // and NumberOfLineNum do not handle values greater than 65535. 235 W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt); 236 W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum); 237} 238 239static const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = { 240#define ECase(X) \ 241 { #X, XCOFF::X } 242 ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT), 243 ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL), 244 ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU), 245 ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG), 246 ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK), 247 ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE), 248 ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL), 249 ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF), 250 ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM), 251 ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM), 252 ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY), 253 ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS), 254 ECase(C_STTLS), ECase(C_EFCN) 255#undef ECase 256}; 257 258static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { 259 switch (SC) { 260 case XCOFF::C_EXT: 261 case XCOFF::C_WEAKEXT: 262 case XCOFF::C_HIDEXT: 263 case XCOFF::C_STAT: 264 return "Value (RelocatableAddress)"; 265 case XCOFF::C_FILE: 266 return "Value (SymbolTableIndex)"; 267 case XCOFF::C_FCN: 268 case XCOFF::C_BLOCK: 269 case XCOFF::C_FUN: 270 case XCOFF::C_STSYM: 271 case XCOFF::C_BINCL: 272 case XCOFF::C_EINCL: 273 case XCOFF::C_INFO: 274 case XCOFF::C_BSTAT: 275 case XCOFF::C_LSYM: 276 case XCOFF::C_PSYM: 277 case XCOFF::C_RPSYM: 278 case XCOFF::C_RSYM: 279 case XCOFF::C_ECOML: 280 case XCOFF::C_DWARF: 281 assert(false && "This StorageClass for the symbol is not yet implemented."); 282 return ""; 283 default: 284 return "Value"; 285 } 286} 287 288static const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = { 289#define ECase(X) \ 290 { #X, XCOFF::X } 291 ECase(TB_C), ECase(TB_CPLUSPLUS) 292#undef ECase 293}; 294 295static const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = { 296#define ECase(X) \ 297 { #X, XCOFF::X } 298 ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970) 299#undef ECase 300}; 301 302void XCOFFDumper::printSymbol(const SymbolRef &S) { 303 if (Obj.is64Bit()) 304 report_fatal_error("64-bit support is unimplemented."); 305 306 DataRefImpl SymbolDRI = S.getRawDataRefImpl(); 307 const XCOFFSymbolEntry *SymbolEntPtr = Obj.toSymbolEntry(SymbolDRI); 308 309 XCOFFSymbolRef XCOFFSymRef(SymbolDRI, &Obj); 310 uint8_t NumberOfAuxEntries = XCOFFSymRef.getNumberOfAuxEntries(); 311 312 DictScope SymDs(W, "Symbol"); 313 314 StringRef SymbolName = 315 unwrapOrError(Obj.getFileName(), Obj.getSymbolName(SymbolDRI)); 316 317 W.printNumber("Index", 318 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(SymbolEntPtr))); 319 W.printString("Name", SymbolName); 320 W.printHex(GetSymbolValueName(SymbolEntPtr->StorageClass), 321 SymbolEntPtr->Value); 322 323 StringRef SectionName = 324 unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntPtr)); 325 326 W.printString("Section", SectionName); 327 if (XCOFFSymRef.getStorageClass() == XCOFF::C_FILE) { 328 W.printEnum("Source Language ID", 329 SymbolEntPtr->CFileLanguageIdAndTypeId.LanguageId, 330 makeArrayRef(CFileLangIdClass)); 331 W.printEnum("CPU Version ID", 332 SymbolEntPtr->CFileLanguageIdAndTypeId.CpuTypeId, 333 makeArrayRef(CFileCpuIdClass)); 334 } else 335 W.printHex("Type", SymbolEntPtr->SymbolType); 336 337 W.printEnum("StorageClass", static_cast<uint8_t>(SymbolEntPtr->StorageClass), 338 makeArrayRef(SymStorageClass)); 339 W.printNumber("NumberOfAuxEntries", SymbolEntPtr->NumberOfAuxEntries); 340 341 if (NumberOfAuxEntries == 0) 342 return; 343 344 switch (XCOFFSymRef.getStorageClass()) { 345 case XCOFF::C_FILE: 346 // If the symbol is C_FILE and has auxiliary entries... 347 for (int i = 1; i <= NumberOfAuxEntries; i++) { 348 const XCOFFFileAuxEnt *FileAuxEntPtr = 349 reinterpret_cast<const XCOFFFileAuxEnt *>(SymbolEntPtr + i); 350#ifndef NDEBUG 351 Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(FileAuxEntPtr)); 352#endif 353 printFileAuxEnt(FileAuxEntPtr); 354 } 355 break; 356 case XCOFF::C_EXT: 357 case XCOFF::C_WEAKEXT: 358 case XCOFF::C_HIDEXT: 359 // If the symbol is for a function, and it has more than 1 auxiliary entry, 360 // then one of them must be function auxiliary entry which we do not 361 // support yet. 362 if (XCOFFSymRef.isFunction() && NumberOfAuxEntries >= 2) 363 report_fatal_error("Function auxiliary entry printing is unimplemented."); 364 365 // If there is more than 1 auxiliary entry, instead of printing out 366 // error information, print out the raw Auxiliary entry from 1st till 367 // the last - 1. The last one must be a CSECT Auxiliary Entry. 368 for (int i = 1; i < NumberOfAuxEntries; i++) { 369 W.startLine() << "!Unexpected raw auxiliary entry data:\n"; 370 W.startLine() << format_bytes( 371 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i), 372 XCOFF::SymbolTableEntrySize)); 373 } 374 375 // The symbol's last auxiliary entry is a CSECT Auxiliary Entry. 376 printCsectAuxEnt32(XCOFFSymRef.getXCOFFCsectAuxEnt32()); 377 break; 378 case XCOFF::C_STAT: 379 if (NumberOfAuxEntries > 1) 380 report_fatal_error( 381 "C_STAT symbol should not have more than 1 auxiliary entry."); 382 383 const XCOFFSectAuxEntForStat *StatAuxEntPtr; 384 StatAuxEntPtr = 385 reinterpret_cast<const XCOFFSectAuxEntForStat *>(SymbolEntPtr + 1); 386#ifndef NDEBUG 387 Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(StatAuxEntPtr)); 388#endif 389 printSectAuxEntForStat(StatAuxEntPtr); 390 break; 391 case XCOFF::C_DWARF: 392 case XCOFF::C_BLOCK: 393 case XCOFF::C_FCN: 394 report_fatal_error("Symbol table entry printing for this storage class " 395 "type is unimplemented."); 396 break; 397 default: 398 for (int i = 1; i <= NumberOfAuxEntries; i++) { 399 W.startLine() << "!Unexpected raw auxiliary entry data:\n"; 400 W.startLine() << format_bytes( 401 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(SymbolEntPtr + i), 402 XCOFF::SymbolTableEntrySize)); 403 } 404 break; 405 } 406} 407 408void XCOFFDumper::printSymbols() { 409 ListScope Group(W, "Symbols"); 410 for (const SymbolRef &S : Obj.symbols()) 411 printSymbol(S); 412} 413 414void XCOFFDumper::printDynamicSymbols() { 415 llvm_unreachable("Unimplemented functionality for XCOFFDumper"); 416} 417 418void XCOFFDumper::printUnwindInfo() { 419 llvm_unreachable("Unimplemented functionality for XCOFFDumper"); 420} 421 422void XCOFFDumper::printStackMap() const { 423 llvm_unreachable("Unimplemented functionality for XCOFFDumper"); 424} 425 426void XCOFFDumper::printNeededLibraries() { 427 llvm_unreachable("Unimplemented functionality for XCOFFDumper"); 428} 429 430static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = { 431#define ECase(X) \ 432 { #X, XCOFF::X } 433 ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT), 434 ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT), 435 ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS), 436 ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK), 437 ECase(STYP_OVRFLO) 438#undef ECase 439}; 440 441template <typename T> 442void XCOFFDumper::printOverflowSectionHeader(T &Sec) const { 443 if (Obj.is64Bit()) { 444 reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not " 445 "contain an overflow section header.", 446 object_error::parse_failed), 447 Obj.getFileName()); 448 } 449 450 W.printString("Name", Sec.getName()); 451 W.printNumber("NumberOfRelocations", Sec.PhysicalAddress); 452 W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress); 453 W.printHex("Size", Sec.SectionSize); 454 W.printHex("RawDataOffset", Sec.FileOffsetToRawData); 455 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); 456 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); 457 W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations); 458 W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers); 459} 460 461template <typename T> 462void XCOFFDumper::printGenericSectionHeader(T &Sec) const { 463 W.printString("Name", Sec.getName()); 464 W.printHex("PhysicalAddress", Sec.PhysicalAddress); 465 W.printHex("VirtualAddress", Sec.VirtualAddress); 466 W.printHex("Size", Sec.SectionSize); 467 W.printHex("RawDataOffset", Sec.FileOffsetToRawData); 468 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); 469 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); 470 W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); 471 W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); 472} 473 474template <typename T> 475void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { 476 ListScope Group(W, "Sections"); 477 478 uint16_t Index = 1; 479 for (const T &Sec : Sections) { 480 DictScope SecDS(W, "Section"); 481 482 W.printNumber("Index", Index++); 483 uint16_t SectionType = Sec.getSectionType(); 484 switch (SectionType) { 485 case XCOFF::STYP_OVRFLO: 486 printOverflowSectionHeader(Sec); 487 break; 488 case XCOFF::STYP_LOADER: 489 case XCOFF::STYP_EXCEPT: 490 case XCOFF::STYP_TYPCHK: 491 // TODO The interpretation of loader, exception and type check section 492 // headers are different from that of generic section headers. We will 493 // implement them later. We interpret them as generic section headers for 494 // now. 495 default: 496 printGenericSectionHeader(Sec); 497 break; 498 } 499 if (Sec.isReservedSectionType()) 500 W.printHex("Flags", "Reserved", SectionType); 501 else 502 W.printEnum("Type", SectionType, makeArrayRef(SectionTypeFlagsNames)); 503 } 504 505 if (opts::SectionRelocations) 506 report_fatal_error("Dumping section relocations is unimplemented"); 507 508 if (opts::SectionSymbols) 509 report_fatal_error("Dumping symbols is unimplemented"); 510 511 if (opts::SectionData) 512 report_fatal_error("Dumping section data is unimplemented"); 513} 514 515namespace llvm { 516std::unique_ptr<ObjDumper> 517createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) { 518 return std::make_unique<XCOFFDumper>(XObj, Writer); 519} 520} // namespace llvm 521