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