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