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/Demangle/Demangle.h" 16 #include "llvm/Object/XCOFFObjectFile.h" 17 #include "llvm/Support/FormattedStream.h" 18 #include "llvm/Support/ScopedPrinter.h" 19 20 #include <ctime> 21 22 using namespace llvm; 23 using namespace object; 24 25 namespace { 26 27 class XCOFFDumper : public ObjDumper { 28 29 public: 30 XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) 31 : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {} 32 33 void printFileHeaders() override; 34 void printAuxiliaryHeader() override; 35 void printSectionHeaders() override; 36 void printRelocations() override; 37 void printSymbols(bool ExtraSymInfo) override; 38 void printDynamicSymbols() override; 39 void printUnwindInfo() override; 40 void printStackMap() const override; 41 void printNeededLibraries() override; 42 void printStringTable() override; 43 void printExceptionSection() override; 44 void printLoaderSection(bool PrintHeader, bool PrintSymbols, 45 bool PrintRelocations) override; 46 47 ScopedPrinter &getScopedPrinter() const { return W; } 48 49 private: 50 template <typename T> void printSectionHeaders(ArrayRef<T> Sections); 51 template <typename T> void printGenericSectionHeader(T &Sec) const; 52 template <typename T> void printOverflowSectionHeader(T &Sec) const; 53 template <typename T> 54 void printExceptionSectionEntry(const T &ExceptionSectEnt) const; 55 template <typename T> void printExceptionSectionEntries() const; 56 template <typename T> const T *getAuxEntPtr(uintptr_t AuxAddress); 57 void printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr); 58 void printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef); 59 void printSectAuxEntForStat(const XCOFFSectAuxEntForStat *AuxEntPtr); 60 void printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr); 61 void printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr); 62 void printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr); 63 void printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr); 64 void printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr); 65 template <typename T> void printSectAuxEntForDWARF(const T *AuxEntPtr); 66 void printSymbol(const SymbolRef &); 67 template <typename RelTy> void printRelocation(RelTy Reloc); 68 template <typename Shdr, typename RelTy> 69 void printRelocations(ArrayRef<Shdr> Sections); 70 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader); 71 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader); 72 void printLoaderSectionHeader(uintptr_t LoaderSectAddr); 73 void printLoaderSectionSymbols(uintptr_t LoaderSectAddr); 74 template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader> 75 void printLoaderSectionSymbolsHelper(uintptr_t LoaderSectAddr); 76 template <typename LoadSectionRelocTy> 77 void printLoaderSectionRelocationEntry(LoadSectionRelocTy *LoaderSecRelEntPtr, 78 StringRef SymbolName); 79 void printLoaderSectionRelocationEntries(uintptr_t LoaderSectAddr); 80 template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry, 81 typename LoaderSectionRelocationEntry> 82 void printLoaderSectionRelocationEntriesHelper(uintptr_t LoaderSectAddr); 83 84 const XCOFFObjectFile &Obj; 85 const static int32_t FirstSymIdxOfLoaderSec = 3; 86 }; 87 } // anonymous namespace 88 89 void XCOFFDumper::printFileHeaders() { 90 DictScope DS(W, "FileHeader"); 91 W.printHex("Magic", Obj.getMagic()); 92 W.printNumber("NumberOfSections", Obj.getNumberOfSections()); 93 94 // Negative timestamp values are reserved for future use. 95 int32_t TimeStamp = Obj.getTimeStamp(); 96 if (TimeStamp > 0) { 97 // This handling of the time stamp assumes that the host system's time_t is 98 // compatible with AIX time_t. If a platform is not compatible, the lit 99 // tests will let us know. 100 time_t TimeDate = TimeStamp; 101 102 char FormattedTime[80] = {}; 103 104 size_t BytesFormatted = 105 strftime(FormattedTime, sizeof(FormattedTime), "%F %T", gmtime(&TimeDate)); 106 if (BytesFormatted) 107 W.printHex("TimeStamp", FormattedTime, TimeStamp); 108 else 109 W.printHex("Timestamp", TimeStamp); 110 } else { 111 W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value", 112 TimeStamp); 113 } 114 115 // The number of symbol table entries is an unsigned value in 64-bit objects 116 // and a signed value (with negative values being 'reserved') in 32-bit 117 // objects. 118 if (Obj.is64Bit()) { 119 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64()); 120 W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64()); 121 } else { 122 W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32()); 123 int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32(); 124 if (SymTabEntries >= 0) 125 W.printNumber("SymbolTableEntries", SymTabEntries); 126 else 127 W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries); 128 } 129 130 W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize()); 131 W.printHex("Flags", Obj.getFlags()); 132 133 // TODO FIXME Add support for the auxiliary header (if any) once 134 // XCOFFObjectFile has the necessary support. 135 } 136 137 void XCOFFDumper::printAuxiliaryHeader() { 138 DictScope DS(W, "AuxiliaryHeader"); 139 140 if (Obj.is64Bit()) 141 printAuxiliaryHeader(Obj.auxiliaryHeader64()); 142 else 143 printAuxiliaryHeader(Obj.auxiliaryHeader32()); 144 } 145 146 void XCOFFDumper::printSectionHeaders() { 147 if (Obj.is64Bit()) 148 printSectionHeaders(Obj.sections64()); 149 else 150 printSectionHeaders(Obj.sections32()); 151 } 152 153 void XCOFFDumper::printLoaderSection(bool PrintHeader, bool PrintSymbols, 154 bool PrintRelocations) { 155 DictScope DS(W, "Loader Section"); 156 Expected<uintptr_t> LoaderSectionAddrOrError = 157 Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER); 158 if (!LoaderSectionAddrOrError) { 159 reportUniqueWarning(LoaderSectionAddrOrError.takeError()); 160 return; 161 } 162 uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get(); 163 164 if (LoaderSectionAddr == 0) 165 return; 166 167 W.indent(); 168 if (PrintHeader) 169 printLoaderSectionHeader(LoaderSectionAddr); 170 171 if (PrintSymbols) 172 printLoaderSectionSymbols(LoaderSectionAddr); 173 174 if (PrintRelocations) 175 printLoaderSectionRelocationEntries(LoaderSectionAddr); 176 177 W.unindent(); 178 } 179 180 void XCOFFDumper::printLoaderSectionHeader(uintptr_t LoaderSectionAddr) { 181 DictScope DS(W, "Loader Section Header"); 182 183 auto PrintLoadSecHeaderCommon = [&](const auto *LDHeader) { 184 W.printNumber("Version", LDHeader->Version); 185 W.printNumber("NumberOfSymbolEntries", LDHeader->NumberOfSymTabEnt); 186 W.printNumber("NumberOfRelocationEntries", LDHeader->NumberOfRelTabEnt); 187 W.printNumber("LengthOfImportFileIDStringTable", 188 LDHeader->LengthOfImpidStrTbl); 189 W.printNumber("NumberOfImportFileIDs", LDHeader->NumberOfImpid); 190 W.printHex("OffsetToImportFileIDs", LDHeader->OffsetToImpid); 191 W.printNumber("LengthOfStringTable", LDHeader->LengthOfStrTbl); 192 W.printHex("OffsetToStringTable", LDHeader->OffsetToStrTbl); 193 }; 194 195 if (Obj.is64Bit()) { 196 const LoaderSectionHeader64 *LoaderSec64 = 197 reinterpret_cast<const LoaderSectionHeader64 *>(LoaderSectionAddr); 198 PrintLoadSecHeaderCommon(LoaderSec64); 199 W.printHex("OffsetToSymbolTable", LoaderSec64->OffsetToSymTbl); 200 W.printHex("OffsetToRelocationEntries", LoaderSec64->OffsetToRelEnt); 201 } else { 202 const LoaderSectionHeader32 *LoaderSec32 = 203 reinterpret_cast<const LoaderSectionHeader32 *>(LoaderSectionAddr); 204 PrintLoadSecHeaderCommon(LoaderSec32); 205 } 206 } 207 208 const EnumEntry<XCOFF::StorageClass> SymStorageClass[] = { 209 #define ECase(X) \ 210 { #X, XCOFF::X } 211 ECase(C_NULL), ECase(C_AUTO), ECase(C_EXT), ECase(C_STAT), 212 ECase(C_REG), ECase(C_EXTDEF), ECase(C_LABEL), ECase(C_ULABEL), 213 ECase(C_MOS), ECase(C_ARG), ECase(C_STRTAG), ECase(C_MOU), 214 ECase(C_UNTAG), ECase(C_TPDEF), ECase(C_USTATIC), ECase(C_ENTAG), 215 ECase(C_MOE), ECase(C_REGPARM), ECase(C_FIELD), ECase(C_BLOCK), 216 ECase(C_FCN), ECase(C_EOS), ECase(C_FILE), ECase(C_LINE), 217 ECase(C_ALIAS), ECase(C_HIDDEN), ECase(C_HIDEXT), ECase(C_BINCL), 218 ECase(C_EINCL), ECase(C_INFO), ECase(C_WEAKEXT), ECase(C_DWARF), 219 ECase(C_GSYM), ECase(C_LSYM), ECase(C_PSYM), ECase(C_RSYM), 220 ECase(C_RPSYM), ECase(C_STSYM), ECase(C_TCSYM), ECase(C_BCOMM), 221 ECase(C_ECOML), ECase(C_ECOMM), ECase(C_DECL), ECase(C_ENTRY), 222 ECase(C_FUN), ECase(C_BSTAT), ECase(C_ESTAT), ECase(C_GTLS), 223 ECase(C_STTLS), ECase(C_EFCN) 224 #undef ECase 225 }; 226 227 template <typename LoaderSectionSymbolEntry, typename LoaderSectionHeader> 228 void XCOFFDumper::printLoaderSectionSymbolsHelper(uintptr_t LoaderSectionAddr) { 229 const LoaderSectionHeader *LoadSecHeader = 230 reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr); 231 const LoaderSectionSymbolEntry *LoadSecSymEntPtr = 232 reinterpret_cast<LoaderSectionSymbolEntry *>( 233 LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl())); 234 235 for (uint32_t i = 0; i < LoadSecHeader->NumberOfSymTabEnt; 236 ++i, ++LoadSecSymEntPtr) { 237 if (Error E = Binary::checkOffset( 238 Obj.getMemoryBufferRef(), 239 LoaderSectionAddr + uintptr_t(LoadSecHeader->getOffsetToSymTbl()) + 240 (i * sizeof(LoaderSectionSymbolEntry)), 241 sizeof(LoaderSectionSymbolEntry))) { 242 reportUniqueWarning(std::move(E)); 243 return; 244 } 245 246 Expected<StringRef> SymbolNameOrErr = 247 LoadSecSymEntPtr->getSymbolName(LoadSecHeader); 248 if (!SymbolNameOrErr) { 249 reportUniqueWarning(SymbolNameOrErr.takeError()); 250 return; 251 } 252 253 DictScope DS(W, "Symbol"); 254 StringRef SymbolName = SymbolNameOrErr.get(); 255 W.printString("Name", opts::Demangle ? demangle(SymbolName) : SymbolName); 256 W.printHex("Virtual Address", LoadSecSymEntPtr->Value); 257 W.printNumber("SectionNum", LoadSecSymEntPtr->SectionNumber); 258 W.printHex("SymbolType", LoadSecSymEntPtr->SymbolType); 259 W.printEnum("StorageClass", 260 static_cast<uint8_t>(LoadSecSymEntPtr->StorageClass), 261 ArrayRef(SymStorageClass)); 262 W.printHex("ImportFileID", LoadSecSymEntPtr->ImportFileID); 263 W.printNumber("ParameterTypeCheck", LoadSecSymEntPtr->ParameterTypeCheck); 264 } 265 } 266 267 void XCOFFDumper::printLoaderSectionSymbols(uintptr_t LoaderSectionAddr) { 268 DictScope DS(W, "Loader Section Symbols"); 269 if (Obj.is64Bit()) 270 printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry64, 271 LoaderSectionHeader64>(LoaderSectionAddr); 272 else 273 printLoaderSectionSymbolsHelper<LoaderSectionSymbolEntry32, 274 LoaderSectionHeader32>(LoaderSectionAddr); 275 } 276 277 const EnumEntry<XCOFF::RelocationType> RelocationTypeNameclass[] = { 278 #define ECase(X) \ 279 { #X, XCOFF::X } 280 ECase(R_POS), ECase(R_RL), ECase(R_RLA), ECase(R_NEG), 281 ECase(R_REL), ECase(R_TOC), ECase(R_TRL), ECase(R_TRLA), 282 ECase(R_GL), ECase(R_TCL), ECase(R_REF), ECase(R_BA), 283 ECase(R_BR), ECase(R_RBA), ECase(R_RBR), ECase(R_TLS), 284 ECase(R_TLS_IE), ECase(R_TLS_LD), ECase(R_TLS_LE), ECase(R_TLSM), 285 ECase(R_TLSML), ECase(R_TOCU), ECase(R_TOCL) 286 #undef ECase 287 }; 288 289 // From the XCOFF specification: there are five implicit external symbols, one 290 // each for the .text, .data, .bss, .tdata, and .tbss sections. These symbols 291 // are referenced from the relocation table entries using symbol table index 292 // values 0, 1, 2, -1, and -2, respectively. 293 static const char *getImplicitLoaderSectionSymName(int SymIndx) { 294 switch (SymIndx) { 295 default: 296 return "Unkown Symbol Name"; 297 case -2: 298 return ".tbss"; 299 case -1: 300 return ".tdata"; 301 case 0: 302 return ".text"; 303 case 1: 304 return ".data"; 305 case 2: 306 return ".bss"; 307 } 308 } 309 310 template <typename LoadSectionRelocTy> 311 void XCOFFDumper::printLoaderSectionRelocationEntry( 312 LoadSectionRelocTy *LoaderSecRelEntPtr, StringRef SymbolName) { 313 uint16_t Type = LoaderSecRelEntPtr->Type; 314 if (opts::ExpandRelocs) { 315 DictScope DS(W, "Relocation"); 316 auto IsRelocationSigned = [](uint8_t Info) { 317 return Info & XCOFF::XR_SIGN_INDICATOR_MASK; 318 }; 319 auto IsFixupIndicated = [](uint8_t Info) { 320 return Info & XCOFF::XR_FIXUP_INDICATOR_MASK; 321 }; 322 auto GetRelocatedLength = [](uint8_t Info) { 323 // The relocation encodes the bit length being relocated minus 1. Add 324 // back 325 // the 1 to get the actual length being relocated. 326 return (Info & XCOFF::XR_BIASED_LENGTH_MASK) + 1; 327 }; 328 329 uint8_t Info = Type >> 8; 330 W.printHex("Virtual Address", LoaderSecRelEntPtr->VirtualAddr); 331 W.printNumber("Symbol", opts::Demangle ? demangle(SymbolName) : SymbolName, 332 LoaderSecRelEntPtr->SymbolIndex); 333 W.printString("IsSigned", IsRelocationSigned(Info) ? "Yes" : "No"); 334 W.printNumber("FixupBitValue", IsFixupIndicated(Info) ? 1 : 0); 335 W.printNumber("Length", GetRelocatedLength(Info)); 336 W.printEnum("Type", static_cast<uint8_t>(Type), 337 ArrayRef(RelocationTypeNameclass)); 338 W.printNumber("SectionNumber", LoaderSecRelEntPtr->SectionNum); 339 } else { 340 W.startLine() << format_hex(LoaderSecRelEntPtr->VirtualAddr, 341 Obj.is64Bit() ? 18 : 10) 342 << " " << format_hex(Type, 6) << " (" 343 << XCOFF::getRelocationTypeString( 344 static_cast<XCOFF::RelocationType>(Type)) 345 << ")" << format_decimal(LoaderSecRelEntPtr->SectionNum, 8) 346 << " " 347 << (opts::Demangle ? demangle(SymbolName) : SymbolName) 348 << " (" << LoaderSecRelEntPtr->SymbolIndex << ")\n"; 349 } 350 } 351 352 template <typename LoaderSectionHeader, typename LoaderSectionSymbolEntry, 353 typename LoaderSectionRelocationEntry> 354 void XCOFFDumper::printLoaderSectionRelocationEntriesHelper( 355 uintptr_t LoaderSectionAddr) { 356 const LoaderSectionHeader *LoaderSec = 357 reinterpret_cast<const LoaderSectionHeader *>(LoaderSectionAddr); 358 const LoaderSectionRelocationEntry *LoaderSecRelEntPtr = 359 reinterpret_cast<const LoaderSectionRelocationEntry *>( 360 LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToRelEnt())); 361 362 if (!opts::ExpandRelocs) 363 W.startLine() << center_justify("Vaddr", Obj.is64Bit() ? 18 : 10) 364 << center_justify("Type", 15) << right_justify("SecNum", 8) 365 << center_justify("SymbolName (Index) ", 24) << "\n"; 366 367 for (uint32_t i = 0; i < LoaderSec->NumberOfRelTabEnt; 368 ++i, ++LoaderSecRelEntPtr) { 369 StringRef SymbolName; 370 if (LoaderSecRelEntPtr->SymbolIndex >= FirstSymIdxOfLoaderSec) { 371 // Because there are implicit symbol index values (-2, -1, 0, 1, 2), 372 // LoaderSecRelEnt.SymbolIndex - FirstSymIdxOfLoaderSec will get the 373 // real symbol from the symbol table. 374 const uint64_t SymOffset = 375 (LoaderSecRelEntPtr->SymbolIndex - FirstSymIdxOfLoaderSec) * 376 sizeof(LoaderSectionSymbolEntry); 377 const LoaderSectionSymbolEntry *LoaderSecRelSymEntPtr = 378 reinterpret_cast<LoaderSectionSymbolEntry *>( 379 LoaderSectionAddr + uintptr_t(LoaderSec->getOffsetToSymTbl()) + 380 SymOffset); 381 382 Expected<StringRef> SymbolNameOrErr = 383 LoaderSecRelSymEntPtr->getSymbolName(LoaderSec); 384 if (!SymbolNameOrErr) { 385 reportUniqueWarning(SymbolNameOrErr.takeError()); 386 return; 387 } 388 SymbolName = SymbolNameOrErr.get(); 389 } else 390 SymbolName = 391 getImplicitLoaderSectionSymName(LoaderSecRelEntPtr->SymbolIndex); 392 393 printLoaderSectionRelocationEntry(LoaderSecRelEntPtr, SymbolName); 394 } 395 } 396 397 void XCOFFDumper::printLoaderSectionRelocationEntries( 398 uintptr_t LoaderSectionAddr) { 399 DictScope DS(W, "Loader Section Relocations"); 400 401 if (Obj.is64Bit()) 402 printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader64, 403 LoaderSectionSymbolEntry64, 404 LoaderSectionRelocationEntry64>( 405 LoaderSectionAddr); 406 else 407 printLoaderSectionRelocationEntriesHelper<LoaderSectionHeader32, 408 LoaderSectionSymbolEntry32, 409 LoaderSectionRelocationEntry32>( 410 LoaderSectionAddr); 411 } 412 413 template <typename T> 414 void XCOFFDumper::printExceptionSectionEntry(const T &ExceptionSectEnt) const { 415 if (ExceptionSectEnt.getReason()) 416 W.printHex("Trap Instr Addr", ExceptionSectEnt.getTrapInstAddr()); 417 else { 418 uint32_t SymIdx = ExceptionSectEnt.getSymbolIndex(); 419 Expected<StringRef> ErrOrSymbolName = Obj.getSymbolNameByIndex(SymIdx); 420 if (Error E = ErrOrSymbolName.takeError()) { 421 reportUniqueWarning(std::move(E)); 422 return; 423 } 424 StringRef SymName = *ErrOrSymbolName; 425 426 W.printNumber("Symbol", SymName, SymIdx); 427 } 428 W.printNumber("LangID", ExceptionSectEnt.getLangID()); 429 W.printNumber("Reason", ExceptionSectEnt.getReason()); 430 } 431 432 template <typename T> void XCOFFDumper::printExceptionSectionEntries() const { 433 Expected<ArrayRef<T>> ExceptSectEntsOrErr = Obj.getExceptionEntries<T>(); 434 if (Error E = ExceptSectEntsOrErr.takeError()) { 435 reportUniqueWarning(std::move(E)); 436 return; 437 } 438 ArrayRef<T> ExceptSectEnts = *ExceptSectEntsOrErr; 439 440 DictScope DS(W, "Exception section"); 441 if (ExceptSectEnts.empty()) 442 return; 443 for (auto &Ent : ExceptSectEnts) 444 printExceptionSectionEntry(Ent); 445 } 446 447 void XCOFFDumper::printExceptionSection() { 448 if (Obj.is64Bit()) 449 printExceptionSectionEntries<ExceptionSectionEntry64>(); 450 else 451 printExceptionSectionEntries<ExceptionSectionEntry32>(); 452 } 453 454 void XCOFFDumper::printRelocations() { 455 if (Obj.is64Bit()) 456 printRelocations<XCOFFSectionHeader64, XCOFFRelocation64>(Obj.sections64()); 457 else 458 printRelocations<XCOFFSectionHeader32, XCOFFRelocation32>(Obj.sections32()); 459 } 460 461 template <typename RelTy> void XCOFFDumper::printRelocation(RelTy Reloc) { 462 Expected<StringRef> ErrOrSymbolName = 463 Obj.getSymbolNameByIndex(Reloc.SymbolIndex); 464 if (Error E = ErrOrSymbolName.takeError()) { 465 reportUniqueWarning(std::move(E)); 466 return; 467 } 468 StringRef SymbolName = *ErrOrSymbolName; 469 StringRef RelocName = XCOFF::getRelocationTypeString(Reloc.Type); 470 if (opts::ExpandRelocs) { 471 DictScope Group(W, "Relocation"); 472 W.printHex("Virtual Address", Reloc.VirtualAddress); 473 W.printNumber("Symbol", opts::Demangle ? demangle(SymbolName) : SymbolName, 474 Reloc.SymbolIndex); 475 W.printString("IsSigned", Reloc.isRelocationSigned() ? "Yes" : "No"); 476 W.printNumber("FixupBitValue", Reloc.isFixupIndicated() ? 1 : 0); 477 W.printNumber("Length", Reloc.getRelocatedLength()); 478 W.printEnum("Type", (uint8_t)Reloc.Type, ArrayRef(RelocationTypeNameclass)); 479 } else { 480 raw_ostream &OS = W.startLine(); 481 OS << W.hex(Reloc.VirtualAddress) << " " << RelocName << " " 482 << (opts::Demangle ? demangle(SymbolName) : SymbolName) << "(" 483 << Reloc.SymbolIndex << ") " << W.hex(Reloc.Info) << "\n"; 484 } 485 } 486 487 template <typename Shdr, typename RelTy> 488 void XCOFFDumper::printRelocations(ArrayRef<Shdr> Sections) { 489 ListScope LS(W, "Relocations"); 490 uint16_t Index = 0; 491 for (const Shdr &Sec : Sections) { 492 ++Index; 493 // Only the .text, .data, .tdata, and STYP_DWARF sections have relocation. 494 if (Sec.Flags != XCOFF::STYP_TEXT && Sec.Flags != XCOFF::STYP_DATA && 495 Sec.Flags != XCOFF::STYP_TDATA && Sec.Flags != XCOFF::STYP_DWARF) 496 continue; 497 Expected<ArrayRef<RelTy>> ErrOrRelocations = Obj.relocations<Shdr, RelTy>(Sec); 498 if (Error E = ErrOrRelocations.takeError()) { 499 reportUniqueWarning(std::move(E)); 500 continue; 501 } 502 503 const ArrayRef<RelTy> Relocations = *ErrOrRelocations; 504 if (Relocations.empty()) 505 continue; 506 507 W.startLine() << "Section (index: " << Index << ") " << Sec.getName() 508 << " {\n"; 509 W.indent(); 510 511 for (const RelTy Reloc : Relocations) 512 printRelocation(Reloc); 513 514 W.unindent(); 515 W.startLine() << "}\n"; 516 } 517 } 518 519 const EnumEntry<XCOFF::CFileStringType> FileStringType[] = { 520 #define ECase(X) \ 521 { #X, XCOFF::X } 522 ECase(XFT_FN), ECase(XFT_CT), ECase(XFT_CV), ECase(XFT_CD) 523 #undef ECase 524 }; 525 526 const EnumEntry<XCOFF::SymbolAuxType> SymAuxType[] = { 527 #define ECase(X) \ 528 { #X, XCOFF::X } 529 ECase(AUX_EXCEPT), ECase(AUX_FCN), ECase(AUX_SYM), ECase(AUX_FILE), 530 ECase(AUX_CSECT), ECase(AUX_SECT) 531 #undef ECase 532 }; 533 534 void XCOFFDumper::printFileAuxEnt(const XCOFFFileAuxEnt *AuxEntPtr) { 535 assert((!Obj.is64Bit() || AuxEntPtr->AuxType == XCOFF::AUX_FILE) && 536 "Mismatched auxiliary type!"); 537 StringRef FileName = 538 unwrapOrError(Obj.getFileName(), Obj.getCFileName(AuxEntPtr)); 539 DictScope SymDs(W, "File Auxiliary Entry"); 540 W.printNumber("Index", 541 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 542 W.printString("Name", FileName); 543 W.printEnum("Type", static_cast<uint8_t>(AuxEntPtr->Type), 544 ArrayRef(FileStringType)); 545 if (Obj.is64Bit()) { 546 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType), 547 ArrayRef(SymAuxType)); 548 } 549 } 550 551 static const EnumEntry<XCOFF::StorageMappingClass> CsectStorageMappingClass[] = 552 { 553 #define ECase(X) \ 554 { #X, XCOFF::X } 555 ECase(XMC_PR), ECase(XMC_RO), ECase(XMC_DB), ECase(XMC_GL), 556 ECase(XMC_XO), ECase(XMC_SV), ECase(XMC_SV64), ECase(XMC_SV3264), 557 ECase(XMC_TI), ECase(XMC_TB), ECase(XMC_RW), ECase(XMC_TC0), 558 ECase(XMC_TC), ECase(XMC_TD), ECase(XMC_DS), ECase(XMC_UA), 559 ECase(XMC_BS), ECase(XMC_UC), ECase(XMC_TL), ECase(XMC_UL), 560 ECase(XMC_TE) 561 #undef ECase 562 }; 563 564 const EnumEntry<XCOFF::SymbolType> CsectSymbolTypeClass[] = { 565 #define ECase(X) \ 566 { #X, XCOFF::X } 567 ECase(XTY_ER), ECase(XTY_SD), ECase(XTY_LD), ECase(XTY_CM) 568 #undef ECase 569 }; 570 571 void XCOFFDumper::printCsectAuxEnt(XCOFFCsectAuxRef AuxEntRef) { 572 assert((!Obj.is64Bit() || AuxEntRef.getAuxType64() == XCOFF::AUX_CSECT) && 573 "Mismatched auxiliary type!"); 574 575 DictScope SymDs(W, "CSECT Auxiliary Entry"); 576 W.printNumber("Index", Obj.getSymbolIndex(AuxEntRef.getEntryAddress())); 577 W.printNumber(AuxEntRef.isLabel() ? "ContainingCsectSymbolIndex" 578 : "SectionLen", 579 AuxEntRef.getSectionOrLength()); 580 W.printHex("ParameterHashIndex", AuxEntRef.getParameterHashIndex()); 581 W.printHex("TypeChkSectNum", AuxEntRef.getTypeChkSectNum()); 582 // Print out symbol alignment and type. 583 W.printNumber("SymbolAlignmentLog2", AuxEntRef.getAlignmentLog2()); 584 W.printEnum("SymbolType", AuxEntRef.getSymbolType(), 585 ArrayRef(CsectSymbolTypeClass)); 586 W.printEnum("StorageMappingClass", 587 static_cast<uint8_t>(AuxEntRef.getStorageMappingClass()), 588 ArrayRef(CsectStorageMappingClass)); 589 590 if (Obj.is64Bit()) { 591 W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_CSECT), 592 ArrayRef(SymAuxType)); 593 } else { 594 W.printHex("StabInfoIndex", AuxEntRef.getStabInfoIndex32()); 595 W.printHex("StabSectNum", AuxEntRef.getStabSectNum32()); 596 } 597 } 598 599 void XCOFFDumper::printSectAuxEntForStat( 600 const XCOFFSectAuxEntForStat *AuxEntPtr) { 601 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); 602 603 DictScope SymDs(W, "Sect Auxiliary Entry For Stat"); 604 W.printNumber("Index", 605 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 606 W.printNumber("SectionLength", AuxEntPtr->SectionLength); 607 608 // Unlike the corresponding fields in the section header, NumberOfRelocEnt 609 // and NumberOfLineNum do not handle values greater than 65535. 610 W.printNumber("NumberOfRelocEnt", AuxEntPtr->NumberOfRelocEnt); 611 W.printNumber("NumberOfLineNum", AuxEntPtr->NumberOfLineNum); 612 } 613 614 void XCOFFDumper::printExceptionAuxEnt(const XCOFFExceptionAuxEnt *AuxEntPtr) { 615 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file."); 616 617 DictScope SymDs(W, "Exception Auxiliary Entry"); 618 W.printNumber("Index", 619 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 620 W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl); 621 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction); 622 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond); 623 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType), 624 ArrayRef(SymAuxType)); 625 } 626 627 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt32 *AuxEntPtr) { 628 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); 629 630 DictScope SymDs(W, "Function Auxiliary Entry"); 631 W.printNumber("Index", 632 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 633 W.printHex("OffsetToExceptionTable", AuxEntPtr->OffsetToExceptionTbl); 634 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction); 635 W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum); 636 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond); 637 } 638 639 void XCOFFDumper::printFunctionAuxEnt(const XCOFFFunctionAuxEnt64 *AuxEntPtr) { 640 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file."); 641 642 DictScope SymDs(W, "Function Auxiliary Entry"); 643 W.printNumber("Index", 644 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 645 W.printHex("SizeOfFunction", AuxEntPtr->SizeOfFunction); 646 W.printHex("PointerToLineNum", AuxEntPtr->PtrToLineNum); 647 W.printNumber("SymbolIndexOfNextBeyond", AuxEntPtr->SymIdxOfNextBeyond); 648 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType), 649 ArrayRef(SymAuxType)); 650 } 651 652 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt32 *AuxEntPtr) { 653 assert(!Obj.is64Bit() && "32-bit interface called on 64-bit object file."); 654 655 DictScope SymDs(W, "Block Auxiliary Entry"); 656 W.printNumber("Index", 657 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 658 W.printHex("LineNumber (High 2 Bytes)", AuxEntPtr->LineNumHi); 659 W.printHex("LineNumber (Low 2 Bytes)", AuxEntPtr->LineNumLo); 660 } 661 662 void XCOFFDumper::printBlockAuxEnt(const XCOFFBlockAuxEnt64 *AuxEntPtr) { 663 assert(Obj.is64Bit() && "64-bit interface called on 32-bit object file."); 664 665 DictScope SymDs(W, "Block Auxiliary Entry"); 666 W.printNumber("Index", 667 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 668 W.printHex("LineNumber", AuxEntPtr->LineNum); 669 W.printEnum("Auxiliary Type", static_cast<uint8_t>(AuxEntPtr->AuxType), 670 ArrayRef(SymAuxType)); 671 } 672 673 template <typename T> 674 void XCOFFDumper::printSectAuxEntForDWARF(const T *AuxEntPtr) { 675 DictScope SymDs(W, "Sect Auxiliary Entry For DWARF"); 676 W.printNumber("Index", 677 Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr))); 678 W.printHex("LengthOfSectionPortion", AuxEntPtr->LengthOfSectionPortion); 679 W.printNumber("NumberOfRelocEntries", AuxEntPtr->NumberOfRelocEnt); 680 if (Obj.is64Bit()) 681 W.printEnum("Auxiliary Type", static_cast<uint8_t>(XCOFF::AUX_SECT), 682 ArrayRef(SymAuxType)); 683 } 684 685 static StringRef GetSymbolValueName(XCOFF::StorageClass SC) { 686 switch (SC) { 687 case XCOFF::C_EXT: 688 case XCOFF::C_WEAKEXT: 689 case XCOFF::C_HIDEXT: 690 case XCOFF::C_STAT: 691 case XCOFF::C_FCN: 692 case XCOFF::C_BLOCK: 693 return "Value (RelocatableAddress)"; 694 case XCOFF::C_FILE: 695 return "Value (SymbolTableIndex)"; 696 case XCOFF::C_DWARF: 697 return "Value (OffsetInDWARF)"; 698 case XCOFF::C_FUN: 699 case XCOFF::C_STSYM: 700 case XCOFF::C_BINCL: 701 case XCOFF::C_EINCL: 702 case XCOFF::C_INFO: 703 case XCOFF::C_BSTAT: 704 case XCOFF::C_LSYM: 705 case XCOFF::C_PSYM: 706 case XCOFF::C_RPSYM: 707 case XCOFF::C_RSYM: 708 case XCOFF::C_ECOML: 709 assert(false && "This StorageClass for the symbol is not yet implemented."); 710 return ""; 711 default: 712 return "Value"; 713 } 714 } 715 716 const EnumEntry<XCOFF::CFileLangId> CFileLangIdClass[] = { 717 #define ECase(X) \ 718 { #X, XCOFF::X } 719 ECase(TB_C), ECase(TB_Fortran), ECase(TB_CPLUSPLUS) 720 #undef ECase 721 }; 722 723 const EnumEntry<XCOFF::CFileCpuId> CFileCpuIdClass[] = { 724 #define ECase(X) \ 725 { #X, XCOFF::X } 726 ECase(TCPU_PPC64), ECase(TCPU_COM), ECase(TCPU_970) 727 #undef ECase 728 }; 729 730 template <typename T> const T *XCOFFDumper::getAuxEntPtr(uintptr_t AuxAddress) { 731 const T *AuxEntPtr = reinterpret_cast<const T *>(AuxAddress); 732 Obj.checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(AuxEntPtr)); 733 return AuxEntPtr; 734 } 735 736 static void printUnexpectedRawAuxEnt(ScopedPrinter &W, uintptr_t AuxAddress) { 737 W.startLine() << "!Unexpected raw auxiliary entry data:\n"; 738 W.startLine() << format_bytes( 739 ArrayRef<uint8_t>( 740 reinterpret_cast<const uint8_t *>(AuxAddress), 741 XCOFF::SymbolTableEntrySize), 742 std::nullopt, XCOFF::SymbolTableEntrySize) 743 << "\n"; 744 } 745 746 void XCOFFDumper::printSymbol(const SymbolRef &S) { 747 DataRefImpl SymbolDRI = S.getRawDataRefImpl(); 748 XCOFFSymbolRef SymbolEntRef = Obj.toSymbolRef(SymbolDRI); 749 750 uint8_t NumberOfAuxEntries = SymbolEntRef.getNumberOfAuxEntries(); 751 752 DictScope SymDs(W, "Symbol"); 753 754 StringRef SymbolName = 755 unwrapOrError(Obj.getFileName(), SymbolEntRef.getName()); 756 757 uint32_t SymbolIdx = Obj.getSymbolIndex(SymbolEntRef.getEntryAddress()); 758 XCOFF::StorageClass SymbolClass = SymbolEntRef.getStorageClass(); 759 760 W.printNumber("Index", SymbolIdx); 761 W.printString("Name", opts::Demangle ? demangle(SymbolName) : SymbolName); 762 W.printHex(GetSymbolValueName(SymbolClass), SymbolEntRef.getValue()); 763 764 StringRef SectionName = 765 unwrapOrError(Obj.getFileName(), Obj.getSymbolSectionName(SymbolEntRef)); 766 767 W.printString("Section", SectionName); 768 if (SymbolClass == XCOFF::C_FILE) { 769 W.printEnum("Source Language ID", SymbolEntRef.getLanguageIdForCFile(), 770 ArrayRef(CFileLangIdClass)); 771 W.printEnum("CPU Version ID", SymbolEntRef.getCPUTypeIddForCFile(), 772 ArrayRef(CFileCpuIdClass)); 773 } else 774 W.printHex("Type", SymbolEntRef.getSymbolType()); 775 776 W.printEnum("StorageClass", static_cast<uint8_t>(SymbolClass), 777 ArrayRef(SymStorageClass)); 778 W.printNumber("NumberOfAuxEntries", NumberOfAuxEntries); 779 780 if (NumberOfAuxEntries == 0) 781 return; 782 783 auto checkNumOfAux = [=] { 784 if (NumberOfAuxEntries > 1) 785 reportUniqueWarning("the " + 786 enumToString(static_cast<uint8_t>(SymbolClass), 787 ArrayRef(SymStorageClass)) + 788 " symbol at index " + Twine(SymbolIdx) + 789 " should not have more than 1 " 790 "auxiliary entry"); 791 }; 792 793 switch (SymbolClass) { 794 case XCOFF::C_FILE: 795 // If the symbol is C_FILE and has auxiliary entries... 796 for (int I = 1; I <= NumberOfAuxEntries; I++) { 797 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( 798 SymbolEntRef.getEntryAddress(), I); 799 800 if (Obj.is64Bit() && 801 *Obj.getSymbolAuxType(AuxAddress) != XCOFF::SymbolAuxType::AUX_FILE) { 802 printUnexpectedRawAuxEnt(W, AuxAddress); 803 continue; 804 } 805 806 const XCOFFFileAuxEnt *FileAuxEntPtr = 807 getAuxEntPtr<XCOFFFileAuxEnt>(AuxAddress); 808 printFileAuxEnt(FileAuxEntPtr); 809 } 810 break; 811 case XCOFF::C_EXT: 812 case XCOFF::C_WEAKEXT: 813 case XCOFF::C_HIDEXT: { 814 // For 32-bit objects, print the function auxiliary symbol table entry. The 815 // last one must be a CSECT auxiliary entry. 816 // For 64-bit objects, both a function auxiliary entry and an exception 817 // auxiliary entry may appear, print them in the loop and skip printing the 818 // CSECT auxiliary entry, which will be printed outside the loop. 819 for (int I = 1; I <= NumberOfAuxEntries; I++) { 820 if (I == NumberOfAuxEntries && !Obj.is64Bit()) 821 break; 822 823 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( 824 SymbolEntRef.getEntryAddress(), I); 825 826 if (Obj.is64Bit()) { 827 XCOFF::SymbolAuxType Type = *Obj.getSymbolAuxType(AuxAddress); 828 if (Type == XCOFF::SymbolAuxType::AUX_CSECT) 829 continue; 830 if (Type == XCOFF::SymbolAuxType::AUX_FCN) { 831 const XCOFFFunctionAuxEnt64 *AuxEntPtr = 832 getAuxEntPtr<XCOFFFunctionAuxEnt64>(AuxAddress); 833 printFunctionAuxEnt(AuxEntPtr); 834 } else if (Type == XCOFF::SymbolAuxType::AUX_EXCEPT) { 835 const XCOFFExceptionAuxEnt *AuxEntPtr = 836 getAuxEntPtr<XCOFFExceptionAuxEnt>(AuxAddress); 837 printExceptionAuxEnt(AuxEntPtr); 838 } else { 839 printUnexpectedRawAuxEnt(W, AuxAddress); 840 } 841 } else { 842 const XCOFFFunctionAuxEnt32 *AuxEntPtr = 843 getAuxEntPtr<XCOFFFunctionAuxEnt32>(AuxAddress); 844 printFunctionAuxEnt(AuxEntPtr); 845 } 846 } 847 848 // Print the CSECT auxiliary entry. 849 auto ErrOrCsectAuxRef = SymbolEntRef.getXCOFFCsectAuxRef(); 850 if (!ErrOrCsectAuxRef) 851 reportUniqueWarning(ErrOrCsectAuxRef.takeError()); 852 else 853 printCsectAuxEnt(*ErrOrCsectAuxRef); 854 855 break; 856 } 857 case XCOFF::C_STAT: { 858 checkNumOfAux(); 859 860 const XCOFFSectAuxEntForStat *StatAuxEntPtr = 861 getAuxEntPtr<XCOFFSectAuxEntForStat>( 862 XCOFFObjectFile::getAdvancedSymbolEntryAddress( 863 SymbolEntRef.getEntryAddress(), 1)); 864 printSectAuxEntForStat(StatAuxEntPtr); 865 break; 866 } 867 case XCOFF::C_DWARF: { 868 checkNumOfAux(); 869 870 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( 871 SymbolEntRef.getEntryAddress(), 1); 872 873 if (Obj.is64Bit()) { 874 const XCOFFSectAuxEntForDWARF64 *AuxEntPtr = 875 getAuxEntPtr<XCOFFSectAuxEntForDWARF64>(AuxAddress); 876 printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF64>(AuxEntPtr); 877 } else { 878 const XCOFFSectAuxEntForDWARF32 *AuxEntPtr = 879 getAuxEntPtr<XCOFFSectAuxEntForDWARF32>(AuxAddress); 880 printSectAuxEntForDWARF<XCOFFSectAuxEntForDWARF32>(AuxEntPtr); 881 } 882 break; 883 } 884 case XCOFF::C_BLOCK: 885 case XCOFF::C_FCN: { 886 checkNumOfAux(); 887 888 uintptr_t AuxAddress = XCOFFObjectFile::getAdvancedSymbolEntryAddress( 889 SymbolEntRef.getEntryAddress(), 1); 890 891 if (Obj.is64Bit()) { 892 const XCOFFBlockAuxEnt64 *AuxEntPtr = 893 getAuxEntPtr<XCOFFBlockAuxEnt64>(AuxAddress); 894 printBlockAuxEnt(AuxEntPtr); 895 } else { 896 const XCOFFBlockAuxEnt32 *AuxEntPtr = 897 getAuxEntPtr<XCOFFBlockAuxEnt32>(AuxAddress); 898 printBlockAuxEnt(AuxEntPtr); 899 } 900 break; 901 } 902 default: 903 for (int i = 1; i <= NumberOfAuxEntries; i++) { 904 printUnexpectedRawAuxEnt(W, 905 XCOFFObjectFile::getAdvancedSymbolEntryAddress( 906 SymbolEntRef.getEntryAddress(), i)); 907 } 908 break; 909 } 910 } 911 912 void XCOFFDumper::printSymbols(bool /*ExtraSymInfo*/) { 913 ListScope Group(W, "Symbols"); 914 for (const SymbolRef &S : Obj.symbols()) 915 printSymbol(S); 916 } 917 918 void XCOFFDumper::printStringTable() { 919 DictScope DS(W, "StringTable"); 920 StringRef StrTable = Obj.getStringTable(); 921 uint32_t StrTabSize = StrTable.size(); 922 W.printNumber("Length", StrTabSize); 923 // Print strings from the fifth byte, since the first four bytes contain the 924 // length (in bytes) of the string table (including the length field). 925 if (StrTabSize > 4) 926 printAsStringList(StrTable, 4); 927 } 928 929 void XCOFFDumper::printDynamicSymbols() { 930 llvm_unreachable("Unimplemented functionality for XCOFFDumper"); 931 } 932 933 void XCOFFDumper::printUnwindInfo() { 934 llvm_unreachable("Unimplemented functionality for XCOFFDumper"); 935 } 936 937 void XCOFFDumper::printStackMap() const { 938 llvm_unreachable("Unimplemented functionality for XCOFFDumper"); 939 } 940 941 void XCOFFDumper::printNeededLibraries() { 942 ListScope D(W, "NeededLibraries"); 943 auto ImportFilesOrError = Obj.getImportFileTable(); 944 if (!ImportFilesOrError) { 945 reportUniqueWarning(ImportFilesOrError.takeError()); 946 return; 947 } 948 949 StringRef ImportFileTable = ImportFilesOrError.get(); 950 const char *CurrentStr = ImportFileTable.data(); 951 const char *TableEnd = ImportFileTable.end(); 952 // Default column width for names is 13 even if no names are that long. 953 size_t BaseWidth = 13; 954 955 // Get the max width of BASE columns. 956 for (size_t StrIndex = 0; CurrentStr < TableEnd; ++StrIndex) { 957 size_t CurrentLen = strlen(CurrentStr); 958 CurrentStr += strlen(CurrentStr) + 1; 959 if (StrIndex % 3 == 1) 960 BaseWidth = std::max(BaseWidth, CurrentLen); 961 } 962 963 auto &OS = static_cast<formatted_raw_ostream &>(W.startLine()); 964 // Each entry consists of 3 strings: the path_name, base_name and 965 // archive_member_name. The first entry is a default LIBPATH value and other 966 // entries have no path_name. We just dump the base_name and 967 // archive_member_name here. 968 OS << left_justify("BASE", BaseWidth) << " MEMBER\n"; 969 CurrentStr = ImportFileTable.data(); 970 for (size_t StrIndex = 0; CurrentStr < TableEnd; 971 ++StrIndex, CurrentStr += strlen(CurrentStr) + 1) { 972 if (StrIndex >= 3 && StrIndex % 3 != 0) { 973 if (StrIndex % 3 == 1) 974 OS << " " << left_justify(CurrentStr, BaseWidth) << " "; 975 else 976 OS << CurrentStr << "\n"; 977 } 978 } 979 } 980 981 const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = { 982 #define ECase(X) \ 983 { #X, XCOFF::X } 984 ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT), 985 ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT), 986 ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS), 987 ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK), 988 ECase(STYP_OVRFLO) 989 #undef ECase 990 }; 991 992 const EnumEntry<XCOFF::DwarfSectionSubtypeFlags> 993 DWARFSectionSubtypeFlagsNames[] = { 994 #define ECase(X) \ 995 { #X, XCOFF::X } 996 ECase(SSUBTYP_DWINFO), ECase(SSUBTYP_DWLINE), ECase(SSUBTYP_DWPBNMS), 997 ECase(SSUBTYP_DWPBTYP), ECase(SSUBTYP_DWARNGE), ECase(SSUBTYP_DWABREV), 998 ECase(SSUBTYP_DWSTR), ECase(SSUBTYP_DWRNGES), ECase(SSUBTYP_DWLOC), 999 ECase(SSUBTYP_DWFRAME), ECase(SSUBTYP_DWMAC) 1000 #undef ECase 1001 }; 1002 1003 template <typename T> 1004 void XCOFFDumper::printOverflowSectionHeader(T &Sec) const { 1005 if (Obj.is64Bit()) { 1006 reportWarning(make_error<StringError>("An 64-bit XCOFF object file may not " 1007 "contain an overflow section header.", 1008 object_error::parse_failed), 1009 Obj.getFileName()); 1010 } 1011 1012 W.printString("Name", Sec.getName()); 1013 W.printNumber("NumberOfRelocations", Sec.PhysicalAddress); 1014 W.printNumber("NumberOfLineNumbers", Sec.VirtualAddress); 1015 W.printHex("Size", Sec.SectionSize); 1016 W.printHex("RawDataOffset", Sec.FileOffsetToRawData); 1017 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); 1018 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); 1019 W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfRelocations); 1020 W.printNumber("IndexOfSectionOverflowed", Sec.NumberOfLineNumbers); 1021 } 1022 1023 template <typename T> 1024 void XCOFFDumper::printGenericSectionHeader(T &Sec) const { 1025 W.printString("Name", Sec.getName()); 1026 W.printHex("PhysicalAddress", Sec.PhysicalAddress); 1027 W.printHex("VirtualAddress", Sec.VirtualAddress); 1028 W.printHex("Size", Sec.SectionSize); 1029 W.printHex("RawDataOffset", Sec.FileOffsetToRawData); 1030 W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); 1031 W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); 1032 W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); 1033 W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); 1034 } 1035 1036 enum PrintStyle { Hex, Number }; 1037 template <typename T, typename V> 1038 static void printAuxMemberHelper(PrintStyle Style, const char *MemberName, 1039 const T &Member, const V *AuxHeader, 1040 uint16_t AuxSize, uint16_t &PartialFieldOffset, 1041 const char *&PartialFieldName, 1042 ScopedPrinter &W) { 1043 ptrdiff_t Offset = reinterpret_cast<const char *>(&Member) - 1044 reinterpret_cast<const char *>(AuxHeader); 1045 if (Offset + sizeof(Member) <= AuxSize) 1046 Style == Hex ? W.printHex(MemberName, Member) 1047 : W.printNumber(MemberName, Member); 1048 else if (Offset < AuxSize) { 1049 PartialFieldOffset = Offset; 1050 PartialFieldName = MemberName; 1051 } 1052 } 1053 1054 template <class T> 1055 void checkAndPrintAuxHeaderParseError(const char *PartialFieldName, 1056 uint16_t PartialFieldOffset, 1057 uint16_t AuxSize, T &AuxHeader, 1058 XCOFFDumper *Dumper) { 1059 if (PartialFieldOffset < AuxSize) { 1060 Dumper->reportUniqueWarning(Twine("only partial field for ") + 1061 PartialFieldName + " at offset (" + 1062 Twine(PartialFieldOffset) + ")"); 1063 Dumper->getScopedPrinter().printBinary( 1064 "Raw data", "", 1065 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) + 1066 PartialFieldOffset, 1067 AuxSize - PartialFieldOffset)); 1068 } else if (sizeof(AuxHeader) < AuxSize) 1069 Dumper->getScopedPrinter().printBinary( 1070 "Extra raw data", "", 1071 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) + 1072 sizeof(AuxHeader), 1073 AuxSize - sizeof(AuxHeader))); 1074 } 1075 1076 void XCOFFDumper::printAuxiliaryHeader( 1077 const XCOFFAuxiliaryHeader32 *AuxHeader) { 1078 if (AuxHeader == nullptr) 1079 return; 1080 uint16_t AuxSize = Obj.getOptionalHeaderSize(); 1081 uint16_t PartialFieldOffset = AuxSize; 1082 const char *PartialFieldName = nullptr; 1083 1084 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName, 1085 auto &Member) { 1086 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize, 1087 PartialFieldOffset, PartialFieldName, W); 1088 }; 1089 1090 PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic); 1091 PrintAuxMember(Hex, "Version", AuxHeader->Version); 1092 PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize); 1093 PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize); 1094 PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize); 1095 PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr); 1096 PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr); 1097 PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr); 1098 PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr); 1099 PrintAuxMember(Number, "Section number of entryPoint", 1100 AuxHeader->SecNumOfEntryPoint); 1101 PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText); 1102 PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData); 1103 PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC); 1104 PrintAuxMember(Number, "Section number of loader data", 1105 AuxHeader->SecNumOfLoader); 1106 PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS); 1107 PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText); 1108 PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData); 1109 PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType); 1110 PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag); 1111 PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType); 1112 PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize); 1113 PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize); 1114 PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger); 1115 PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize); 1116 PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize); 1117 PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize); 1118 if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) + 1119 sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <= 1120 AuxSize) { 1121 W.printHex("Flag", AuxHeader->getFlag()); 1122 W.printHex("Alignment of thread-local storage", 1123 AuxHeader->getTDataAlignment()); 1124 } 1125 1126 PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData); 1127 PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS); 1128 1129 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset, 1130 AuxSize, *AuxHeader, this); 1131 } 1132 1133 void XCOFFDumper::printAuxiliaryHeader( 1134 const XCOFFAuxiliaryHeader64 *AuxHeader) { 1135 if (AuxHeader == nullptr) 1136 return; 1137 uint16_t AuxSize = Obj.getOptionalHeaderSize(); 1138 uint16_t PartialFieldOffset = AuxSize; 1139 const char *PartialFieldName = nullptr; 1140 1141 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName, 1142 auto &Member) { 1143 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize, 1144 PartialFieldOffset, PartialFieldName, W); 1145 }; 1146 1147 PrintAuxMember(Hex, "Magic", AuxHeader->AuxMagic); 1148 PrintAuxMember(Hex, "Version", AuxHeader->Version); 1149 PrintAuxMember(Hex, "Reserved for debugger", AuxHeader->ReservedForDebugger); 1150 PrintAuxMember(Hex, ".text section start address", AuxHeader->TextStartAddr); 1151 PrintAuxMember(Hex, ".data section start address", AuxHeader->DataStartAddr); 1152 PrintAuxMember(Hex, "TOC anchor address", AuxHeader->TOCAnchorAddr); 1153 PrintAuxMember(Number, "Section number of entryPoint", 1154 AuxHeader->SecNumOfEntryPoint); 1155 PrintAuxMember(Number, "Section number of .text", AuxHeader->SecNumOfText); 1156 PrintAuxMember(Number, "Section number of .data", AuxHeader->SecNumOfData); 1157 PrintAuxMember(Number, "Section number of TOC", AuxHeader->SecNumOfTOC); 1158 PrintAuxMember(Number, "Section number of loader data", 1159 AuxHeader->SecNumOfLoader); 1160 PrintAuxMember(Number, "Section number of .bss", AuxHeader->SecNumOfBSS); 1161 PrintAuxMember(Hex, "Maxium alignment of .text", AuxHeader->MaxAlignOfText); 1162 PrintAuxMember(Hex, "Maxium alignment of .data", AuxHeader->MaxAlignOfData); 1163 PrintAuxMember(Hex, "Module type", AuxHeader->ModuleType); 1164 PrintAuxMember(Hex, "CPU type of objects", AuxHeader->CpuFlag); 1165 PrintAuxMember(Hex, "(Reserved)", AuxHeader->CpuType); 1166 PrintAuxMember(Hex, "Text page size", AuxHeader->TextPageSize); 1167 PrintAuxMember(Hex, "Data page size", AuxHeader->DataPageSize); 1168 PrintAuxMember(Hex, "Stack page size", AuxHeader->StackPageSize); 1169 if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) + 1170 sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <= 1171 AuxSize) { 1172 W.printHex("Flag", AuxHeader->getFlag()); 1173 W.printHex("Alignment of thread-local storage", 1174 AuxHeader->getTDataAlignment()); 1175 } 1176 PrintAuxMember(Hex, "Size of .text section", AuxHeader->TextSize); 1177 PrintAuxMember(Hex, "Size of .data section", AuxHeader->InitDataSize); 1178 PrintAuxMember(Hex, "Size of .bss section", AuxHeader->BssDataSize); 1179 PrintAuxMember(Hex, "Entry point address", AuxHeader->EntryPointAddr); 1180 PrintAuxMember(Hex, "Maximum stack size", AuxHeader->MaxStackSize); 1181 PrintAuxMember(Hex, "Maximum data size", AuxHeader->MaxDataSize); 1182 PrintAuxMember(Number, "Section number for .tdata", AuxHeader->SecNumOfTData); 1183 PrintAuxMember(Number, "Section number for .tbss", AuxHeader->SecNumOfTBSS); 1184 PrintAuxMember(Hex, "Additional flags 64-bit XCOFF", AuxHeader->XCOFF64Flag); 1185 1186 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset, 1187 AuxSize, *AuxHeader, this); 1188 } 1189 1190 template <typename T> 1191 void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { 1192 ListScope Group(W, "Sections"); 1193 1194 uint16_t Index = 1; 1195 for (const T &Sec : Sections) { 1196 DictScope SecDS(W, "Section"); 1197 1198 W.printNumber("Index", Index++); 1199 uint16_t SectionType = Sec.getSectionType(); 1200 int32_t SectionSubtype = Sec.getSectionSubtype(); 1201 switch (SectionType) { 1202 case XCOFF::STYP_OVRFLO: 1203 printOverflowSectionHeader(Sec); 1204 break; 1205 case XCOFF::STYP_LOADER: 1206 case XCOFF::STYP_EXCEPT: 1207 case XCOFF::STYP_TYPCHK: 1208 // TODO The interpretation of loader, exception and type check section 1209 // headers are different from that of generic section headers. We will 1210 // implement them later. We interpret them as generic section headers for 1211 // now. 1212 default: 1213 printGenericSectionHeader(Sec); 1214 break; 1215 } 1216 if (Sec.isReservedSectionType()) 1217 W.printHex("Flags", "Reserved", SectionType); 1218 else { 1219 W.printEnum("Type", SectionType, ArrayRef(SectionTypeFlagsNames)); 1220 if (SectionType == XCOFF::STYP_DWARF) { 1221 W.printEnum("DWARFSubType", SectionSubtype, 1222 ArrayRef(DWARFSectionSubtypeFlagsNames)); 1223 } 1224 } 1225 } 1226 1227 if (opts::SectionRelocations) 1228 report_fatal_error("Dumping section relocations is unimplemented"); 1229 1230 if (opts::SectionSymbols) 1231 report_fatal_error("Dumping symbols is unimplemented"); 1232 1233 if (opts::SectionData) 1234 report_fatal_error("Dumping section data is unimplemented"); 1235 } 1236 1237 namespace llvm { 1238 std::unique_ptr<ObjDumper> 1239 createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) { 1240 return std::make_unique<XCOFFDumper>(XObj, Writer); 1241 } 1242 } // namespace llvm 1243