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