LLVM  16.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 
14 #include <algorithm>
15 #include <inttypes.h>
16 
17 using namespace llvm;
18 using namespace gsym;
19 
20 
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 
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>
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 
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.
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 
224  uint64_t BaseAddr) {
225  uint64_t Offset = 0;
226  return ::decode(Data, Offset, BaseAddr);
227 }
228 
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 }
llvm::gsym::SourceLocations
std::vector< SourceLocation > SourceLocations
Definition: LookupResult.h:36
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
llvm::AddressRanges::contains
bool contains(uint64_t Addr) const
Definition: AddressRanges.h:62
InlineInfo.h
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:329
llvm::gsym::SourceLocation::Name
StringRef Name
Function or symbol name.
Definition: LookupResult.h:22
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:41
llvm::gsym::InlineInfo::CallFile
uint32_t CallFile
1 based file index in the file table.
Definition: InlineInfo.h:62
llvm::gsym::InlineInfo
Inline information stores the name of the inline function along with an array of address ranges.
Definition: InlineInfo.h:59
llvm::Data
@ Data
Definition: SIMachineScheduler.h:55
llvm::gsym::SourceLocation::Dir
StringRef Dir
Line entry source file directory path.
Definition: LookupResult.h:23
llvm::gsym::SourceLocation::Offset
uint32_t Offset
Byte size offset within the named function.
Definition: LookupResult.h:26
llvm::gsym::decodeRanges
void decodeRanges(AddressRanges &Ranges, DataExtractor &Data, uint64_t BaseAddr, uint64_t &Offset)
Address ranges are decoded and encoded to be relative to a base address.
Definition: ExtractRanges.cpp:42
FileEntry.h
llvm::gsym::InlineInfo::CallLine
uint32_t CallLine
Source line number.
Definition: InlineInfo.h:63
llvm::gsym::GsymReader
GsymReader is used to read GSYM data from a file or buffer.
Definition: GsymReader.h:44
llvm::gsym::operator<<
raw_ostream & operator<<(raw_ostream &OS, const FunctionInfo &R)
Definition: FunctionInfo.cpp:28
llvm::gsym::InlineInfo::decode
static llvm::Expected< InlineInfo > decode(DataExtractor &Data, uint64_t BaseAddr)
Decode an InlineInfo object from a binary data stream.
Definition: InlineInfo.cpp:223
llvm::gsym::skipRanges
uint64_t skipRanges(DataExtractor &Data, uint64_t &Offset)
Skip an address range object in the specified data a the specified offset.
Definition: ExtractRanges.cpp:56
llvm::gsym::GsymReader::getString
StringRef getString(uint32_t Offset) const
Get a string from the string table.
Definition: GsymReader.h:130
skip
static bool skip(DataExtractor &Data, uint64_t &Offset, bool SkippedRanges)
Skip an InlineInfo object in the specified data at the specified offset.
Definition: InlineInfo.cpp:77
First
into llvm powi allowing the code generator to produce balanced multiplication trees First
Definition: README.txt:54
llvm::raw_ostream
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:53
llvm::RISCVFenceField::O
@ O
Definition: RISCVBaseInfo.h:264
llvm::gsym::InlineInfo::encode
llvm::Error encode(FileWriter &O, uint64_t BaseAddr) const
Encode this InlineInfo object into FileWriter stream.
Definition: InlineInfo.cpp:229
llvm::gsym::InlineInfo::Name
uint32_t Name
String table offset in the string table.
Definition: InlineInfo.h:61
uint64_t
llvm::gsym::InlineInfo::isValid
bool isValid() const
Definition: InlineInfo.h:74
llvm::gsym::InlineInfo::getInlineStack
std::optional< InlineArray > getInlineStack(uint64_t Addr) const
Lookup an address in the InlineInfo object.
Definition: InlineInfo.cpp:57
Addr
uint64_t Addr
Definition: ELFObjHandler.cpp:79
llvm::gsym::InlineInfo::InlineArray
std::vector< const InlineInfo * > InlineArray
Definition: InlineInfo.h:76
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
FileWriter.h
llvm::gsym::FileWriter
A simplified binary data writer class that doesn't require targets, target definitions,...
Definition: FileWriter.h:29
HEX32
#define HEX32(v)
Definition: ExtractRanges.h:20
llvm::gsym::SourceLocation::Base
StringRef Base
Line entry source file basename.
Definition: LookupResult.h:24
decode
static llvm::Expected< InlineInfo > decode(DataExtractor &Data, uint64_t &Offset, uint64_t BaseAddr)
Decode an InlineInfo in Data at the specified offset.
Definition: InlineInfo.cpp:180
llvm::Expected::get
reference get()
Returns a reference to the stored T value.
Definition: Error.h:566
uint32_t
GsymReader.h
llvm::gsym::encodeRanges
void encodeRanges(const AddressRanges &Ranges, FileWriter &O, uint64_t BaseAddr)
Definition: ExtractRanges.cpp:33
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1238
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
DataExtractor.h
llvm::Expected::takeError
Error takeError()
Take ownership of the stored error.
Definition: Error.h:596
llvm::gsym::InlineInfo::lookup
static llvm::Error lookup(const GsymReader &GR, DataExtractor &Data, uint64_t BaseAddr, uint64_t Addr, SourceLocations &SrcLocs)
Lookup a single address within the inline info data.
Definition: InlineInfo.cpp:160
llvm::DataExtractor
Definition: DataExtractor.h:41
llvm::gsym::InlineInfo::Ranges
AddressRanges Ranges
Definition: InlineInfo.h:64
lookup
static bool lookup(const GsymReader &GR, DataExtractor &Data, uint64_t &Offset, uint64_t BaseAddr, uint64_t Addr, SourceLocations &SrcLocs, llvm::Error &Err)
A Lookup helper functions.
Definition: InlineInfo.cpp:109
llvm::gsym::SourceLocation
Definition: LookupResult.h:21
llvm::StringRef::back
char back() const
back - Get the last character in the string.
Definition: StringRef.h:146
llvm::gsym::GsymReader::getFile
std::optional< FileEntry > getFile(uint32_t Index) const
Get the a file entry for the suppplied file index.
Definition: GsymReader.h:141
getInlineStackHelper
static bool getInlineStackHelper(const InlineInfo &II, uint64_t Addr, std::vector< const InlineInfo * > &InlineStack)
Definition: InlineInfo.cpp:39
llvm::gsym::InlineInfo::Children
std::vector< InlineInfo > Children
Definition: InlineInfo.h:65
llvm::gsym::SourceLocation::Line
uint32_t Line
Source file line number.
Definition: LookupResult.h:25