LLVM 23.0.0git
FunctionInfo.cpp
Go to the documentation of this file.
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
16#include <optional>
17
18using namespace llvm;
19using namespace gsym;
20
21/// FunctionInfo information type that is used to encode the optional data
22/// that is associated with a FunctionInfo object.
30
32 OS << FI.Range << ": " << "Name=" << HEX32(FI.Name) << '\n';
33 if (FI.OptLineTable)
34 OS << FI.OptLineTable << '\n';
35 if (FI.Inline)
36 OS << FI.Inline << '\n';
37 if (FI.CallSites)
38 OS << *FI.CallSites << '\n';
39 return OS;
40}
41
43 uint64_t BaseAddr) {
44 FunctionInfo FI;
45 uint64_t Offset = 0;
46 if (!Data.isValidOffsetForDataOfSize(Offset, 4))
47 return createStringError(std::errc::io_error,
48 "0x%8.8" PRIx64 ": missing FunctionInfo Size", Offset);
49 FI.Range = {BaseAddr, BaseAddr + Data.getU32(&Offset)};
50 if (!Data.isValidOffsetForDataOfSize(Offset, 4))
51 return createStringError(std::errc::io_error,
52 "0x%8.8" PRIx64 ": missing FunctionInfo Name", Offset);
53 FI.Name = Data.getStringOffset(&Offset);
54 if (FI.Name == 0)
55 return createStringError(std::errc::io_error,
56 "0x%8.8" PRIx64
57 ": invalid FunctionInfo Name value 0x%" PRIx64,
58 Offset - Data.getStringOffsetSize(), FI.Name);
59 bool Done = false;
60 while (!Done) {
61 if (!Data.isValidOffsetForDataOfSize(Offset, 4))
62 return createStringError(std::errc::io_error,
63 "0x%8.8" PRIx64 ": missing FunctionInfo InfoType value", Offset);
64 const uint32_t IT = Data.getU32(&Offset);
65 if (!Data.isValidOffsetForDataOfSize(Offset, 4))
66 return createStringError(std::errc::io_error,
67 "0x%8.8" PRIx64 ": missing FunctionInfo InfoType length", Offset);
68 const uint32_t InfoLength = Data.getU32(&Offset);
69 if (!Data.isValidOffsetForDataOfSize(Offset, InfoLength))
70 return createStringError(std::errc::io_error,
71 "0x%8.8" PRIx64 ": missing FunctionInfo data for InfoType %u",
72 Offset, IT);
73 GsymDataExtractor InfoData(Data, Offset, InfoLength);
74 switch (IT) {
76 Done = true;
77 break;
78
80 if (Expected<LineTable> LT = LineTable::decode(InfoData, BaseAddr))
81 FI.OptLineTable = std::move(LT.get());
82 else
83 return LT.takeError();
84 break;
85
87 if (Expected<InlineInfo> II = InlineInfo::decode(InfoData, BaseAddr))
88 FI.Inline = std::move(II.get());
89 else
90 return II.takeError();
91 break;
92
95 MergedFunctionsInfo::decode(InfoData, BaseAddr))
96 FI.MergedFunctions = std::move(MI.get());
97 else
98 return MI.takeError();
99 break;
100
104 FI.CallSites = std::move(CI.get());
105 else
106 return CI.takeError();
107 break;
108
109 default:
110 return createStringError(std::errc::io_error,
111 "0x%8.8" PRIx64 ": unsupported InfoType %u",
112 Offset-8, IT);
113 }
114 Offset += InfoLength;
115 }
116 return std::move(FI);
117}
118
120 EncodingCache.clear();
121 if (!isValid())
122 return 0;
125 FW.setStringOffsetSize(GC.getStringOffsetSize());
126 llvm::Expected<uint64_t> Result = encode(FW);
127 if (!Result) {
128 EncodingCache.clear();
129 consumeError(Result.takeError());
130 return 0;
131 }
132 return EncodingCache.size();
133}
134
136 bool NoPadding) const {
137 if (!isValid())
138 return createStringError(std::errc::invalid_argument,
139 "attempted to encode invalid FunctionInfo object");
140 // Align FunctionInfo data to a 4 byte alignment, if padding is allowed
141 if (NoPadding == false)
142 Out.alignTo(4);
143 const uint64_t FuncInfoOffset = Out.tell();
144 // Check if we have already encoded this function info into EncodingCache.
145 // This will be non empty when creating segmented GSYM files as we need to
146 // precompute exactly how big FunctionInfo objects encode into so we can
147 // accurately make segments of a specific size.
148 if (!EncodingCache.empty() &&
150 // We already encoded this object, just write out the bytes.
152 EncodingCache.size()));
153 return FuncInfoOffset;
154 }
155 // Write the size in bytes of this function as a uint32_t. This can be zero
156 // if we just have a symbol from a symbol table and that symbol has no size.
157 Out.writeU32(size());
158 // Write the name of this function as a string table offset.
160
161 if (OptLineTable) {
163 // Write a uint32_t length as zero for now, we will fix this up after
164 // writing the LineTable out with the number of bytes that were written.
165 Out.writeU32(0);
166 const auto StartOffset = Out.tell();
167 llvm::Error err = OptLineTable->encode(Out, Range.start());
168 if (err)
169 return std::move(err);
170 const auto Length = Out.tell() - StartOffset;
171 if (Length > UINT32_MAX)
172 return createStringError(std::errc::invalid_argument,
173 "LineTable length is greater than UINT32_MAX");
174 // Fixup the size of the LineTable data with the correct size.
175 Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
176 }
177
178 // Write out the inline function info if we have any and if it is valid.
179 if (Inline) {
181 // Write a uint32_t length as zero for now, we will fix this up after
182 // writing the LineTable out with the number of bytes that were written.
183 Out.writeU32(0);
184 const auto StartOffset = Out.tell();
185 llvm::Error err = Inline->encode(Out, Range.start());
186 if (err)
187 return std::move(err);
188 const auto Length = Out.tell() - StartOffset;
189 if (Length > UINT32_MAX)
190 return createStringError(std::errc::invalid_argument,
191 "InlineInfo length is greater than UINT32_MAX");
192 // Fixup the size of the InlineInfo data with the correct size.
193 Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
194 }
195
196 // Write out the merged functions info if we have any and if it is valid.
197 if (MergedFunctions) {
199 // Write a uint32_t length as zero for now, we will fix this up after
200 // writing the LineTable out with the number of bytes that were written.
201 Out.writeU32(0);
202 const auto StartOffset = Out.tell();
203 llvm::Error err = MergedFunctions->encode(Out);
204 if (err)
205 return std::move(err);
206 const auto Length = Out.tell() - StartOffset;
207 if (Length > UINT32_MAX)
208 return createStringError(
209 std::errc::invalid_argument,
210 "MergedFunctionsInfo length is greater than UINT32_MAX");
211 // Fixup the size of the MergedFunctionsInfo data with the correct size.
212 Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
213 }
214
215 // Write out the call sites if we have any and if they are valid.
216 if (CallSites) {
218 // Write a uint32_t length as zero for now, we will fix this up after
219 // writing the CallSites out with the number of bytes that were written.
220 Out.writeU32(0);
221 const auto StartOffset = Out.tell();
222 Error Err = CallSites->encode(Out);
223 if (Err)
224 return std::move(Err);
225 const auto Length = Out.tell() - StartOffset;
226 if (Length > UINT32_MAX)
227 return createStringError(std::errc::invalid_argument,
228 "CallSites length is greater than UINT32_MAX");
229 // Fixup the size of the CallSites data with the correct size.
230 Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
231 }
232
233 // Terminate the data chunks with an end of list with zero size.
235 Out.writeU32(0);
236 return FuncInfoOffset;
237}
238
241 uint64_t FuncAddr, uint64_t Addr,
242 std::optional<GsymDataExtractor> *MergedFuncsData) {
243 LookupResult LR;
244 LR.LookupAddr = Addr;
245 uint64_t Offset = 0;
246 LR.FuncRange = {FuncAddr, FuncAddr + Data.getU32(&Offset)};
247 gsym_strp_t NameOffset = Data.getStringOffset(&Offset);
248 // The "lookup" functions doesn't report errors as accurately as the "decode"
249 // function as it is meant to be fast. For more accurage errors we could call
250 // "decode".
251 if (!Data.isValidOffset(Offset))
252 return createStringError(std::errc::io_error,
253 "FunctionInfo data is truncated");
254 // This function will be called with the result of a binary search of the
255 // address table, we must still make sure the address does not fall into a
256 // gap between functions are after the last function.
257 if (LR.FuncRange.size() > 0 && !LR.FuncRange.contains(Addr))
258 return createStringError(std::errc::io_error,
259 "address 0x%" PRIx64 " is not in GSYM", Addr);
260
261 if (NameOffset == 0)
262 return createStringError(std::errc::io_error,
263 "0x%8.8" PRIx64
264 ": invalid FunctionInfo Name value 0x0",
265 Offset - Data.getStringOffsetSize());
266 LR.FuncName = GR.getString(NameOffset);
267 bool Done = false;
268 std::optional<LineEntry> LineEntry;
269 std::optional<GsymDataExtractor> InlineInfoData;
270 while (!Done) {
271 if (!Data.isValidOffsetForDataOfSize(Offset, 8))
272 return createStringError(std::errc::io_error,
273 "FunctionInfo data is truncated");
274 const uint32_t IT = Data.getU32(&Offset);
275 const uint32_t InfoLength = Data.getU32(&Offset);
276 const StringRef InfoBytes = Data.getData().substr(Offset, InfoLength);
277 if (InfoLength != InfoBytes.size())
278 return createStringError(std::errc::io_error,
279 "FunctionInfo data is truncated");
280 GsymDataExtractor InfoData(Data, Offset, InfoLength);
281 switch (IT) {
283 Done = true;
284 break;
285
287 if (auto ExpectedLE = LineTable::lookup(InfoData, FuncAddr, Addr))
288 LineEntry = ExpectedLE.get();
289 else
290 return ExpectedLE.takeError();
291 break;
292
294 // Store the merged functions data for later parsing, if needed.
295 if (MergedFuncsData)
296 *MergedFuncsData = InfoData;
297 break;
298
300 // We will parse the inline info after our line table, but only if
301 // we have a line entry.
302 InlineInfoData = InfoData;
303 break;
304
306 if (auto CSIC = CallSiteInfoCollection::decode(InfoData)) {
307 // Find matching call site based on relative offset
308 for (const auto &CS : CSIC->CallSites) {
309 // Check if the call site matches the lookup address
310 if (CS.ReturnOffset == Addr - FuncAddr) {
311 // Get regex patterns
312 for (gsym_strp_t RegexOffset : CS.MatchRegex) {
313 LR.CallSiteFuncRegex.push_back(GR.getString(RegexOffset));
314 }
315 break;
316 }
317 }
318 } else {
319 return CSIC.takeError();
320 }
321 break;
322
323 default:
324 break;
325 }
326 Offset += InfoLength;
327 }
328
329 if (!LineEntry) {
330 // We don't have a valid line entry for our address, fill in our source
331 // location as best we can and return.
332 SourceLocation SrcLoc;
333 SrcLoc.Name = LR.FuncName;
334 SrcLoc.Offset = Addr - FuncAddr;
335 LR.Locations.push_back(SrcLoc);
336 return LR;
337 }
338
339 std::optional<FileEntry> LineEntryFile = GR.getFile(LineEntry->File);
340 if (!LineEntryFile)
341 return createStringError(std::errc::invalid_argument,
342 "failed to extract file[%" PRIu32 "]",
343 LineEntry->File);
344
345 SourceLocation SrcLoc;
346 SrcLoc.Name = LR.FuncName;
347 SrcLoc.Offset = Addr - FuncAddr;
348 SrcLoc.Dir = GR.getString(LineEntryFile->Dir);
349 SrcLoc.Base = GR.getString(LineEntryFile->Base);
350 SrcLoc.Line = LineEntry->Line;
351 LR.Locations.push_back(SrcLoc);
352 // If we don't have inline information, we are done.
353 if (!InlineInfoData)
354 return LR;
355 // We have inline information. Try to augment the lookup result with this
356 // data.
357 llvm::Error Err = InlineInfo::lookup(GR, *InlineInfoData, FuncAddr, Addr,
358 LR.Locations);
359 if (Err)
360 return std::move(Err);
361 return LR;
362}
static cl::opt< ITMode > IT(cl::desc("IT block support"), cl::Hidden, cl::init(DefaultIT), cl::values(clEnumValN(DefaultIT, "arm-default-it", "Generate any type of IT block"), clEnumValN(RestrictedIT, "arm-restrict-it", "Disallow complex IT blocks")))
InfoType
FunctionInfo information type that is used to encode the optional data that is associated with a Func...
@ MergedFunctionsInfo
@ EndOfList
@ CallSiteInfo
@ InlineInfo
@ LineTableInfo
#define HEX32(v)
IRTranslator LLVM IR MI
uint64_t IntrinsicInst * II
bool contains(uint64_t Addr) const
uint64_t size() const
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Tagged union holding either a T or a Error.
Definition Error.h:485
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
constexpr size_t size() const
size - Get the string size.
Definition StringRef.h:143
A simplified binary data writer class that doesn't require targets, target definitions,...
Definition FileWriter.h:30
LLVM_ABI uint64_t tell()
Return the current offset within the file.
LLVM_ABI void fixup32(uint32_t Value, uint64_t Offset)
Fixup a uint32_t value at the specified offset in the stream.
LLVM_ABI void alignTo(size_t Align)
Pad with zeroes at the current file position until the current file position matches the specified al...
LLVM_ABI void writeStringOffset(uint64_t Value)
Write a string table offset of StringOffsetSize bytes into the stream.
LLVM_ABI void writeU32(uint32_t Value)
Write a single uint32_t value into the stream at the current file position.
void setStringOffsetSize(uint8_t Size)
Set the string offset size for this writer.
Definition FileWriter.h:139
LLVM_ABI void writeData(llvm::ArrayRef< uint8_t > Data)
Write an array of uint8_t values into the stream at the current file position.
llvm::endianness getByteOrder() const
Definition FileWriter.h:134
GsymCreator is used to emit GSYM data to a stand alone file or section within a file.
A DataExtractor subclass that adds GSYM-specific string offset support.
GsymReader is used to read GSYM data from a file or buffer.
Definition GsymReader.h:48
StringRef getString(gsym_strp_t Offset) const
Get a string from the string table.
Definition GsymReader.h:173
std::optional< FileEntry > getFile(uint32_t Index) const
Get the a file entry for the suppplied file index.
Definition GsymReader.h:184
static LLVM_ABI Expected< LineEntry > lookup(GsymDataExtractor &Data, uint64_t BaseAddr, uint64_t Addr)
Lookup a single address within a line table's data.
static LLVM_ABI llvm::Expected< LineTable > decode(GsymDataExtractor &Data, uint64_t BaseAddr)
Decode an LineTable object from a binary data stream.
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A raw_ostream that writes to an SmallVector or SmallString.
uint64_t gsym_strp_t
The type of string offset used in the code.
Definition GsymTypes.h:21
LLVM_ABI raw_ostream & operator<<(raw_ostream &OS, const CallSiteInfo &CSI)
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:532
@ Length
Definition DWP.cpp:532
@ Done
Definition Threading.h:60
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
FunctionAddr VTableAddr uintptr_t uintptr_t Data
Definition InstrProf.h:221
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
static LLVM_ABI llvm::Expected< CallSiteInfoCollection > decode(GsymDataExtractor &Data)
Decode a CallSiteInfoCollection object from a binary data stream.
Function information in GSYM files encodes information for one contiguous address range.
std::optional< InlineInfo > Inline
std::optional< MergedFunctionsInfo > MergedFunctions
static LLVM_ABI llvm::Expected< FunctionInfo > decode(GsymDataExtractor &Data, uint64_t BaseAddr)
Decode an object from a binary data stream.
bool isValid() const
Query if a FunctionInfo object is valid.
std::optional< CallSiteInfoCollection > CallSites
uint64_t size() const
FunctionInfo(uint64_t Addr=0, uint64_t Size=0, gsym_strp_t Name=0)
gsym_strp_t Name
String table offset in the string table.
LLVM_ABI llvm::Expected< uint64_t > encode(FileWriter &O, bool NoPadding=false) const
Encode this object into FileWriter stream.
SmallString< 32 > EncodingCache
If we encode a FunctionInfo during segmenting so we know its size, we can cache that encoding here so...
std::optional< LineTable > OptLineTable
LLVM_ABI uint64_t cacheEncoding(GsymCreator &GC)
Encode this function info into the internal byte cache and return the size in bytes.
static LLVM_ABI llvm::Expected< LookupResult > lookup(GsymDataExtractor &Data, const GsymReader &GR, uint64_t FuncAddr, uint64_t Addr, std::optional< GsymDataExtractor > *MergedFuncsData=nullptr)
Lookup an address within a FunctionInfo object's data stream.
Inline information stores the name of the inline function along with an array of address ranges.
Definition InlineInfo.h:61
static LLVM_ABI llvm::Expected< InlineInfo > decode(GsymDataExtractor &Data, uint64_t BaseAddr)
Decode an InlineInfo object from a binary data stream.
static LLVM_ABI llvm::Error lookup(const GsymReader &GR, GsymDataExtractor &Data, uint64_t BaseAddr, uint64_t Addr, SourceLocations &SrcLocs)
Lookup a single address within the inline info data.
Line entries are used to encode the line tables in FunctionInfo objects.
Definition LineEntry.h:22
uint32_t File
1 based index of file in FileTable
Definition LineEntry.h:24
uint32_t Line
Source line number.
Definition LineEntry.h:25
uint64_t LookupAddr
The address that this lookup pertains to.
AddressRange FuncRange
The concrete function address range.
std::vector< StringRef > CallSiteFuncRegex
Function name regex patterns associated with a call site at the lookup address.
StringRef FuncName
The concrete function name that contains LookupAddr.
SourceLocations Locations
The source locations that match this address.
static LLVM_ABI llvm::Expected< MergedFunctionsInfo > decode(GsymDataExtractor &Data, uint64_t BaseAddr)
Decode an MergedFunctionsInfo object from a binary data stream.
StringRef Base
Line entry source file basename.
uint32_t Line
Source file line number.
uint32_t Offset
Byte size offset within the named function.
StringRef Dir
Line entry source file directory path.
StringRef Name
Function or symbol name.