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