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