GsymReader.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. //===- GsymReader.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. #include "llvm/DebugInfo/GSYM/GsymReader.h"
  9. #include <assert.h>
  10. #include <inttypes.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include "llvm/DebugInfo/GSYM/GsymCreator.h"
  14. #include "llvm/DebugInfo/GSYM/InlineInfo.h"
  15. #include "llvm/DebugInfo/GSYM/LineTable.h"
  16. #include "llvm/Support/BinaryStreamReader.h"
  17. #include "llvm/Support/DataExtractor.h"
  18. #include "llvm/Support/MemoryBuffer.h"
  19. using namespace llvm;
  20. using namespace gsym;
  21. GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) :
  22. MemBuffer(std::move(Buffer)),
  23. Endian(support::endian::system_endianness()) {}
  24. GsymReader::GsymReader(GsymReader &&RHS) = default;
  25. GsymReader::~GsymReader() = default;
  26. llvm::Expected<GsymReader> GsymReader::openFile(StringRef Filename) {
  27. // Open the input file and return an appropriate error if needed.
  28. ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
  29. MemoryBuffer::getFileOrSTDIN(Filename);
  30. auto Err = BuffOrErr.getError();
  31. if (Err)
  32. return llvm::errorCodeToError(Err);
  33. return create(BuffOrErr.get());
  34. }
  35. llvm::Expected<GsymReader> GsymReader::copyBuffer(StringRef Bytes) {
  36. auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes");
  37. return create(MemBuffer);
  38. }
  39. llvm::Expected<llvm::gsym::GsymReader>
  40. GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) {
  41. if (!MemBuffer.get())
  42. return createStringError(std::errc::invalid_argument,
  43. "invalid memory buffer");
  44. GsymReader GR(std::move(MemBuffer));
  45. llvm::Error Err = GR.parse();
  46. if (Err)
  47. return std::move(Err);
  48. return std::move(GR);
  49. }
  50. llvm::Error
  51. GsymReader::parse() {
  52. BinaryStreamReader FileData(MemBuffer->getBuffer(),
  53. support::endian::system_endianness());
  54. // Check for the magic bytes. This file format is designed to be mmap'ed
  55. // into a process and accessed as read only. This is done for performance
  56. // and efficiency for symbolicating and parsing GSYM data.
  57. if (FileData.readObject(Hdr))
  58. return createStringError(std::errc::invalid_argument,
  59. "not enough data for a GSYM header");
  60. const auto HostByteOrder = support::endian::system_endianness();
  61. switch (Hdr->Magic) {
  62. case GSYM_MAGIC:
  63. Endian = HostByteOrder;
  64. break;
  65. case GSYM_CIGAM:
  66. // This is a GSYM file, but not native endianness.
  67. Endian = sys::IsBigEndianHost ? support::little : support::big;
  68. Swap.reset(new SwappedData);
  69. break;
  70. default:
  71. return createStringError(std::errc::invalid_argument,
  72. "not a GSYM file");
  73. }
  74. bool DataIsLittleEndian = HostByteOrder != support::little;
  75. // Read a correctly byte swapped header if we need to.
  76. if (Swap) {
  77. DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
  78. if (auto ExpectedHdr = Header::decode(Data))
  79. Swap->Hdr = ExpectedHdr.get();
  80. else
  81. return ExpectedHdr.takeError();
  82. Hdr = &Swap->Hdr;
  83. }
  84. // Detect errors in the header and report any that are found. If we make it
  85. // past this without errors, we know we have a good magic value, a supported
  86. // version number, verified address offset size and a valid UUID size.
  87. if (Error Err = Hdr->checkForError())
  88. return Err;
  89. if (!Swap) {
  90. // This is the native endianness case that is most common and optimized for
  91. // efficient lookups. Here we just grab pointers to the native data and
  92. // use ArrayRef objects to allow efficient read only access.
  93. // Read the address offsets.
  94. if (FileData.padToAlignment(Hdr->AddrOffSize) ||
  95. FileData.readArray(AddrOffsets,
  96. Hdr->NumAddresses * Hdr->AddrOffSize))
  97. return createStringError(std::errc::invalid_argument,
  98. "failed to read address table");
  99. // Read the address info offsets.
  100. if (FileData.padToAlignment(4) ||
  101. FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses))
  102. return createStringError(std::errc::invalid_argument,
  103. "failed to read address info offsets table");
  104. // Read the file table.
  105. uint32_t NumFiles = 0;
  106. if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles))
  107. return createStringError(std::errc::invalid_argument,
  108. "failed to read file table");
  109. // Get the string table.
  110. FileData.setOffset(Hdr->StrtabOffset);
  111. if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize))
  112. return createStringError(std::errc::invalid_argument,
  113. "failed to read string table");
  114. } else {
  115. // This is the non native endianness case that is not common and not
  116. // optimized for lookups. Here we decode the important tables into local
  117. // storage and then set the ArrayRef objects to point to these swapped
  118. // copies of the read only data so lookups can be as efficient as possible.
  119. DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
  120. // Read the address offsets.
  121. uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize);
  122. Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize);
  123. switch (Hdr->AddrOffSize) {
  124. case 1:
  125. if (!Data.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses))
  126. return createStringError(std::errc::invalid_argument,
  127. "failed to read address table");
  128. break;
  129. case 2:
  130. if (!Data.getU16(&Offset,
  131. reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
  132. Hdr->NumAddresses))
  133. return createStringError(std::errc::invalid_argument,
  134. "failed to read address table");
  135. break;
  136. case 4:
  137. if (!Data.getU32(&Offset,
  138. reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
  139. Hdr->NumAddresses))
  140. return createStringError(std::errc::invalid_argument,
  141. "failed to read address table");
  142. break;
  143. case 8:
  144. if (!Data.getU64(&Offset,
  145. reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
  146. Hdr->NumAddresses))
  147. return createStringError(std::errc::invalid_argument,
  148. "failed to read address table");
  149. }
  150. AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
  151. // Read the address info offsets.
  152. Offset = alignTo(Offset, 4);
  153. Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
  154. if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses))
  155. AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets);
  156. else
  157. return createStringError(std::errc::invalid_argument,
  158. "failed to read address table");
  159. // Read the file table.
  160. const uint32_t NumFiles = Data.getU32(&Offset);
  161. if (NumFiles > 0) {
  162. Swap->Files.resize(NumFiles);
  163. if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2))
  164. Files = ArrayRef<FileEntry>(Swap->Files);
  165. else
  166. return createStringError(std::errc::invalid_argument,
  167. "failed to read file table");
  168. }
  169. // Get the string table.
  170. StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset,
  171. Hdr->StrtabSize);
  172. if (StrTab.Data.empty())
  173. return createStringError(std::errc::invalid_argument,
  174. "failed to read string table");
  175. }
  176. return Error::success();
  177. }
  178. const Header &GsymReader::getHeader() const {
  179. // The only way to get a GsymReader is from GsymReader::openFile(...) or
  180. // GsymReader::copyBuffer() and the header must be valid and initialized to
  181. // a valid pointer value, so the assert below should not trigger.
  182. assert(Hdr);
  183. return *Hdr;
  184. }
  185. Optional<uint64_t> GsymReader::getAddress(size_t Index) const {
  186. switch (Hdr->AddrOffSize) {
  187. case 1: return addressForIndex<uint8_t>(Index);
  188. case 2: return addressForIndex<uint16_t>(Index);
  189. case 4: return addressForIndex<uint32_t>(Index);
  190. case 8: return addressForIndex<uint64_t>(Index);
  191. }
  192. return llvm::None;
  193. }
  194. Optional<uint64_t> GsymReader::getAddressInfoOffset(size_t Index) const {
  195. const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
  196. if (Index < NumAddrInfoOffsets)
  197. return AddrInfoOffsets[Index];
  198. return llvm::None;
  199. }
  200. Expected<uint64_t>
  201. GsymReader::getAddressIndex(const uint64_t Addr) const {
  202. if (Addr >= Hdr->BaseAddress) {
  203. const uint64_t AddrOffset = Addr - Hdr->BaseAddress;
  204. Optional<uint64_t> AddrOffsetIndex;
  205. switch (Hdr->AddrOffSize) {
  206. case 1:
  207. AddrOffsetIndex = getAddressOffsetIndex<uint8_t>(AddrOffset);
  208. break;
  209. case 2:
  210. AddrOffsetIndex = getAddressOffsetIndex<uint16_t>(AddrOffset);
  211. break;
  212. case 4:
  213. AddrOffsetIndex = getAddressOffsetIndex<uint32_t>(AddrOffset);
  214. break;
  215. case 8:
  216. AddrOffsetIndex = getAddressOffsetIndex<uint64_t>(AddrOffset);
  217. break;
  218. default:
  219. return createStringError(std::errc::invalid_argument,
  220. "unsupported address offset size %u",
  221. Hdr->AddrOffSize);
  222. }
  223. if (AddrOffsetIndex)
  224. return *AddrOffsetIndex;
  225. }
  226. return createStringError(std::errc::invalid_argument,
  227. "address 0x%" PRIx64 " is not in GSYM", Addr);
  228. }
  229. llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
  230. Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
  231. if (!AddressIndex)
  232. return AddressIndex.takeError();
  233. // Address info offsets size should have been checked in parse().
  234. assert(*AddressIndex < AddrInfoOffsets.size());
  235. auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
  236. DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
  237. if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex)) {
  238. auto ExpectedFI = FunctionInfo::decode(Data, *OptAddr);
  239. if (ExpectedFI) {
  240. if (ExpectedFI->Range.contains(Addr) || ExpectedFI->Range.size() == 0)
  241. return ExpectedFI;
  242. return createStringError(std::errc::invalid_argument,
  243. "address 0x%" PRIx64 " is not in GSYM", Addr);
  244. }
  245. }
  246. return createStringError(std::errc::invalid_argument,
  247. "failed to extract address[%" PRIu64 "]",
  248. *AddressIndex);
  249. }
  250. llvm::Expected<LookupResult> GsymReader::lookup(uint64_t Addr) const {
  251. Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
  252. if (!AddressIndex)
  253. return AddressIndex.takeError();
  254. // Address info offsets size should have been checked in parse().
  255. assert(*AddressIndex < AddrInfoOffsets.size());
  256. auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
  257. DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
  258. if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex))
  259. return FunctionInfo::lookup(Data, *this, *OptAddr, Addr);
  260. return createStringError(std::errc::invalid_argument,
  261. "failed to extract address[%" PRIu64 "]",
  262. *AddressIndex);
  263. }
  264. void GsymReader::dump(raw_ostream &OS) {
  265. const auto &Header = getHeader();
  266. // Dump the GSYM header.
  267. OS << Header << "\n";
  268. // Dump the address table.
  269. OS << "Address Table:\n";
  270. OS << "INDEX OFFSET";
  271. switch (Hdr->AddrOffSize) {
  272. case 1: OS << "8 "; break;
  273. case 2: OS << "16"; break;
  274. case 4: OS << "32"; break;
  275. case 8: OS << "64"; break;
  276. default: OS << "??"; break;
  277. }
  278. OS << " (ADDRESS)\n";
  279. OS << "====== =============================== \n";
  280. for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
  281. OS << format("[%4u] ", I);
  282. switch (Hdr->AddrOffSize) {
  283. case 1: OS << HEX8(getAddrOffsets<uint8_t>()[I]); break;
  284. case 2: OS << HEX16(getAddrOffsets<uint16_t>()[I]); break;
  285. case 4: OS << HEX32(getAddrOffsets<uint32_t>()[I]); break;
  286. case 8: OS << HEX32(getAddrOffsets<uint64_t>()[I]); break;
  287. default: break;
  288. }
  289. OS << " (" << HEX64(*getAddress(I)) << ")\n";
  290. }
  291. // Dump the address info offsets table.
  292. OS << "\nAddress Info Offsets:\n";
  293. OS << "INDEX Offset\n";
  294. OS << "====== ==========\n";
  295. for (uint32_t I = 0; I < Header.NumAddresses; ++I)
  296. OS << format("[%4u] ", I) << HEX32(AddrInfoOffsets[I]) << "\n";
  297. // Dump the file table.
  298. OS << "\nFiles:\n";
  299. OS << "INDEX DIRECTORY BASENAME PATH\n";
  300. OS << "====== ========== ========== ==============================\n";
  301. for (uint32_t I = 0; I < Files.size(); ++I) {
  302. OS << format("[%4u] ", I) << HEX32(Files[I].Dir) << ' '
  303. << HEX32(Files[I].Base) << ' ';
  304. dump(OS, getFile(I));
  305. OS << "\n";
  306. }
  307. OS << "\n" << StrTab << "\n";
  308. for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
  309. OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": ";
  310. if (auto FI = getFunctionInfo(*getAddress(I)))
  311. dump(OS, *FI);
  312. else
  313. logAllUnhandledErrors(FI.takeError(), OS, "FunctionInfo:");
  314. }
  315. }
  316. void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI) {
  317. OS << FI.Range << " \"" << getString(FI.Name) << "\"\n";
  318. if (FI.OptLineTable)
  319. dump(OS, *FI.OptLineTable);
  320. if (FI.Inline)
  321. dump(OS, *FI.Inline);
  322. }
  323. void GsymReader::dump(raw_ostream &OS, const LineTable &LT) {
  324. OS << "LineTable:\n";
  325. for (auto &LE: LT) {
  326. OS << " " << HEX64(LE.Addr) << ' ';
  327. if (LE.File)
  328. dump(OS, getFile(LE.File));
  329. OS << ':' << LE.Line << '\n';
  330. }
  331. }
  332. void GsymReader::dump(raw_ostream &OS, const InlineInfo &II, uint32_t Indent) {
  333. if (Indent == 0)
  334. OS << "InlineInfo:\n";
  335. else
  336. OS.indent(Indent);
  337. OS << II.Ranges << ' ' << getString(II.Name);
  338. if (II.CallFile != 0) {
  339. if (auto File = getFile(II.CallFile)) {
  340. OS << " called from ";
  341. dump(OS, File);
  342. OS << ':' << II.CallLine;
  343. }
  344. }
  345. OS << '\n';
  346. for (const auto &ChildII: II.Children)
  347. dump(OS, ChildII, Indent + 2);
  348. }
  349. void GsymReader::dump(raw_ostream &OS, Optional<FileEntry> FE) {
  350. if (FE) {
  351. // IF we have the file from index 0, then don't print anything
  352. if (FE->Dir == 0 && FE->Base == 0)
  353. return;
  354. StringRef Dir = getString(FE->Dir);
  355. StringRef Base = getString(FE->Base);
  356. if (!Dir.empty()) {
  357. OS << Dir;
  358. if (Dir.contains('\\') && !Dir.contains('/'))
  359. OS << '\\';
  360. else
  361. OS << '/';
  362. }
  363. if (!Base.empty()) {
  364. OS << Base;
  365. }
  366. if (!Dir.empty() || !Base.empty())
  367. return;
  368. }
  369. OS << "<invalid-file>";
  370. }