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/InlineInfo.cpp
35269 views
1
//===- InlineInfo.cpp -------------------------------------------*- C++ -*-===//
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/FileEntry.h"
10
#include "llvm/DebugInfo/GSYM/FileWriter.h"
11
#include "llvm/DebugInfo/GSYM/GsymReader.h"
12
#include "llvm/DebugInfo/GSYM/InlineInfo.h"
13
#include "llvm/Support/DataExtractor.h"
14
#include <algorithm>
15
#include <inttypes.h>
16
17
using namespace llvm;
18
using namespace gsym;
19
20
21
raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const InlineInfo &II) {
22
if (!II.isValid())
23
return OS;
24
bool First = true;
25
for (auto Range : II.Ranges) {
26
if (First)
27
First = false;
28
else
29
OS << ' ';
30
OS << Range;
31
}
32
OS << " Name = " << HEX32(II.Name) << ", CallFile = " << II.CallFile
33
<< ", CallLine = " << II.CallFile << '\n';
34
for (const auto &Child : II.Children)
35
OS << Child;
36
return OS;
37
}
38
39
static bool getInlineStackHelper(const InlineInfo &II, uint64_t Addr,
40
std::vector<const InlineInfo *> &InlineStack) {
41
if (II.Ranges.contains(Addr)) {
42
// If this is the top level that represents the concrete function,
43
// there will be no name and we shoud clear the inline stack. Otherwise
44
// we have found an inline call stack that we need to insert.
45
if (II.Name != 0)
46
InlineStack.insert(InlineStack.begin(), &II);
47
for (const auto &Child : II.Children) {
48
if (::getInlineStackHelper(Child, Addr, InlineStack))
49
break;
50
}
51
return !InlineStack.empty();
52
}
53
return false;
54
}
55
56
std::optional<InlineInfo::InlineArray>
57
InlineInfo::getInlineStack(uint64_t Addr) const {
58
InlineArray Result;
59
if (getInlineStackHelper(*this, Addr, Result))
60
return Result;
61
return std::nullopt;
62
}
63
64
/// Skip an InlineInfo object in the specified data at the specified offset.
65
///
66
/// Used during the InlineInfo::lookup() call to quickly skip child InlineInfo
67
/// objects where the addres ranges isn't contained in the InlineInfo object
68
/// or its children. This avoids allocations by not appending child InlineInfo
69
/// objects to the InlineInfo::Children array.
70
///
71
/// \param Data The binary stream to read the data from.
72
///
73
/// \param Offset The byte offset within \a Data.
74
///
75
/// \param SkippedRanges If true, address ranges have already been skipped.
76
77
static bool skip(DataExtractor &Data, uint64_t &Offset, bool SkippedRanges) {
78
if (!SkippedRanges) {
79
if (skipRanges(Data, Offset) == 0)
80
return false;
81
}
82
bool HasChildren = Data.getU8(&Offset) != 0;
83
Data.getU32(&Offset); // Skip Inline.Name.
84
Data.getULEB128(&Offset); // Skip Inline.CallFile.
85
Data.getULEB128(&Offset); // Skip Inline.CallLine.
86
if (HasChildren) {
87
while (skip(Data, Offset, false /* SkippedRanges */))
88
/* Do nothing */;
89
}
90
// We skipped a valid InlineInfo.
91
return true;
92
}
93
94
/// A Lookup helper functions.
95
///
96
/// Used during the InlineInfo::lookup() call to quickly only parse an
97
/// InlineInfo object if the address falls within this object. This avoids
98
/// allocations by not appending child InlineInfo objects to the
99
/// InlineInfo::Children array and also skips any InlineInfo objects that do
100
/// not contain the address we are looking up.
101
///
102
/// \param Data The binary stream to read the data from.
103
///
104
/// \param Offset The byte offset within \a Data.
105
///
106
/// \param BaseAddr The address that the relative address range offsets are
107
/// relative to.
108
109
static bool lookup(const GsymReader &GR, DataExtractor &Data, uint64_t &Offset,
110
uint64_t BaseAddr, uint64_t Addr, SourceLocations &SrcLocs,
111
llvm::Error &Err) {
112
InlineInfo Inline;
113
decodeRanges(Inline.Ranges, Data, BaseAddr, Offset);
114
if (Inline.Ranges.empty())
115
return true;
116
// Check if the address is contained within the inline information, and if
117
// not, quickly skip this InlineInfo object and all its children.
118
if (!Inline.Ranges.contains(Addr)) {
119
skip(Data, Offset, true /* SkippedRanges */);
120
return false;
121
}
122
123
// The address range is contained within this InlineInfo, add the source
124
// location for this InlineInfo and any children that contain the address.
125
bool HasChildren = Data.getU8(&Offset) != 0;
126
Inline.Name = Data.getU32(&Offset);
127
Inline.CallFile = (uint32_t)Data.getULEB128(&Offset);
128
Inline.CallLine = (uint32_t)Data.getULEB128(&Offset);
129
if (HasChildren) {
130
// Child address ranges are encoded relative to the first address in the
131
// parent InlineInfo object.
132
const auto ChildBaseAddr = Inline.Ranges[0].start();
133
bool Done = false;
134
while (!Done)
135
Done = lookup(GR, Data, Offset, ChildBaseAddr, Addr, SrcLocs, Err);
136
}
137
138
std::optional<FileEntry> CallFile = GR.getFile(Inline.CallFile);
139
if (!CallFile) {
140
Err = createStringError(std::errc::invalid_argument,
141
"failed to extract file[%" PRIu32 "]",
142
Inline.CallFile);
143
return false;
144
}
145
146
if (CallFile->Dir || CallFile->Base) {
147
SourceLocation SrcLoc;
148
SrcLoc.Name = SrcLocs.back().Name;
149
SrcLoc.Offset = SrcLocs.back().Offset;
150
SrcLoc.Dir = GR.getString(CallFile->Dir);
151
SrcLoc.Base = GR.getString(CallFile->Base);
152
SrcLoc.Line = Inline.CallLine;
153
SrcLocs.back().Name = GR.getString(Inline.Name);
154
SrcLocs.back().Offset = Addr - Inline.Ranges[0].start();
155
SrcLocs.push_back(SrcLoc);
156
}
157
return true;
158
}
159
160
llvm::Error InlineInfo::lookup(const GsymReader &GR, DataExtractor &Data,
161
uint64_t BaseAddr, uint64_t Addr,
162
SourceLocations &SrcLocs) {
163
// Call our recursive helper function starting at offset zero.
164
uint64_t Offset = 0;
165
llvm::Error Err = Error::success();
166
::lookup(GR, Data, Offset, BaseAddr, Addr, SrcLocs, Err);
167
return Err;
168
}
169
170
/// Decode an InlineInfo in Data at the specified offset.
171
///
172
/// A local helper function to decode InlineInfo objects. This function is
173
/// called recursively when parsing child InlineInfo objects.
174
///
175
/// \param Data The data extractor to decode from.
176
/// \param Offset The offset within \a Data to decode from.
177
/// \param BaseAddr The base address to use when decoding address ranges.
178
/// \returns An InlineInfo or an error describing the issue that was
179
/// encountered during decoding.
180
static llvm::Expected<InlineInfo> decode(DataExtractor &Data, uint64_t &Offset,
181
uint64_t BaseAddr) {
182
InlineInfo Inline;
183
if (!Data.isValidOffset(Offset))
184
return createStringError(std::errc::io_error,
185
"0x%8.8" PRIx64 ": missing InlineInfo address ranges data", Offset);
186
decodeRanges(Inline.Ranges, Data, BaseAddr, Offset);
187
if (Inline.Ranges.empty())
188
return Inline;
189
if (!Data.isValidOffsetForDataOfSize(Offset, 1))
190
return createStringError(std::errc::io_error,
191
"0x%8.8" PRIx64 ": missing InlineInfo uint8_t indicating children",
192
Offset);
193
bool HasChildren = Data.getU8(&Offset) != 0;
194
if (!Data.isValidOffsetForDataOfSize(Offset, 4))
195
return createStringError(std::errc::io_error,
196
"0x%8.8" PRIx64 ": missing InlineInfo uint32_t for name", Offset);
197
Inline.Name = Data.getU32(&Offset);
198
if (!Data.isValidOffset(Offset))
199
return createStringError(std::errc::io_error,
200
"0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call file", Offset);
201
Inline.CallFile = (uint32_t)Data.getULEB128(&Offset);
202
if (!Data.isValidOffset(Offset))
203
return createStringError(std::errc::io_error,
204
"0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call line", Offset);
205
Inline.CallLine = (uint32_t)Data.getULEB128(&Offset);
206
if (HasChildren) {
207
// Child address ranges are encoded relative to the first address in the
208
// parent InlineInfo object.
209
const auto ChildBaseAddr = Inline.Ranges[0].start();
210
while (true) {
211
llvm::Expected<InlineInfo> Child = decode(Data, Offset, ChildBaseAddr);
212
if (!Child)
213
return Child.takeError();
214
// InlineInfo with empty Ranges termintes a child sibling chain.
215
if (Child.get().Ranges.empty())
216
break;
217
Inline.Children.emplace_back(std::move(*Child));
218
}
219
}
220
return Inline;
221
}
222
223
llvm::Expected<InlineInfo> InlineInfo::decode(DataExtractor &Data,
224
uint64_t BaseAddr) {
225
uint64_t Offset = 0;
226
return ::decode(Data, Offset, BaseAddr);
227
}
228
229
llvm::Error InlineInfo::encode(FileWriter &O, uint64_t BaseAddr) const {
230
// Users must verify the InlineInfo is valid prior to calling this funtion.
231
// We don't want to emit any InlineInfo objects if they are not valid since
232
// it will waste space in the GSYM file.
233
if (!isValid())
234
return createStringError(std::errc::invalid_argument,
235
"attempted to encode invalid InlineInfo object");
236
encodeRanges(Ranges, O, BaseAddr);
237
bool HasChildren = !Children.empty();
238
O.writeU8(HasChildren);
239
O.writeU32(Name);
240
O.writeULEB(CallFile);
241
O.writeULEB(CallLine);
242
if (HasChildren) {
243
// Child address ranges are encoded as relative to the first
244
// address in the Ranges for this object. This keeps the offsets
245
// small and allows for efficient encoding using ULEB offsets.
246
const uint64_t ChildBaseAddr = Ranges[0].start();
247
for (const auto &Child : Children) {
248
// Make sure all child address ranges are contained in the parent address
249
// ranges.
250
for (const auto &ChildRange: Child.Ranges) {
251
if (!Ranges.contains(ChildRange))
252
return createStringError(std::errc::invalid_argument,
253
"child range not contained in parent");
254
}
255
llvm::Error Err = Child.encode(O, ChildBaseAddr);
256
if (Err)
257
return Err;
258
}
259
260
// Terminate child sibling chain by emitting a zero. This zero will cause
261
// the decodeAll() function above to return false and stop the decoding
262
// of child InlineInfo objects that are siblings.
263
O.writeULEB(0);
264
}
265
return Error::success();
266
}
267
268
static uint64_t GetTotalNumChildren(const InlineInfo &II) {
269
uint64_t NumChildren = II.Children.size();
270
for (const auto &Child : II.Children)
271
NumChildren += GetTotalNumChildren(Child);
272
return NumChildren;
273
}
274
275
bool InlineInfo::operator<(const InlineInfo &RHS) const {
276
return GetTotalNumChildren(*this) < GetTotalNumChildren(RHS);
277
}
278
279