1//===- GsymReaderV1.cpp ---------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/DebugInfo/GSYM/GsymReaderV1.h"
10
11#include <assert.h>
12#include <inttypes.h>
13
14#include "llvm/DebugInfo/GSYM/GsymDataExtractor.h"
15#include "llvm/DebugInfo/GSYM/Header.h"
16#include "llvm/Support/FormatVariadic.h"
17#include "llvm/Support/MemoryBuffer.h"
18
19using namespace llvm;
20using namespace gsym;
21
22GsymReaderV1::GsymReaderV1(std::unique_ptr<MemoryBuffer> Buffer,
23 llvm::endianness Endian)
24 : GsymReader(std::move(Buffer), Endian) {}
25
26llvm::Error GsymReaderV1::parseHeaderAndGlobalDataEntries() {
27 if (auto Err = parseHeader(OutHdr&: Hdr, OutSwappedHdr&: SwappedHdr))
28 return Err;
29
30 // Compute section offsets from the fixed V1 layout and populate the
31 // GlobalDataSections map. V1 sections are laid out sequentially:
32 // [Header] [AddrOffsets] [AddrInfoOffsets] [FileTable] ... [StringTable]
33 const StringRef Buf = MemBuffer->getBuffer();
34 const uint64_t NumAddrs = Hdr->NumAddresses;
35 const uint8_t AddrOffSize = Hdr->AddrOffSize;
36
37 // AddrOffsets
38 uint64_t Offset = alignTo(Value: sizeof(Header), Align: AddrOffSize);
39 uint64_t AddrOffsetsSize = NumAddrs * AddrOffSize;
40 GlobalDataSections[GlobalInfoType::AddrOffsets] = {
41 .Type: GlobalInfoType::AddrOffsets, .FileOffset: Offset, .FileSize: AddrOffsetsSize};
42 Offset += AddrOffsetsSize;
43
44 // AddrInfoOffsets
45 Offset = alignTo(Value: Offset, Align: 4);
46 uint64_t AddrInfoOffsetsSize = NumAddrs * Header::getAddressInfoOffsetSize();
47 GlobalDataSections[GlobalInfoType::AddrInfoOffsets] = {
48 .Type: GlobalInfoType::AddrInfoOffsets, .FileOffset: Offset, .FileSize: AddrInfoOffsetsSize};
49 Offset += AddrInfoOffsetsSize;
50
51 // FileTable: read NumFiles to compute the size.
52 GsymDataExtractor Data(Buf, isLittleEndian());
53 uint64_t FTOffset = Offset;
54 uint32_t NumFiles = Data.getU32(offset_ptr: &FTOffset);
55 uint64_t FileTableSize =
56 4 + static_cast<uint64_t>(NumFiles) *
57 FileEntry::getEncodedSize(StringOffsetSize: Header::getStringOffsetSize());
58 GlobalDataSections[GlobalInfoType::FileTable] = {.Type: GlobalInfoType::FileTable,
59 .FileOffset: Offset, .FileSize: FileTableSize};
60
61 // StringTable: offset and size are in the header.
62 GlobalDataSections[GlobalInfoType::StringTable] = {
63 .Type: GlobalInfoType::StringTable, .FileOffset: Hdr->StrtabOffset, .FileSize: Hdr->StrtabSize};
64
65 // FunctionInfo: starts after the string table and extends to end of file.
66 const uint64_t FIOffset = Hdr->StrtabOffset + Hdr->StrtabSize;
67 GlobalDataSections[GlobalInfoType::FunctionInfo] = {
68 .Type: GlobalInfoType::FunctionInfo, .FileOffset: FIOffset, .FileSize: Buf.size() - FIOffset};
69
70 return Error::success();
71}
72
73void GsymReaderV1::dump(raw_ostream &OS) {
74 OS << *Hdr << "\n";
75 OS << "Address Table:\n";
76 OS << "INDEX OFFSET";
77
78 switch (getAddressOffsetSize()) {
79 case 1:
80 OS << "8 ";
81 break;
82 case 2:
83 OS << "16";
84 break;
85 case 4:
86 OS << "32";
87 break;
88 case 8:
89 OS << "64";
90 break;
91 default:
92 OS << "??";
93 break;
94 }
95 OS << " (ADDRESS)\n";
96 OS << "====== =============================== \n";
97 for (uint32_t I = 0; I < getNumAddresses(); ++I) {
98 OS << formatv(Fmt: "[{0,4}] ", Vals&: I);
99 switch (getAddressOffsetSize()) {
100 case 1:
101 OS << HEX8(getAddrOffsets<uint8_t>()[I]);
102 break;
103 case 2:
104 OS << HEX16(getAddrOffsets<uint16_t>()[I]);
105 break;
106 case 4:
107 OS << HEX32(getAddrOffsets<uint32_t>()[I]);
108 break;
109 case 8:
110 OS << HEX32(getAddrOffsets<uint64_t>()[I]);
111 break;
112 default:
113 break;
114 }
115 OS << " (" << HEX64(*getAddress(I)) << ")\n";
116 }
117 OS << "\nAddress Info Offsets:\n";
118 OS << "INDEX Offset\n";
119 OS << "====== ==========\n";
120 for (uint32_t I = 0; I < getNumAddresses(); ++I)
121 OS << formatv(Fmt: "[{0,4}] ", Vals&: I) << HEX32(*getAddressInfoOffset(I)) << "\n";
122 OS << "\nFiles:\n";
123 OS << "INDEX DIRECTORY BASENAME PATH\n";
124 OS << "====== ========== ========== ==============================\n";
125 for (uint32_t I = 0;; ++I) {
126 auto FE = getFile(Index: I);
127 if (!FE)
128 break;
129 OS << formatv(Fmt: "[{0,4}] ", Vals&: I) << HEX32(FE->Dir) << ' ' << HEX32(FE->Base)
130 << ' ';
131 dump(OS, FE);
132 OS << "\n";
133 }
134 OS << "\n";
135 gsym::dump(OS, S: StrTab, StringOffsetSize: 4);
136 OS << "\n";
137
138 for (uint32_t I = 0; I < getNumAddresses(); ++I) {
139 OS << "FunctionInfo @ " << HEX32(*getAddressInfoOffset(I)) << ": ";
140 if (auto FI = getFunctionInfoAtIndex(AddrIdx: I))
141 dump(OS, FI: *FI);
142 else
143 logAllUnhandledErrors(E: FI.takeError(), OS, ErrorBanner: "FunctionInfo:");
144 }
145}
146