18bcb0991SDimitry Andric //===- GsymReader.cpp -----------------------------------------------------===// 28bcb0991SDimitry Andric // 3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 68bcb0991SDimitry Andric // 78bcb0991SDimitry Andric //===----------------------------------------------------------------------===// 88bcb0991SDimitry Andric 98bcb0991SDimitry Andric #include "llvm/DebugInfo/GSYM/GsymReader.h" 108bcb0991SDimitry Andric 118bcb0991SDimitry Andric #include <assert.h> 128bcb0991SDimitry Andric #include <inttypes.h> 138bcb0991SDimitry Andric #include <stdio.h> 148bcb0991SDimitry Andric #include <stdlib.h> 158bcb0991SDimitry Andric 168bcb0991SDimitry Andric #include "llvm/DebugInfo/GSYM/GsymCreator.h" 178bcb0991SDimitry Andric #include "llvm/DebugInfo/GSYM/InlineInfo.h" 188bcb0991SDimitry Andric #include "llvm/DebugInfo/GSYM/LineTable.h" 198bcb0991SDimitry Andric #include "llvm/Support/BinaryStreamReader.h" 208bcb0991SDimitry Andric #include "llvm/Support/DataExtractor.h" 218bcb0991SDimitry Andric #include "llvm/Support/MemoryBuffer.h" 228bcb0991SDimitry Andric 238bcb0991SDimitry Andric using namespace llvm; 248bcb0991SDimitry Andric using namespace gsym; 258bcb0991SDimitry Andric 268bcb0991SDimitry Andric GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) : 278bcb0991SDimitry Andric MemBuffer(std::move(Buffer)), 288bcb0991SDimitry Andric Endian(support::endian::system_endianness()) {} 298bcb0991SDimitry Andric 308bcb0991SDimitry Andric GsymReader::GsymReader(GsymReader &&RHS) = default; 318bcb0991SDimitry Andric 328bcb0991SDimitry Andric GsymReader::~GsymReader() = default; 338bcb0991SDimitry Andric 348bcb0991SDimitry Andric llvm::Expected<GsymReader> GsymReader::openFile(StringRef Filename) { 358bcb0991SDimitry Andric // Open the input file and return an appropriate error if needed. 368bcb0991SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr = 378bcb0991SDimitry Andric MemoryBuffer::getFileOrSTDIN(Filename); 388bcb0991SDimitry Andric auto Err = BuffOrErr.getError(); 398bcb0991SDimitry Andric if (Err) 408bcb0991SDimitry Andric return llvm::errorCodeToError(Err); 418bcb0991SDimitry Andric return create(BuffOrErr.get()); 428bcb0991SDimitry Andric } 438bcb0991SDimitry Andric 448bcb0991SDimitry Andric llvm::Expected<GsymReader> GsymReader::copyBuffer(StringRef Bytes) { 458bcb0991SDimitry Andric auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes"); 468bcb0991SDimitry Andric return create(MemBuffer); 478bcb0991SDimitry Andric } 488bcb0991SDimitry Andric 498bcb0991SDimitry Andric llvm::Expected<llvm::gsym::GsymReader> 508bcb0991SDimitry Andric GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) { 51*81ad6265SDimitry Andric if (!MemBuffer) 528bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 538bcb0991SDimitry Andric "invalid memory buffer"); 548bcb0991SDimitry Andric GsymReader GR(std::move(MemBuffer)); 558bcb0991SDimitry Andric llvm::Error Err = GR.parse(); 568bcb0991SDimitry Andric if (Err) 578bcb0991SDimitry Andric return std::move(Err); 588bcb0991SDimitry Andric return std::move(GR); 598bcb0991SDimitry Andric } 608bcb0991SDimitry Andric 618bcb0991SDimitry Andric llvm::Error 628bcb0991SDimitry Andric GsymReader::parse() { 638bcb0991SDimitry Andric BinaryStreamReader FileData(MemBuffer->getBuffer(), 648bcb0991SDimitry Andric support::endian::system_endianness()); 658bcb0991SDimitry Andric // Check for the magic bytes. This file format is designed to be mmap'ed 668bcb0991SDimitry Andric // into a process and accessed as read only. This is done for performance 678bcb0991SDimitry Andric // and efficiency for symbolicating and parsing GSYM data. 688bcb0991SDimitry Andric if (FileData.readObject(Hdr)) 698bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 708bcb0991SDimitry Andric "not enough data for a GSYM header"); 718bcb0991SDimitry Andric 728bcb0991SDimitry Andric const auto HostByteOrder = support::endian::system_endianness(); 738bcb0991SDimitry Andric switch (Hdr->Magic) { 748bcb0991SDimitry Andric case GSYM_MAGIC: 758bcb0991SDimitry Andric Endian = HostByteOrder; 768bcb0991SDimitry Andric break; 778bcb0991SDimitry Andric case GSYM_CIGAM: 788bcb0991SDimitry Andric // This is a GSYM file, but not native endianness. 798bcb0991SDimitry Andric Endian = sys::IsBigEndianHost ? support::little : support::big; 808bcb0991SDimitry Andric Swap.reset(new SwappedData); 818bcb0991SDimitry Andric break; 828bcb0991SDimitry Andric default: 838bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 848bcb0991SDimitry Andric "not a GSYM file"); 858bcb0991SDimitry Andric } 868bcb0991SDimitry Andric 878bcb0991SDimitry Andric bool DataIsLittleEndian = HostByteOrder != support::little; 888bcb0991SDimitry Andric // Read a correctly byte swapped header if we need to. 898bcb0991SDimitry Andric if (Swap) { 908bcb0991SDimitry Andric DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4); 918bcb0991SDimitry Andric if (auto ExpectedHdr = Header::decode(Data)) 928bcb0991SDimitry Andric Swap->Hdr = ExpectedHdr.get(); 938bcb0991SDimitry Andric else 948bcb0991SDimitry Andric return ExpectedHdr.takeError(); 958bcb0991SDimitry Andric Hdr = &Swap->Hdr; 968bcb0991SDimitry Andric } 978bcb0991SDimitry Andric 988bcb0991SDimitry Andric // Detect errors in the header and report any that are found. If we make it 998bcb0991SDimitry Andric // past this without errors, we know we have a good magic value, a supported 1008bcb0991SDimitry Andric // version number, verified address offset size and a valid UUID size. 1018bcb0991SDimitry Andric if (Error Err = Hdr->checkForError()) 1028bcb0991SDimitry Andric return Err; 1038bcb0991SDimitry Andric 1048bcb0991SDimitry Andric if (!Swap) { 1058bcb0991SDimitry Andric // This is the native endianness case that is most common and optimized for 1068bcb0991SDimitry Andric // efficient lookups. Here we just grab pointers to the native data and 1078bcb0991SDimitry Andric // use ArrayRef objects to allow efficient read only access. 1088bcb0991SDimitry Andric 1098bcb0991SDimitry Andric // Read the address offsets. 1108bcb0991SDimitry Andric if (FileData.padToAlignment(Hdr->AddrOffSize) || 1118bcb0991SDimitry Andric FileData.readArray(AddrOffsets, 1128bcb0991SDimitry Andric Hdr->NumAddresses * Hdr->AddrOffSize)) 1138bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1148bcb0991SDimitry Andric "failed to read address table"); 1158bcb0991SDimitry Andric 1168bcb0991SDimitry Andric // Read the address info offsets. 1178bcb0991SDimitry Andric if (FileData.padToAlignment(4) || 1188bcb0991SDimitry Andric FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses)) 1198bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1208bcb0991SDimitry Andric "failed to read address info offsets table"); 1218bcb0991SDimitry Andric 1228bcb0991SDimitry Andric // Read the file table. 1238bcb0991SDimitry Andric uint32_t NumFiles = 0; 1248bcb0991SDimitry Andric if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles)) 1258bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1268bcb0991SDimitry Andric "failed to read file table"); 1278bcb0991SDimitry Andric 1288bcb0991SDimitry Andric // Get the string table. 1298bcb0991SDimitry Andric FileData.setOffset(Hdr->StrtabOffset); 1308bcb0991SDimitry Andric if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize)) 1318bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1328bcb0991SDimitry Andric "failed to read string table"); 1338bcb0991SDimitry Andric } else { 1348bcb0991SDimitry Andric // This is the non native endianness case that is not common and not 1358bcb0991SDimitry Andric // optimized for lookups. Here we decode the important tables into local 1368bcb0991SDimitry Andric // storage and then set the ArrayRef objects to point to these swapped 1378bcb0991SDimitry Andric // copies of the read only data so lookups can be as efficient as possible. 1388bcb0991SDimitry Andric DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4); 1398bcb0991SDimitry Andric 1408bcb0991SDimitry Andric // Read the address offsets. 1418bcb0991SDimitry Andric uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize); 1428bcb0991SDimitry Andric Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize); 1438bcb0991SDimitry Andric switch (Hdr->AddrOffSize) { 1448bcb0991SDimitry Andric case 1: 1458bcb0991SDimitry Andric if (!Data.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses)) 1468bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1478bcb0991SDimitry Andric "failed to read address table"); 1488bcb0991SDimitry Andric break; 1498bcb0991SDimitry Andric case 2: 1508bcb0991SDimitry Andric if (!Data.getU16(&Offset, 1518bcb0991SDimitry Andric reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()), 1528bcb0991SDimitry Andric Hdr->NumAddresses)) 1538bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1548bcb0991SDimitry Andric "failed to read address table"); 1558bcb0991SDimitry Andric break; 1568bcb0991SDimitry Andric case 4: 1578bcb0991SDimitry Andric if (!Data.getU32(&Offset, 1588bcb0991SDimitry Andric reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()), 1598bcb0991SDimitry Andric Hdr->NumAddresses)) 1608bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1618bcb0991SDimitry Andric "failed to read address table"); 1628bcb0991SDimitry Andric break; 1638bcb0991SDimitry Andric case 8: 1648bcb0991SDimitry Andric if (!Data.getU64(&Offset, 1658bcb0991SDimitry Andric reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()), 1668bcb0991SDimitry Andric Hdr->NumAddresses)) 1678bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1688bcb0991SDimitry Andric "failed to read address table"); 1698bcb0991SDimitry Andric } 1708bcb0991SDimitry Andric AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets); 1718bcb0991SDimitry Andric 1728bcb0991SDimitry Andric // Read the address info offsets. 1738bcb0991SDimitry Andric Offset = alignTo(Offset, 4); 1748bcb0991SDimitry Andric Swap->AddrInfoOffsets.resize(Hdr->NumAddresses); 1758bcb0991SDimitry Andric if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses)) 1768bcb0991SDimitry Andric AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets); 1778bcb0991SDimitry Andric else 1788bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1798bcb0991SDimitry Andric "failed to read address table"); 1808bcb0991SDimitry Andric // Read the file table. 1818bcb0991SDimitry Andric const uint32_t NumFiles = Data.getU32(&Offset); 1828bcb0991SDimitry Andric if (NumFiles > 0) { 1838bcb0991SDimitry Andric Swap->Files.resize(NumFiles); 1848bcb0991SDimitry Andric if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2)) 1858bcb0991SDimitry Andric Files = ArrayRef<FileEntry>(Swap->Files); 1868bcb0991SDimitry Andric else 1878bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1888bcb0991SDimitry Andric "failed to read file table"); 1898bcb0991SDimitry Andric } 1908bcb0991SDimitry Andric // Get the string table. 1918bcb0991SDimitry Andric StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset, 1928bcb0991SDimitry Andric Hdr->StrtabSize); 1938bcb0991SDimitry Andric if (StrTab.Data.empty()) 1948bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 1958bcb0991SDimitry Andric "failed to read string table"); 1968bcb0991SDimitry Andric } 1978bcb0991SDimitry Andric return Error::success(); 1988bcb0991SDimitry Andric 1998bcb0991SDimitry Andric } 2008bcb0991SDimitry Andric 2018bcb0991SDimitry Andric const Header &GsymReader::getHeader() const { 2028bcb0991SDimitry Andric // The only way to get a GsymReader is from GsymReader::openFile(...) or 2038bcb0991SDimitry Andric // GsymReader::copyBuffer() and the header must be valid and initialized to 2048bcb0991SDimitry Andric // a valid pointer value, so the assert below should not trigger. 2058bcb0991SDimitry Andric assert(Hdr); 2068bcb0991SDimitry Andric return *Hdr; 2078bcb0991SDimitry Andric } 2088bcb0991SDimitry Andric 2098bcb0991SDimitry Andric Optional<uint64_t> GsymReader::getAddress(size_t Index) const { 2108bcb0991SDimitry Andric switch (Hdr->AddrOffSize) { 2118bcb0991SDimitry Andric case 1: return addressForIndex<uint8_t>(Index); 2128bcb0991SDimitry Andric case 2: return addressForIndex<uint16_t>(Index); 2138bcb0991SDimitry Andric case 4: return addressForIndex<uint32_t>(Index); 2148bcb0991SDimitry Andric case 8: return addressForIndex<uint64_t>(Index); 2158bcb0991SDimitry Andric } 2168bcb0991SDimitry Andric return llvm::None; 2178bcb0991SDimitry Andric } 2188bcb0991SDimitry Andric 2198bcb0991SDimitry Andric Optional<uint64_t> GsymReader::getAddressInfoOffset(size_t Index) const { 2208bcb0991SDimitry Andric const auto NumAddrInfoOffsets = AddrInfoOffsets.size(); 2218bcb0991SDimitry Andric if (Index < NumAddrInfoOffsets) 2228bcb0991SDimitry Andric return AddrInfoOffsets[Index]; 2238bcb0991SDimitry Andric return llvm::None; 2248bcb0991SDimitry Andric } 2258bcb0991SDimitry Andric 2268bcb0991SDimitry Andric Expected<uint64_t> 2278bcb0991SDimitry Andric GsymReader::getAddressIndex(const uint64_t Addr) const { 2285ffd83dbSDimitry Andric if (Addr >= Hdr->BaseAddress) { 2298bcb0991SDimitry Andric const uint64_t AddrOffset = Addr - Hdr->BaseAddress; 2305ffd83dbSDimitry Andric Optional<uint64_t> AddrOffsetIndex; 2318bcb0991SDimitry Andric switch (Hdr->AddrOffSize) { 2325ffd83dbSDimitry Andric case 1: 2335ffd83dbSDimitry Andric AddrOffsetIndex = getAddressOffsetIndex<uint8_t>(AddrOffset); 2345ffd83dbSDimitry Andric break; 2355ffd83dbSDimitry Andric case 2: 2365ffd83dbSDimitry Andric AddrOffsetIndex = getAddressOffsetIndex<uint16_t>(AddrOffset); 2375ffd83dbSDimitry Andric break; 2385ffd83dbSDimitry Andric case 4: 2395ffd83dbSDimitry Andric AddrOffsetIndex = getAddressOffsetIndex<uint32_t>(AddrOffset); 2405ffd83dbSDimitry Andric break; 2415ffd83dbSDimitry Andric case 8: 2425ffd83dbSDimitry Andric AddrOffsetIndex = getAddressOffsetIndex<uint64_t>(AddrOffset); 2435ffd83dbSDimitry Andric break; 2445ffd83dbSDimitry Andric default: 2458bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 2468bcb0991SDimitry Andric "unsupported address offset size %u", 2478bcb0991SDimitry Andric Hdr->AddrOffSize); 2488bcb0991SDimitry Andric } 2495ffd83dbSDimitry Andric if (AddrOffsetIndex) 2505ffd83dbSDimitry Andric return *AddrOffsetIndex; 2515ffd83dbSDimitry Andric } 2525ffd83dbSDimitry Andric return createStringError(std::errc::invalid_argument, 2535ffd83dbSDimitry Andric "address 0x%" PRIx64 " is not in GSYM", Addr); 2545ffd83dbSDimitry Andric 2555ffd83dbSDimitry Andric } 2568bcb0991SDimitry Andric 2578bcb0991SDimitry Andric llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const { 2588bcb0991SDimitry Andric Expected<uint64_t> AddressIndex = getAddressIndex(Addr); 2598bcb0991SDimitry Andric if (!AddressIndex) 2608bcb0991SDimitry Andric return AddressIndex.takeError(); 2618bcb0991SDimitry Andric // Address info offsets size should have been checked in parse(). 2628bcb0991SDimitry Andric assert(*AddressIndex < AddrInfoOffsets.size()); 2638bcb0991SDimitry Andric auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex]; 2648bcb0991SDimitry Andric DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4); 2658bcb0991SDimitry Andric if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex)) { 2668bcb0991SDimitry Andric auto ExpectedFI = FunctionInfo::decode(Data, *OptAddr); 2678bcb0991SDimitry Andric if (ExpectedFI) { 2688bcb0991SDimitry Andric if (ExpectedFI->Range.contains(Addr) || ExpectedFI->Range.size() == 0) 2698bcb0991SDimitry Andric return ExpectedFI; 2708bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 2715ffd83dbSDimitry Andric "address 0x%" PRIx64 " is not in GSYM", Addr); 2728bcb0991SDimitry Andric } 2738bcb0991SDimitry Andric } 2748bcb0991SDimitry Andric return createStringError(std::errc::invalid_argument, 2758bcb0991SDimitry Andric "failed to extract address[%" PRIu64 "]", 2768bcb0991SDimitry Andric *AddressIndex); 2778bcb0991SDimitry Andric } 278480093f4SDimitry Andric 279480093f4SDimitry Andric llvm::Expected<LookupResult> GsymReader::lookup(uint64_t Addr) const { 280480093f4SDimitry Andric Expected<uint64_t> AddressIndex = getAddressIndex(Addr); 281480093f4SDimitry Andric if (!AddressIndex) 282480093f4SDimitry Andric return AddressIndex.takeError(); 283480093f4SDimitry Andric // Address info offsets size should have been checked in parse(). 284480093f4SDimitry Andric assert(*AddressIndex < AddrInfoOffsets.size()); 285480093f4SDimitry Andric auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex]; 286480093f4SDimitry Andric DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4); 287480093f4SDimitry Andric if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex)) 288480093f4SDimitry Andric return FunctionInfo::lookup(Data, *this, *OptAddr, Addr); 289480093f4SDimitry Andric return createStringError(std::errc::invalid_argument, 290480093f4SDimitry Andric "failed to extract address[%" PRIu64 "]", 291480093f4SDimitry Andric *AddressIndex); 292480093f4SDimitry Andric } 2935ffd83dbSDimitry Andric 2945ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS) { 2955ffd83dbSDimitry Andric const auto &Header = getHeader(); 2965ffd83dbSDimitry Andric // Dump the GSYM header. 2975ffd83dbSDimitry Andric OS << Header << "\n"; 2985ffd83dbSDimitry Andric // Dump the address table. 2995ffd83dbSDimitry Andric OS << "Address Table:\n"; 3005ffd83dbSDimitry Andric OS << "INDEX OFFSET"; 3015ffd83dbSDimitry Andric 3025ffd83dbSDimitry Andric switch (Hdr->AddrOffSize) { 3035ffd83dbSDimitry Andric case 1: OS << "8 "; break; 3045ffd83dbSDimitry Andric case 2: OS << "16"; break; 3055ffd83dbSDimitry Andric case 4: OS << "32"; break; 3065ffd83dbSDimitry Andric case 8: OS << "64"; break; 3075ffd83dbSDimitry Andric default: OS << "??"; break; 3085ffd83dbSDimitry Andric } 3095ffd83dbSDimitry Andric OS << " (ADDRESS)\n"; 3105ffd83dbSDimitry Andric OS << "====== =============================== \n"; 3115ffd83dbSDimitry Andric for (uint32_t I = 0; I < Header.NumAddresses; ++I) { 3125ffd83dbSDimitry Andric OS << format("[%4u] ", I); 3135ffd83dbSDimitry Andric switch (Hdr->AddrOffSize) { 3145ffd83dbSDimitry Andric case 1: OS << HEX8(getAddrOffsets<uint8_t>()[I]); break; 3155ffd83dbSDimitry Andric case 2: OS << HEX16(getAddrOffsets<uint16_t>()[I]); break; 3165ffd83dbSDimitry Andric case 4: OS << HEX32(getAddrOffsets<uint32_t>()[I]); break; 3175ffd83dbSDimitry Andric case 8: OS << HEX32(getAddrOffsets<uint64_t>()[I]); break; 3185ffd83dbSDimitry Andric default: break; 3195ffd83dbSDimitry Andric } 3205ffd83dbSDimitry Andric OS << " (" << HEX64(*getAddress(I)) << ")\n"; 3215ffd83dbSDimitry Andric } 3225ffd83dbSDimitry Andric // Dump the address info offsets table. 3235ffd83dbSDimitry Andric OS << "\nAddress Info Offsets:\n"; 3245ffd83dbSDimitry Andric OS << "INDEX Offset\n"; 3255ffd83dbSDimitry Andric OS << "====== ==========\n"; 3265ffd83dbSDimitry Andric for (uint32_t I = 0; I < Header.NumAddresses; ++I) 3275ffd83dbSDimitry Andric OS << format("[%4u] ", I) << HEX32(AddrInfoOffsets[I]) << "\n"; 3285ffd83dbSDimitry Andric // Dump the file table. 3295ffd83dbSDimitry Andric OS << "\nFiles:\n"; 3305ffd83dbSDimitry Andric OS << "INDEX DIRECTORY BASENAME PATH\n"; 3315ffd83dbSDimitry Andric OS << "====== ========== ========== ==============================\n"; 3325ffd83dbSDimitry Andric for (uint32_t I = 0; I < Files.size(); ++I) { 3335ffd83dbSDimitry Andric OS << format("[%4u] ", I) << HEX32(Files[I].Dir) << ' ' 3345ffd83dbSDimitry Andric << HEX32(Files[I].Base) << ' '; 3355ffd83dbSDimitry Andric dump(OS, getFile(I)); 3365ffd83dbSDimitry Andric OS << "\n"; 3375ffd83dbSDimitry Andric } 3385ffd83dbSDimitry Andric OS << "\n" << StrTab << "\n"; 3395ffd83dbSDimitry Andric 3405ffd83dbSDimitry Andric for (uint32_t I = 0; I < Header.NumAddresses; ++I) { 3415ffd83dbSDimitry Andric OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": "; 3425ffd83dbSDimitry Andric if (auto FI = getFunctionInfo(*getAddress(I))) 3435ffd83dbSDimitry Andric dump(OS, *FI); 3445ffd83dbSDimitry Andric else 3455ffd83dbSDimitry Andric logAllUnhandledErrors(FI.takeError(), OS, "FunctionInfo:"); 3465ffd83dbSDimitry Andric } 3475ffd83dbSDimitry Andric } 3485ffd83dbSDimitry Andric 3495ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI) { 3505ffd83dbSDimitry Andric OS << FI.Range << " \"" << getString(FI.Name) << "\"\n"; 3515ffd83dbSDimitry Andric if (FI.OptLineTable) 3525ffd83dbSDimitry Andric dump(OS, *FI.OptLineTable); 3535ffd83dbSDimitry Andric if (FI.Inline) 3545ffd83dbSDimitry Andric dump(OS, *FI.Inline); 3555ffd83dbSDimitry Andric } 3565ffd83dbSDimitry Andric 3575ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS, const LineTable <) { 3585ffd83dbSDimitry Andric OS << "LineTable:\n"; 3595ffd83dbSDimitry Andric for (auto &LE: LT) { 3605ffd83dbSDimitry Andric OS << " " << HEX64(LE.Addr) << ' '; 3615ffd83dbSDimitry Andric if (LE.File) 3625ffd83dbSDimitry Andric dump(OS, getFile(LE.File)); 3635ffd83dbSDimitry Andric OS << ':' << LE.Line << '\n'; 3645ffd83dbSDimitry Andric } 3655ffd83dbSDimitry Andric } 3665ffd83dbSDimitry Andric 3675ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS, const InlineInfo &II, uint32_t Indent) { 3685ffd83dbSDimitry Andric if (Indent == 0) 3695ffd83dbSDimitry Andric OS << "InlineInfo:\n"; 3705ffd83dbSDimitry Andric else 3715ffd83dbSDimitry Andric OS.indent(Indent); 3725ffd83dbSDimitry Andric OS << II.Ranges << ' ' << getString(II.Name); 3735ffd83dbSDimitry Andric if (II.CallFile != 0) { 3745ffd83dbSDimitry Andric if (auto File = getFile(II.CallFile)) { 3755ffd83dbSDimitry Andric OS << " called from "; 3765ffd83dbSDimitry Andric dump(OS, File); 3775ffd83dbSDimitry Andric OS << ':' << II.CallLine; 3785ffd83dbSDimitry Andric } 3795ffd83dbSDimitry Andric } 3805ffd83dbSDimitry Andric OS << '\n'; 3815ffd83dbSDimitry Andric for (const auto &ChildII: II.Children) 3825ffd83dbSDimitry Andric dump(OS, ChildII, Indent + 2); 3835ffd83dbSDimitry Andric } 3845ffd83dbSDimitry Andric 3855ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS, Optional<FileEntry> FE) { 3865ffd83dbSDimitry Andric if (FE) { 3875ffd83dbSDimitry Andric // IF we have the file from index 0, then don't print anything 3885ffd83dbSDimitry Andric if (FE->Dir == 0 && FE->Base == 0) 3895ffd83dbSDimitry Andric return; 3905ffd83dbSDimitry Andric StringRef Dir = getString(FE->Dir); 3915ffd83dbSDimitry Andric StringRef Base = getString(FE->Base); 3925ffd83dbSDimitry Andric if (!Dir.empty()) { 3935ffd83dbSDimitry Andric OS << Dir; 3945ffd83dbSDimitry Andric if (Dir.contains('\\') && !Dir.contains('/')) 3955ffd83dbSDimitry Andric OS << '\\'; 3965ffd83dbSDimitry Andric else 3975ffd83dbSDimitry Andric OS << '/'; 3985ffd83dbSDimitry Andric } 3995ffd83dbSDimitry Andric if (!Base.empty()) { 4005ffd83dbSDimitry Andric OS << Base; 4015ffd83dbSDimitry Andric } 4025ffd83dbSDimitry Andric if (!Dir.empty() || !Base.empty()) 4035ffd83dbSDimitry Andric return; 4045ffd83dbSDimitry Andric } 4055ffd83dbSDimitry Andric OS << "<invalid-file>"; 4065ffd83dbSDimitry Andric } 407