LLVM 19.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
15#include <optional>
16
17using namespace llvm;
18using namespace gsym;
19
20/// FunctionInfo information type that is used to encode the optional data
21/// that is associated with a FunctionInfo object.
25 InlineInfo = 2u
26};
27
29 OS << FI.Range << ": " << "Name=" << HEX32(FI.Name) << '\n';
30 if (FI.OptLineTable)
31 OS << FI.OptLineTable << '\n';
32 if (FI.Inline)
33 OS << FI.Inline << '\n';
34 return OS;
35}
36
38 uint64_t BaseAddr) {
39 FunctionInfo FI;
40 uint64_t Offset = 0;
41 if (!Data.isValidOffsetForDataOfSize(Offset, 4))
42 return createStringError(std::errc::io_error,
43 "0x%8.8" PRIx64 ": missing FunctionInfo Size", Offset);
44 FI.Range = {BaseAddr, BaseAddr + Data.getU32(&Offset)};
45 if (!Data.isValidOffsetForDataOfSize(Offset, 4))
46 return createStringError(std::errc::io_error,
47 "0x%8.8" PRIx64 ": missing FunctionInfo Name", Offset);
48 FI.Name = Data.getU32(&Offset);
49 if (FI.Name == 0)
50 return createStringError(std::errc::io_error,
51 "0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x%8.8x",
52 Offset - 4, FI.Name);
53 bool Done = false;
54 while (!Done) {
55 if (!Data.isValidOffsetForDataOfSize(Offset, 4))
56 return createStringError(std::errc::io_error,
57 "0x%8.8" PRIx64 ": missing FunctionInfo InfoType value", Offset);
58 const uint32_t IT = Data.getU32(&Offset);
59 if (!Data.isValidOffsetForDataOfSize(Offset, 4))
60 return createStringError(std::errc::io_error,
61 "0x%8.8" PRIx64 ": missing FunctionInfo InfoType length", Offset);
62 const uint32_t InfoLength = Data.getU32(&Offset);
63 if (!Data.isValidOffsetForDataOfSize(Offset, InfoLength))
64 return createStringError(std::errc::io_error,
65 "0x%8.8" PRIx64 ": missing FunctionInfo data for InfoType %u",
66 Offset, IT);
67 DataExtractor InfoData(Data.getData().substr(Offset, InfoLength),
68 Data.isLittleEndian(),
69 Data.getAddressSize());
70 switch (IT) {
71 case InfoType::EndOfList:
72 Done = true;
73 break;
74
75 case InfoType::LineTableInfo:
76 if (Expected<LineTable> LT = LineTable::decode(InfoData, BaseAddr))
77 FI.OptLineTable = std::move(LT.get());
78 else
79 return LT.takeError();
80 break;
81
82 case InfoType::InlineInfo:
83 if (Expected<InlineInfo> II = InlineInfo::decode(InfoData, BaseAddr))
84 FI.Inline = std::move(II.get());
85 else
86 return II.takeError();
87 break;
88
89 default:
90 return createStringError(std::errc::io_error,
91 "0x%8.8" PRIx64 ": unsupported InfoType %u",
92 Offset-8, IT);
93 }
94 Offset += InfoLength;
95 }
96 return std::move(FI);
97}
98
101 if (!isValid())
102 return 0;
105 llvm::Expected<uint64_t> Result = encode(FW);
106 if (!Result) {
108 consumeError(Result.takeError());
109 return 0;
110 }
111 return EncodingCache.size();
112}
113
115 if (!isValid())
116 return createStringError(std::errc::invalid_argument,
117 "attempted to encode invalid FunctionInfo object");
118 // Align FunctionInfo data to a 4 byte alignment.
119 Out.alignTo(4);
120 const uint64_t FuncInfoOffset = Out.tell();
121 // Check if we have already encoded this function info into EncodingCache.
122 // This will be non empty when creating segmented GSYM files as we need to
123 // precompute exactly how big FunctionInfo objects encode into so we can
124 // accurately make segments of a specific size.
125 if (!EncodingCache.empty() &&
127 // We already encoded this object, just write out the bytes.
130 return FuncInfoOffset;
131 }
132 // Write the size in bytes of this function as a uint32_t. This can be zero
133 // if we just have a symbol from a symbol table and that symbol has no size.
134 Out.writeU32(size());
135 // Write the name of this function as a uint32_t string table offset.
136 Out.writeU32(Name);
137
138 if (OptLineTable) {
139 Out.writeU32(InfoType::LineTableInfo);
140 // Write a uint32_t length as zero for now, we will fix this up after
141 // writing the LineTable out with the number of bytes that were written.
142 Out.writeU32(0);
143 const auto StartOffset = Out.tell();
144 llvm::Error err = OptLineTable->encode(Out, Range.start());
145 if (err)
146 return std::move(err);
147 const auto Length = Out.tell() - StartOffset;
148 if (Length > UINT32_MAX)
149 return createStringError(std::errc::invalid_argument,
150 "LineTable length is greater than UINT32_MAX");
151 // Fixup the size of the LineTable data with the correct size.
152 Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
153 }
154
155 // Write out the inline function info if we have any and if it is valid.
156 if (Inline) {
157 Out.writeU32(InfoType::InlineInfo);
158 // Write a uint32_t length as zero for now, we will fix this up after
159 // writing the LineTable out with the number of bytes that were written.
160 Out.writeU32(0);
161 const auto StartOffset = Out.tell();
162 llvm::Error err = Inline->encode(Out, Range.start());
163 if (err)
164 return std::move(err);
165 const auto Length = Out.tell() - StartOffset;
166 if (Length > UINT32_MAX)
167 return createStringError(std::errc::invalid_argument,
168 "InlineInfo length is greater than UINT32_MAX");
169 // Fixup the size of the InlineInfo data with the correct size.
170 Out.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
171 }
172
173 // Terminate the data chunks with and end of list with zero size
174 Out.writeU32(InfoType::EndOfList);
175 Out.writeU32(0);
176 return FuncInfoOffset;
177}
178
179
181 const GsymReader &GR,
182 uint64_t FuncAddr,
183 uint64_t Addr) {
184 LookupResult LR;
185 LR.LookupAddr = Addr;
186 uint64_t Offset = 0;
187 LR.FuncRange = {FuncAddr, FuncAddr + Data.getU32(&Offset)};
188 uint32_t NameOffset = Data.getU32(&Offset);
189 // The "lookup" functions doesn't report errors as accurately as the "decode"
190 // function as it is meant to be fast. For more accurage errors we could call
191 // "decode".
192 if (!Data.isValidOffset(Offset))
193 return createStringError(std::errc::io_error,
194 "FunctionInfo data is truncated");
195 // This function will be called with the result of a binary search of the
196 // address table, we must still make sure the address does not fall into a
197 // gap between functions are after the last function.
198 if (LR.FuncRange.size() > 0 && !LR.FuncRange.contains(Addr))
199 return createStringError(std::errc::io_error,
200 "address 0x%" PRIx64 " is not in GSYM", Addr);
201
202 if (NameOffset == 0)
203 return createStringError(std::errc::io_error,
204 "0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x00000000",
205 Offset - 4);
206 LR.FuncName = GR.getString(NameOffset);
207 bool Done = false;
208 std::optional<LineEntry> LineEntry;
209 std::optional<DataExtractor> InlineInfoData;
210 while (!Done) {
211 if (!Data.isValidOffsetForDataOfSize(Offset, 8))
212 return createStringError(std::errc::io_error,
213 "FunctionInfo data is truncated");
214 const uint32_t IT = Data.getU32(&Offset);
215 const uint32_t InfoLength = Data.getU32(&Offset);
216 const StringRef InfoBytes = Data.getData().substr(Offset, InfoLength);
217 if (InfoLength != InfoBytes.size())
218 return createStringError(std::errc::io_error,
219 "FunctionInfo data is truncated");
220 DataExtractor InfoData(InfoBytes, Data.isLittleEndian(),
221 Data.getAddressSize());
222 switch (IT) {
223 case InfoType::EndOfList:
224 Done = true;
225 break;
226
227 case InfoType::LineTableInfo:
228 if (auto ExpectedLE = LineTable::lookup(InfoData, FuncAddr, Addr))
229 LineEntry = ExpectedLE.get();
230 else
231 return ExpectedLE.takeError();
232 break;
233
234 case InfoType::InlineInfo:
235 // We will parse the inline info after our line table, but only if
236 // we have a line entry.
237 InlineInfoData = InfoData;
238 break;
239
240 default:
241 break;
242 }
243 Offset += InfoLength;
244 }
245
246 if (!LineEntry) {
247 // We don't have a valid line entry for our address, fill in our source
248 // location as best we can and return.
249 SourceLocation SrcLoc;
250 SrcLoc.Name = LR.FuncName;
251 SrcLoc.Offset = Addr - FuncAddr;
252 LR.Locations.push_back(SrcLoc);
253 return LR;
254 }
255
256 std::optional<FileEntry> LineEntryFile = GR.getFile(LineEntry->File);
257 if (!LineEntryFile)
258 return createStringError(std::errc::invalid_argument,
259 "failed to extract file[%" PRIu32 "]",
260 LineEntry->File);
261
262 SourceLocation SrcLoc;
263 SrcLoc.Name = LR.FuncName;
264 SrcLoc.Offset = Addr - FuncAddr;
265 SrcLoc.Dir = GR.getString(LineEntryFile->Dir);
266 SrcLoc.Base = GR.getString(LineEntryFile->Base);
267 SrcLoc.Line = LineEntry->Line;
268 LR.Locations.push_back(SrcLoc);
269 // If we don't have inline information, we are done.
270 if (!InlineInfoData)
271 return LR;
272 // We have inline information. Try to augment the lookup result with this
273 // data.
274 llvm::Error Err = InlineInfo::lookup(GR, *InlineInfoData, FuncAddr, Addr,
275 LR.Locations);
276 if (Err)
277 return std::move(Err);
278 return LR;
279}
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")))
uint64_t Addr
#define HEX32(v)
Definition: ExtractRanges.h:19
InfoType
FunctionInfo information type that is used to encode the optional data that is associated with a Func...
@ EndOfList
@ LineTableInfo
raw_pwrite_stream & OS
uint64_t start() const
Definition: AddressRanges.h:28
bool contains(uint64_t Addr) const
Definition: AddressRanges.h:32
uint64_t size() const
Definition: AddressRanges.h:30
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: ArrayRef.h:41
Lightweight error class with error context and mandatory checking.
Definition: Error.h:160
Tagged union holding either a T or a Error.
Definition: Error.h:474
bool empty() const
Definition: SmallVector.h:94
size_t size() const
Definition: SmallVector.h:91
pointer data()
Return a pointer to the vector's buffer, even if empty().
Definition: SmallVector.h:299
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr size_t size() const
size - Get the string size.
Definition: StringRef.h:137
A simplified binary data writer class that doesn't require targets, target definitions,...
Definition: FileWriter.h:29
uint64_t tell()
Return the current offset within the file.
Definition: FileWriter.cpp:66
void fixup32(uint32_t Value, uint64_t Offset)
Fixup a uint32_t value at the specified offset in the stream.
Definition: FileWriter.cpp:52
void alignTo(size_t Align)
Pad with zeroes at the current file position until the current file position matches the specified al...
Definition: FileWriter.cpp:70
void writeU32(uint32_t Value)
Write a single uint32_t value into the stream at the current file position.
Definition: FileWriter.cpp:42
void writeData(llvm::ArrayRef< uint8_t > Data)
Write an array of uint8_t values into the stream at the current file position.
Definition: FileWriter.cpp:58
llvm::endianness getByteOrder() const
Definition: FileWriter.h:117
GsymReader is used to read GSYM data from a file or buffer.
Definition: GsymReader.h:44
std::optional< FileEntry > getFile(uint32_t Index) const
Get the a file entry for the suppplied file index.
Definition: GsymReader.h:150
StringRef getString(uint32_t Offset) const
Get a string from the string table.
Definition: GsymReader.h:139
static llvm::Expected< LineTable > decode(DataExtractor &Data, uint64_t BaseAddr)
Decode an LineTable object from a binary data stream.
Definition: LineTable.cpp:251
static Expected< LineEntry > lookup(DataExtractor &Data, uint64_t BaseAddr, uint64_t Addr)
Lookup a single address within a line table's data.
Definition: LineTable.cpp:266
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
A raw_ostream that writes to an SmallVector or SmallString.
Definition: raw_ostream.h:690
raw_ostream & operator<<(raw_ostream &OS, const FunctionInfo &R)
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:456
@ Length
Definition: DWP.cpp:456
@ Done
Definition: Threading.h:61
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1244
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1041
Function information in GSYM files encodes information for one contiguous address range.
Definition: FunctionInfo.h:88
std::optional< InlineInfo > Inline
Definition: FunctionInfo.h:92
bool isValid() const
Query if a FunctionInfo object is valid.
Definition: FunctionInfo.h:119
uint64_t size() const
Definition: FunctionInfo.h:187
static llvm::Expected< LookupResult > lookup(DataExtractor &Data, const GsymReader &GR, uint64_t FuncAddr, uint64_t Addr)
Lookup an address within a FunctionInfo object's data stream.
uint64_t cacheEncoding()
Encode this function info into the internal byte cache and return the size in bytes.
uint32_t Name
String table offset in the string table.
Definition: FunctionInfo.h:90
SmallString< 32 > EncodingCache
If we encode a FunctionInfo during segmenting so we know its size, we can cache that encoding here so...
Definition: FunctionInfo.h:96
std::optional< LineTable > OptLineTable
Definition: FunctionInfo.h:91
llvm::Expected< uint64_t > encode(FileWriter &O) const
Encode this object into FileWriter stream.
Inline information stores the name of the inline function along with an array of address ranges.
Definition: InlineInfo.h:59
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
static llvm::Expected< InlineInfo > decode(DataExtractor &Data, uint64_t BaseAddr)
Decode an InlineInfo object from a binary data stream.
Definition: InlineInfo.cpp:223
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.
Definition: LookupResult.h:39
AddressRange FuncRange
The concrete function address range.
Definition: LookupResult.h:40
StringRef FuncName
The concrete function name that contains LookupAddr.
Definition: LookupResult.h:41
SourceLocations Locations
The source locations that match this address.
Definition: LookupResult.h:51
StringRef Base
Line entry source file basename.
Definition: LookupResult.h:24
uint32_t Line
Source file line number.
Definition: LookupResult.h:25
uint32_t Offset
Byte size offset within the named function.
Definition: LookupResult.h:26
StringRef Dir
Line entry source file directory path.
Definition: LookupResult.h:23
StringRef Name
Function or symbol name.
Definition: LookupResult.h:22