xref: /netbsd-src/external/apache2/llvm/dist/llvm/lib/DebugInfo/GSYM/GsymReader.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
17330f729Sjoerg //===- GsymReader.cpp -----------------------------------------------------===//
27330f729Sjoerg //
3*82d56013Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*82d56013Sjoerg // See https://llvm.org/LICENSE.txt for license information.
5*82d56013Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg 
97330f729Sjoerg #include "llvm/DebugInfo/GSYM/GsymReader.h"
107330f729Sjoerg 
117330f729Sjoerg #include <assert.h>
127330f729Sjoerg #include <inttypes.h>
137330f729Sjoerg #include <stdio.h>
147330f729Sjoerg #include <stdlib.h>
157330f729Sjoerg 
167330f729Sjoerg #include "llvm/DebugInfo/GSYM/GsymCreator.h"
177330f729Sjoerg #include "llvm/DebugInfo/GSYM/InlineInfo.h"
187330f729Sjoerg #include "llvm/DebugInfo/GSYM/LineTable.h"
197330f729Sjoerg #include "llvm/Support/BinaryStreamReader.h"
207330f729Sjoerg #include "llvm/Support/DataExtractor.h"
217330f729Sjoerg #include "llvm/Support/MemoryBuffer.h"
227330f729Sjoerg 
237330f729Sjoerg using namespace llvm;
247330f729Sjoerg using namespace gsym;
257330f729Sjoerg 
GsymReader(std::unique_ptr<MemoryBuffer> Buffer)267330f729Sjoerg GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) :
277330f729Sjoerg     MemBuffer(std::move(Buffer)),
287330f729Sjoerg     Endian(support::endian::system_endianness()) {}
297330f729Sjoerg 
307330f729Sjoerg   GsymReader::GsymReader(GsymReader &&RHS) = default;
317330f729Sjoerg 
327330f729Sjoerg GsymReader::~GsymReader() = default;
337330f729Sjoerg 
openFile(StringRef Filename)347330f729Sjoerg llvm::Expected<GsymReader> GsymReader::openFile(StringRef Filename) {
357330f729Sjoerg   // Open the input file and return an appropriate error if needed.
367330f729Sjoerg   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
377330f729Sjoerg       MemoryBuffer::getFileOrSTDIN(Filename);
387330f729Sjoerg   auto Err = BuffOrErr.getError();
397330f729Sjoerg   if (Err)
407330f729Sjoerg     return llvm::errorCodeToError(Err);
417330f729Sjoerg   return create(BuffOrErr.get());
427330f729Sjoerg }
437330f729Sjoerg 
copyBuffer(StringRef Bytes)447330f729Sjoerg llvm::Expected<GsymReader> GsymReader::copyBuffer(StringRef Bytes) {
457330f729Sjoerg   auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes");
467330f729Sjoerg   return create(MemBuffer);
477330f729Sjoerg }
487330f729Sjoerg 
497330f729Sjoerg llvm::Expected<llvm::gsym::GsymReader>
create(std::unique_ptr<MemoryBuffer> & MemBuffer)507330f729Sjoerg GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) {
517330f729Sjoerg   if (!MemBuffer.get())
527330f729Sjoerg     return createStringError(std::errc::invalid_argument,
537330f729Sjoerg                              "invalid memory buffer");
547330f729Sjoerg   GsymReader GR(std::move(MemBuffer));
557330f729Sjoerg   llvm::Error Err = GR.parse();
567330f729Sjoerg   if (Err)
577330f729Sjoerg     return std::move(Err);
587330f729Sjoerg   return std::move(GR);
597330f729Sjoerg }
607330f729Sjoerg 
617330f729Sjoerg llvm::Error
parse()627330f729Sjoerg GsymReader::parse() {
637330f729Sjoerg   BinaryStreamReader FileData(MemBuffer->getBuffer(),
647330f729Sjoerg                               support::endian::system_endianness());
657330f729Sjoerg   // Check for the magic bytes. This file format is designed to be mmap'ed
667330f729Sjoerg   // into a process and accessed as read only. This is done for performance
677330f729Sjoerg   // and efficiency for symbolicating and parsing GSYM data.
687330f729Sjoerg   if (FileData.readObject(Hdr))
697330f729Sjoerg     return createStringError(std::errc::invalid_argument,
707330f729Sjoerg                              "not enough data for a GSYM header");
717330f729Sjoerg 
727330f729Sjoerg   const auto HostByteOrder = support::endian::system_endianness();
737330f729Sjoerg   switch (Hdr->Magic) {
747330f729Sjoerg     case GSYM_MAGIC:
757330f729Sjoerg       Endian = HostByteOrder;
767330f729Sjoerg       break;
777330f729Sjoerg     case GSYM_CIGAM:
787330f729Sjoerg       // This is a GSYM file, but not native endianness.
797330f729Sjoerg       Endian = sys::IsBigEndianHost ? support::little : support::big;
807330f729Sjoerg       Swap.reset(new SwappedData);
817330f729Sjoerg       break;
827330f729Sjoerg     default:
837330f729Sjoerg       return createStringError(std::errc::invalid_argument,
847330f729Sjoerg                                "not a GSYM file");
857330f729Sjoerg   }
867330f729Sjoerg 
877330f729Sjoerg   bool DataIsLittleEndian = HostByteOrder != support::little;
887330f729Sjoerg   // Read a correctly byte swapped header if we need to.
897330f729Sjoerg   if (Swap) {
907330f729Sjoerg     DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
917330f729Sjoerg     if (auto ExpectedHdr = Header::decode(Data))
927330f729Sjoerg       Swap->Hdr = ExpectedHdr.get();
937330f729Sjoerg     else
947330f729Sjoerg       return ExpectedHdr.takeError();
957330f729Sjoerg     Hdr = &Swap->Hdr;
967330f729Sjoerg   }
977330f729Sjoerg 
987330f729Sjoerg   // Detect errors in the header and report any that are found. If we make it
997330f729Sjoerg   // past this without errors, we know we have a good magic value, a supported
1007330f729Sjoerg   // version number, verified address offset size and a valid UUID size.
1017330f729Sjoerg   if (Error Err = Hdr->checkForError())
1027330f729Sjoerg     return Err;
1037330f729Sjoerg 
1047330f729Sjoerg   if (!Swap) {
1057330f729Sjoerg     // This is the native endianness case that is most common and optimized for
1067330f729Sjoerg     // efficient lookups. Here we just grab pointers to the native data and
1077330f729Sjoerg     // use ArrayRef objects to allow efficient read only access.
1087330f729Sjoerg 
1097330f729Sjoerg     // Read the address offsets.
1107330f729Sjoerg     if (FileData.padToAlignment(Hdr->AddrOffSize) ||
1117330f729Sjoerg         FileData.readArray(AddrOffsets,
1127330f729Sjoerg                            Hdr->NumAddresses * Hdr->AddrOffSize))
1137330f729Sjoerg       return createStringError(std::errc::invalid_argument,
1147330f729Sjoerg                               "failed to read address table");
1157330f729Sjoerg 
1167330f729Sjoerg     // Read the address info offsets.
1177330f729Sjoerg     if (FileData.padToAlignment(4) ||
1187330f729Sjoerg         FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses))
1197330f729Sjoerg       return createStringError(std::errc::invalid_argument,
1207330f729Sjoerg                               "failed to read address info offsets table");
1217330f729Sjoerg 
1227330f729Sjoerg     // Read the file table.
1237330f729Sjoerg     uint32_t NumFiles = 0;
1247330f729Sjoerg     if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles))
1257330f729Sjoerg       return createStringError(std::errc::invalid_argument,
1267330f729Sjoerg                               "failed to read file table");
1277330f729Sjoerg 
1287330f729Sjoerg     // Get the string table.
1297330f729Sjoerg     FileData.setOffset(Hdr->StrtabOffset);
1307330f729Sjoerg     if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize))
1317330f729Sjoerg       return createStringError(std::errc::invalid_argument,
1327330f729Sjoerg                               "failed to read string table");
1337330f729Sjoerg } else {
1347330f729Sjoerg   // This is the non native endianness case that is not common and not
1357330f729Sjoerg   // optimized for lookups. Here we decode the important tables into local
1367330f729Sjoerg   // storage and then set the ArrayRef objects to point to these swapped
1377330f729Sjoerg   // copies of the read only data so lookups can be as efficient as possible.
1387330f729Sjoerg   DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
1397330f729Sjoerg 
1407330f729Sjoerg   // Read the address offsets.
1417330f729Sjoerg   uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize);
1427330f729Sjoerg   Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize);
1437330f729Sjoerg   switch (Hdr->AddrOffSize) {
1447330f729Sjoerg     case 1:
1457330f729Sjoerg       if (!Data.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses))
1467330f729Sjoerg         return createStringError(std::errc::invalid_argument,
1477330f729Sjoerg                                   "failed to read address table");
1487330f729Sjoerg       break;
1497330f729Sjoerg     case 2:
1507330f729Sjoerg       if (!Data.getU16(&Offset,
1517330f729Sjoerg                         reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
1527330f729Sjoerg                         Hdr->NumAddresses))
1537330f729Sjoerg         return createStringError(std::errc::invalid_argument,
1547330f729Sjoerg                                   "failed to read address table");
1557330f729Sjoerg       break;
1567330f729Sjoerg     case 4:
1577330f729Sjoerg       if (!Data.getU32(&Offset,
1587330f729Sjoerg                         reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
1597330f729Sjoerg                         Hdr->NumAddresses))
1607330f729Sjoerg         return createStringError(std::errc::invalid_argument,
1617330f729Sjoerg                                   "failed to read address table");
1627330f729Sjoerg       break;
1637330f729Sjoerg     case 8:
1647330f729Sjoerg       if (!Data.getU64(&Offset,
1657330f729Sjoerg                         reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
1667330f729Sjoerg                         Hdr->NumAddresses))
1677330f729Sjoerg         return createStringError(std::errc::invalid_argument,
1687330f729Sjoerg                                   "failed to read address table");
1697330f729Sjoerg     }
1707330f729Sjoerg     AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
1717330f729Sjoerg 
1727330f729Sjoerg     // Read the address info offsets.
1737330f729Sjoerg     Offset = alignTo(Offset, 4);
1747330f729Sjoerg     Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
1757330f729Sjoerg     if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses))
1767330f729Sjoerg       AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets);
1777330f729Sjoerg     else
1787330f729Sjoerg       return createStringError(std::errc::invalid_argument,
1797330f729Sjoerg                                "failed to read address table");
1807330f729Sjoerg     // Read the file table.
1817330f729Sjoerg     const uint32_t NumFiles = Data.getU32(&Offset);
1827330f729Sjoerg     if (NumFiles > 0) {
1837330f729Sjoerg       Swap->Files.resize(NumFiles);
1847330f729Sjoerg       if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2))
1857330f729Sjoerg         Files = ArrayRef<FileEntry>(Swap->Files);
1867330f729Sjoerg       else
1877330f729Sjoerg         return createStringError(std::errc::invalid_argument,
1887330f729Sjoerg                                  "failed to read file table");
1897330f729Sjoerg     }
1907330f729Sjoerg     // Get the string table.
1917330f729Sjoerg     StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset,
1927330f729Sjoerg                                                 Hdr->StrtabSize);
1937330f729Sjoerg     if (StrTab.Data.empty())
1947330f729Sjoerg       return createStringError(std::errc::invalid_argument,
1957330f729Sjoerg                                "failed to read string table");
1967330f729Sjoerg   }
1977330f729Sjoerg   return Error::success();
1987330f729Sjoerg 
1997330f729Sjoerg }
2007330f729Sjoerg 
getHeader() const2017330f729Sjoerg const Header &GsymReader::getHeader() const {
2027330f729Sjoerg   // The only way to get a GsymReader is from GsymReader::openFile(...) or
2037330f729Sjoerg   // GsymReader::copyBuffer() and the header must be valid and initialized to
2047330f729Sjoerg   // a valid pointer value, so the assert below should not trigger.
2057330f729Sjoerg   assert(Hdr);
2067330f729Sjoerg   return *Hdr;
2077330f729Sjoerg }
2087330f729Sjoerg 
getAddress(size_t Index) const2097330f729Sjoerg Optional<uint64_t> GsymReader::getAddress(size_t Index) const {
2107330f729Sjoerg   switch (Hdr->AddrOffSize) {
2117330f729Sjoerg   case 1: return addressForIndex<uint8_t>(Index);
2127330f729Sjoerg   case 2: return addressForIndex<uint16_t>(Index);
2137330f729Sjoerg   case 4: return addressForIndex<uint32_t>(Index);
2147330f729Sjoerg   case 8: return addressForIndex<uint64_t>(Index);
2157330f729Sjoerg   }
2167330f729Sjoerg   return llvm::None;
2177330f729Sjoerg }
2187330f729Sjoerg 
getAddressInfoOffset(size_t Index) const2197330f729Sjoerg Optional<uint64_t> GsymReader::getAddressInfoOffset(size_t Index) const {
2207330f729Sjoerg   const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
2217330f729Sjoerg   if (Index < NumAddrInfoOffsets)
2227330f729Sjoerg     return AddrInfoOffsets[Index];
2237330f729Sjoerg   return llvm::None;
2247330f729Sjoerg }
2257330f729Sjoerg 
2267330f729Sjoerg Expected<uint64_t>
getAddressIndex(const uint64_t Addr) const2277330f729Sjoerg GsymReader::getAddressIndex(const uint64_t Addr) const {
228*82d56013Sjoerg   if (Addr >= Hdr->BaseAddress) {
2297330f729Sjoerg     const uint64_t AddrOffset = Addr - Hdr->BaseAddress;
230*82d56013Sjoerg     Optional<uint64_t> AddrOffsetIndex;
2317330f729Sjoerg     switch (Hdr->AddrOffSize) {
232*82d56013Sjoerg     case 1:
233*82d56013Sjoerg       AddrOffsetIndex = getAddressOffsetIndex<uint8_t>(AddrOffset);
234*82d56013Sjoerg       break;
235*82d56013Sjoerg     case 2:
236*82d56013Sjoerg       AddrOffsetIndex = getAddressOffsetIndex<uint16_t>(AddrOffset);
237*82d56013Sjoerg       break;
238*82d56013Sjoerg     case 4:
239*82d56013Sjoerg       AddrOffsetIndex = getAddressOffsetIndex<uint32_t>(AddrOffset);
240*82d56013Sjoerg       break;
241*82d56013Sjoerg     case 8:
242*82d56013Sjoerg       AddrOffsetIndex = getAddressOffsetIndex<uint64_t>(AddrOffset);
243*82d56013Sjoerg       break;
244*82d56013Sjoerg     default:
2457330f729Sjoerg       return createStringError(std::errc::invalid_argument,
2467330f729Sjoerg                                "unsupported address offset size %u",
2477330f729Sjoerg                                Hdr->AddrOffSize);
2487330f729Sjoerg     }
249*82d56013Sjoerg     if (AddrOffsetIndex)
250*82d56013Sjoerg       return *AddrOffsetIndex;
251*82d56013Sjoerg   }
252*82d56013Sjoerg   return createStringError(std::errc::invalid_argument,
253*82d56013Sjoerg                            "address 0x%" PRIx64 " is not in GSYM", Addr);
254*82d56013Sjoerg 
255*82d56013Sjoerg }
2567330f729Sjoerg 
getFunctionInfo(uint64_t Addr) const2577330f729Sjoerg llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
2587330f729Sjoerg   Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
2597330f729Sjoerg   if (!AddressIndex)
2607330f729Sjoerg     return AddressIndex.takeError();
2617330f729Sjoerg   // Address info offsets size should have been checked in parse().
2627330f729Sjoerg   assert(*AddressIndex < AddrInfoOffsets.size());
2637330f729Sjoerg   auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
2647330f729Sjoerg   DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
2657330f729Sjoerg   if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex)) {
2667330f729Sjoerg     auto ExpectedFI = FunctionInfo::decode(Data, *OptAddr);
2677330f729Sjoerg     if (ExpectedFI) {
2687330f729Sjoerg       if (ExpectedFI->Range.contains(Addr) || ExpectedFI->Range.size() == 0)
2697330f729Sjoerg         return ExpectedFI;
2707330f729Sjoerg       return createStringError(std::errc::invalid_argument,
271*82d56013Sjoerg                                 "address 0x%" PRIx64 " is not in GSYM", Addr);
2727330f729Sjoerg     }
2737330f729Sjoerg   }
2747330f729Sjoerg   return createStringError(std::errc::invalid_argument,
2757330f729Sjoerg                            "failed to extract address[%" PRIu64 "]",
2767330f729Sjoerg                            *AddressIndex);
2777330f729Sjoerg }
278*82d56013Sjoerg 
lookup(uint64_t Addr) const279*82d56013Sjoerg llvm::Expected<LookupResult> GsymReader::lookup(uint64_t Addr) const {
280*82d56013Sjoerg   Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
281*82d56013Sjoerg   if (!AddressIndex)
282*82d56013Sjoerg     return AddressIndex.takeError();
283*82d56013Sjoerg   // Address info offsets size should have been checked in parse().
284*82d56013Sjoerg   assert(*AddressIndex < AddrInfoOffsets.size());
285*82d56013Sjoerg   auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
286*82d56013Sjoerg   DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
287*82d56013Sjoerg   if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex))
288*82d56013Sjoerg     return FunctionInfo::lookup(Data, *this, *OptAddr, Addr);
289*82d56013Sjoerg   return createStringError(std::errc::invalid_argument,
290*82d56013Sjoerg                            "failed to extract address[%" PRIu64 "]",
291*82d56013Sjoerg                            *AddressIndex);
292*82d56013Sjoerg }
293*82d56013Sjoerg 
dump(raw_ostream & OS)294*82d56013Sjoerg void GsymReader::dump(raw_ostream &OS) {
295*82d56013Sjoerg   const auto &Header = getHeader();
296*82d56013Sjoerg   // Dump the GSYM header.
297*82d56013Sjoerg   OS << Header << "\n";
298*82d56013Sjoerg   // Dump the address table.
299*82d56013Sjoerg   OS << "Address Table:\n";
300*82d56013Sjoerg   OS << "INDEX  OFFSET";
301*82d56013Sjoerg 
302*82d56013Sjoerg   switch (Hdr->AddrOffSize) {
303*82d56013Sjoerg   case 1: OS << "8 "; break;
304*82d56013Sjoerg   case 2: OS << "16"; break;
305*82d56013Sjoerg   case 4: OS << "32"; break;
306*82d56013Sjoerg   case 8: OS << "64"; break;
307*82d56013Sjoerg   default: OS << "??"; break;
308*82d56013Sjoerg   }
309*82d56013Sjoerg   OS << " (ADDRESS)\n";
310*82d56013Sjoerg   OS << "====== =============================== \n";
311*82d56013Sjoerg   for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
312*82d56013Sjoerg     OS << format("[%4u] ", I);
313*82d56013Sjoerg     switch (Hdr->AddrOffSize) {
314*82d56013Sjoerg     case 1: OS << HEX8(getAddrOffsets<uint8_t>()[I]); break;
315*82d56013Sjoerg     case 2: OS << HEX16(getAddrOffsets<uint16_t>()[I]); break;
316*82d56013Sjoerg     case 4: OS << HEX32(getAddrOffsets<uint32_t>()[I]); break;
317*82d56013Sjoerg     case 8: OS << HEX32(getAddrOffsets<uint64_t>()[I]); break;
318*82d56013Sjoerg     default: break;
319*82d56013Sjoerg     }
320*82d56013Sjoerg     OS << " (" << HEX64(*getAddress(I)) << ")\n";
321*82d56013Sjoerg   }
322*82d56013Sjoerg   // Dump the address info offsets table.
323*82d56013Sjoerg   OS << "\nAddress Info Offsets:\n";
324*82d56013Sjoerg   OS << "INDEX  Offset\n";
325*82d56013Sjoerg   OS << "====== ==========\n";
326*82d56013Sjoerg   for (uint32_t I = 0; I < Header.NumAddresses; ++I)
327*82d56013Sjoerg     OS << format("[%4u] ", I) << HEX32(AddrInfoOffsets[I]) << "\n";
328*82d56013Sjoerg   // Dump the file table.
329*82d56013Sjoerg   OS << "\nFiles:\n";
330*82d56013Sjoerg   OS << "INDEX  DIRECTORY  BASENAME   PATH\n";
331*82d56013Sjoerg   OS << "====== ========== ========== ==============================\n";
332*82d56013Sjoerg   for (uint32_t I = 0; I < Files.size(); ++I) {
333*82d56013Sjoerg     OS << format("[%4u] ", I) << HEX32(Files[I].Dir) << ' '
334*82d56013Sjoerg        << HEX32(Files[I].Base) << ' ';
335*82d56013Sjoerg     dump(OS, getFile(I));
336*82d56013Sjoerg     OS << "\n";
337*82d56013Sjoerg   }
338*82d56013Sjoerg   OS << "\n" << StrTab << "\n";
339*82d56013Sjoerg 
340*82d56013Sjoerg   for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
341*82d56013Sjoerg     OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": ";
342*82d56013Sjoerg     if (auto FI = getFunctionInfo(*getAddress(I)))
343*82d56013Sjoerg       dump(OS, *FI);
344*82d56013Sjoerg     else
345*82d56013Sjoerg       logAllUnhandledErrors(FI.takeError(), OS, "FunctionInfo:");
346*82d56013Sjoerg   }
347*82d56013Sjoerg }
348*82d56013Sjoerg 
dump(raw_ostream & OS,const FunctionInfo & FI)349*82d56013Sjoerg void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI) {
350*82d56013Sjoerg   OS << FI.Range << " \"" << getString(FI.Name) << "\"\n";
351*82d56013Sjoerg   if (FI.OptLineTable)
352*82d56013Sjoerg     dump(OS, *FI.OptLineTable);
353*82d56013Sjoerg   if (FI.Inline)
354*82d56013Sjoerg     dump(OS, *FI.Inline);
355*82d56013Sjoerg }
356*82d56013Sjoerg 
dump(raw_ostream & OS,const LineTable & LT)357*82d56013Sjoerg void GsymReader::dump(raw_ostream &OS, const LineTable &LT) {
358*82d56013Sjoerg   OS << "LineTable:\n";
359*82d56013Sjoerg   for (auto &LE: LT) {
360*82d56013Sjoerg     OS << "  " << HEX64(LE.Addr) << ' ';
361*82d56013Sjoerg     if (LE.File)
362*82d56013Sjoerg       dump(OS, getFile(LE.File));
363*82d56013Sjoerg     OS << ':' << LE.Line << '\n';
364*82d56013Sjoerg   }
365*82d56013Sjoerg }
366*82d56013Sjoerg 
dump(raw_ostream & OS,const InlineInfo & II,uint32_t Indent)367*82d56013Sjoerg void GsymReader::dump(raw_ostream &OS, const InlineInfo &II, uint32_t Indent) {
368*82d56013Sjoerg   if (Indent == 0)
369*82d56013Sjoerg     OS << "InlineInfo:\n";
370*82d56013Sjoerg   else
371*82d56013Sjoerg     OS.indent(Indent);
372*82d56013Sjoerg   OS << II.Ranges << ' ' << getString(II.Name);
373*82d56013Sjoerg   if (II.CallFile != 0) {
374*82d56013Sjoerg     if (auto File = getFile(II.CallFile)) {
375*82d56013Sjoerg       OS << " called from ";
376*82d56013Sjoerg       dump(OS, File);
377*82d56013Sjoerg       OS << ':' << II.CallLine;
378*82d56013Sjoerg     }
379*82d56013Sjoerg   }
380*82d56013Sjoerg   OS << '\n';
381*82d56013Sjoerg   for (const auto &ChildII: II.Children)
382*82d56013Sjoerg     dump(OS, ChildII, Indent + 2);
383*82d56013Sjoerg }
384*82d56013Sjoerg 
dump(raw_ostream & OS,Optional<FileEntry> FE)385*82d56013Sjoerg void GsymReader::dump(raw_ostream &OS, Optional<FileEntry> FE) {
386*82d56013Sjoerg   if (FE) {
387*82d56013Sjoerg     // IF we have the file from index 0, then don't print anything
388*82d56013Sjoerg     if (FE->Dir == 0 && FE->Base == 0)
389*82d56013Sjoerg       return;
390*82d56013Sjoerg     StringRef Dir = getString(FE->Dir);
391*82d56013Sjoerg     StringRef Base = getString(FE->Base);
392*82d56013Sjoerg     if (!Dir.empty()) {
393*82d56013Sjoerg       OS << Dir;
394*82d56013Sjoerg       if (Dir.contains('\\') && !Dir.contains('/'))
395*82d56013Sjoerg         OS << '\\';
396*82d56013Sjoerg       else
397*82d56013Sjoerg         OS << '/';
398*82d56013Sjoerg     }
399*82d56013Sjoerg     if (!Base.empty()) {
400*82d56013Sjoerg       OS << Base;
401*82d56013Sjoerg     }
402*82d56013Sjoerg     if (!Dir.empty() || !Base.empty())
403*82d56013Sjoerg       return;
404*82d56013Sjoerg   }
405*82d56013Sjoerg   OS << "<invalid-file>";
406*82d56013Sjoerg }
407