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");
52 GsymReader GR(std::move(MemBuffer));
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
139 uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize);
140 Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize);
141 switch (Hdr->AddrOffSize) {
142 case 1:
143 if (.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses))
145 "failed to read address table");
146 break;
147 case 2:
149 reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
150 Hdr->NumAddresses))
152 "failed to read address table");
153 break;
154 case 4:
156 reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
157 Hdr->NumAddresses))
159 "failed to read address table");
160 break;
161 case 8:
163 reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
164 Hdr->NumAddresses))
166 "failed to read address table");
167 }
168 AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
169
170
172 Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
173 if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses))
174 AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets);
175 else
177 "failed to read address table");
178
179 const uint32_t NumFiles = Data.getU32(&Offset);
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,
190 Hdr->StrtabSize);
191 if (StrTab.Data.empty())
193 "failed to read string table");
194 }
196
197}
198
200
201
202
204 return *Hdr;
205}
206
208 switch (Hdr->AddrOffSize) {
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
226 if (Addr >= Hdr->BaseAddress) {
227 const uint64_t AddrOffset = Addr - Hdr->BaseAddress;
228 std::optional<uint64_t> AddrOffsetIndex;
229 switch (Hdr->AddrOffSize) {
230 case 1:
232 break;
233 case 2:
235 break;
236 case 4:
238 break;
239 case 8:
241 break;
242 default:
244 "unsupported address offset size %u",
245 Hdr->AddrOffSize);
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
386 OS << Header << "\n";
387
388 OS << "Address Table:\n";
389 OS << "INDEX OFFSET";
390
391 switch (Hdr->AddrOffSize) {
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";
401 OS << format("[%4u] ", I);
402 switch (Hdr->AddrOffSize) {
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) {
422 OS << format("[%4u] ", I) << HEX32(Files[I].Dir) << ' '
425 OS << "\n";
426 }
427 OS << "\n" << StrTab << "\n";
428
430 OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": ";
432 dump(OS, *FI);
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 << " ";
502 dump(OS, CS);
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 ";
528 dump(OS, File);
529 OS << ':' << II.CallLine;
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}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
Function Alias Analysis Results
uint64_t IntrinsicInst * II
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
A class that represents an address range.
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 StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
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.
LLVM_ABI void dump(raw_ostream &OS)
Dump the entire Gsym data contained in this object.
Definition GsymReader.cpp:383
uint32_t getNumAddresses() const
Get the number of addresses in this Gsym file.
static LLVM_ABI llvm::Expected< GsymReader > openFile(StringRef Path)
Construct a GsymReader from a file on disk.
Definition GsymReader.cpp:32
LLVM_ABI std::optional< uint64_t > getAddress(size_t Index) const
Gets an address from the address table.
Definition GsymReader.cpp:207
LLVM_ABI std::optional< uint64_t > getAddressInfoOffset(size_t Index) const
Given an address index, get the offset for the FunctionInfo.
Definition GsymReader.cpp:217
StringRef getString(uint32_t Offset) const
Get a string from the string table.
LLVM_ABI llvm::Expected< FunctionInfo > getFunctionInfo(uint64_t Addr) const
Get the full function info for an address.
Definition GsymReader.cpp:320
LLVM_ABI const Header & getHeader() const
Access the GSYM header.
Definition GsymReader.cpp:199
std::optional< uint64_t > addressForIndex(size_t Index) const
Get an appropriate address from the address table.
LLVM_ABI llvm::Expected< llvm::DataExtractor > getFunctionInfoDataAtIndex(uint64_t AddrIdx, uint64_t &FuncStartAddr) const
Get the function data and address given an address index.
Definition GsymReader.cpp:299
LLVM_ABI Expected< uint64_t > getAddressIndex(const uint64_t Addr) const
Given an address, find the address index.
Definition GsymReader.cpp:225
static LLVM_ABI llvm::Expected< GsymReader > copyBuffer(StringRef Bytes)
Construct a GsymReader from a buffer.
Definition GsymReader.cpp:42
LLVM_ABI llvm::Expected< LookupResult > lookup(uint64_t Addr, std::optional< DataExtractor > *MergedFuncsData=nullptr) const
Lookup an address in the a GSYM.
Definition GsymReader.cpp:338
static LLVM_ABI llvm::Expected< llvm::gsym::GsymReader > create(std::unique_ptr< MemoryBuffer > &MemBuffer)
Create a GSYM from a memory buffer.
Definition GsymReader.cpp:48
LLVM_ABI llvm::Expected< FunctionInfo > getFunctionInfoAtIndex(uint64_t AddrIdx) const
Get the full function info given an address index.
Definition GsymReader.cpp:329
LLVM_ABI llvm::Expected< llvm::DataExtractor > getFunctionInfoDataForAddress(uint64_t Addr, uint64_t &FuncStartAddr) const
Given an address, find the correct function info data and function address.
Definition GsymReader.cpp:256
LLVM_ABI llvm::Expected< std::vector< LookupResult > > lookupAll(uint64_t Addr) const
Lookup all merged functions for a given address.
Definition GsymReader.cpp:349
std::optional< uint64_t > getAddressOffsetIndex(const uint64_t AddrOffset) const
Lookup an address offset in the AddrOffsets table.
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.
LLVM_ABI 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.
FunctionAddr VTableAddr uintptr_t uintptr_t Data
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
ArrayRef(const T &OneElt) -> ArrayRef< T >
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
LLVM_ABI 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_ABI 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_ABI 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_ABI 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