| //===- 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 <assert.h> | |
| #include <inttypes.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<MemoryBuffer> 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<uint8_t>()[I]); | |
| break; | |
| case 2: | |
| OS << HEX16(getAddrOffsets<uint16_t>()[I]); | |
| break; | |
| case 4: | |
| OS << HEX32(getAddrOffsets<uint32_t>()[I]); | |
| break; | |
| case 8: | |
| OS << HEX32(getAddrOffsets<uint64_t>()[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:"); | |
| } | |
| } |