14b6c9de8SGreg Clayton //===- GsymReader.cpp -----------------------------------------------------===//
24b6c9de8SGreg Clayton //
3aeda128aSGreg Clayton // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4aeda128aSGreg Clayton // See https://llvm.org/LICENSE.txt for license information.
5aeda128aSGreg Clayton // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
64b6c9de8SGreg Clayton //
74b6c9de8SGreg Clayton //===----------------------------------------------------------------------===//
84b6c9de8SGreg Clayton 
94b6c9de8SGreg Clayton #include "llvm/DebugInfo/GSYM/GsymReader.h"
104b6c9de8SGreg Clayton 
114b6c9de8SGreg Clayton #include <assert.h>
124b6c9de8SGreg Clayton #include <inttypes.h>
134b6c9de8SGreg Clayton #include <stdio.h>
144b6c9de8SGreg Clayton #include <stdlib.h>
154b6c9de8SGreg Clayton 
164b6c9de8SGreg Clayton #include "llvm/DebugInfo/GSYM/GsymCreator.h"
174b6c9de8SGreg Clayton #include "llvm/DebugInfo/GSYM/InlineInfo.h"
184b6c9de8SGreg Clayton #include "llvm/DebugInfo/GSYM/LineTable.h"
194b6c9de8SGreg Clayton #include "llvm/Support/BinaryStreamReader.h"
204b6c9de8SGreg Clayton #include "llvm/Support/DataExtractor.h"
214b6c9de8SGreg Clayton #include "llvm/Support/MemoryBuffer.h"
224b6c9de8SGreg Clayton 
234b6c9de8SGreg Clayton using namespace llvm;
244b6c9de8SGreg Clayton using namespace gsym;
254b6c9de8SGreg Clayton 
GsymReader(std::unique_ptr<MemoryBuffer> Buffer)264b6c9de8SGreg Clayton GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) :
274b6c9de8SGreg Clayton     MemBuffer(std::move(Buffer)),
284b6c9de8SGreg Clayton     Endian(support::endian::system_endianness()) {}
294b6c9de8SGreg Clayton 
304b6c9de8SGreg Clayton   GsymReader::GsymReader(GsymReader &&RHS) = default;
314b6c9de8SGreg Clayton 
324b6c9de8SGreg Clayton GsymReader::~GsymReader() = default;
334b6c9de8SGreg Clayton 
openFile(StringRef Filename)344b6c9de8SGreg Clayton llvm::Expected<GsymReader> GsymReader::openFile(StringRef Filename) {
354b6c9de8SGreg Clayton   // Open the input file and return an appropriate error if needed.
364b6c9de8SGreg Clayton   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
374b6c9de8SGreg Clayton       MemoryBuffer::getFileOrSTDIN(Filename);
384b6c9de8SGreg Clayton   auto Err = BuffOrErr.getError();
394b6c9de8SGreg Clayton   if (Err)
404b6c9de8SGreg Clayton     return llvm::errorCodeToError(Err);
414b6c9de8SGreg Clayton   return create(BuffOrErr.get());
424b6c9de8SGreg Clayton }
434b6c9de8SGreg Clayton 
copyBuffer(StringRef Bytes)444b6c9de8SGreg Clayton llvm::Expected<GsymReader> GsymReader::copyBuffer(StringRef Bytes) {
454b6c9de8SGreg Clayton   auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes");
464b6c9de8SGreg Clayton   return create(MemBuffer);
474b6c9de8SGreg Clayton }
484b6c9de8SGreg Clayton 
494b6c9de8SGreg Clayton llvm::Expected<llvm::gsym::GsymReader>
create(std::unique_ptr<MemoryBuffer> & MemBuffer)504b6c9de8SGreg Clayton GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) {
51*9fcd7710SKazu Hirata   if (!MemBuffer)
524b6c9de8SGreg Clayton     return createStringError(std::errc::invalid_argument,
534b6c9de8SGreg Clayton                              "invalid memory buffer");
544b6c9de8SGreg Clayton   GsymReader GR(std::move(MemBuffer));
554b6c9de8SGreg Clayton   llvm::Error Err = GR.parse();
564b6c9de8SGreg Clayton   if (Err)
57c55cf4afSBill Wendling     return std::move(Err);
58c55cf4afSBill Wendling   return std::move(GR);
594b6c9de8SGreg Clayton }
604b6c9de8SGreg Clayton 
614b6c9de8SGreg Clayton llvm::Error
parse()624b6c9de8SGreg Clayton GsymReader::parse() {
634b6c9de8SGreg Clayton   BinaryStreamReader FileData(MemBuffer->getBuffer(),
644b6c9de8SGreg Clayton                               support::endian::system_endianness());
654b6c9de8SGreg Clayton   // Check for the magic bytes. This file format is designed to be mmap'ed
664b6c9de8SGreg Clayton   // into a process and accessed as read only. This is done for performance
674b6c9de8SGreg Clayton   // and efficiency for symbolicating and parsing GSYM data.
684b6c9de8SGreg Clayton   if (FileData.readObject(Hdr))
694b6c9de8SGreg Clayton     return createStringError(std::errc::invalid_argument,
704b6c9de8SGreg Clayton                              "not enough data for a GSYM header");
714b6c9de8SGreg Clayton 
724b6c9de8SGreg Clayton   const auto HostByteOrder = support::endian::system_endianness();
734b6c9de8SGreg Clayton   switch (Hdr->Magic) {
744b6c9de8SGreg Clayton     case GSYM_MAGIC:
754b6c9de8SGreg Clayton       Endian = HostByteOrder;
764b6c9de8SGreg Clayton       break;
774b6c9de8SGreg Clayton     case GSYM_CIGAM:
784b6c9de8SGreg Clayton       // This is a GSYM file, but not native endianness.
794b6c9de8SGreg Clayton       Endian = sys::IsBigEndianHost ? support::little : support::big;
804b6c9de8SGreg Clayton       Swap.reset(new SwappedData);
814b6c9de8SGreg Clayton       break;
824b6c9de8SGreg Clayton     default:
834b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
844b6c9de8SGreg Clayton                                "not a GSYM file");
854b6c9de8SGreg Clayton   }
864b6c9de8SGreg Clayton 
874b6c9de8SGreg Clayton   bool DataIsLittleEndian = HostByteOrder != support::little;
884b6c9de8SGreg Clayton   // Read a correctly byte swapped header if we need to.
894b6c9de8SGreg Clayton   if (Swap) {
904b6c9de8SGreg Clayton     DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
914b6c9de8SGreg Clayton     if (auto ExpectedHdr = Header::decode(Data))
924b6c9de8SGreg Clayton       Swap->Hdr = ExpectedHdr.get();
934b6c9de8SGreg Clayton     else
944b6c9de8SGreg Clayton       return ExpectedHdr.takeError();
954b6c9de8SGreg Clayton     Hdr = &Swap->Hdr;
964b6c9de8SGreg Clayton   }
974b6c9de8SGreg Clayton 
984b6c9de8SGreg Clayton   // Detect errors in the header and report any that are found. If we make it
994b6c9de8SGreg Clayton   // past this without errors, we know we have a good magic value, a supported
1004b6c9de8SGreg Clayton   // version number, verified address offset size and a valid UUID size.
1014b6c9de8SGreg Clayton   if (Error Err = Hdr->checkForError())
1024b6c9de8SGreg Clayton     return Err;
1034b6c9de8SGreg Clayton 
1044b6c9de8SGreg Clayton   if (!Swap) {
1054b6c9de8SGreg Clayton     // This is the native endianness case that is most common and optimized for
1064b6c9de8SGreg Clayton     // efficient lookups. Here we just grab pointers to the native data and
1074b6c9de8SGreg Clayton     // use ArrayRef objects to allow efficient read only access.
1084b6c9de8SGreg Clayton 
1094b6c9de8SGreg Clayton     // Read the address offsets.
1104b6c9de8SGreg Clayton     if (FileData.padToAlignment(Hdr->AddrOffSize) ||
1114b6c9de8SGreg Clayton         FileData.readArray(AddrOffsets,
1124b6c9de8SGreg Clayton                            Hdr->NumAddresses * Hdr->AddrOffSize))
1134b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
1144b6c9de8SGreg Clayton                               "failed to read address table");
1154b6c9de8SGreg Clayton 
1164b6c9de8SGreg Clayton     // Read the address info offsets.
1174b6c9de8SGreg Clayton     if (FileData.padToAlignment(4) ||
1184b6c9de8SGreg Clayton         FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses))
1194b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
1204b6c9de8SGreg Clayton                               "failed to read address info offsets table");
1214b6c9de8SGreg Clayton 
1224b6c9de8SGreg Clayton     // Read the file table.
1234b6c9de8SGreg Clayton     uint32_t NumFiles = 0;
1244b6c9de8SGreg Clayton     if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles))
1254b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
1264b6c9de8SGreg Clayton                               "failed to read file table");
1274b6c9de8SGreg Clayton 
1284b6c9de8SGreg Clayton     // Get the string table.
1294b6c9de8SGreg Clayton     FileData.setOffset(Hdr->StrtabOffset);
1304b6c9de8SGreg Clayton     if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize))
1314b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
1324b6c9de8SGreg Clayton                               "failed to read string table");
1334b6c9de8SGreg Clayton } else {
1344b6c9de8SGreg Clayton   // This is the non native endianness case that is not common and not
1354b6c9de8SGreg Clayton   // optimized for lookups. Here we decode the important tables into local
1364b6c9de8SGreg Clayton   // storage and then set the ArrayRef objects to point to these swapped
1374b6c9de8SGreg Clayton   // copies of the read only data so lookups can be as efficient as possible.
1384b6c9de8SGreg Clayton   DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
1394b6c9de8SGreg Clayton 
1404b6c9de8SGreg Clayton   // Read the address offsets.
1414b6c9de8SGreg Clayton   uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize);
1424b6c9de8SGreg Clayton   Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize);
1434b6c9de8SGreg Clayton   switch (Hdr->AddrOffSize) {
1444b6c9de8SGreg Clayton     case 1:
1454b6c9de8SGreg Clayton       if (!Data.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses))
1464b6c9de8SGreg Clayton         return createStringError(std::errc::invalid_argument,
1474b6c9de8SGreg Clayton                                   "failed to read address table");
1484b6c9de8SGreg Clayton       break;
1494b6c9de8SGreg Clayton     case 2:
1504b6c9de8SGreg Clayton       if (!Data.getU16(&Offset,
1514b6c9de8SGreg Clayton                         reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
1524b6c9de8SGreg Clayton                         Hdr->NumAddresses))
1534b6c9de8SGreg Clayton         return createStringError(std::errc::invalid_argument,
1544b6c9de8SGreg Clayton                                   "failed to read address table");
1554b6c9de8SGreg Clayton       break;
1564b6c9de8SGreg Clayton     case 4:
1574b6c9de8SGreg Clayton       if (!Data.getU32(&Offset,
1584b6c9de8SGreg Clayton                         reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
1594b6c9de8SGreg Clayton                         Hdr->NumAddresses))
1604b6c9de8SGreg Clayton         return createStringError(std::errc::invalid_argument,
1614b6c9de8SGreg Clayton                                   "failed to read address table");
1624b6c9de8SGreg Clayton       break;
1634b6c9de8SGreg Clayton     case 8:
1644b6c9de8SGreg Clayton       if (!Data.getU64(&Offset,
1654b6c9de8SGreg Clayton                         reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
1664b6c9de8SGreg Clayton                         Hdr->NumAddresses))
1674b6c9de8SGreg Clayton         return createStringError(std::errc::invalid_argument,
1684b6c9de8SGreg Clayton                                   "failed to read address table");
1694b6c9de8SGreg Clayton     }
1704b6c9de8SGreg Clayton     AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
1714b6c9de8SGreg Clayton 
1724b6c9de8SGreg Clayton     // Read the address info offsets.
1734b6c9de8SGreg Clayton     Offset = alignTo(Offset, 4);
1744b6c9de8SGreg Clayton     Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
1754b6c9de8SGreg Clayton     if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses))
1764b6c9de8SGreg Clayton       AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets);
1774b6c9de8SGreg Clayton     else
1784b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
1794b6c9de8SGreg Clayton                                "failed to read address table");
1804b6c9de8SGreg Clayton     // Read the file table.
1814b6c9de8SGreg Clayton     const uint32_t NumFiles = Data.getU32(&Offset);
1824b6c9de8SGreg Clayton     if (NumFiles > 0) {
1834b6c9de8SGreg Clayton       Swap->Files.resize(NumFiles);
1844b6c9de8SGreg Clayton       if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2))
1854b6c9de8SGreg Clayton         Files = ArrayRef<FileEntry>(Swap->Files);
1864b6c9de8SGreg Clayton       else
1874b6c9de8SGreg Clayton         return createStringError(std::errc::invalid_argument,
1884b6c9de8SGreg Clayton                                  "failed to read file table");
1894b6c9de8SGreg Clayton     }
1904b6c9de8SGreg Clayton     // Get the string table.
1914b6c9de8SGreg Clayton     StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset,
1924b6c9de8SGreg Clayton                                                 Hdr->StrtabSize);
1934b6c9de8SGreg Clayton     if (StrTab.Data.empty())
1944b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
1954b6c9de8SGreg Clayton                                "failed to read string table");
1964b6c9de8SGreg Clayton   }
1974b6c9de8SGreg Clayton   return Error::success();
1984b6c9de8SGreg Clayton 
1994b6c9de8SGreg Clayton }
2004b6c9de8SGreg Clayton 
getHeader() const2014b6c9de8SGreg Clayton const Header &GsymReader::getHeader() const {
2024b6c9de8SGreg Clayton   // The only way to get a GsymReader is from GsymReader::openFile(...) or
2034b6c9de8SGreg Clayton   // GsymReader::copyBuffer() and the header must be valid and initialized to
2044b6c9de8SGreg Clayton   // a valid pointer value, so the assert below should not trigger.
2054b6c9de8SGreg Clayton   assert(Hdr);
2064b6c9de8SGreg Clayton   return *Hdr;
2074b6c9de8SGreg Clayton }
2084b6c9de8SGreg Clayton 
getAddress(size_t Index) const2094b6c9de8SGreg Clayton Optional<uint64_t> GsymReader::getAddress(size_t Index) const {
2104b6c9de8SGreg Clayton   switch (Hdr->AddrOffSize) {
2114b6c9de8SGreg Clayton   case 1: return addressForIndex<uint8_t>(Index);
2124b6c9de8SGreg Clayton   case 2: return addressForIndex<uint16_t>(Index);
2134b6c9de8SGreg Clayton   case 4: return addressForIndex<uint32_t>(Index);
2144b6c9de8SGreg Clayton   case 8: return addressForIndex<uint64_t>(Index);
2154b6c9de8SGreg Clayton   }
2164b6c9de8SGreg Clayton   return llvm::None;
2174b6c9de8SGreg Clayton }
2184b6c9de8SGreg Clayton 
getAddressInfoOffset(size_t Index) const2194b6c9de8SGreg Clayton Optional<uint64_t> GsymReader::getAddressInfoOffset(size_t Index) const {
2204b6c9de8SGreg Clayton   const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
2214b6c9de8SGreg Clayton   if (Index < NumAddrInfoOffsets)
2224b6c9de8SGreg Clayton     return AddrInfoOffsets[Index];
2234b6c9de8SGreg Clayton   return llvm::None;
2244b6c9de8SGreg Clayton }
2254b6c9de8SGreg Clayton 
2264b6c9de8SGreg Clayton Expected<uint64_t>
getAddressIndex(const uint64_t Addr) const2274b6c9de8SGreg Clayton GsymReader::getAddressIndex(const uint64_t Addr) const {
2282f6cc21fSGreg Clayton   if (Addr >= Hdr->BaseAddress) {
2294b6c9de8SGreg Clayton     const uint64_t AddrOffset = Addr - Hdr->BaseAddress;
2302f6cc21fSGreg Clayton     Optional<uint64_t> AddrOffsetIndex;
2314b6c9de8SGreg Clayton     switch (Hdr->AddrOffSize) {
2322f6cc21fSGreg Clayton     case 1:
2332f6cc21fSGreg Clayton       AddrOffsetIndex = getAddressOffsetIndex<uint8_t>(AddrOffset);
2342f6cc21fSGreg Clayton       break;
2352f6cc21fSGreg Clayton     case 2:
2362f6cc21fSGreg Clayton       AddrOffsetIndex = getAddressOffsetIndex<uint16_t>(AddrOffset);
2372f6cc21fSGreg Clayton       break;
2382f6cc21fSGreg Clayton     case 4:
2392f6cc21fSGreg Clayton       AddrOffsetIndex = getAddressOffsetIndex<uint32_t>(AddrOffset);
2402f6cc21fSGreg Clayton       break;
2412f6cc21fSGreg Clayton     case 8:
2422f6cc21fSGreg Clayton       AddrOffsetIndex = getAddressOffsetIndex<uint64_t>(AddrOffset);
2432f6cc21fSGreg Clayton       break;
2442f6cc21fSGreg Clayton     default:
2454b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
2464b6c9de8SGreg Clayton                                "unsupported address offset size %u",
2474b6c9de8SGreg Clayton                                Hdr->AddrOffSize);
2484b6c9de8SGreg Clayton     }
2492f6cc21fSGreg Clayton     if (AddrOffsetIndex)
2502f6cc21fSGreg Clayton       return *AddrOffsetIndex;
2512f6cc21fSGreg Clayton   }
2522f6cc21fSGreg Clayton   return createStringError(std::errc::invalid_argument,
2532f6cc21fSGreg Clayton                            "address 0x%" PRIx64 " is not in GSYM", Addr);
2542f6cc21fSGreg Clayton 
2552f6cc21fSGreg Clayton }
2564b6c9de8SGreg Clayton 
getFunctionInfo(uint64_t Addr) const2574b6c9de8SGreg Clayton llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
2584b6c9de8SGreg Clayton   Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
2594b6c9de8SGreg Clayton   if (!AddressIndex)
2604b6c9de8SGreg Clayton     return AddressIndex.takeError();
2614b6c9de8SGreg Clayton   // Address info offsets size should have been checked in parse().
2624b6c9de8SGreg Clayton   assert(*AddressIndex < AddrInfoOffsets.size());
2634b6c9de8SGreg Clayton   auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
2644b6c9de8SGreg Clayton   DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
2654b6c9de8SGreg Clayton   if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex)) {
2664b6c9de8SGreg Clayton     auto ExpectedFI = FunctionInfo::decode(Data, *OptAddr);
2674b6c9de8SGreg Clayton     if (ExpectedFI) {
2684b6c9de8SGreg Clayton       if (ExpectedFI->Range.contains(Addr) || ExpectedFI->Range.size() == 0)
2694b6c9de8SGreg Clayton         return ExpectedFI;
2704b6c9de8SGreg Clayton       return createStringError(std::errc::invalid_argument,
2715e13e0ceSGreg Clayton                                 "address 0x%" PRIx64 " is not in GSYM", Addr);
2724b6c9de8SGreg Clayton     }
2734b6c9de8SGreg Clayton   }
2744b6c9de8SGreg Clayton   return createStringError(std::errc::invalid_argument,
2754b6c9de8SGreg Clayton                            "failed to extract address[%" PRIu64 "]",
2764b6c9de8SGreg Clayton                            *AddressIndex);
2774b6c9de8SGreg Clayton }
278aeda128aSGreg Clayton 
lookup(uint64_t Addr) const279aeda128aSGreg Clayton llvm::Expected<LookupResult> GsymReader::lookup(uint64_t Addr) const {
280aeda128aSGreg Clayton   Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
281aeda128aSGreg Clayton   if (!AddressIndex)
282aeda128aSGreg Clayton     return AddressIndex.takeError();
283aeda128aSGreg Clayton   // Address info offsets size should have been checked in parse().
284aeda128aSGreg Clayton   assert(*AddressIndex < AddrInfoOffsets.size());
285aeda128aSGreg Clayton   auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
286aeda128aSGreg Clayton   DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
287aeda128aSGreg Clayton   if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex))
288aeda128aSGreg Clayton     return FunctionInfo::lookup(Data, *this, *OptAddr, Addr);
289aeda128aSGreg Clayton   return createStringError(std::errc::invalid_argument,
290aeda128aSGreg Clayton                            "failed to extract address[%" PRIu64 "]",
291aeda128aSGreg Clayton                            *AddressIndex);
292aeda128aSGreg Clayton }
29319602b71SGreg Clayton 
dump(raw_ostream & OS)29419602b71SGreg Clayton void GsymReader::dump(raw_ostream &OS) {
29519602b71SGreg Clayton   const auto &Header = getHeader();
29619602b71SGreg Clayton   // Dump the GSYM header.
29719602b71SGreg Clayton   OS << Header << "\n";
29819602b71SGreg Clayton   // Dump the address table.
29919602b71SGreg Clayton   OS << "Address Table:\n";
30019602b71SGreg Clayton   OS << "INDEX  OFFSET";
30119602b71SGreg Clayton 
30219602b71SGreg Clayton   switch (Hdr->AddrOffSize) {
30319602b71SGreg Clayton   case 1: OS << "8 "; break;
30419602b71SGreg Clayton   case 2: OS << "16"; break;
30519602b71SGreg Clayton   case 4: OS << "32"; break;
30619602b71SGreg Clayton   case 8: OS << "64"; break;
30719602b71SGreg Clayton   default: OS << "??"; break;
30819602b71SGreg Clayton   }
30919602b71SGreg Clayton   OS << " (ADDRESS)\n";
31019602b71SGreg Clayton   OS << "====== =============================== \n";
31119602b71SGreg Clayton   for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
31219602b71SGreg Clayton     OS << format("[%4u] ", I);
31319602b71SGreg Clayton     switch (Hdr->AddrOffSize) {
31419602b71SGreg Clayton     case 1: OS << HEX8(getAddrOffsets<uint8_t>()[I]); break;
31519602b71SGreg Clayton     case 2: OS << HEX16(getAddrOffsets<uint16_t>()[I]); break;
31619602b71SGreg Clayton     case 4: OS << HEX32(getAddrOffsets<uint32_t>()[I]); break;
31719602b71SGreg Clayton     case 8: OS << HEX32(getAddrOffsets<uint64_t>()[I]); break;
31819602b71SGreg Clayton     default: break;
31919602b71SGreg Clayton     }
32019602b71SGreg Clayton     OS << " (" << HEX64(*getAddress(I)) << ")\n";
32119602b71SGreg Clayton   }
32219602b71SGreg Clayton   // Dump the address info offsets table.
32319602b71SGreg Clayton   OS << "\nAddress Info Offsets:\n";
32419602b71SGreg Clayton   OS << "INDEX  Offset\n";
32519602b71SGreg Clayton   OS << "====== ==========\n";
32619602b71SGreg Clayton   for (uint32_t I = 0; I < Header.NumAddresses; ++I)
32719602b71SGreg Clayton     OS << format("[%4u] ", I) << HEX32(AddrInfoOffsets[I]) << "\n";
32819602b71SGreg Clayton   // Dump the file table.
32919602b71SGreg Clayton   OS << "\nFiles:\n";
33019602b71SGreg Clayton   OS << "INDEX  DIRECTORY  BASENAME   PATH\n";
33119602b71SGreg Clayton   OS << "====== ========== ========== ==============================\n";
33219602b71SGreg Clayton   for (uint32_t I = 0; I < Files.size(); ++I) {
33319602b71SGreg Clayton     OS << format("[%4u] ", I) << HEX32(Files[I].Dir) << ' '
33419602b71SGreg Clayton        << HEX32(Files[I].Base) << ' ';
33519602b71SGreg Clayton     dump(OS, getFile(I));
33619602b71SGreg Clayton     OS << "\n";
33719602b71SGreg Clayton   }
3385e13e0ceSGreg Clayton   OS << "\n" << StrTab << "\n";
33919602b71SGreg Clayton 
34019602b71SGreg Clayton   for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
3415e13e0ceSGreg Clayton     OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": ";
34219602b71SGreg Clayton     if (auto FI = getFunctionInfo(*getAddress(I)))
34319602b71SGreg Clayton       dump(OS, *FI);
34419602b71SGreg Clayton     else
34519602b71SGreg Clayton       logAllUnhandledErrors(FI.takeError(), OS, "FunctionInfo:");
34619602b71SGreg Clayton   }
34719602b71SGreg Clayton }
34819602b71SGreg Clayton 
dump(raw_ostream & OS,const FunctionInfo & FI)34919602b71SGreg Clayton void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI) {
35019602b71SGreg Clayton   OS << FI.Range << " \"" << getString(FI.Name) << "\"\n";
35119602b71SGreg Clayton   if (FI.OptLineTable)
35219602b71SGreg Clayton     dump(OS, *FI.OptLineTable);
35319602b71SGreg Clayton   if (FI.Inline)
35419602b71SGreg Clayton     dump(OS, *FI.Inline);
35519602b71SGreg Clayton }
35619602b71SGreg Clayton 
dump(raw_ostream & OS,const LineTable & LT)35719602b71SGreg Clayton void GsymReader::dump(raw_ostream &OS, const LineTable &LT) {
35819602b71SGreg Clayton   OS << "LineTable:\n";
35919602b71SGreg Clayton   for (auto &LE: LT) {
36019602b71SGreg Clayton     OS << "  " << HEX64(LE.Addr) << ' ';
36119602b71SGreg Clayton     if (LE.File)
36219602b71SGreg Clayton       dump(OS, getFile(LE.File));
36319602b71SGreg Clayton     OS << ':' << LE.Line << '\n';
36419602b71SGreg Clayton   }
36519602b71SGreg Clayton }
36619602b71SGreg Clayton 
dump(raw_ostream & OS,const InlineInfo & II,uint32_t Indent)36719602b71SGreg Clayton void GsymReader::dump(raw_ostream &OS, const InlineInfo &II, uint32_t Indent) {
36819602b71SGreg Clayton   if (Indent == 0)
36919602b71SGreg Clayton     OS << "InlineInfo:\n";
37019602b71SGreg Clayton   else
37119602b71SGreg Clayton     OS.indent(Indent);
37219602b71SGreg Clayton   OS << II.Ranges << ' ' << getString(II.Name);
37319602b71SGreg Clayton   if (II.CallFile != 0) {
37419602b71SGreg Clayton     if (auto File = getFile(II.CallFile)) {
37519602b71SGreg Clayton       OS << " called from ";
37619602b71SGreg Clayton       dump(OS, File);
37719602b71SGreg Clayton       OS << ':' << II.CallLine;
37819602b71SGreg Clayton     }
37919602b71SGreg Clayton   }
38019602b71SGreg Clayton   OS << '\n';
38119602b71SGreg Clayton   for (const auto &ChildII: II.Children)
38219602b71SGreg Clayton     dump(OS, ChildII, Indent + 2);
38319602b71SGreg Clayton }
38419602b71SGreg Clayton 
dump(raw_ostream & OS,Optional<FileEntry> FE)38519602b71SGreg Clayton void GsymReader::dump(raw_ostream &OS, Optional<FileEntry> FE) {
38619602b71SGreg Clayton   if (FE) {
38719602b71SGreg Clayton     // IF we have the file from index 0, then don't print anything
38819602b71SGreg Clayton     if (FE->Dir == 0 && FE->Base == 0)
38919602b71SGreg Clayton       return;
39019602b71SGreg Clayton     StringRef Dir = getString(FE->Dir);
39119602b71SGreg Clayton     StringRef Base = getString(FE->Base);
39219602b71SGreg Clayton     if (!Dir.empty()) {
39319602b71SGreg Clayton       OS << Dir;
39422d63b63SGreg Clayton       if (Dir.contains('\\') && !Dir.contains('/'))
39519602b71SGreg Clayton         OS << '\\';
39619602b71SGreg Clayton       else
39719602b71SGreg Clayton         OS << '/';
39819602b71SGreg Clayton     }
39919602b71SGreg Clayton     if (!Base.empty()) {
40019602b71SGreg Clayton       OS << Base;
40119602b71SGreg Clayton     }
40219602b71SGreg Clayton     if (!Dir.empty() || !Base.empty())
40319602b71SGreg Clayton       return;
40419602b71SGreg Clayton   }
40519602b71SGreg Clayton   OS << "<invalid-file>";
40619602b71SGreg Clayton }
407