Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/GSYM/FunctionInfo.cpp
35266 views
1
//===- FunctionInfo.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/FunctionInfo.h"
10
#include "llvm/DebugInfo/GSYM/FileWriter.h"
11
#include "llvm/DebugInfo/GSYM/GsymReader.h"
12
#include "llvm/DebugInfo/GSYM/LineTable.h"
13
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
14
#include "llvm/Support/DataExtractor.h"
15
#include <optional>
16
17
using namespace llvm;
18
using namespace gsym;
19
20
/// FunctionInfo information type that is used to encode the optional data
21
/// that is associated with a FunctionInfo object.
22
enum InfoType : uint32_t {
23
EndOfList = 0u,
24
LineTableInfo = 1u,
25
InlineInfo = 2u
26
};
27
28
raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const FunctionInfo &FI) {
29
OS << FI.Range << ": " << "Name=" << HEX32(FI.Name) << '\n';
30
if (FI.OptLineTable)
31
OS << FI.OptLineTable << '\n';
32
if (FI.Inline)
33
OS << FI.Inline << '\n';
34
return OS;
35
}
36
37
llvm::Expected<FunctionInfo> FunctionInfo::decode(DataExtractor &Data,
38
uint64_t BaseAddr) {
39
FunctionInfo FI;
40
uint64_t Offset = 0;
41
if (!Data.isValidOffsetForDataOfSize(Offset, 4))
42
return createStringError(std::errc::io_error,
43
"0x%8.8" PRIx64 ": missing FunctionInfo Size", Offset);
44
FI.Range = {BaseAddr, BaseAddr + Data.getU32(&Offset)};
45
if (!Data.isValidOffsetForDataOfSize(Offset, 4))
46
return createStringError(std::errc::io_error,
47
"0x%8.8" PRIx64 ": missing FunctionInfo Name", Offset);
48
FI.Name = Data.getU32(&Offset);
49
if (FI.Name == 0)
50
return createStringError(std::errc::io_error,
51
"0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x%8.8x",
52
Offset - 4, FI.Name);
53
bool Done = false;
54
while (!Done) {
55
if (!Data.isValidOffsetForDataOfSize(Offset, 4))
56
return createStringError(std::errc::io_error,
57
"0x%8.8" PRIx64 ": missing FunctionInfo InfoType value", Offset);
58
const uint32_t IT = Data.getU32(&Offset);
59
if (!Data.isValidOffsetForDataOfSize(Offset, 4))
60
return createStringError(std::errc::io_error,
61
"0x%8.8" PRIx64 ": missing FunctionInfo InfoType length", Offset);
62
const uint32_t InfoLength = Data.getU32(&Offset);
63
if (!Data.isValidOffsetForDataOfSize(Offset, InfoLength))
64
return createStringError(std::errc::io_error,
65
"0x%8.8" PRIx64 ": missing FunctionInfo data for InfoType %u",
66
Offset, IT);
67
DataExtractor InfoData(Data.getData().substr(Offset, InfoLength),
68
Data.isLittleEndian(),
69
Data.getAddressSize());
70
switch (IT) {
71
case InfoType::EndOfList:
72
Done = true;
73
break;
74
75
case InfoType::LineTableInfo:
76
if (Expected<LineTable> LT = LineTable::decode(InfoData, BaseAddr))
77
FI.OptLineTable = std::move(LT.get());
78
else
79
return LT.takeError();
80
break;
81
82
case InfoType::InlineInfo:
83
if (Expected<InlineInfo> II = InlineInfo::decode(InfoData, BaseAddr))
84
FI.Inline = std::move(II.get());
85
else
86
return II.takeError();
87
break;
88
89
default:
90
return createStringError(std::errc::io_error,
91
"0x%8.8" PRIx64 ": unsupported InfoType %u",
92
Offset-8, IT);
93
}
94
Offset += InfoLength;
95
}
96
return std::move(FI);
97
}
98
99
uint64_t FunctionInfo::cacheEncoding() {
100
EncodingCache.clear();
101
if (!isValid())
102
return 0;
103
raw_svector_ostream OutStrm(EncodingCache);
104
FileWriter FW(OutStrm, llvm::endianness::native);
105
llvm::Expected<uint64_t> Result = encode(FW);
106
if (!Result) {
107
EncodingCache.clear();
108
consumeError(Result.takeError());
109
return 0;
110
}
111
return EncodingCache.size();
112
}
113
114
llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &Out) const {
115
if (!isValid())
116
return createStringError(std::errc::invalid_argument,
117
"attempted to encode invalid FunctionInfo object");
118
// Align FunctionInfo data to a 4 byte alignment.
119
Out.alignTo(4);
120
const uint64_t FuncInfoOffset = Out.tell();
121
// Check if we have already encoded this function info into EncodingCache.
122
// This will be non empty when creating segmented GSYM files as we need to
123
// precompute exactly how big FunctionInfo objects encode into so we can
124
// accurately make segments of a specific size.
125
if (!EncodingCache.empty() &&
126
llvm::endianness::native == Out.getByteOrder()) {
127
// We already encoded this object, just write out the bytes.
128
Out.writeData(llvm::ArrayRef<uint8_t>((const uint8_t *)EncodingCache.data(),
129
EncodingCache.size()));
130
return FuncInfoOffset;
131
}
132
// Write the size in bytes of this function as a uint32_t. This can be zero
133
// if we just have a symbol from a symbol table and that symbol has no size.
134
Out.writeU32(size());
135
// Write the name of this function as a uint32_t string table offset.
136
Out.writeU32(Name);
137
138
if (OptLineTable) {
139
Out.writeU32(InfoType::LineTableInfo);
140
// Write a uint32_t length as zero for now, we will fix this up after
141
// writing the LineTable out with the number of bytes that were written.
142
Out.writeU32(0);
143
const auto StartOffset = Out.tell();
144
llvm::Error err = OptLineTable->encode(Out, Range.start());
145
if (err)
146
return std::move(err);
147
const auto Length = Out.tell() - StartOffset;
148
if (Length > UINT32_MAX)
149
return createStringError(std::errc::invalid_argument,
150
"LineTable length is greater than UINT32_MAX");
151
// Fixup the size of the LineTable data with the correct size.
152
Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
153
}
154
155
// Write out the inline function info if we have any and if it is valid.
156
if (Inline) {
157
Out.writeU32(InfoType::InlineInfo);
158
// Write a uint32_t length as zero for now, we will fix this up after
159
// writing the LineTable out with the number of bytes that were written.
160
Out.writeU32(0);
161
const auto StartOffset = Out.tell();
162
llvm::Error err = Inline->encode(Out, Range.start());
163
if (err)
164
return std::move(err);
165
const auto Length = Out.tell() - StartOffset;
166
if (Length > UINT32_MAX)
167
return createStringError(std::errc::invalid_argument,
168
"InlineInfo length is greater than UINT32_MAX");
169
// Fixup the size of the InlineInfo data with the correct size.
170
Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
171
}
172
173
// Terminate the data chunks with and end of list with zero size
174
Out.writeU32(InfoType::EndOfList);
175
Out.writeU32(0);
176
return FuncInfoOffset;
177
}
178
179
180
llvm::Expected<LookupResult> FunctionInfo::lookup(DataExtractor &Data,
181
const GsymReader &GR,
182
uint64_t FuncAddr,
183
uint64_t Addr) {
184
LookupResult LR;
185
LR.LookupAddr = Addr;
186
uint64_t Offset = 0;
187
LR.FuncRange = {FuncAddr, FuncAddr + Data.getU32(&Offset)};
188
uint32_t NameOffset = Data.getU32(&Offset);
189
// The "lookup" functions doesn't report errors as accurately as the "decode"
190
// function as it is meant to be fast. For more accurage errors we could call
191
// "decode".
192
if (!Data.isValidOffset(Offset))
193
return createStringError(std::errc::io_error,
194
"FunctionInfo data is truncated");
195
// This function will be called with the result of a binary search of the
196
// address table, we must still make sure the address does not fall into a
197
// gap between functions are after the last function.
198
if (LR.FuncRange.size() > 0 && !LR.FuncRange.contains(Addr))
199
return createStringError(std::errc::io_error,
200
"address 0x%" PRIx64 " is not in GSYM", Addr);
201
202
if (NameOffset == 0)
203
return createStringError(std::errc::io_error,
204
"0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x00000000",
205
Offset - 4);
206
LR.FuncName = GR.getString(NameOffset);
207
bool Done = false;
208
std::optional<LineEntry> LineEntry;
209
std::optional<DataExtractor> InlineInfoData;
210
while (!Done) {
211
if (!Data.isValidOffsetForDataOfSize(Offset, 8))
212
return createStringError(std::errc::io_error,
213
"FunctionInfo data is truncated");
214
const uint32_t IT = Data.getU32(&Offset);
215
const uint32_t InfoLength = Data.getU32(&Offset);
216
const StringRef InfoBytes = Data.getData().substr(Offset, InfoLength);
217
if (InfoLength != InfoBytes.size())
218
return createStringError(std::errc::io_error,
219
"FunctionInfo data is truncated");
220
DataExtractor InfoData(InfoBytes, Data.isLittleEndian(),
221
Data.getAddressSize());
222
switch (IT) {
223
case InfoType::EndOfList:
224
Done = true;
225
break;
226
227
case InfoType::LineTableInfo:
228
if (auto ExpectedLE = LineTable::lookup(InfoData, FuncAddr, Addr))
229
LineEntry = ExpectedLE.get();
230
else
231
return ExpectedLE.takeError();
232
break;
233
234
case InfoType::InlineInfo:
235
// We will parse the inline info after our line table, but only if
236
// we have a line entry.
237
InlineInfoData = InfoData;
238
break;
239
240
default:
241
break;
242
}
243
Offset += InfoLength;
244
}
245
246
if (!LineEntry) {
247
// We don't have a valid line entry for our address, fill in our source
248
// location as best we can and return.
249
SourceLocation SrcLoc;
250
SrcLoc.Name = LR.FuncName;
251
SrcLoc.Offset = Addr - FuncAddr;
252
LR.Locations.push_back(SrcLoc);
253
return LR;
254
}
255
256
std::optional<FileEntry> LineEntryFile = GR.getFile(LineEntry->File);
257
if (!LineEntryFile)
258
return createStringError(std::errc::invalid_argument,
259
"failed to extract file[%" PRIu32 "]",
260
LineEntry->File);
261
262
SourceLocation SrcLoc;
263
SrcLoc.Name = LR.FuncName;
264
SrcLoc.Offset = Addr - FuncAddr;
265
SrcLoc.Dir = GR.getString(LineEntryFile->Dir);
266
SrcLoc.Base = GR.getString(LineEntryFile->Base);
267
SrcLoc.Line = LineEntry->Line;
268
LR.Locations.push_back(SrcLoc);
269
// If we don't have inline information, we are done.
270
if (!InlineInfoData)
271
return LR;
272
// We have inline information. Try to augment the lookup result with this
273
// data.
274
llvm::Error Err = InlineInfo::lookup(GR, *InlineInfoData, FuncAddr, Addr,
275
LR.Locations);
276
if (Err)
277
return std::move(Err);
278
return LR;
279
}
280
281