xref: /freebsd-src/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/GsymReader.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
GsymReader(std::unique_ptr<MemoryBuffer> Buffer)26*5f757f3fSDimitry Andric GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer)
27*5f757f3fSDimitry Andric     : MemBuffer(std::move(Buffer)), Endian(llvm::endianness::native) {}
288bcb0991SDimitry Andric 
298bcb0991SDimitry Andric GsymReader::GsymReader(GsymReader &&RHS) = default;
308bcb0991SDimitry Andric 
318bcb0991SDimitry Andric GsymReader::~GsymReader() = default;
328bcb0991SDimitry Andric 
openFile(StringRef Filename)338bcb0991SDimitry Andric llvm::Expected<GsymReader> GsymReader::openFile(StringRef Filename) {
348bcb0991SDimitry Andric   // Open the input file and return an appropriate error if needed.
358bcb0991SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
368bcb0991SDimitry Andric       MemoryBuffer::getFileOrSTDIN(Filename);
378bcb0991SDimitry Andric   auto Err = BuffOrErr.getError();
388bcb0991SDimitry Andric   if (Err)
398bcb0991SDimitry Andric     return llvm::errorCodeToError(Err);
408bcb0991SDimitry Andric   return create(BuffOrErr.get());
418bcb0991SDimitry Andric }
428bcb0991SDimitry Andric 
copyBuffer(StringRef Bytes)438bcb0991SDimitry Andric llvm::Expected<GsymReader> GsymReader::copyBuffer(StringRef Bytes) {
448bcb0991SDimitry Andric   auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes");
458bcb0991SDimitry Andric   return create(MemBuffer);
468bcb0991SDimitry Andric }
478bcb0991SDimitry Andric 
488bcb0991SDimitry Andric llvm::Expected<llvm::gsym::GsymReader>
create(std::unique_ptr<MemoryBuffer> & MemBuffer)498bcb0991SDimitry Andric GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) {
5081ad6265SDimitry Andric   if (!MemBuffer)
518bcb0991SDimitry Andric     return createStringError(std::errc::invalid_argument,
528bcb0991SDimitry Andric                              "invalid memory buffer");
538bcb0991SDimitry Andric   GsymReader GR(std::move(MemBuffer));
548bcb0991SDimitry Andric   llvm::Error Err = GR.parse();
558bcb0991SDimitry Andric   if (Err)
568bcb0991SDimitry Andric     return std::move(Err);
578bcb0991SDimitry Andric   return std::move(GR);
588bcb0991SDimitry Andric }
598bcb0991SDimitry Andric 
608bcb0991SDimitry Andric llvm::Error
parse()618bcb0991SDimitry Andric GsymReader::parse() {
62*5f757f3fSDimitry Andric   BinaryStreamReader FileData(MemBuffer->getBuffer(), llvm::endianness::native);
638bcb0991SDimitry Andric   // Check for the magic bytes. This file format is designed to be mmap'ed
648bcb0991SDimitry Andric   // into a process and accessed as read only. This is done for performance
658bcb0991SDimitry Andric   // and efficiency for symbolicating and parsing GSYM data.
668bcb0991SDimitry Andric   if (FileData.readObject(Hdr))
678bcb0991SDimitry Andric     return createStringError(std::errc::invalid_argument,
688bcb0991SDimitry Andric                              "not enough data for a GSYM header");
698bcb0991SDimitry Andric 
70*5f757f3fSDimitry Andric   const auto HostByteOrder = llvm::endianness::native;
718bcb0991SDimitry Andric   switch (Hdr->Magic) {
728bcb0991SDimitry Andric     case GSYM_MAGIC:
738bcb0991SDimitry Andric       Endian = HostByteOrder;
748bcb0991SDimitry Andric       break;
758bcb0991SDimitry Andric     case GSYM_CIGAM:
768bcb0991SDimitry Andric       // This is a GSYM file, but not native endianness.
77*5f757f3fSDimitry Andric       Endian = sys::IsBigEndianHost ? llvm::endianness::little
78*5f757f3fSDimitry Andric                                     : llvm::endianness::big;
798bcb0991SDimitry Andric       Swap.reset(new SwappedData);
808bcb0991SDimitry Andric       break;
818bcb0991SDimitry Andric     default:
828bcb0991SDimitry Andric       return createStringError(std::errc::invalid_argument,
838bcb0991SDimitry Andric                                "not a GSYM file");
848bcb0991SDimitry Andric   }
858bcb0991SDimitry Andric 
86*5f757f3fSDimitry Andric   bool DataIsLittleEndian = HostByteOrder != llvm::endianness::little;
878bcb0991SDimitry Andric   // Read a correctly byte swapped header if we need to.
888bcb0991SDimitry Andric   if (Swap) {
898bcb0991SDimitry Andric     DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
908bcb0991SDimitry Andric     if (auto ExpectedHdr = Header::decode(Data))
918bcb0991SDimitry Andric       Swap->Hdr = ExpectedHdr.get();
928bcb0991SDimitry Andric     else
938bcb0991SDimitry Andric       return ExpectedHdr.takeError();
948bcb0991SDimitry Andric     Hdr = &Swap->Hdr;
958bcb0991SDimitry Andric   }
968bcb0991SDimitry Andric 
978bcb0991SDimitry Andric   // Detect errors in the header and report any that are found. If we make it
988bcb0991SDimitry Andric   // past this without errors, we know we have a good magic value, a supported
998bcb0991SDimitry Andric   // version number, verified address offset size and a valid UUID size.
1008bcb0991SDimitry Andric   if (Error Err = Hdr->checkForError())
1018bcb0991SDimitry Andric     return Err;
1028bcb0991SDimitry Andric 
1038bcb0991SDimitry Andric   if (!Swap) {
1048bcb0991SDimitry Andric     // This is the native endianness case that is most common and optimized for
1058bcb0991SDimitry Andric     // efficient lookups. Here we just grab pointers to the native data and
1068bcb0991SDimitry Andric     // use ArrayRef objects to allow efficient read only access.
1078bcb0991SDimitry Andric 
1088bcb0991SDimitry Andric     // Read the address offsets.
1098bcb0991SDimitry Andric     if (FileData.padToAlignment(Hdr->AddrOffSize) ||
1108bcb0991SDimitry Andric         FileData.readArray(AddrOffsets,
1118bcb0991SDimitry Andric                            Hdr->NumAddresses * Hdr->AddrOffSize))
1128bcb0991SDimitry Andric       return createStringError(std::errc::invalid_argument,
1138bcb0991SDimitry Andric                               "failed to read address table");
1148bcb0991SDimitry Andric 
1158bcb0991SDimitry Andric     // Read the address info offsets.
1168bcb0991SDimitry Andric     if (FileData.padToAlignment(4) ||
1178bcb0991SDimitry Andric         FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses))
1188bcb0991SDimitry Andric       return createStringError(std::errc::invalid_argument,
1198bcb0991SDimitry Andric                               "failed to read address info offsets table");
1208bcb0991SDimitry Andric 
1218bcb0991SDimitry Andric     // Read the file table.
1228bcb0991SDimitry Andric     uint32_t NumFiles = 0;
1238bcb0991SDimitry Andric     if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles))
1248bcb0991SDimitry Andric       return createStringError(std::errc::invalid_argument,
1258bcb0991SDimitry Andric                               "failed to read file table");
1268bcb0991SDimitry Andric 
1278bcb0991SDimitry Andric     // Get the string table.
1288bcb0991SDimitry Andric     FileData.setOffset(Hdr->StrtabOffset);
1298bcb0991SDimitry Andric     if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize))
1308bcb0991SDimitry Andric       return createStringError(std::errc::invalid_argument,
1318bcb0991SDimitry Andric                               "failed to read string table");
1328bcb0991SDimitry Andric } else {
1338bcb0991SDimitry Andric   // This is the non native endianness case that is not common and not
1348bcb0991SDimitry Andric   // optimized for lookups. Here we decode the important tables into local
1358bcb0991SDimitry Andric   // storage and then set the ArrayRef objects to point to these swapped
1368bcb0991SDimitry Andric   // copies of the read only data so lookups can be as efficient as possible.
1378bcb0991SDimitry Andric   DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
1388bcb0991SDimitry Andric 
1398bcb0991SDimitry Andric   // Read the address offsets.
1408bcb0991SDimitry Andric   uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize);
1418bcb0991SDimitry Andric   Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize);
1428bcb0991SDimitry Andric   switch (Hdr->AddrOffSize) {
1438bcb0991SDimitry Andric     case 1:
1448bcb0991SDimitry Andric       if (!Data.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses))
1458bcb0991SDimitry Andric         return createStringError(std::errc::invalid_argument,
1468bcb0991SDimitry Andric                                   "failed to read address table");
1478bcb0991SDimitry Andric       break;
1488bcb0991SDimitry Andric     case 2:
1498bcb0991SDimitry Andric       if (!Data.getU16(&Offset,
1508bcb0991SDimitry Andric                         reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
1518bcb0991SDimitry Andric                         Hdr->NumAddresses))
1528bcb0991SDimitry Andric         return createStringError(std::errc::invalid_argument,
1538bcb0991SDimitry Andric                                   "failed to read address table");
1548bcb0991SDimitry Andric       break;
1558bcb0991SDimitry Andric     case 4:
1568bcb0991SDimitry Andric       if (!Data.getU32(&Offset,
1578bcb0991SDimitry Andric                         reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
1588bcb0991SDimitry Andric                         Hdr->NumAddresses))
1598bcb0991SDimitry Andric         return createStringError(std::errc::invalid_argument,
1608bcb0991SDimitry Andric                                   "failed to read address table");
1618bcb0991SDimitry Andric       break;
1628bcb0991SDimitry Andric     case 8:
1638bcb0991SDimitry Andric       if (!Data.getU64(&Offset,
1648bcb0991SDimitry Andric                         reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
1658bcb0991SDimitry Andric                         Hdr->NumAddresses))
1668bcb0991SDimitry Andric         return createStringError(std::errc::invalid_argument,
1678bcb0991SDimitry Andric                                   "failed to read address table");
1688bcb0991SDimitry Andric     }
1698bcb0991SDimitry Andric     AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
1708bcb0991SDimitry Andric 
1718bcb0991SDimitry Andric     // Read the address info offsets.
1728bcb0991SDimitry Andric     Offset = alignTo(Offset, 4);
1738bcb0991SDimitry Andric     Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
1748bcb0991SDimitry Andric     if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses))
1758bcb0991SDimitry Andric       AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets);
1768bcb0991SDimitry Andric     else
1778bcb0991SDimitry Andric       return createStringError(std::errc::invalid_argument,
1788bcb0991SDimitry Andric                                "failed to read address table");
1798bcb0991SDimitry Andric     // Read the file table.
1808bcb0991SDimitry Andric     const uint32_t NumFiles = Data.getU32(&Offset);
1818bcb0991SDimitry Andric     if (NumFiles > 0) {
1828bcb0991SDimitry Andric       Swap->Files.resize(NumFiles);
1838bcb0991SDimitry Andric       if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2))
1848bcb0991SDimitry Andric         Files = ArrayRef<FileEntry>(Swap->Files);
1858bcb0991SDimitry Andric       else
1868bcb0991SDimitry Andric         return createStringError(std::errc::invalid_argument,
1878bcb0991SDimitry Andric                                  "failed to read file table");
1888bcb0991SDimitry Andric     }
1898bcb0991SDimitry Andric     // Get the string table.
1908bcb0991SDimitry Andric     StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset,
1918bcb0991SDimitry Andric                                                 Hdr->StrtabSize);
1928bcb0991SDimitry Andric     if (StrTab.Data.empty())
1938bcb0991SDimitry Andric       return createStringError(std::errc::invalid_argument,
1948bcb0991SDimitry Andric                                "failed to read string table");
1958bcb0991SDimitry Andric   }
1968bcb0991SDimitry Andric   return Error::success();
1978bcb0991SDimitry Andric 
1988bcb0991SDimitry Andric }
1998bcb0991SDimitry Andric 
getHeader() const2008bcb0991SDimitry Andric const Header &GsymReader::getHeader() const {
2018bcb0991SDimitry Andric   // The only way to get a GsymReader is from GsymReader::openFile(...) or
2028bcb0991SDimitry Andric   // GsymReader::copyBuffer() and the header must be valid and initialized to
2038bcb0991SDimitry Andric   // a valid pointer value, so the assert below should not trigger.
2048bcb0991SDimitry Andric   assert(Hdr);
2058bcb0991SDimitry Andric   return *Hdr;
2068bcb0991SDimitry Andric }
2078bcb0991SDimitry Andric 
getAddress(size_t Index) const208bdd1243dSDimitry Andric std::optional<uint64_t> GsymReader::getAddress(size_t Index) const {
2098bcb0991SDimitry Andric   switch (Hdr->AddrOffSize) {
2108bcb0991SDimitry Andric   case 1: return addressForIndex<uint8_t>(Index);
2118bcb0991SDimitry Andric   case 2: return addressForIndex<uint16_t>(Index);
2128bcb0991SDimitry Andric   case 4: return addressForIndex<uint32_t>(Index);
2138bcb0991SDimitry Andric   case 8: return addressForIndex<uint64_t>(Index);
2148bcb0991SDimitry Andric   }
215bdd1243dSDimitry Andric   return std::nullopt;
2168bcb0991SDimitry Andric }
2178bcb0991SDimitry Andric 
getAddressInfoOffset(size_t Index) const218bdd1243dSDimitry Andric std::optional<uint64_t> GsymReader::getAddressInfoOffset(size_t Index) const {
2198bcb0991SDimitry Andric   const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
2208bcb0991SDimitry Andric   if (Index < NumAddrInfoOffsets)
2218bcb0991SDimitry Andric     return AddrInfoOffsets[Index];
222bdd1243dSDimitry Andric   return std::nullopt;
2238bcb0991SDimitry Andric }
2248bcb0991SDimitry Andric 
2258bcb0991SDimitry Andric Expected<uint64_t>
getAddressIndex(const uint64_t Addr) const2268bcb0991SDimitry Andric GsymReader::getAddressIndex(const uint64_t Addr) const {
2275ffd83dbSDimitry Andric   if (Addr >= Hdr->BaseAddress) {
2288bcb0991SDimitry Andric     const uint64_t AddrOffset = Addr - Hdr->BaseAddress;
229bdd1243dSDimitry Andric     std::optional<uint64_t> AddrOffsetIndex;
2308bcb0991SDimitry Andric     switch (Hdr->AddrOffSize) {
2315ffd83dbSDimitry Andric     case 1:
2325ffd83dbSDimitry Andric       AddrOffsetIndex = getAddressOffsetIndex<uint8_t>(AddrOffset);
2335ffd83dbSDimitry Andric       break;
2345ffd83dbSDimitry Andric     case 2:
2355ffd83dbSDimitry Andric       AddrOffsetIndex = getAddressOffsetIndex<uint16_t>(AddrOffset);
2365ffd83dbSDimitry Andric       break;
2375ffd83dbSDimitry Andric     case 4:
2385ffd83dbSDimitry Andric       AddrOffsetIndex = getAddressOffsetIndex<uint32_t>(AddrOffset);
2395ffd83dbSDimitry Andric       break;
2405ffd83dbSDimitry Andric     case 8:
2415ffd83dbSDimitry Andric       AddrOffsetIndex = getAddressOffsetIndex<uint64_t>(AddrOffset);
2425ffd83dbSDimitry Andric       break;
2435ffd83dbSDimitry Andric     default:
2448bcb0991SDimitry Andric       return createStringError(std::errc::invalid_argument,
2458bcb0991SDimitry Andric                                "unsupported address offset size %u",
2468bcb0991SDimitry Andric                                Hdr->AddrOffSize);
2478bcb0991SDimitry Andric     }
2485ffd83dbSDimitry Andric     if (AddrOffsetIndex)
2495ffd83dbSDimitry Andric       return *AddrOffsetIndex;
2505ffd83dbSDimitry Andric   }
2515ffd83dbSDimitry Andric   return createStringError(std::errc::invalid_argument,
2525ffd83dbSDimitry Andric                            "address 0x%" PRIx64 " is not in GSYM", Addr);
2535ffd83dbSDimitry Andric 
2545ffd83dbSDimitry Andric }
2558bcb0991SDimitry Andric 
256*5f757f3fSDimitry Andric llvm::Expected<DataExtractor>
getFunctionInfoDataForAddress(uint64_t Addr,uint64_t & FuncStartAddr) const257*5f757f3fSDimitry Andric GsymReader::getFunctionInfoDataForAddress(uint64_t Addr,
258*5f757f3fSDimitry Andric                                           uint64_t &FuncStartAddr) const {
259*5f757f3fSDimitry Andric   Expected<uint64_t> ExpectedAddrIdx = getAddressIndex(Addr);
260*5f757f3fSDimitry Andric   if (!ExpectedAddrIdx)
261*5f757f3fSDimitry Andric     return ExpectedAddrIdx.takeError();
262*5f757f3fSDimitry Andric   const uint64_t FirstAddrIdx = *ExpectedAddrIdx;
263*5f757f3fSDimitry Andric   // The AddrIdx is the first index of the function info entries that match
264*5f757f3fSDimitry Andric   // \a Addr. We need to iterate over all function info objects that start with
265*5f757f3fSDimitry Andric   // the same address until we find a range that contains \a Addr.
266*5f757f3fSDimitry Andric   std::optional<uint64_t> FirstFuncStartAddr;
267*5f757f3fSDimitry Andric   const size_t NumAddresses = getNumAddresses();
268*5f757f3fSDimitry Andric   for (uint64_t AddrIdx = FirstAddrIdx; AddrIdx < NumAddresses; ++AddrIdx) {
269*5f757f3fSDimitry Andric     auto ExpextedData = getFunctionInfoDataAtIndex(AddrIdx, FuncStartAddr);
270*5f757f3fSDimitry Andric     // If there was an error, return the error.
271*5f757f3fSDimitry Andric     if (!ExpextedData)
272*5f757f3fSDimitry Andric       return ExpextedData;
273*5f757f3fSDimitry Andric 
274*5f757f3fSDimitry Andric     // Remember the first function start address if it hasn't already been set.
275*5f757f3fSDimitry Andric     // If it is already valid, check to see if it matches the first function
276*5f757f3fSDimitry Andric     // start address and only continue if it matches.
277*5f757f3fSDimitry Andric     if (FirstFuncStartAddr.has_value()) {
278*5f757f3fSDimitry Andric       if (*FirstFuncStartAddr != FuncStartAddr)
279*5f757f3fSDimitry Andric         break; // Done with consecutive function entries with same address.
280*5f757f3fSDimitry Andric     } else {
281*5f757f3fSDimitry Andric       FirstFuncStartAddr = FuncStartAddr;
282*5f757f3fSDimitry Andric     }
283*5f757f3fSDimitry Andric     // Make sure the current function address ranges contains \a Addr.
284*5f757f3fSDimitry Andric     // Some symbols on Darwin don't have valid sizes, so if we run into a
285*5f757f3fSDimitry Andric     // symbol with zero size, then we have found a match for our address.
286*5f757f3fSDimitry Andric 
287*5f757f3fSDimitry Andric     // The first thing the encoding of a FunctionInfo object is the function
288*5f757f3fSDimitry Andric     // size.
289*5f757f3fSDimitry Andric     uint64_t Offset = 0;
290*5f757f3fSDimitry Andric     uint32_t FuncSize = ExpextedData->getU32(&Offset);
291*5f757f3fSDimitry Andric     if (FuncSize == 0 ||
292*5f757f3fSDimitry Andric         AddressRange(FuncStartAddr, FuncStartAddr + FuncSize).contains(Addr))
293*5f757f3fSDimitry Andric       return ExpextedData;
294*5f757f3fSDimitry Andric   }
2958bcb0991SDimitry Andric   return createStringError(std::errc::invalid_argument,
2965ffd83dbSDimitry Andric                            "address 0x%" PRIx64 " is not in GSYM", Addr);
2978bcb0991SDimitry Andric }
298*5f757f3fSDimitry Andric 
299*5f757f3fSDimitry Andric llvm::Expected<DataExtractor>
getFunctionInfoDataAtIndex(uint64_t AddrIdx,uint64_t & FuncStartAddr) const300*5f757f3fSDimitry Andric GsymReader::getFunctionInfoDataAtIndex(uint64_t AddrIdx,
301*5f757f3fSDimitry Andric                                        uint64_t &FuncStartAddr) const {
302*5f757f3fSDimitry Andric   if (AddrIdx >= getNumAddresses())
3038bcb0991SDimitry Andric     return createStringError(std::errc::invalid_argument,
304*5f757f3fSDimitry Andric                              "invalid address index %" PRIu64, AddrIdx);
305*5f757f3fSDimitry Andric   const uint32_t AddrInfoOffset = AddrInfoOffsets[AddrIdx];
306*5f757f3fSDimitry Andric   assert((Endian == endianness::big || Endian == endianness::little) &&
307*5f757f3fSDimitry Andric          "Endian must be either big or little");
308*5f757f3fSDimitry Andric   StringRef Bytes = MemBuffer->getBuffer().substr(AddrInfoOffset);
309*5f757f3fSDimitry Andric   if (Bytes.empty())
310*5f757f3fSDimitry Andric     return createStringError(std::errc::invalid_argument,
311*5f757f3fSDimitry Andric                              "invalid address info offset 0x%" PRIx32,
312*5f757f3fSDimitry Andric                              AddrInfoOffset);
313*5f757f3fSDimitry Andric   std::optional<uint64_t> OptFuncStartAddr = getAddress(AddrIdx);
314*5f757f3fSDimitry Andric   if (!OptFuncStartAddr)
315*5f757f3fSDimitry Andric     return createStringError(std::errc::invalid_argument,
316*5f757f3fSDimitry Andric                              "failed to extract address[%" PRIu64 "]", AddrIdx);
317*5f757f3fSDimitry Andric   FuncStartAddr = *OptFuncStartAddr;
318*5f757f3fSDimitry Andric   return DataExtractor(Bytes, Endian == llvm::endianness::little, 4);
319*5f757f3fSDimitry Andric }
320*5f757f3fSDimitry Andric 
getFunctionInfo(uint64_t Addr) const321*5f757f3fSDimitry Andric llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
322*5f757f3fSDimitry Andric   uint64_t FuncStartAddr = 0;
323*5f757f3fSDimitry Andric   if (auto ExpectedData = getFunctionInfoDataForAddress(Addr, FuncStartAddr))
324*5f757f3fSDimitry Andric     return FunctionInfo::decode(*ExpectedData, FuncStartAddr);
325*5f757f3fSDimitry Andric   else
326*5f757f3fSDimitry Andric     return ExpectedData.takeError();
327*5f757f3fSDimitry Andric }
328*5f757f3fSDimitry Andric 
329*5f757f3fSDimitry Andric llvm::Expected<FunctionInfo>
getFunctionInfoAtIndex(uint64_t Idx) const330*5f757f3fSDimitry Andric GsymReader::getFunctionInfoAtIndex(uint64_t Idx) const {
331*5f757f3fSDimitry Andric   uint64_t FuncStartAddr = 0;
332*5f757f3fSDimitry Andric   if (auto ExpectedData = getFunctionInfoDataAtIndex(Idx, FuncStartAddr))
333*5f757f3fSDimitry Andric     return FunctionInfo::decode(*ExpectedData, FuncStartAddr);
334*5f757f3fSDimitry Andric   else
335*5f757f3fSDimitry Andric     return ExpectedData.takeError();
3368bcb0991SDimitry Andric }
337480093f4SDimitry Andric 
lookup(uint64_t Addr) const338480093f4SDimitry Andric llvm::Expected<LookupResult> GsymReader::lookup(uint64_t Addr) const {
339*5f757f3fSDimitry Andric   uint64_t FuncStartAddr = 0;
340*5f757f3fSDimitry Andric   if (auto ExpectedData = getFunctionInfoDataForAddress(Addr, FuncStartAddr))
341*5f757f3fSDimitry Andric     return FunctionInfo::lookup(*ExpectedData, *this, FuncStartAddr, Addr);
342*5f757f3fSDimitry Andric   else
343*5f757f3fSDimitry Andric     return ExpectedData.takeError();
344480093f4SDimitry Andric }
3455ffd83dbSDimitry Andric 
dump(raw_ostream & OS)3465ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS) {
3475ffd83dbSDimitry Andric   const auto &Header = getHeader();
3485ffd83dbSDimitry Andric   // Dump the GSYM header.
3495ffd83dbSDimitry Andric   OS << Header << "\n";
3505ffd83dbSDimitry Andric   // Dump the address table.
3515ffd83dbSDimitry Andric   OS << "Address Table:\n";
3525ffd83dbSDimitry Andric   OS << "INDEX  OFFSET";
3535ffd83dbSDimitry Andric 
3545ffd83dbSDimitry Andric   switch (Hdr->AddrOffSize) {
3555ffd83dbSDimitry Andric   case 1: OS << "8 "; break;
3565ffd83dbSDimitry Andric   case 2: OS << "16"; break;
3575ffd83dbSDimitry Andric   case 4: OS << "32"; break;
3585ffd83dbSDimitry Andric   case 8: OS << "64"; break;
3595ffd83dbSDimitry Andric   default: OS << "??"; break;
3605ffd83dbSDimitry Andric   }
3615ffd83dbSDimitry Andric   OS << " (ADDRESS)\n";
3625ffd83dbSDimitry Andric   OS << "====== =============================== \n";
3635ffd83dbSDimitry Andric   for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
3645ffd83dbSDimitry Andric     OS << format("[%4u] ", I);
3655ffd83dbSDimitry Andric     switch (Hdr->AddrOffSize) {
3665ffd83dbSDimitry Andric     case 1: OS << HEX8(getAddrOffsets<uint8_t>()[I]); break;
3675ffd83dbSDimitry Andric     case 2: OS << HEX16(getAddrOffsets<uint16_t>()[I]); break;
3685ffd83dbSDimitry Andric     case 4: OS << HEX32(getAddrOffsets<uint32_t>()[I]); break;
3695ffd83dbSDimitry Andric     case 8: OS << HEX32(getAddrOffsets<uint64_t>()[I]); break;
3705ffd83dbSDimitry Andric     default: break;
3715ffd83dbSDimitry Andric     }
3725ffd83dbSDimitry Andric     OS << " (" << HEX64(*getAddress(I)) << ")\n";
3735ffd83dbSDimitry Andric   }
3745ffd83dbSDimitry Andric   // Dump the address info offsets table.
3755ffd83dbSDimitry Andric   OS << "\nAddress Info Offsets:\n";
3765ffd83dbSDimitry Andric   OS << "INDEX  Offset\n";
3775ffd83dbSDimitry Andric   OS << "====== ==========\n";
3785ffd83dbSDimitry Andric   for (uint32_t I = 0; I < Header.NumAddresses; ++I)
3795ffd83dbSDimitry Andric     OS << format("[%4u] ", I) << HEX32(AddrInfoOffsets[I]) << "\n";
3805ffd83dbSDimitry Andric   // Dump the file table.
3815ffd83dbSDimitry Andric   OS << "\nFiles:\n";
3825ffd83dbSDimitry Andric   OS << "INDEX  DIRECTORY  BASENAME   PATH\n";
3835ffd83dbSDimitry Andric   OS << "====== ========== ========== ==============================\n";
3845ffd83dbSDimitry Andric   for (uint32_t I = 0; I < Files.size(); ++I) {
3855ffd83dbSDimitry Andric     OS << format("[%4u] ", I) << HEX32(Files[I].Dir) << ' '
3865ffd83dbSDimitry Andric        << HEX32(Files[I].Base) << ' ';
3875ffd83dbSDimitry Andric     dump(OS, getFile(I));
3885ffd83dbSDimitry Andric     OS << "\n";
3895ffd83dbSDimitry Andric   }
3905ffd83dbSDimitry Andric   OS << "\n" << StrTab << "\n";
3915ffd83dbSDimitry Andric 
3925ffd83dbSDimitry Andric   for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
3935ffd83dbSDimitry Andric     OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": ";
394*5f757f3fSDimitry Andric     if (auto FI = getFunctionInfoAtIndex(I))
3955ffd83dbSDimitry Andric       dump(OS, *FI);
3965ffd83dbSDimitry Andric     else
3975ffd83dbSDimitry Andric       logAllUnhandledErrors(FI.takeError(), OS, "FunctionInfo:");
3985ffd83dbSDimitry Andric   }
3995ffd83dbSDimitry Andric }
4005ffd83dbSDimitry Andric 
dump(raw_ostream & OS,const FunctionInfo & FI)4015ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI) {
4025ffd83dbSDimitry Andric   OS << FI.Range << " \"" << getString(FI.Name) << "\"\n";
4035ffd83dbSDimitry Andric   if (FI.OptLineTable)
4045ffd83dbSDimitry Andric     dump(OS, *FI.OptLineTable);
4055ffd83dbSDimitry Andric   if (FI.Inline)
4065ffd83dbSDimitry Andric     dump(OS, *FI.Inline);
4075ffd83dbSDimitry Andric }
4085ffd83dbSDimitry Andric 
dump(raw_ostream & OS,const LineTable & LT)4095ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS, const LineTable &LT) {
4105ffd83dbSDimitry Andric   OS << "LineTable:\n";
4115ffd83dbSDimitry Andric   for (auto &LE: LT) {
4125ffd83dbSDimitry Andric     OS << "  " << HEX64(LE.Addr) << ' ';
4135ffd83dbSDimitry Andric     if (LE.File)
4145ffd83dbSDimitry Andric       dump(OS, getFile(LE.File));
4155ffd83dbSDimitry Andric     OS << ':' << LE.Line << '\n';
4165ffd83dbSDimitry Andric   }
4175ffd83dbSDimitry Andric }
4185ffd83dbSDimitry Andric 
dump(raw_ostream & OS,const InlineInfo & II,uint32_t Indent)4195ffd83dbSDimitry Andric void GsymReader::dump(raw_ostream &OS, const InlineInfo &II, uint32_t Indent) {
4205ffd83dbSDimitry Andric   if (Indent == 0)
4215ffd83dbSDimitry Andric     OS << "InlineInfo:\n";
4225ffd83dbSDimitry Andric   else
4235ffd83dbSDimitry Andric     OS.indent(Indent);
4245ffd83dbSDimitry Andric   OS << II.Ranges << ' ' << getString(II.Name);
4255ffd83dbSDimitry Andric   if (II.CallFile != 0) {
4265ffd83dbSDimitry Andric     if (auto File = getFile(II.CallFile)) {
4275ffd83dbSDimitry Andric       OS << " called from ";
4285ffd83dbSDimitry Andric       dump(OS, File);
4295ffd83dbSDimitry Andric       OS << ':' << II.CallLine;
4305ffd83dbSDimitry Andric     }
4315ffd83dbSDimitry Andric   }
4325ffd83dbSDimitry Andric   OS << '\n';
4335ffd83dbSDimitry Andric   for (const auto &ChildII: II.Children)
4345ffd83dbSDimitry Andric     dump(OS, ChildII, Indent + 2);
4355ffd83dbSDimitry Andric }
4365ffd83dbSDimitry Andric 
dump(raw_ostream & OS,std::optional<FileEntry> FE)437bdd1243dSDimitry Andric void GsymReader::dump(raw_ostream &OS, std::optional<FileEntry> FE) {
4385ffd83dbSDimitry Andric   if (FE) {
4395ffd83dbSDimitry Andric     // IF we have the file from index 0, then don't print anything
4405ffd83dbSDimitry Andric     if (FE->Dir == 0 && FE->Base == 0)
4415ffd83dbSDimitry Andric       return;
4425ffd83dbSDimitry Andric     StringRef Dir = getString(FE->Dir);
4435ffd83dbSDimitry Andric     StringRef Base = getString(FE->Base);
4445ffd83dbSDimitry Andric     if (!Dir.empty()) {
4455ffd83dbSDimitry Andric       OS << Dir;
4465ffd83dbSDimitry Andric       if (Dir.contains('\\') && !Dir.contains('/'))
4475ffd83dbSDimitry Andric         OS << '\\';
4485ffd83dbSDimitry Andric       else
4495ffd83dbSDimitry Andric         OS << '/';
4505ffd83dbSDimitry Andric     }
4515ffd83dbSDimitry Andric     if (!Base.empty()) {
4525ffd83dbSDimitry Andric       OS << Base;
4535ffd83dbSDimitry Andric     }
4545ffd83dbSDimitry Andric     if (!Dir.empty() || !Base.empty())
4555ffd83dbSDimitry Andric       return;
4565ffd83dbSDimitry Andric   }
4575ffd83dbSDimitry Andric   OS << "<invalid-file>";
4585ffd83dbSDimitry Andric }
459