//===- GsymReaderV2.cpp ---------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/GSYM/GsymReaderV2.h" #include #include #include "llvm/ADT/STLExtras.h" #include "llvm/DebugInfo/GSYM/GlobalData.h" #include "llvm/DebugInfo/GSYM/GsymDataExtractor.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MemoryBuffer.h" using namespace llvm; using namespace gsym; GsymReaderV2::GsymReaderV2(std::unique_ptr Buffer, llvm::endianness Endian) : GsymReader(std::move(Buffer), Endian) {} /// For V2 file layout, see HeaderV2.h llvm::Error GsymReaderV2::parseHeaderAndGlobalDataEntries() { if (auto Err = parseHeader(Hdr, SwappedHdr)) return Err; return parseGlobalDataEntries(HeaderV2::getEncodedSize()); } void GsymReaderV2::dump(raw_ostream &OS) { OS << *Hdr << "\n"; // Print GlobalData entries. OS << "Global Data Sections:\n"; OS << "TYPE FILE OFFSET FILE SIZE\n"; OS << "=============== ================== ==================\n"; /// Re-parse the GlobalData entries to ensure we show the GlobalData /// in the exact order it appears in the GSYM data. const StringRef Buf = MemBuffer->getBuffer(); const uint64_t BufSize = Buf.size(); GsymDataExtractor Data(Buf, isLittleEndian()); uint64_t Offset = HeaderV2::getEncodedSize(); while (Offset + sizeof(GlobalData) <= BufSize) { auto GDOrErr = GlobalData::decode(Data, Offset); assert(GDOrErr && "GlobalData::decode() should not fail"); const GlobalData &GD = *GDOrErr; OS << formatv("{0,-15} ", getNameForGlobalInfoType(GD.Type).data()) << HEX64(GD.FileOffset) << " " << HEX64(GD.FileSize) << "\n"; // Stop printing after the end of list entry. if (GD.Type == GlobalInfoType::EndOfList) break; } OS << "\n"; // Print UUID if present. if (auto UUIDBytes = getOptionalGlobalDataBytes(GlobalInfoType::UUID)) { OS << "UUID:\n"; for (uint8_t Byte : *UUIDBytes) OS << format_hex_no_prefix(Byte, 2); OS << "\n\n"; } OS << "Address Table:\n"; OS << "INDEX OFFSET "; switch (getAddressOffsetSize()) { case 1: OS << "8 "; break; case 2: OS << "16"; break; case 4: OS << "32"; break; case 8: OS << "64"; break; default: OS << "??"; break; } OS << " (ADDRESS 64)\n"; OS << "====== ========================================\n"; for (uint32_t I = 0; I < getNumAddresses(); ++I) { OS << formatv("[{0,4}] ", I); switch (getAddressOffsetSize()) { case 1: OS << HEX8(getAddrOffsets()[I]); break; case 2: OS << HEX16(getAddrOffsets()[I]); break; case 4: OS << HEX32(getAddrOffsets()[I]); break; case 8: OS << HEX32(getAddrOffsets()[I]); break; default: break; } OS << " (" << HEX64(*getAddress(I)) << ")\n"; } OS << "\nAddress Info Offsets:\n"; OS << "INDEX OFFSET 64 (FILE OFFSET 64)\n"; OS << "====== ========================================\n"; for (uint32_t I = 0; I < getNumAddresses(); ++I) { uint64_t RelOffset = I * getAddressInfoOffsetSize(); uint64_t RelValue = AddrInfoOffsetsData.getUnsigned(&RelOffset, getAddressInfoOffsetSize()); OS << formatv("[{0,4}] ", I) << HEX64(RelValue) << " (" << HEX64(*getAddressInfoOffset(I)) << ")\n"; } OS << "\nFiles:\n"; OS << "INDEX DIRECTORY BASENAME PATH\n"; OS << "====== ========== ========== " "========================================\n"; // Since we don't store the total number of files in the file table, loop // until we get a null entry which means the index is out of range. for (uint32_t I = 0;; ++I) { auto FE = getFile(I); if (!FE) break; OS << formatv("[{0,4}] ", I) << HEX32(FE->Dir) << ' ' << HEX32(FE->Base) << ' '; dump(OS, FE); OS << "\n"; } OS << "\n"; gsym::dump(OS, StrTab, 8); OS << "\n"; for (uint32_t I = 0; I < getNumAddresses(); ++I) { OS << "FunctionInfo @ " << HEX32(*getAddressInfoOffset(I)) << ": "; if (auto FI = getFunctionInfoAtIndex(I)) dump(OS, *FI); else logAllUnhandledErrors(FI.takeError(), OS, "FunctionInfo:"); } }