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