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 ";

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 (Base.empty()) {

553 }

554 if (!Dir.empty() || Base.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