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