1 //===-- XCOFFDump.cpp - XCOFF-specific dumper -----------------------------===// 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 /// \file 10 /// This file implements the XCOFF-specific dumper for llvm-objdump. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "XCOFFDump.h" 15 16 #include "llvm-objdump.h" 17 #include "llvm/ADT/StringExtras.h" 18 #include "llvm/Demangle/Demangle.h" 19 #include "llvm/MC/MCInstPrinter.h" 20 #include "llvm/MC/MCSubtargetInfo.h" 21 #include "llvm/Support/Endian.h" 22 #include "llvm/Support/Format.h" 23 #include "llvm/Support/FormattedStream.h" 24 #include "llvm/Support/raw_ostream.h" 25 #include <algorithm> 26 27 using namespace llvm; 28 using namespace llvm::object; 29 using namespace llvm::XCOFF; 30 using namespace llvm::support; 31 32 namespace { 33 class XCOFFDumper : public objdump::Dumper { 34 enum PrintStyle { Hex, Number }; 35 const XCOFFObjectFile &Obj; 36 unsigned Width; 37 38 public: 39 XCOFFDumper(const object::XCOFFObjectFile &O) : Dumper(O), Obj(O) {} 40 41 private: 42 void printPrivateHeaders() override; 43 void printFileHeader(); 44 void printAuxiliaryHeader(); 45 void printLoaderSectionHeader(); 46 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader32 *AuxHeader); 47 void printAuxiliaryHeader(const XCOFFAuxiliaryHeader64 *AuxHeader); 48 template <typename AuxHeaderMemberType, typename XCOFFAuxiliaryHeader> 49 void printAuxMemberHelper(PrintStyle Style, const char *MemberName, 50 const AuxHeaderMemberType &Member, 51 const XCOFFAuxiliaryHeader *AuxHeader, 52 uint16_t AuxSize, uint16_t &PartialFieldOffset, 53 const char *&PartialFieldName); 54 template <typename XCOFFAuxiliaryHeader> 55 void checkAndPrintAuxHeaderParseError(const char *PartialFieldName, 56 uint16_t PartialFieldOffset, 57 uint16_t AuxSize, 58 XCOFFAuxiliaryHeader &AuxHeader); 59 60 void printBinary(StringRef Name, ArrayRef<uint8_t> Data); 61 void printHex(StringRef Name, uint64_t Value); 62 void printNumber(StringRef Name, uint64_t Value); 63 FormattedString formatName(StringRef Name); 64 void printStrHex(StringRef Name, StringRef Str, uint64_t Value); 65 }; 66 67 void XCOFFDumper::printPrivateHeaders() { 68 printFileHeader(); 69 printAuxiliaryHeader(); 70 printLoaderSectionHeader(); 71 } 72 73 FormattedString XCOFFDumper::formatName(StringRef Name) { 74 return FormattedString(Name, Width, FormattedString::JustifyLeft); 75 } 76 77 void XCOFFDumper::printHex(StringRef Name, uint64_t Value) { 78 outs() << formatName(Name) << format_hex(Value, 0) << "\n"; 79 } 80 81 void XCOFFDumper::printNumber(StringRef Name, uint64_t Value) { 82 outs() << formatName(Name) << format_decimal(Value, 0) << "\n"; 83 } 84 85 void XCOFFDumper::printStrHex(StringRef Name, StringRef Str, uint64_t Value) { 86 outs() << formatName(Name) << Str << " (" << format_decimal(Value, 0) 87 << ")\n"; 88 } 89 90 void XCOFFDumper::printBinary(StringRef Name, ArrayRef<uint8_t> Data) { 91 unsigned OrgWidth = Width; 92 Width = 0; 93 outs() << formatName(Name) << " (" << format_bytes(Data) << ")\n"; 94 Width = OrgWidth; 95 } 96 97 void XCOFFDumper::printAuxiliaryHeader() { 98 Width = 36; 99 if (Obj.is64Bit()) 100 printAuxiliaryHeader(Obj.auxiliaryHeader64()); 101 else 102 printAuxiliaryHeader(Obj.auxiliaryHeader32()); 103 } 104 105 template <typename AuxHeaderMemberType, typename XCOFFAuxiliaryHeader> 106 void XCOFFDumper::printAuxMemberHelper(PrintStyle Style, const char *MemberName, 107 const AuxHeaderMemberType &Member, 108 const XCOFFAuxiliaryHeader *AuxHeader, 109 uint16_t AuxSize, 110 uint16_t &PartialFieldOffset, 111 const char *&PartialFieldName) { 112 ptrdiff_t Offset = reinterpret_cast<const char *>(&Member) - 113 reinterpret_cast<const char *>(AuxHeader); 114 if (Offset + sizeof(Member) <= AuxSize) { 115 if (Style == Hex) 116 printHex(MemberName, Member); 117 else 118 printNumber(MemberName, Member); 119 } else if (Offset < AuxSize) { 120 PartialFieldOffset = Offset; 121 PartialFieldName = MemberName; 122 } 123 } 124 125 template <typename XCOFFAuxiliaryHeader> 126 void XCOFFDumper::checkAndPrintAuxHeaderParseError( 127 const char *PartialFieldName, uint16_t PartialFieldOffset, uint16_t AuxSize, 128 XCOFFAuxiliaryHeader &AuxHeader) { 129 if (PartialFieldOffset < AuxSize) { 130 std::string Buf; 131 raw_string_ostream OS(Buf); 132 OS.flush(); 133 OS << FormattedString("Raw data", 0, FormattedString::JustifyLeft) << " (" 134 << format_bytes( 135 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) + 136 PartialFieldOffset, 137 AuxSize - PartialFieldOffset)) 138 << ")\n"; 139 reportUniqueWarning(Twine("only partial field for ") + PartialFieldName + 140 " at offset (" + Twine(PartialFieldOffset) + ")\n" + 141 OS.str()); 142 } else if (sizeof(AuxHeader) < AuxSize) { 143 printBinary( 144 "Extra raw data", 145 ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&AuxHeader) + 146 sizeof(AuxHeader), 147 AuxSize - sizeof(AuxHeader))); 148 } 149 } 150 151 void XCOFFDumper::printAuxiliaryHeader( 152 const XCOFFAuxiliaryHeader32 *AuxHeader) { 153 if (AuxHeader == nullptr) 154 return; 155 outs() << "\n---Auxiliary Header:\n"; 156 uint16_t AuxSize = Obj.getOptionalHeaderSize(); 157 uint16_t PartialFieldOffset = AuxSize; 158 const char *PartialFieldName = nullptr; 159 160 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName, 161 auto &Member) { 162 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize, 163 PartialFieldOffset, PartialFieldName); 164 }; 165 166 PrintAuxMember(Hex, "Magic:", AuxHeader->AuxMagic); 167 PrintAuxMember(Hex, "Version:", AuxHeader->Version); 168 PrintAuxMember(Hex, "Size of .text section:", AuxHeader->TextSize); 169 PrintAuxMember(Hex, "Size of .data section:", AuxHeader->InitDataSize); 170 PrintAuxMember(Hex, "Size of .bss section:", AuxHeader->BssDataSize); 171 PrintAuxMember(Hex, "Entry point address:", AuxHeader->EntryPointAddr); 172 PrintAuxMember(Hex, ".text section start address:", AuxHeader->TextStartAddr); 173 PrintAuxMember(Hex, ".data section start address:", AuxHeader->DataStartAddr); 174 PrintAuxMember(Hex, "TOC anchor address:", AuxHeader->TOCAnchorAddr); 175 PrintAuxMember( 176 Number, "Section number of entryPoint:", AuxHeader->SecNumOfEntryPoint); 177 PrintAuxMember(Number, "Section number of .text:", AuxHeader->SecNumOfText); 178 PrintAuxMember(Number, "Section number of .data:", AuxHeader->SecNumOfData); 179 PrintAuxMember(Number, "Section number of TOC:", AuxHeader->SecNumOfTOC); 180 PrintAuxMember(Number, 181 "Section number of loader data:", AuxHeader->SecNumOfLoader); 182 PrintAuxMember(Number, "Section number of .bss:", AuxHeader->SecNumOfBSS); 183 PrintAuxMember(Hex, "Maxium alignment of .text:", AuxHeader->MaxAlignOfText); 184 PrintAuxMember(Hex, "Maxium alignment of .data:", AuxHeader->MaxAlignOfData); 185 PrintAuxMember(Hex, "Module type:", AuxHeader->ModuleType); 186 PrintAuxMember(Hex, "CPU type of objects:", AuxHeader->CpuFlag); 187 PrintAuxMember(Hex, "Maximum stack size:", AuxHeader->MaxStackSize); 188 PrintAuxMember(Hex, "Maximum data size:", AuxHeader->MaxDataSize); 189 PrintAuxMember(Hex, "Reserved for debugger:", AuxHeader->ReservedForDebugger); 190 PrintAuxMember(Hex, "Text page size:", AuxHeader->TextPageSize); 191 PrintAuxMember(Hex, "Data page size:", AuxHeader->DataPageSize); 192 PrintAuxMember(Hex, "Stack page size:", AuxHeader->StackPageSize); 193 if (offsetof(XCOFFAuxiliaryHeader32, FlagAndTDataAlignment) + 194 sizeof(XCOFFAuxiliaryHeader32::FlagAndTDataAlignment) <= 195 AuxSize) { 196 printHex("Flag:", AuxHeader->getFlag()); 197 printHex("Alignment of thread-local storage:", 198 AuxHeader->getTDataAlignment()); 199 } 200 201 PrintAuxMember(Number, 202 "Section number for .tdata:", AuxHeader->SecNumOfTData); 203 PrintAuxMember(Number, "Section number for .tbss:", AuxHeader->SecNumOfTBSS); 204 205 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset, 206 AuxSize, *AuxHeader); 207 } 208 209 void XCOFFDumper::printAuxiliaryHeader( 210 const XCOFFAuxiliaryHeader64 *AuxHeader) { 211 if (AuxHeader == nullptr) 212 return; 213 uint16_t AuxSize = Obj.getOptionalHeaderSize(); 214 outs() << "\n---Auxiliary Header:\n"; 215 uint16_t PartialFieldOffset = AuxSize; 216 const char *PartialFieldName = nullptr; 217 218 auto PrintAuxMember = [&](PrintStyle Style, const char *MemberName, 219 auto &Member) { 220 printAuxMemberHelper(Style, MemberName, Member, AuxHeader, AuxSize, 221 PartialFieldOffset, PartialFieldName); 222 }; 223 224 PrintAuxMember(Hex, "Magic:", AuxHeader->AuxMagic); 225 PrintAuxMember(Hex, "Version:", AuxHeader->Version); 226 PrintAuxMember(Hex, "Reserved for debugger:", AuxHeader->ReservedForDebugger); 227 PrintAuxMember(Hex, ".text section start address:", AuxHeader->TextStartAddr); 228 PrintAuxMember(Hex, ".data section start address:", AuxHeader->DataStartAddr); 229 PrintAuxMember(Hex, "TOC anchor address:", AuxHeader->TOCAnchorAddr); 230 PrintAuxMember( 231 Number, "Section number of entryPoint:", AuxHeader->SecNumOfEntryPoint); 232 PrintAuxMember(Number, "Section number of .text:", AuxHeader->SecNumOfText); 233 PrintAuxMember(Number, "Section number of .data:", AuxHeader->SecNumOfData); 234 PrintAuxMember(Number, "Section number of TOC:", AuxHeader->SecNumOfTOC); 235 PrintAuxMember(Number, 236 "Section number of loader data:", AuxHeader->SecNumOfLoader); 237 PrintAuxMember(Number, "Section number of .bss:", AuxHeader->SecNumOfBSS); 238 PrintAuxMember(Hex, "Maxium alignment of .text:", AuxHeader->MaxAlignOfText); 239 PrintAuxMember(Hex, "Maxium alignment of .data:", AuxHeader->MaxAlignOfData); 240 PrintAuxMember(Hex, "Module type:", AuxHeader->ModuleType); 241 PrintAuxMember(Hex, "CPU type of objects:", AuxHeader->CpuFlag); 242 PrintAuxMember(Hex, "Text page size:", AuxHeader->TextPageSize); 243 PrintAuxMember(Hex, "Data page size:", AuxHeader->DataPageSize); 244 PrintAuxMember(Hex, "Stack page size:", AuxHeader->StackPageSize); 245 if (offsetof(XCOFFAuxiliaryHeader64, FlagAndTDataAlignment) + 246 sizeof(XCOFFAuxiliaryHeader64::FlagAndTDataAlignment) <= 247 AuxSize) { 248 printHex("Flag:", AuxHeader->getFlag()); 249 printHex("Alignment of thread-local storage:", 250 AuxHeader->getTDataAlignment()); 251 } 252 PrintAuxMember(Hex, "Size of .text section:", AuxHeader->TextSize); 253 PrintAuxMember(Hex, "Size of .data section:", AuxHeader->InitDataSize); 254 PrintAuxMember(Hex, "Size of .bss section:", AuxHeader->BssDataSize); 255 PrintAuxMember(Hex, "Entry point address:", AuxHeader->EntryPointAddr); 256 PrintAuxMember(Hex, "Maximum stack size:", AuxHeader->MaxStackSize); 257 PrintAuxMember(Hex, "Maximum data size:", AuxHeader->MaxDataSize); 258 PrintAuxMember(Number, 259 "Section number for .tdata:", AuxHeader->SecNumOfTData); 260 PrintAuxMember(Number, "Section number for .tbss:", AuxHeader->SecNumOfTBSS); 261 PrintAuxMember(Hex, "Additional flags 64-bit XCOFF:", AuxHeader->XCOFF64Flag); 262 263 checkAndPrintAuxHeaderParseError(PartialFieldName, PartialFieldOffset, 264 AuxSize, *AuxHeader); 265 } 266 267 void XCOFFDumper::printLoaderSectionHeader() { 268 Expected<uintptr_t> LoaderSectionAddrOrError = 269 Obj.getSectionFileOffsetToRawData(XCOFF::STYP_LOADER); 270 if (!LoaderSectionAddrOrError) { 271 reportUniqueWarning(LoaderSectionAddrOrError.takeError()); 272 return; 273 } 274 uintptr_t LoaderSectionAddr = LoaderSectionAddrOrError.get(); 275 276 if (LoaderSectionAddr == 0) 277 return; 278 279 auto PrintLoadSecHeaderCommon = [&](const auto *LDHeader) { 280 printNumber("Version:", LDHeader->Version); 281 printNumber("NumberOfSymbolEntries:", LDHeader->NumberOfSymTabEnt); 282 printNumber("NumberOfRelocationEntries:", LDHeader->NumberOfRelTabEnt); 283 printNumber("LengthOfImportFileIDStringTable:", 284 LDHeader->LengthOfImpidStrTbl); 285 printNumber("NumberOfImportFileIDs:", LDHeader->NumberOfImpid); 286 printHex("OffsetToImportFileIDs:", LDHeader->OffsetToImpid); 287 printNumber("LengthOfStringTable:", LDHeader->LengthOfStrTbl); 288 printHex("OffsetToStringTable:", LDHeader->OffsetToStrTbl); 289 }; 290 291 Width = 35; 292 outs() << "\n---Loader Section Header:\n"; 293 if (Obj.is64Bit()) { 294 const LoaderSectionHeader64 *LoaderSec64 = 295 reinterpret_cast<const LoaderSectionHeader64 *>(LoaderSectionAddr); 296 PrintLoadSecHeaderCommon(LoaderSec64); 297 printHex("OffsetToSymbolTable", LoaderSec64->OffsetToSymTbl); 298 printHex("OffsetToRelocationEntries", LoaderSec64->OffsetToRelEnt); 299 } else { 300 const LoaderSectionHeader32 *LoaderSec32 = 301 reinterpret_cast<const LoaderSectionHeader32 *>(LoaderSectionAddr); 302 PrintLoadSecHeaderCommon(LoaderSec32); 303 } 304 } 305 306 void XCOFFDumper::printFileHeader() { 307 Width = 20; 308 outs() << "\n---File Header:\n"; 309 printHex("Magic:", Obj.getMagic()); 310 printNumber("NumberOfSections:", Obj.getNumberOfSections()); 311 312 int32_t Timestamp = Obj.getTimeStamp(); 313 if (Timestamp > 0) { 314 // This handling of the timestamp assumes that the host system's time_t is 315 // compatible with AIX time_t. If a platform is not compatible, the lit 316 // tests will let us know. 317 time_t TimeDate = Timestamp; 318 319 char FormattedTime[20] = {}; 320 321 size_t BytesFormatted = std::strftime(FormattedTime, sizeof(FormattedTime), 322 "%F %T", std::gmtime(&TimeDate)); 323 assert(BytesFormatted && "The size of the buffer FormattedTime is less " 324 "than the size of the date/time string."); 325 (void)BytesFormatted; 326 printStrHex("Timestamp:", FormattedTime, Timestamp); 327 } else { 328 // Negative timestamp values are reserved for future use. 329 printStrHex("Timestamp:", Timestamp == 0 ? "None" : "Reserved Value", 330 Timestamp); 331 } 332 333 // The number of symbol table entries is an unsigned value in 64-bit objects 334 // and a signed value (with negative values being 'reserved') in 32-bit 335 // objects. 336 if (Obj.is64Bit()) { 337 printHex("SymbolTableOffset:", Obj.getSymbolTableOffset64()); 338 printNumber("SymbolTableEntries:", Obj.getNumberOfSymbolTableEntries64()); 339 } else { 340 printHex("SymbolTableOffset:", Obj.getSymbolTableOffset32()); 341 int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32(); 342 if (SymTabEntries >= 0) 343 printNumber("SymbolTableEntries:", SymTabEntries); 344 else 345 printStrHex("SymbolTableEntries:", "Reserved Value", SymTabEntries); 346 } 347 348 printHex("OptionalHeaderSize:", Obj.getOptionalHeaderSize()); 349 printHex("Flags:", Obj.getFlags()); 350 } 351 352 } // namespace 353 354 std::unique_ptr<objdump::Dumper> 355 objdump::createXCOFFDumper(const object::XCOFFObjectFile &Obj) { 356 return std::make_unique<XCOFFDumper>(Obj); 357 } 358 359 Error objdump::getXCOFFRelocationValueString(const XCOFFObjectFile &Obj, 360 const RelocationRef &Rel, 361 bool SymbolDescription, 362 SmallVectorImpl<char> &Result) { 363 symbol_iterator SymI = Rel.getSymbol(); 364 if (SymI == Obj.symbol_end()) 365 return make_error<GenericBinaryError>( 366 "invalid symbol reference in relocation entry", 367 object_error::parse_failed); 368 369 Expected<StringRef> SymNameOrErr = SymI->getName(); 370 if (!SymNameOrErr) 371 return SymNameOrErr.takeError(); 372 373 std::string SymName = 374 Demangle ? demangle(*SymNameOrErr) : SymNameOrErr->str(); 375 if (SymbolDescription) 376 SymName = getXCOFFSymbolDescription(createSymbolInfo(Obj, *SymI), SymName); 377 378 Result.append(SymName.begin(), SymName.end()); 379 return Error::success(); 380 } 381 382 std::optional<XCOFF::StorageMappingClass> 383 objdump::getXCOFFSymbolCsectSMC(const XCOFFObjectFile &Obj, 384 const SymbolRef &Sym) { 385 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl()); 386 387 if (!SymRef.isCsectSymbol()) 388 return std::nullopt; 389 390 auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef(); 391 if (!CsectAuxEntOrErr) 392 return std::nullopt; 393 394 return CsectAuxEntOrErr.get().getStorageMappingClass(); 395 } 396 397 std::optional<object::SymbolRef> 398 objdump::getXCOFFSymbolContainingSymbolRef(const XCOFFObjectFile &Obj, 399 const SymbolRef &Sym) { 400 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl()); 401 if (!SymRef.isCsectSymbol()) 402 return std::nullopt; 403 404 Expected<XCOFFCsectAuxRef> CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef(); 405 if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel()) 406 return std::nullopt; 407 uint32_t Idx = 408 static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength()); 409 DataRefImpl DRI; 410 DRI.p = Obj.getSymbolByIndex(Idx); 411 return SymbolRef(DRI, &Obj); 412 } 413 414 bool objdump::isLabel(const XCOFFObjectFile &Obj, const SymbolRef &Sym) { 415 const XCOFFSymbolRef SymRef = Obj.toSymbolRef(Sym.getRawDataRefImpl()); 416 if (!SymRef.isCsectSymbol()) 417 return false; 418 419 auto CsectAuxEntOrErr = SymRef.getXCOFFCsectAuxRef(); 420 if (!CsectAuxEntOrErr) 421 return false; 422 423 return CsectAuxEntOrErr.get().isLabel(); 424 } 425 426 std::string objdump::getXCOFFSymbolDescription(const SymbolInfoTy &SymbolInfo, 427 StringRef SymbolName) { 428 assert(SymbolInfo.isXCOFF() && "Must be a XCOFFSymInfo."); 429 430 std::string Result; 431 // Dummy symbols have no symbol index. 432 if (SymbolInfo.XCOFFSymInfo.Index) 433 Result = 434 ("(idx: " + Twine(*SymbolInfo.XCOFFSymInfo.Index) + ") " + SymbolName) 435 .str(); 436 else 437 Result.append(SymbolName.begin(), SymbolName.end()); 438 439 if (SymbolInfo.XCOFFSymInfo.StorageMappingClass && 440 !SymbolInfo.XCOFFSymInfo.IsLabel) { 441 const XCOFF::StorageMappingClass Smc = 442 *SymbolInfo.XCOFFSymInfo.StorageMappingClass; 443 Result.append(("[" + XCOFF::getMappingClassString(Smc) + "]").str()); 444 } 445 446 return Result; 447 } 448 449 #define PRINTBOOL(Prefix, Obj, Field) \ 450 OS << Prefix << " " << ((Obj.Field()) ? "+" : "-") << #Field 451 452 #define PRINTGET(Prefix, Obj, Field) \ 453 OS << Prefix << " " << #Field << " = " \ 454 << static_cast<unsigned>(Obj.get##Field()) 455 456 #define PRINTOPTIONAL(Field) \ 457 if (TbTable.get##Field()) { \ 458 OS << '\n'; \ 459 printRawData(Bytes.slice(Index, 4), Address + Index, OS, STI); \ 460 Index += 4; \ 461 OS << "\t# " << #Field << " = " << *TbTable.get##Field(); \ 462 } 463 464 void objdump::dumpTracebackTable(ArrayRef<uint8_t> Bytes, uint64_t Address, 465 formatted_raw_ostream &OS, uint64_t End, 466 const MCSubtargetInfo &STI, 467 const XCOFFObjectFile *Obj) { 468 uint64_t Index = 0; 469 unsigned TabStop = getInstStartColumn(STI) - 1; 470 // Print traceback table boundary. 471 printRawData(Bytes.slice(Index, 4), Address, OS, STI); 472 OS << "\t# Traceback table start\n"; 473 Index += 4; 474 475 uint64_t Size = End - Address; 476 bool Is64Bit = Obj->is64Bit(); 477 478 // XCOFFTracebackTable::create modifies the size parameter, so ensure Size 479 // isn't changed. 480 uint64_t SizeCopy = End - Address; 481 Expected<XCOFFTracebackTable> TTOrErr = 482 XCOFFTracebackTable::create(Bytes.data() + Index, SizeCopy, Is64Bit); 483 484 if (!TTOrErr) { 485 std::string WarningMsgStr; 486 raw_string_ostream WarningStream(WarningMsgStr); 487 WarningStream << "failure parsing traceback table with address: 0x" 488 << utohexstr(Address) + "\n>>> " 489 << toString(TTOrErr.takeError()) 490 << "\n>>> Raw traceback table data is:\n"; 491 492 uint64_t LastNonZero = Index; 493 for (uint64_t I = Index; I < Size; I += 4) 494 if (support::endian::read32be(Bytes.slice(I, 4).data()) != 0) 495 LastNonZero = I + 4 > Size ? Size : I + 4; 496 497 if (Size - LastNonZero <= 4) 498 LastNonZero = Size; 499 500 formatted_raw_ostream FOS(WarningStream); 501 while (Index < LastNonZero) { 502 printRawData(Bytes.slice(Index, 4), Address + Index, FOS, STI); 503 Index += 4; 504 WarningStream << '\n'; 505 } 506 507 // Print all remaining zeroes as ... 508 if (Size - LastNonZero >= 8) 509 WarningStream << "\t\t...\n"; 510 511 reportWarning(WarningMsgStr, Obj->getFileName()); 512 return; 513 } 514 515 auto PrintBytes = [&](uint64_t N) { 516 printRawData(Bytes.slice(Index, N), Address + Index, OS, STI); 517 Index += N; 518 }; 519 520 XCOFFTracebackTable TbTable = *TTOrErr; 521 // Print the first of the 8 bytes of mandatory fields. 522 PrintBytes(1); 523 OS << format("\t# Version = %i", TbTable.getVersion()) << '\n'; 524 525 // Print the second of the 8 bytes of mandatory fields. 526 PrintBytes(1); 527 TracebackTable::LanguageID LangId = 528 static_cast<TracebackTable::LanguageID>(TbTable.getLanguageID()); 529 OS << "\t# Language = " << getNameForTracebackTableLanguageId(LangId) << '\n'; 530 531 auto Split = [&]() { 532 OS << '\n'; 533 OS.indent(TabStop); 534 }; 535 536 // Print the third of the 8 bytes of mandatory fields. 537 PrintBytes(1); 538 PRINTBOOL("\t#", TbTable, isGlobalLinkage); 539 PRINTBOOL(",", TbTable, isOutOfLineEpilogOrPrologue); 540 Split(); 541 PRINTBOOL("\t ", TbTable, hasTraceBackTableOffset); 542 PRINTBOOL(",", TbTable, isInternalProcedure); 543 Split(); 544 PRINTBOOL("\t ", TbTable, hasControlledStorage); 545 PRINTBOOL(",", TbTable, isTOCless); 546 Split(); 547 PRINTBOOL("\t ", TbTable, isFloatingPointPresent); 548 Split(); 549 PRINTBOOL("\t ", TbTable, isFloatingPointOperationLogOrAbortEnabled); 550 OS << '\n'; 551 552 // Print the 4th of the 8 bytes of mandatory fields. 553 PrintBytes(1); 554 PRINTBOOL("\t#", TbTable, isInterruptHandler); 555 PRINTBOOL(",", TbTable, isFuncNamePresent); 556 PRINTBOOL(",", TbTable, isAllocaUsed); 557 Split(); 558 PRINTGET("\t ", TbTable, OnConditionDirective); 559 PRINTBOOL(",", TbTable, isCRSaved); 560 PRINTBOOL(",", TbTable, isLRSaved); 561 OS << '\n'; 562 563 // Print the 5th of the 8 bytes of mandatory fields. 564 PrintBytes(1); 565 PRINTBOOL("\t#", TbTable, isBackChainStored); 566 PRINTBOOL(",", TbTable, isFixup); 567 PRINTGET(",", TbTable, NumOfFPRsSaved); 568 OS << '\n'; 569 570 // Print the 6th of the 8 bytes of mandatory fields. 571 PrintBytes(1); 572 PRINTBOOL("\t#", TbTable, hasExtensionTable); 573 PRINTBOOL(",", TbTable, hasVectorInfo); 574 PRINTGET(",", TbTable, NumOfGPRsSaved); 575 OS << '\n'; 576 577 // Print the 7th of the 8 bytes of mandatory fields. 578 PrintBytes(1); 579 PRINTGET("\t#", TbTable, NumberOfFixedParms); 580 OS << '\n'; 581 582 // Print the 8th of the 8 bytes of mandatory fields. 583 PrintBytes(1); 584 PRINTGET("\t#", TbTable, NumberOfFPParms); 585 PRINTBOOL(",", TbTable, hasParmsOnStack); 586 587 PRINTOPTIONAL(ParmsType); 588 PRINTOPTIONAL(TraceBackTableOffset); 589 PRINTOPTIONAL(HandlerMask); 590 PRINTOPTIONAL(NumOfCtlAnchors); 591 592 if (TbTable.getControlledStorageInfoDisp()) { 593 SmallVector<uint32_t, 8> Disp = *TbTable.getControlledStorageInfoDisp(); 594 for (unsigned I = 0; I < Disp.size(); ++I) { 595 OS << '\n'; 596 PrintBytes(4); 597 OS << "\t" << (I ? " " : "#") << " ControlledStorageInfoDisp[" << I 598 << "] = " << Disp[I]; 599 } 600 } 601 602 // If there is a name, print the function name and function name length. 603 if (TbTable.isFuncNamePresent()) { 604 uint16_t FunctionNameLen = TbTable.getFunctionName()->size(); 605 if (FunctionNameLen == 0) { 606 OS << '\n'; 607 reportWarning( 608 "the length of the function name must be greater than zero if the " 609 "isFuncNamePresent bit is set in the traceback table", 610 Obj->getFileName()); 611 return; 612 } 613 614 OS << '\n'; 615 PrintBytes(2); 616 OS << "\t# FunctionNameLen = " << FunctionNameLen; 617 618 uint16_t RemainingBytes = FunctionNameLen; 619 bool HasPrinted = false; 620 while (RemainingBytes > 0) { 621 OS << '\n'; 622 uint16_t PrintLen = RemainingBytes >= 4 ? 4 : RemainingBytes; 623 printRawData(Bytes.slice(Index, PrintLen), Address + Index, OS, STI); 624 Index += PrintLen; 625 RemainingBytes -= PrintLen; 626 627 if (!HasPrinted) { 628 OS << "\t# FunctionName = " << *TbTable.getFunctionName(); 629 HasPrinted = true; 630 } 631 } 632 } 633 634 if (TbTable.isAllocaUsed()) { 635 OS << '\n'; 636 PrintBytes(1); 637 OS << format("\t# AllocaRegister = %u", *TbTable.getAllocaRegister()); 638 } 639 640 if (TbTable.getVectorExt()) { 641 OS << '\n'; 642 TBVectorExt VecExt = *TbTable.getVectorExt(); 643 // Print first byte of VectorExt. 644 PrintBytes(1); 645 PRINTGET("\t#", VecExt, NumberOfVRSaved); 646 PRINTBOOL(",", VecExt, isVRSavedOnStack); 647 PRINTBOOL(",", VecExt, hasVarArgs); 648 OS << '\n'; 649 650 // Print the second byte of VectorExt. 651 PrintBytes(1); 652 PRINTGET("\t#", VecExt, NumberOfVectorParms); 653 PRINTBOOL(",", VecExt, hasVMXInstruction); 654 OS << '\n'; 655 656 PrintBytes(4); 657 OS << "\t# VectorParmsInfoString = " << VecExt.getVectorParmsInfo(); 658 659 // There are two bytes of padding after vector info. 660 OS << '\n'; 661 PrintBytes(2); 662 OS << "\t# Padding"; 663 } 664 665 if (TbTable.getExtensionTable()) { 666 OS << '\n'; 667 PrintBytes(1); 668 ExtendedTBTableFlag Flag = 669 static_cast<ExtendedTBTableFlag>(*TbTable.getExtensionTable()); 670 OS << "\t# ExtensionTable = " << getExtendedTBTableFlagString(Flag); 671 } 672 673 if (TbTable.getEhInfoDisp()) { 674 // There are 4 bytes alignment before eh info displacement. 675 if (Index % 4) { 676 OS << '\n'; 677 PrintBytes(4 - Index % 4); 678 OS << "\t# Alignment padding for eh info displacement"; 679 } 680 OS << '\n'; 681 // The size of the displacement (address) is 4 bytes in 32-bit object files, 682 // and 8 bytes in 64-bit object files. 683 PrintBytes(4); 684 OS << "\t# EH info displacement"; 685 if (Is64Bit) { 686 OS << '\n'; 687 PrintBytes(4); 688 } 689 } 690 691 OS << '\n'; 692 if (End == Address + Index) 693 return; 694 695 Size = End - Address; 696 697 const char *LineSuffix = "\t# Padding\n"; 698 auto IsWordZero = [&](uint64_t WordPos) { 699 if (WordPos >= Size) 700 return false; 701 uint64_t LineLength = std::min(4 - WordPos % 4, Size - WordPos); 702 return std::all_of(Bytes.begin() + WordPos, 703 Bytes.begin() + WordPos + LineLength, 704 [](uint8_t Byte) { return Byte == 0; }); 705 }; 706 707 bool AreWordsZero[] = {IsWordZero(Index), IsWordZero(alignTo(Index, 4) + 4), 708 IsWordZero(alignTo(Index, 4) + 8)}; 709 bool ShouldPrintLine = true; 710 while (true) { 711 // Determine the length of the line (4, except for the first line, which 712 // will be just enough to align to the word boundary, and the last line, 713 // which will be the remainder of the data). 714 uint64_t LineLength = std::min(4 - Index % 4, Size - Index); 715 if (ShouldPrintLine) { 716 // Print the line. 717 printRawData(Bytes.slice(Index, LineLength), Address + Index, OS, STI); 718 OS << LineSuffix; 719 LineSuffix = "\n"; 720 } 721 722 Index += LineLength; 723 if (Index == Size) 724 return; 725 726 // For 3 or more consecutive lines of zeros, skip all but the first one, and 727 // replace them with "...". 728 if (AreWordsZero[0] && AreWordsZero[1] && AreWordsZero[2]) { 729 if (ShouldPrintLine) 730 OS << std::string(8, ' ') << "...\n"; 731 ShouldPrintLine = false; 732 } else if (!AreWordsZero[1]) { 733 // We have reached the end of a skipped block of zeros. 734 ShouldPrintLine = true; 735 } 736 AreWordsZero[0] = AreWordsZero[1]; 737 AreWordsZero[1] = AreWordsZero[2]; 738 AreWordsZero[2] = IsWordZero(Index + 8); 739 } 740 } 741 #undef PRINTBOOL 742 #undef PRINTGET 743 #undef PRINTOPTIONAL 744