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

553 }

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