LLVM: lib/DebugInfo/GSYM/GsymReader.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
10
11#include <assert.h>
12#include <inttypes.h>
13#include <stdio.h>
14#include <stdlib.h>
15
21
22using namespace llvm;
23using namespace gsym;
24
25GsymReader::GsymReader(std::unique_ptr Buffer)
27
28GsymReader::GsymReader(GsymReader &&RHS) = default;
29
31
33
36 auto Err = BuffOrErr.getError();
37 if (Err)
40}
41
44 return create(MemBuffer);
45}
46
49 if (!MemBuffer)
51 "invalid memory buffer");
54 if (Err)
55 return std::move(Err);
56 return std::move(GR);
57}
58
60GsymReader::parse() {
62
63
64
65 if (FileData.readObject(Hdr))
67 "not enough data for a GSYM header");
68
70 switch (Hdr->Magic) {
72 Endian = HostByteOrder;
73 break;
75
78 Swap.reset(new SwappedData);
79 break;
80 default:
82 "not a GSYM file");
83 }
84
86
87 if (Swap) {
88 DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
90 Swap->Hdr = ExpectedHdr.get();
91 else
92 return ExpectedHdr.takeError();
93 Hdr = &Swap->Hdr;
94 }
95
96
97
98
100 return Err;
101
102 if (!Swap) {
103
104
105
106
107
108 if (FileData.padToAlignment(Hdr->AddrOffSize) ||
109 FileData.readArray(AddrOffsets,
112 "failed to read address table");
113
114
115 if (FileData.padToAlignment(4) ||
116 FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses))
118 "failed to read address info offsets table");
119
120
122 if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles))
124 "failed to read file table");
125
126
128 if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize))
130 "failed to read string table");
131} else {
132
133
134
135
136 DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
137
138
142 case 1:
145 "failed to read address table");
146 break;
147 case 2:
149 reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
152 "failed to read address table");
153 break;
154 case 4:
156 reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
159 "failed to read address table");
160 break;
161 case 8:
163 reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
166 "failed to read address table");
167 }
169
170
172 Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
175 else
177 "failed to read address table");
178
180 if (NumFiles > 0) {
181 Swap->Files.resize(NumFiles);
182 if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2))
184 else
186 "failed to read file table");
187 }
188
189 StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset,
193 "failed to read string table");
194 }
196
197}
198
200
201
202
204 return *Hdr;
205}
206
209 case 1: return addressForIndex<uint8_t>(Index);
210 case 2: return addressForIndex<uint16_t>(Index);
211 case 4: return addressForIndex<uint32_t>(Index);
212 case 8: return addressForIndex<uint64_t>(Index);
213 }
214 return std::nullopt;
215}
216
218 const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
219 if (Index < NumAddrInfoOffsets)
220 return AddrInfoOffsets[Index];
221 return std::nullopt;
222}
223
228 std::optional<uint64_t> AddrOffsetIndex;
230 case 1:
231 AddrOffsetIndex = getAddressOffsetIndex<uint8_t>(AddrOffset);
232 break;
233 case 2:
234 AddrOffsetIndex = getAddressOffsetIndex<uint16_t>(AddrOffset);
235 break;
236 case 4:
237 AddrOffsetIndex = getAddressOffsetIndex<uint32_t>(AddrOffset);
238 break;
239 case 8:
240 AddrOffsetIndex = getAddressOffsetIndex<uint64_t>(AddrOffset);
241 break;
242 default:
244 "unsupported address offset size %u",
246 }
247 if (AddrOffsetIndex)
248 return *AddrOffsetIndex;
249 }
251 "address 0x%" PRIx64 " is not in GSYM", Addr);
252
253}
254
257 uint64_t &FuncStartAddr) const {
259 if (!ExpectedAddrIdx)
260 return ExpectedAddrIdx.takeError();
261 const uint64_t FirstAddrIdx = *ExpectedAddrIdx;
262
263
264
265 std::optional<uint64_t> FirstFuncStartAddr;
267 for (uint64_t AddrIdx = FirstAddrIdx; AddrIdx < NumAddresses; ++AddrIdx) {
269
270 if (!ExpextedData)
271 return ExpextedData;
272
273
274
275
276 if (FirstFuncStartAddr.has_value()) {
277 if (*FirstFuncStartAddr != FuncStartAddr)
278 break;
279 } else {
280 FirstFuncStartAddr = FuncStartAddr;
281 }
282
283
284
285
286
287
290 if (FuncSize == 0 ||
292 return ExpextedData;
293 }
295 "address 0x%" PRIx64 " is not in GSYM", Addr);
296}
297
300 uint64_t &FuncStartAddr) const {
303 "invalid address index %" PRIu64, AddrIdx);
304 const uint32_t AddrInfoOffset = AddrInfoOffsets[AddrIdx];
306 "Endian must be either big or little");
307 StringRef Bytes = MemBuffer->getBuffer().substr(AddrInfoOffset);
308 if (Bytes.empty())
310 "invalid address info offset 0x%" PRIx32,
311 AddrInfoOffset);
312 std::optional<uint64_t> OptFuncStartAddr = getAddress(AddrIdx);
313 if (!OptFuncStartAddr)
315 "failed to extract address[%" PRIu64 "]", AddrIdx);
316 FuncStartAddr = *OptFuncStartAddr;
318}
319
324 else
325 return ExpectedData.takeError();
326}
327
333 else
334 return ExpectedData.takeError();
335}
336
339 std::optional *MergedFunctionsData) const {
343 MergedFunctionsData);
344 else
345 return ExpectedData.takeError();
346}
347
350 std::vector Results;
351 std::optional MergedFunctionsData;
352
353
354 auto MainResult = lookup(Addr, &MergedFunctionsData);
355 if (!MainResult)
356 return MainResult.takeError();
357
358
359 Results.push_back(std::move(*MainResult));
360
361
362 if (MergedFunctionsData) {
363
364 auto ExpectedMergedFuncExtractors =
366 if (!ExpectedMergedFuncExtractors)
367 return ExpectedMergedFuncExtractors.takeError();
368
369
370 for (DataExtractor &MergedData : *ExpectedMergedFuncExtractors) {
372 MainResult->FuncRange.start(), Addr)) {
373 Results.push_back(std::move(*FI));
374 } else {
375 return FI.takeError();
376 }
377 }
378 }
379
381}
382
385
387
388 OS << "Address Table:\n";
389 OS << "INDEX OFFSET";
390
392 case 1: OS << "8 "; break;
393 case 2: OS << "16"; break;
394 case 4: OS << "32"; break;
395 case 8: OS << "64"; break;
396 default: OS << "??"; break;
397 }
398 OS << " (ADDRESS)\n";
399 OS << "====== =============================== \n";
403 case 1: OS << HEX8(getAddrOffsets<uint8_t>()[I]); break;
404 case 2: OS << HEX16(getAddrOffsets<uint16_t>()[I]); break;
405 case 4: OS << HEX32(getAddrOffsets<uint32_t>()[I]); break;
406 case 8: OS << HEX32(getAddrOffsets<uint64_t>()[I]); break;
407 default: break;
408 }
410 }
411
412 OS << "\nAddress Info Offsets:\n";
413 OS << "INDEX Offset\n";
414 OS << "====== ==========\n";
416 OS << format("[%4u] ", I) << HEX32(AddrInfoOffsets[I]) << "\n";
417
418 OS << "\nFiles:\n";
419 OS << "INDEX DIRECTORY BASENAME PATH\n";
420 OS << "====== ========== ========== ==============================\n";
421 for (uint32_t I = 0; I < Files.size(); ++I) {
425 OS << "\n";
426 }
427 OS << "\n" << StrTab << "\n";
428
430 OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": ";
433 else
435 }
436}
437
446
449
451 assert(Indent == 0 && "MergedFunctionsInfo should only exist at top level");
453 }
454}
455
458 OS << "++ Merged FunctionInfos[" << inx << "]:\n";
460 }
461}
462
465
466 std::string Flags;
467 auto addFlag = [&](const char *Flag) {
468 if (!Flags.empty())
469 Flags += " | ";
470 Flags += Flag;
471 };
472
474 Flags = "None";
475 else {
477 addFlag("InternalCall");
478
480 addFlag("ExternalCall");
481 }
482 OS << " Flags[" << Flags << "]";
483
485 OS << " MatchRegex[";
487 if (i > 0)
488 OS << ";";
490 }
491 OS << "]";
492 }
493}
494
498 OS << "CallSites (by relative return offset):\n";
499 for (const auto &CS : CSIC.CallSites) {
501 OS << " ";
503 OS << "\n";
504 }
505}
506
509 OS << "LineTable:\n";
510 for (auto &LE: LT) {
512 OS << " " << HEX64(LE.Addr) << ' ';
513 if (LE.File)
515 OS << ':' << LE.Line << '\n';
516 }
517}
518
520 if (Indent == 0)
521 OS << "InlineInfo:\n";
522 else
525 if (II.CallFile != 0) {
526 if (auto File = getFile(II.CallFile)) {
527 OS << " called from ";
530 }
531 }
532 OS << '\n';
533 for (const auto &ChildII: II.Children)
534 dump(OS, ChildII, Indent + 2);
535}
536
538 if (FE) {
539
540 if (FE->Dir == 0 && FE->Base == 0)
541 return;
544 if (!Dir.empty()) {
545 OS << Dir;
546 if (Dir.contains('\\') && !Dir.contains('/'))
547 OS << '\\';
548 else
549 OS << '/';
550 }
551 if (.empty()) {
553 }
554 if (!Dir.empty() || .empty())
555 return;
556 }
557 OS << "";
558}
Function Alias Analysis Results
Returns the sub type a function will return at a given Idx Should correspond to the result type of an ExtractValue instruction executed with just that one unsigned Idx
uint64_t IntrinsicInst * II
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
A class that represents an address range.
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
size - Get the array size.
Provides read only access to a subclass of BinaryStream.
Represents either an error or a value T.
std::error_code getError() const
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
static ErrorOr< std::unique_ptr< MemoryBuffer > > getFileOrSTDIN(const Twine &Filename, bool IsText=false, bool RequiresNullTerminator=true, std::optional< Align > Alignment=std::nullopt)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
StringRef - Represent a constant reference to a string, i.e.
constexpr bool empty() const
empty - Check if the string is empty.
GsymReader is used to read GSYM data from a file or buffer.
std::optional< FileEntry > getFile(uint32_t Index) const
Get the a file entry for the suppplied file index.
void dump(raw_ostream &OS)
Dump the entire Gsym data contained in this object.
uint32_t getNumAddresses() const
Get the number of addresses in this Gsym file.
static llvm::Expected< GsymReader > openFile(StringRef Path)
Construct a GsymReader from a file on disk.
std::optional< uint64_t > getAddress(size_t Index) const
Gets an address from the address table.
std::optional< uint64_t > getAddressInfoOffset(size_t Index) const
Given an address index, get the offset for the FunctionInfo.
StringRef getString(uint32_t Offset) const
Get a string from the string table.
llvm::Expected< FunctionInfo > getFunctionInfo(uint64_t Addr) const
Get the full function info for an address.
const Header & getHeader() const
Access the GSYM header.
llvm::Expected< llvm::DataExtractor > getFunctionInfoDataAtIndex(uint64_t AddrIdx, uint64_t &FuncStartAddr) const
Get the function data and address given an address index.
Expected< uint64_t > getAddressIndex(const uint64_t Addr) const
Given an address, find the address index.
static llvm::Expected< GsymReader > copyBuffer(StringRef Bytes)
Construct a GsymReader from a buffer.
llvm::Expected< LookupResult > lookup(uint64_t Addr, std::optional< DataExtractor > *MergedFuncsData=nullptr) const
Lookup an address in the a GSYM.
static llvm::Expected< llvm::gsym::GsymReader > create(std::unique_ptr< MemoryBuffer > &MemBuffer)
Create a GSYM from a memory buffer.
llvm::Expected< FunctionInfo > getFunctionInfoAtIndex(uint64_t AddrIdx) const
Get the full function info given an address index.
llvm::Expected< llvm::DataExtractor > getFunctionInfoDataForAddress(uint64_t Addr, uint64_t &FuncStartAddr) const
Given an address, find the correct function info data and function address.
llvm::Expected< std::vector< LookupResult > > lookupAll(uint64_t Addr) const
Lookup all merged functions for a given address.
LineTable class contains deserialized versions of line tables for each function's address ranges.
This class implements an extremely fast bulk output stream that can only output to a stream.
raw_ostream & indent(unsigned NumSpaces)
indent - Insert 'NumSpaces' spaces.
constexpr uint32_t GSYM_MAGIC
constexpr uint32_t GSYM_CIGAM
constexpr bool IsBigEndianHost
This is an optimization pass for GlobalISel generic memory operations.
void logAllUnhandledErrors(Error E, raw_ostream &OS, Twine ErrorBanner={})
Log all errors (if any) in E to OS.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
format_object< Ts... > format(const char *Fmt, const Ts &... Vals)
These are helper functions used to produce formatted output.
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Implement std::hash so that hash_code can be used in STL containers.
std::vector< CallSiteInfo > CallSites
std::vector< uint32_t > MatchRegex
Offsets into the string table for function names regex patterns.
uint64_t ReturnOffset
The return offset of the call site - relative to the function start.
Function information in GSYM files encodes information for one contiguous address range.
std::optional< InlineInfo > Inline
std::optional< MergedFunctionsInfo > MergedFunctions
std::optional< CallSiteInfoCollection > CallSites
static llvm::Expected< LookupResult > lookup(DataExtractor &Data, const GsymReader &GR, uint64_t FuncAddr, uint64_t Addr, std::optional< DataExtractor > *MergedFuncsData=nullptr)
Lookup an address within a FunctionInfo object's data stream.
uint32_t Name
String table offset in the string table.
std::optional< LineTable > OptLineTable
static llvm::Expected< FunctionInfo > decode(DataExtractor &Data, uint64_t BaseAddr)
Decode an object from a binary data stream.
Inline information stores the name of the inline function along with an array of address ranges.
static llvm::Expected< std::vector< DataExtractor > > getFuncsDataExtractors(DataExtractor &Data)
Get a vector of DataExtractor objects for the functions in this MergedFunctionsInfo object.
std::vector< FunctionInfo > MergedFunctions