LLVM 22.0.0git
CallSiteInfo.cpp
Go to the documentation of this file.
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
19#include <string>
20#include <vector>
21
22using namespace llvm;
23using namespace gsym;
24
25Error 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
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
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
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) {
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.
103namespace llvm {
104namespace yaml {
105
107 // The offset of the return address of the call site - relative to the start
108 // of the function.
110 std::vector<std::string> match_regex;
111 std::vector<std::string> flags;
112};
113
115 std::string name;
116 std::vector<CallSiteYAML> callsites;
117};
118
120 std::vector<FunctionYAML> functions;
121};
122
123template <> 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
131template <> 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
138template <> 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
149
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
173StringMap<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.
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
189Error 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
233 OS << " Return=" << HEX64(CSI.ReturnOffset);
234 OS << " Flags=" << HEX8(CSI.Flags);
235 OS << " RegEx=" << llvm::interleaved(CSI.MatchRegex, ",");
236 return OS;
237}
238
240 const CallSiteInfoCollection &CSIC) {
241 for (const auto &CS : CSIC.CallSites) {
242 OS << CS;
243 OS << "\n";
244 }
245 return OS;
246}
#define HEX8(v)
Definition: ExtractRanges.h:18
#define HEX64(v)
Definition: ExtractRanges.h:21
global merge func
static Error loadYAML(sys::fs::file_t Fd, size_t FileSize, StringRef Filename, InstrumentationMap::SledContainer &Sleds, InstrumentationMap::FunctionAddressMap &FunctionAddresses, InstrumentationMap::FunctionAddressReverseMap &FunctionIds)
raw_pwrite_stream & OS
#define LLVM_YAML_IS_SEQUENCE_VECTOR(type)
Lightweight error class with error context and mandatory checking.
Definition: Error.h:159
static ErrorSuccess success()
Create a success value.
Definition: Error.h:336
Tagged union holding either a T or a Error.
Definition: Error.h:485
Error takeError()
Take ownership of the stored error.
Definition: Error.h:612
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFile(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, bool IsVolatile=false, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, returning a new MemoryBuffer if successful,...
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition: StringMap.h:133
iterator end()
Definition: StringMap.h:224
iterator find(StringRef Key)
Definition: StringMap.h:237
std::pair< iterator, bool > try_emplace(StringRef Key, ArgsTy &&...Args)
Emplace a new element for the specified key into the map if the key isn't already in the map.
Definition: StringMap.h:372
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
A simplified binary data writer class that doesn't require targets, target definitions,...
Definition: FileWriter.h:30
LLVM_ABI uint32_t insertString(StringRef S, bool Copy=true)
Insert a string into the GSYM string table.
LLVM_ABI StringRef getString(uint32_t Offset)
Retrieve a string from the GSYM string table given its offset.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
LLVM_ABI raw_ostream & operator<<(raw_ostream &OS, const CallSiteInfo &CSI)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:477
InterleavedRange< Range > interleaved(const Range &R, StringRef Separator=", ", StringRef Prefix="", StringRef Suffix="")
Output range R as a sequence of interleaved elements.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1305
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:111
LLVM_ABI llvm::Error encode(FileWriter &O) const
Encode this CallSiteInfoCollection object into a FileWriter stream.
std::vector< CallSiteInfo > CallSites
Definition: CallSiteInfo.h:78
static LLVM_ABI llvm::Expected< CallSiteInfoCollection > decode(DataExtractor &Data)
Decode a CallSiteInfoCollection object from a binary data stream.
std::vector< uint32_t > MatchRegex
Offsets into the string table for function names regex patterns.
Definition: CallSiteInfo.h:48
uint64_t ReturnOffset
The return offset of the call site - relative to the function start.
Definition: CallSiteInfo.h:45
static LLVM_ABI llvm::Expected< CallSiteInfo > decode(DataExtractor &Data, uint64_t &Offset)
Decode a CallSiteInfo object from a binary data stream.
Function information in GSYM files encodes information for one contiguous address range.
Definition: FunctionInfo.h:93
std::optional< CallSiteInfoCollection > CallSites
Definition: FunctionInfo.h:99
std::vector< std::string > flags
std::vector< std::string > match_regex
std::vector< CallSiteYAML > callsites
std::vector< FunctionYAML > functions
static void mapping(IO &io, CallSiteYAML &callsite)
static void mapping(IO &io, FunctionYAML &func)
static void mapping(IO &io, FunctionsYAML &FuncYAMLs)