1//===- GsymCreatorV2.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#include "llvm/DebugInfo/GSYM/GsymCreatorV2.h"
9#include "llvm/DebugInfo/GSYM/FileWriter.h"
10#include "llvm/DebugInfo/GSYM/GlobalData.h"
11#include "llvm/DebugInfo/GSYM/HeaderV2.h"
12#include "llvm/Support/MathExtras.h"
13
14#include <cassert>
15
16using namespace llvm;
17using namespace gsym;
18
19uint64_t GsymCreatorV2::calculateHeaderAndTableSize() const {
20 const uint64_t HeaderSize = HeaderV2::getEncodedSize();
21 const size_t NumFuncs = Funcs.size();
22 const uint32_t NumEntries = 5 + (UUID.empty() ? 0 : 1) + 1;
23 uint64_t Size = HeaderSize + NumEntries * 20;
24 Size = llvm::alignTo(Value: Size, Align: getAddressOffsetSize());
25 Size += NumFuncs * getAddressOffsetSize();
26 Size = llvm::alignTo(Value: Size, Align: HeaderV2::getAddressInfoOffsetSize());
27 Size += NumFuncs * HeaderV2::getAddressInfoOffsetSize();
28 Size = llvm::alignTo(Value: Size, Align: 4);
29 Size += 4 + Files.size() * FileEntry::getEncodedSize(StringOffsetSize: getStringOffsetSize());
30 Size += StrTab.getSize();
31 Size += UUID.size();
32 return Size;
33}
34
35/// For V2 file layout, see HeaderV2.h
36llvm::Error GsymCreatorV2::encode(FileWriter &O) const {
37 std::lock_guard<std::mutex> Guard(Mutex);
38 std::optional<uint64_t> BaseAddr;
39 if (auto Err = validateForEncoding(BaseAddr))
40 return Err;
41
42 const uint8_t AddrOffSize = getAddressOffsetSize();
43
44 // Pre-encode all FunctionInfo objects into a temporary buffer so we know the
45 // total FunctionInfo section size and each function's offset within it.
46 SmallVector<char, 0> FIBuf;
47 raw_svector_ostream FIOS(FIBuf);
48 FileWriter FIFW(FIOS, O.getByteOrder());
49 FIFW.setStringOffsetSize(getStringOffsetSize());
50 std::vector<uint64_t> FIRelativeOffsets;
51 for (const auto &FI : Funcs) {
52 if (auto OffOrErr = FI.encode(O&: FIFW))
53 FIRelativeOffsets.push_back(x: *OffOrErr);
54 else
55 return OffOrErr.takeError();
56 }
57 const uint64_t FISectionSize = FIBuf.size();
58 const uint64_t StringTableSize = StrTab.getSize();
59
60 const uint8_t StrpSize = 8;
61
62 const bool HasUUID = !UUID.empty();
63 const uint32_t NumGlobalDataEntries = 5 + (HasUUID ? 1 : 0) + 1;
64 const uint64_t GlobalDataArraySize =
65 static_cast<uint64_t>(NumGlobalDataEntries) * 20;
66
67 const uint64_t HeaderSize = HeaderV2::getEncodedSize();
68 uint64_t CurOffset = HeaderSize + GlobalDataArraySize;
69
70 // UUID section (first, no alignment requirement).
71 const uint64_t UUIDOffset = CurOffset;
72 const uint64_t UUIDSectionSize = UUID.size();
73 if (HasUUID)
74 CurOffset += UUIDSectionSize;
75
76 // AddrOffsets section.
77 CurOffset = llvm::alignTo(Value: CurOffset, Align: AddrOffSize);
78 const uint64_t AddrOffsetsOffset = CurOffset;
79 const uint64_t AddrOffsetsSize = Funcs.size() * AddrOffSize;
80 CurOffset += AddrOffsetsSize;
81
82 // AddrInfoOffsets section.
83 const uint8_t AddrInfoOffSize = 8;
84 CurOffset = llvm::alignTo(Value: CurOffset, Align: AddrInfoOffSize);
85 const uint64_t AddrInfoOffsetsOffset = CurOffset;
86 const uint64_t AddrInfoOffsetsSize = Funcs.size() * AddrInfoOffSize;
87 CurOffset += AddrInfoOffsetsSize;
88
89 // FileTable section.
90 CurOffset = llvm::alignTo(Value: CurOffset, Align: 4);
91 const uint64_t FileTableOffset = CurOffset;
92 const uint64_t FileTableSize =
93 4 + Files.size() * FileEntry::getEncodedSize(StringOffsetSize: StrpSize);
94 CurOffset += FileTableSize;
95
96 // StringTable section.
97 const uint64_t StringTableOffset = CurOffset;
98 CurOffset += StringTableSize;
99
100 // FunctionInfo section.
101 CurOffset = llvm::alignTo(Value: CurOffset, Align: 4);
102 const uint64_t FISectionOffset = CurOffset;
103 CurOffset += FISectionSize;
104
105 // Build and write the header.
106 HeaderV2 Hdr;
107 Hdr.Magic = GSYM_MAGIC;
108 Hdr.Version = HeaderV2::getVersion();
109 Hdr.BaseAddress = *BaseAddr;
110 Hdr.NumAddresses = static_cast<uint32_t>(Funcs.size());
111 Hdr.AddrOffSize = AddrOffSize;
112 Hdr.StrTableEncoding = StringTableEncoding::Default;
113 if (auto Err = Hdr.encode(O))
114 return Err;
115
116 // Write GlobalData entries.
117 if (HasUUID)
118 GlobalData{.Type: GlobalInfoType::UUID, .FileOffset: UUIDOffset, .FileSize: UUIDSectionSize}.encode(O);
119 GlobalData{.Type: GlobalInfoType::AddrOffsets, .FileOffset: AddrOffsetsOffset, .FileSize: AddrOffsetsSize}
120 .encode(O);
121 GlobalData{.Type: GlobalInfoType::AddrInfoOffsets, .FileOffset: AddrInfoOffsetsOffset,
122 .FileSize: AddrInfoOffsetsSize}
123 .encode(O);
124 GlobalData{.Type: GlobalInfoType::FileTable, .FileOffset: FileTableOffset, .FileSize: FileTableSize}.encode(
125 O);
126 GlobalData{.Type: GlobalInfoType::StringTable, .FileOffset: StringTableOffset, .FileSize: StringTableSize}
127 .encode(O);
128 GlobalData{.Type: GlobalInfoType::FunctionInfo, .FileOffset: FISectionOffset, .FileSize: FISectionSize}
129 .encode(O);
130 GlobalData{.Type: GlobalInfoType::EndOfList, .FileOffset: 0, .FileSize: 0}.encode(O);
131
132 // Write UUID section.
133 if (HasUUID) {
134 assert(O.tell() == UUIDOffset);
135 O.writeData(Data: ArrayRef<uint8_t>(UUID.data(), UUID.size()));
136 }
137
138 // Write AddrOffsets section.
139 O.alignTo(Align: AddrOffSize);
140 assert(O.tell() == AddrOffsetsOffset);
141 encodeAddrOffsets(O, AddrOffSize, BaseAddr: *BaseAddr);
142
143 // Write AddrInfoOffsets section. Values are relative to FunctionInfo section.
144 O.alignTo(Align: AddrInfoOffSize);
145 assert(O.tell() == AddrInfoOffsetsOffset);
146 for (uint64_t RelOff : FIRelativeOffsets)
147 O.writeU64(Value: RelOff);
148
149 // Write FileTable section.
150 O.alignTo(Align: 4);
151 assert(O.tell() == FileTableOffset);
152 if (auto Err = encodeFileTable(O))
153 return Err;
154
155 // Write StringTable section.
156 assert(O.tell() == StringTableOffset);
157 StrTab.write(OS&: O.get_stream());
158
159 // Write FunctionInfo section.
160 O.alignTo(Align: 4);
161 assert(O.tell() == FISectionOffset);
162 O.writeData(Data: ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(FIBuf.data()),
163 FIBuf.size()));
164
165 return Error::success();
166}
167