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