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/CallSiteInfo.cpp
213799 views
1
//===- CallSiteInfo.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/CallSiteInfo.h"
10
#include "llvm/DebugInfo/GSYM/FileWriter.h"
11
#include "llvm/DebugInfo/GSYM/FunctionInfo.h"
12
#include "llvm/DebugInfo/GSYM/GsymCreator.h"
13
#include "llvm/MC/StringTableBuilder.h"
14
#include "llvm/Support/DataExtractor.h"
15
#include "llvm/Support/InterleavedRange.h"
16
#include "llvm/Support/YAMLParser.h"
17
#include "llvm/Support/YAMLTraits.h"
18
#include "llvm/Support/raw_ostream.h"
19
#include <string>
20
#include <vector>
21
22
using namespace llvm;
23
using namespace gsym;
24
25
Error CallSiteInfo::encode(FileWriter &O) const {
26
O.writeU64(ReturnOffset);
27
O.writeU8(Flags);
28
O.writeU32(MatchRegex.size());
29
for (uint32_t Entry : MatchRegex)
30
O.writeU32(Entry);
31
return Error::success();
32
}
33
34
Expected<CallSiteInfo> CallSiteInfo::decode(DataExtractor &Data,
35
uint64_t &Offset) {
36
CallSiteInfo CSI;
37
38
// Read ReturnOffset
39
if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint64_t)))
40
return createStringError(std::errc::io_error,
41
"0x%8.8" PRIx64 ": missing ReturnOffset", Offset);
42
CSI.ReturnOffset = Data.getU64(&Offset);
43
44
// Read Flags
45
if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint8_t)))
46
return createStringError(std::errc::io_error,
47
"0x%8.8" PRIx64 ": missing Flags", Offset);
48
CSI.Flags = Data.getU8(&Offset);
49
50
// Read number of MatchRegex entries
51
if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
52
return createStringError(std::errc::io_error,
53
"0x%8.8" PRIx64 ": missing MatchRegex count",
54
Offset);
55
uint32_t NumEntries = Data.getU32(&Offset);
56
57
CSI.MatchRegex.reserve(NumEntries);
58
for (uint32_t i = 0; i < NumEntries; ++i) {
59
if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
60
return createStringError(std::errc::io_error,
61
"0x%8.8" PRIx64 ": missing MatchRegex entry",
62
Offset);
63
uint32_t Entry = Data.getU32(&Offset);
64
CSI.MatchRegex.push_back(Entry);
65
}
66
67
return CSI;
68
}
69
70
Error CallSiteInfoCollection::encode(FileWriter &O) const {
71
O.writeU32(CallSites.size());
72
for (const CallSiteInfo &CSI : CallSites)
73
if (Error Err = CSI.encode(O))
74
return Err;
75
76
return Error::success();
77
}
78
79
Expected<CallSiteInfoCollection>
80
CallSiteInfoCollection::decode(DataExtractor &Data) {
81
CallSiteInfoCollection CSC;
82
uint64_t Offset = 0;
83
84
// Read number of CallSiteInfo entries
85
if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(uint32_t)))
86
return createStringError(std::errc::io_error,
87
"0x%8.8" PRIx64 ": missing CallSiteInfo count",
88
Offset);
89
uint32_t NumCallSites = Data.getU32(&Offset);
90
91
CSC.CallSites.reserve(NumCallSites);
92
for (uint32_t i = 0; i < NumCallSites; ++i) {
93
Expected<CallSiteInfo> ECSI = CallSiteInfo::decode(Data, Offset);
94
if (!ECSI)
95
return ECSI.takeError();
96
CSC.CallSites.emplace_back(*ECSI);
97
}
98
99
return CSC;
100
}
101
102
/// Structures necessary for reading CallSiteInfo from YAML.
103
namespace llvm {
104
namespace yaml {
105
106
struct CallSiteYAML {
107
// The offset of the return address of the call site - relative to the start
108
// of the function.
109
Hex64 return_offset;
110
std::vector<std::string> match_regex;
111
std::vector<std::string> flags;
112
};
113
114
struct FunctionYAML {
115
std::string name;
116
std::vector<CallSiteYAML> callsites;
117
};
118
119
struct FunctionsYAML {
120
std::vector<FunctionYAML> functions;
121
};
122
123
template <> struct MappingTraits<CallSiteYAML> {
124
static void mapping(IO &io, CallSiteYAML &callsite) {
125
io.mapRequired("return_offset", callsite.return_offset);
126
io.mapRequired("match_regex", callsite.match_regex);
127
io.mapOptional("flags", callsite.flags);
128
}
129
};
130
131
template <> struct MappingTraits<FunctionYAML> {
132
static void mapping(IO &io, FunctionYAML &func) {
133
io.mapRequired("name", func.name);
134
io.mapOptional("callsites", func.callsites);
135
}
136
};
137
138
template <> struct MappingTraits<FunctionsYAML> {
139
static void mapping(IO &io, FunctionsYAML &FuncYAMLs) {
140
io.mapRequired("functions", FuncYAMLs.functions);
141
}
142
};
143
144
} // namespace yaml
145
} // namespace llvm
146
147
LLVM_YAML_IS_SEQUENCE_VECTOR(CallSiteYAML)
148
LLVM_YAML_IS_SEQUENCE_VECTOR(FunctionYAML)
149
150
Error CallSiteInfoLoader::loadYAML(StringRef YAMLFile) {
151
// Step 1: Read YAML file
152
auto BufferOrError = MemoryBuffer::getFile(YAMLFile, /*IsText=*/true);
153
if (!BufferOrError)
154
return errorCodeToError(BufferOrError.getError());
155
156
std::unique_ptr<MemoryBuffer> Buffer = std::move(*BufferOrError);
157
158
// Step 2: Parse YAML content
159
yaml::FunctionsYAML FuncsYAML;
160
yaml::Input Yin(Buffer->getMemBufferRef());
161
Yin >> FuncsYAML;
162
if (Yin.error())
163
return createStringError(Yin.error(), "Error parsing YAML file: %s\n",
164
Buffer->getBufferIdentifier().str().c_str());
165
166
// Step 3: Build function map from Funcs
167
auto FuncMap = buildFunctionMap();
168
169
// Step 4: Process parsed YAML functions and update FuncMap
170
return processYAMLFunctions(FuncsYAML, FuncMap);
171
}
172
173
StringMap<FunctionInfo *> CallSiteInfoLoader::buildFunctionMap() {
174
// If the function name is already in the map, don't update it. This way we
175
// preferentially use the first encountered function. Since symbols are
176
// loaded from dSYM first, we end up preferring keeping track of symbols
177
// from dSYM rather than from the symbol table - which is what we want to
178
// do.
179
StringMap<FunctionInfo *> FuncMap;
180
for (auto &Func : Funcs) {
181
FuncMap.try_emplace(GCreator.getString(Func.Name), &Func);
182
if (auto &MFuncs = Func.MergedFunctions)
183
for (auto &MFunc : MFuncs->MergedFunctions)
184
FuncMap.try_emplace(GCreator.getString(MFunc.Name), &MFunc);
185
}
186
return FuncMap;
187
}
188
189
Error CallSiteInfoLoader::processYAMLFunctions(
190
const yaml::FunctionsYAML &FuncYAMLs, StringMap<FunctionInfo *> &FuncMap) {
191
// For each function in the YAML file
192
for (const auto &FuncYAML : FuncYAMLs.functions) {
193
auto It = FuncMap.find(FuncYAML.name);
194
if (It == FuncMap.end())
195
return createStringError(
196
std::errc::invalid_argument,
197
"Can't find function '%s' specified in callsite YAML\n",
198
FuncYAML.name.c_str());
199
200
FunctionInfo *FuncInfo = It->second;
201
// Create a CallSiteInfoCollection if not already present
202
if (!FuncInfo->CallSites)
203
FuncInfo->CallSites = CallSiteInfoCollection();
204
for (const auto &CallSiteYAML : FuncYAML.callsites) {
205
CallSiteInfo CSI;
206
// Since YAML has specifies relative return offsets, add the function
207
// start address to make the offset absolute.
208
CSI.ReturnOffset = CallSiteYAML.return_offset;
209
for (const auto &Regex : CallSiteYAML.match_regex) {
210
uint32_t StrOffset = GCreator.insertString(Regex);
211
CSI.MatchRegex.push_back(StrOffset);
212
}
213
214
// Parse flags and combine them
215
for (const auto &FlagStr : CallSiteYAML.flags) {
216
if (FlagStr == "InternalCall") {
217
CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::InternalCall);
218
} else if (FlagStr == "ExternalCall") {
219
CSI.Flags |= static_cast<uint8_t>(CallSiteInfo::ExternalCall);
220
} else {
221
return createStringError(std::errc::invalid_argument,
222
"Unknown flag in callsite YAML: %s\n",
223
FlagStr.c_str());
224
}
225
}
226
FuncInfo->CallSites->CallSites.push_back(CSI);
227
}
228
}
229
return Error::success();
230
}
231
232
raw_ostream &gsym::operator<<(raw_ostream &OS, const CallSiteInfo &CSI) {
233
OS << " Return=" << HEX64(CSI.ReturnOffset);
234
OS << " Flags=" << HEX8(CSI.Flags);
235
OS << " RegEx=" << llvm::interleaved(CSI.MatchRegex, ",");
236
return OS;
237
}
238
239
raw_ostream &gsym::operator<<(raw_ostream &OS,
240
const CallSiteInfoCollection &CSIC) {
241
for (const auto &CS : CSIC.CallSites) {
242
OS << CS;
243
OS << "\n";
244
}
245
return OS;
246
}
247
248