LLVM  12.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 
39 static bool getInlineStackHelper(const InlineInfo &II, uint64_t Addr,
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 
57  InlineArray Result;
58  if (getInlineStackHelper(*this, Addr, Result))
59  return Result;
60  return llvm::None;
61 }
62 
63 /// Skip an InlineInfo object in the specified data at the specified offset.
64 ///
65 /// Used during the InlineInfo::lookup() call to quickly skip child InlineInfo
66 /// objects where the addres ranges isn't contained in the InlineInfo object
67 /// or its children. This avoids allocations by not appending child InlineInfo
68 /// objects to the InlineInfo::Children array.
69 ///
70 /// \param Data The binary stream to read the data from.
71 ///
72 /// \param Offset The byte offset within \a Data.
73 ///
74 /// \param SkippedRanges If true, address ranges have already been skipped.
75 
76 static bool skip(DataExtractor &Data, uint64_t &Offset, bool SkippedRanges) {
77  if (!SkippedRanges) {
78  if (AddressRanges::skip(Data, Offset) == 0)
79  return false;
80  }
81  bool HasChildren = Data.getU8(&Offset) != 0;
82  Data.getU32(&Offset); // Skip Inline.Name.
83  Data.getULEB128(&Offset); // Skip Inline.CallFile.
84  Data.getULEB128(&Offset); // Skip Inline.CallLine.
85  if (HasChildren) {
86  while (skip(Data, Offset, false /* SkippedRanges */))
87  /* Do nothing */;
88  }
89  // We skipped a valid InlineInfo.
90  return true;
91 }
92 
93 /// A Lookup helper functions.
94 ///
95 /// Used during the InlineInfo::lookup() call to quickly only parse an
96 /// InlineInfo object if the address falls within this object. This avoids
97 /// allocations by not appending child InlineInfo objects to the
98 /// InlineInfo::Children array and also skips any InlineInfo objects that do
99 /// not contain the address we are looking up.
100 ///
101 /// \param Data The binary stream to read the data from.
102 ///
103 /// \param Offset The byte offset within \a Data.
104 ///
105 /// \param BaseAddr The address that the relative address range offsets are
106 /// relative to.
107 
108 static bool lookup(const GsymReader &GR, DataExtractor &Data, uint64_t &Offset,
109  uint64_t BaseAddr, uint64_t Addr, SourceLocations &SrcLocs,
110  llvm::Error &Err) {
111  InlineInfo Inline;
112  Inline.Ranges.decode(Data, BaseAddr, Offset);
113  if (Inline.Ranges.empty())
114  return true;
115  // Check if the address is contained within the inline information, and if
116  // not, quickly skip this InlineInfo object and all its children.
117  if (!Inline.Ranges.contains(Addr)) {
118  skip(Data, Offset, true /* SkippedRanges */);
119  return false;
120  }
121 
122  // The address range is contained within this InlineInfo, add the source
123  // location for this InlineInfo and any children that contain the address.
124  bool HasChildren = Data.getU8(&Offset) != 0;
125  Inline.Name = Data.getU32(&Offset);
126  Inline.CallFile = (uint32_t)Data.getULEB128(&Offset);
127  Inline.CallLine = (uint32_t)Data.getULEB128(&Offset);
128  if (HasChildren) {
129  // Child address ranges are encoded relative to the first address in the
130  // parent InlineInfo object.
131  const auto ChildBaseAddr = Inline.Ranges[0].Start;
132  bool Done = false;
133  while (!Done)
134  Done = lookup(GR, Data, Offset, ChildBaseAddr, Addr, SrcLocs, Err);
135  }
136 
138  if (!CallFile) {
139  Err = createStringError(std::errc::invalid_argument,
140  "failed to extract file[%" PRIu32 "]",
141  Inline.CallFile);
142  return false;
143  }
144 
145  if (CallFile->Dir || CallFile->Base) {
146  SourceLocation SrcLoc;
147  SrcLoc.Name = SrcLocs.back().Name;
148  SrcLoc.Offset = SrcLocs.back().Offset;
149  SrcLoc.Dir = GR.getString(CallFile->Dir);
150  SrcLoc.Base = GR.getString(CallFile->Base);
151  SrcLoc.Line = Inline.CallLine;
152  SrcLocs.back().Name = GR.getString(Inline.Name);
153  SrcLocs.back().Offset = Addr - Inline.Ranges[0].Start;
154  SrcLocs.push_back(SrcLoc);
155  }
156  return true;
157 }
158 
160  uint64_t BaseAddr, uint64_t Addr,
161  SourceLocations &SrcLocs) {
162  // Call our recursive helper function starting at offset zero.
163  uint64_t Offset = 0;
164  llvm::Error Err = Error::success();
165  ::lookup(GR, Data, Offset, BaseAddr, Addr, SrcLocs, Err);
166  return Err;
167 }
168 
169 /// Decode an InlineInfo in Data at the specified offset.
170 ///
171 /// A local helper function to decode InlineInfo objects. This function is
172 /// called recursively when parsing child InlineInfo objects.
173 ///
174 /// \param Data The data extractor to decode from.
175 /// \param Offset The offset within \a Data to decode from.
176 /// \param BaseAddr The base address to use when decoding address ranges.
177 /// \returns An InlineInfo or an error describing the issue that was
178 /// encountered during decoding.
180  uint64_t BaseAddr) {
181  InlineInfo Inline;
182  if (!Data.isValidOffset(Offset))
183  return createStringError(std::errc::io_error,
184  "0x%8.8" PRIx64 ": missing InlineInfo address ranges data", Offset);
185  Inline.Ranges.decode(Data, BaseAddr, Offset);
186  if (Inline.Ranges.empty())
187  return Inline;
188  if (!Data.isValidOffsetForDataOfSize(Offset, 1))
189  return createStringError(std::errc::io_error,
190  "0x%8.8" PRIx64 ": missing InlineInfo uint8_t indicating children",
191  Offset);
192  bool HasChildren = Data.getU8(&Offset) != 0;
193  if (!Data.isValidOffsetForDataOfSize(Offset, 4))
194  return createStringError(std::errc::io_error,
195  "0x%8.8" PRIx64 ": missing InlineInfo uint32_t for name", Offset);
196  Inline.Name = Data.getU32(&Offset);
197  if (!Data.isValidOffset(Offset))
198  return createStringError(std::errc::io_error,
199  "0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call file", Offset);
200  Inline.CallFile = (uint32_t)Data.getULEB128(&Offset);
201  if (!Data.isValidOffset(Offset))
202  return createStringError(std::errc::io_error,
203  "0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call line", Offset);
204  Inline.CallLine = (uint32_t)Data.getULEB128(&Offset);
205  if (HasChildren) {
206  // Child address ranges are encoded relative to the first address in the
207  // parent InlineInfo object.
208  const auto ChildBaseAddr = Inline.Ranges[0].Start;
209  while (true) {
210  llvm::Expected<InlineInfo> Child = decode(Data, Offset, ChildBaseAddr);
211  if (!Child)
212  return Child.takeError();
213  // InlineInfo with empty Ranges termintes a child sibling chain.
214  if (Child.get().Ranges.empty())
215  break;
216  Inline.Children.emplace_back(std::move(*Child));
217  }
218  }
219  return Inline;
220 }
221 
223  uint64_t BaseAddr) {
224  uint64_t Offset = 0;
225  return ::decode(Data, Offset, BaseAddr);
226 }
227 
228 llvm::Error InlineInfo::encode(FileWriter &O, uint64_t BaseAddr) const {
229  // Users must verify the InlineInfo is valid prior to calling this funtion.
230  // We don't want to emit any InlineInfo objects if they are not valid since
231  // it will waste space in the GSYM file.
232  if (!isValid())
233  return createStringError(std::errc::invalid_argument,
234  "attempted to encode invalid InlineInfo object");
235  Ranges.encode(O, BaseAddr);
236  bool HasChildren = !Children.empty();
237  O.writeU8(HasChildren);
238  O.writeU32(Name);
239  O.writeULEB(CallFile);
240  O.writeULEB(CallLine);
241  if (HasChildren) {
242  // Child address ranges are encoded as relative to the first
243  // address in the Ranges for this object. This keeps the offsets
244  // small and allows for efficient encoding using ULEB offsets.
245  const uint64_t ChildBaseAddr = Ranges[0].Start;
246  for (const auto &Child : Children) {
247  // Make sure all child address ranges are contained in the parent address
248  // ranges.
249  for (const auto &ChildRange: Child.Ranges) {
250  if (!Ranges.contains(ChildRange))
251  return createStringError(std::errc::invalid_argument,
252  "child range not contained in parent");
253  }
254  llvm::Error Err = Child.encode(O, ChildBaseAddr);
255  if (Err)
256  return Err;
257  }
258 
259  // Terminate child sibling chain by emitting a zero. This zero will cause
260  // the decodeAll() function above to return false and stop the decoding
261  // of child InlineInfo objects that are siblings.
262  O.writeULEB(0);
263  }
264  return Error::success();
265 }
GsymReader is used to read GSYM data from a file or buffer.
Definition: GsymReader.h:47
uint8_t getU8(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint8_t value from *offset_ptr.
static uint64_t skip(DataExtractor &Data, uint64_t &Offset)
Skip an address range object in the specified data a the specified offset.
Definition: Range.cpp:119
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:159
StringRef Base
Line entry source file basename.
Definition: LookupResult.h:25
This class represents lattice values for constants.
Definition: AllocatorList.h:23
StringRef Dir
Line entry source file directory path.
Definition: LookupResult.h:24
void writeU8(uint8_t Value)
Write a single uint8_t value into the stream at the current file position.
Definition: FileWriter.cpp:34
void writeULEB(uint64_t Value)
Write the value into the stream encoded using unsigned LEB128 at the current file position...
Definition: FileWriter.cpp:27
Inline information stores the name of the inline function along with an array of address ranges...
Definition: InlineInfo.h:61
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:76
bool contains(uint64_t Addr) const
Definition: Range.cpp:38
uint32_t Line
Source file line number.
Definition: LookupResult.h:26
uint32_t getU32(uint64_t *offset_ptr, Error *Err=nullptr) const
Extract a uint32_t value from *offset_ptr.
uint32_t Dir
Offsets in the string table.
Definition: FileEntry.h:29
Error takeError()
Take ownership of the stored error.
Definition: Error.h:557
void writeU32(uint32_t Value)
Write a single uint32_t value into the stream at the current file position.
Definition: FileWriter.cpp:43
uint32_t Name
String table offset in the string table.
Definition: InlineInfo.h:63
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
Optional< FileEntry > getFile(uint32_t Index) const
Get the a file entry for the suppplied file index.
Definition: GsymReader.h:144
StringRef getString(uint32_t Offset) const
Get a string from the string table.
Definition: GsymReader.h:133
std::vector< InlineInfo > Children
Definition: InlineInfo.h:67
llvm::Optional< InlineArray > getInlineStack(uint64_t Addr) const
Lookup an address in the InlineInfo object.
Definition: InlineInfo.cpp:56
A simplified binary data writer class that doesn&#39;t require targets, target definitions, architectures, or require any other optional compile time libraries to be enabled via the build process.
Definition: FileWriter.h:29
bool empty() const
Definition: Range.h:90
uint64_t getULEB128(uint64_t *offset_ptr, llvm::Error *Err=nullptr) const
Extract a unsigned LEB128 value from *offset_ptr.
static llvm::Expected< InlineInfo > decode(DataExtractor &Data, uint64_t BaseAddr)
Decode an InlineInfo object from a binary data stream.
Definition: InlineInfo.cpp:222
std::vector< const InlineInfo * > InlineArray
Definition: InlineInfo.h:78
uint32_t CallFile
1 based file index in the file table.
Definition: InlineInfo.h:64
StringRef Name
Function or symbol name.
Definition: LookupResult.h:23
LLVM_NODISCARD char back() const
back - Get the last character in the string.
Definition: StringRef.h:171
uint32_t Offset
Byte size offset within the named function.
Definition: LookupResult.h:27
AddressRanges Ranges
Definition: InlineInfo.h:66
static ErrorSuccess success()
Create a success value.
Definition: Error.h:332
bool isValidOffsetForDataOfSize(uint64_t offset, uint64_t length) const
Test the availability of length bytes of data from offset.
std::vector< SourceLocation > SourceLocations
Definition: LookupResult.h:38
reference get()
Returns a reference to the stored T value.
Definition: Error.h:537
void encode(FileWriter &O, uint64_t BaseAddr) const
Definition: Range.cpp:95
bool isValidOffset(uint64_t offset) const
Test the validity of offset.
uint32_t CallLine
Source line number.
Definition: InlineInfo.h:65
static bool getInlineStackHelper(const InlineInfo &II, uint64_t Addr, std::vector< const InlineInfo *> &InlineStack)
Definition: InlineInfo.cpp:39
void decode(DataExtractor &Data, uint64_t BaseAddr, uint64_t &Offset)
Address ranges are decoded and encoded to be relative to a base address.
Definition: Range.cpp:103
#define HEX32(v)
Definition: Range.h:20
bool isValid() const
Definition: InlineInfo.h:76
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:179
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:46
llvm::Error encode(FileWriter &O, uint64_t BaseAddr) const
Encode this InlineInfo object into FileWriter stream.
Definition: InlineInfo.cpp:228
raw_ostream & operator<<(raw_ostream &OS, const FunctionInfo &R)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1202