GsymReader.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. //===- GsymReader.cpp -----------------------------------------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file is distributed under the University of Illinois Open Source
  6. // License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. #include "llvm/DebugInfo/GSYM/GsymReader.h"
  10. #include <assert.h>
  11. #include <fcntl.h>
  12. #include <inttypes.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <sys/mman.h>
  16. #include <sys/stat.h>
  17. #include <sys/types.h>
  18. #include <unistd.h>
  19. #include <fstream>
  20. #include <functional>
  21. #include <vector>
  22. #include "llvm/DebugInfo/GSYM/GsymCreator.h"
  23. #include "llvm/DebugInfo/GSYM/InlineInfo.h"
  24. #include "llvm/DebugInfo/GSYM/LineTable.h"
  25. #include "llvm/Support/BinaryStreamReader.h"
  26. #include "llvm/Support/DataExtractor.h"
  27. #include "llvm/Support/MemoryBuffer.h"
  28. using namespace llvm;
  29. using namespace gsym;
  30. GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) :
  31. MemBuffer(std::move(Buffer)),
  32. Endian(support::endian::system_endianness()) {}
  33. GsymReader::GsymReader(GsymReader &&RHS) = default;
  34. GsymReader::~GsymReader() = default;
  35. llvm::Expected<GsymReader> GsymReader::openFile(StringRef Filename) {
  36. // Open the input file and return an appropriate error if needed.
  37. ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
  38. MemoryBuffer::getFileOrSTDIN(Filename);
  39. auto Err = BuffOrErr.getError();
  40. if (Err)
  41. return llvm::errorCodeToError(Err);
  42. return create(BuffOrErr.get());
  43. }
  44. llvm::Expected<GsymReader> GsymReader::copyBuffer(StringRef Bytes) {
  45. auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes");
  46. return create(MemBuffer);
  47. }
  48. llvm::Expected<llvm::gsym::GsymReader>
  49. GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) {
  50. if (!MemBuffer.get())
  51. return createStringError(std::errc::invalid_argument,
  52. "invalid memory buffer");
  53. GsymReader GR(std::move(MemBuffer));
  54. llvm::Error Err = GR.parse();
  55. if (Err)
  56. return std::move(Err);
  57. return std::move(GR);
  58. }
  59. llvm::Error
  60. GsymReader::parse() {
  61. BinaryStreamReader FileData(MemBuffer->getBuffer(),
  62. support::endian::system_endianness());
  63. // Check for the magic bytes. This file format is designed to be mmap'ed
  64. // into a process and accessed as read only. This is done for performance
  65. // and efficiency for symbolicating and parsing GSYM data.
  66. if (FileData.readObject(Hdr))
  67. return createStringError(std::errc::invalid_argument,
  68. "not enough data for a GSYM header");
  69. const auto HostByteOrder = support::endian::system_endianness();
  70. switch (Hdr->Magic) {
  71. case GSYM_MAGIC:
  72. Endian = HostByteOrder;
  73. break;
  74. case GSYM_CIGAM:
  75. // This is a GSYM file, but not native endianness.
  76. Endian = sys::IsBigEndianHost ? support::little : support::big;
  77. Swap.reset(new SwappedData);
  78. break;
  79. default:
  80. return createStringError(std::errc::invalid_argument,
  81. "not a GSYM file");
  82. }
  83. bool DataIsLittleEndian = HostByteOrder != support::little;
  84. // Read a correctly byte swapped header if we need to.
  85. if (Swap) {
  86. DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
  87. if (auto ExpectedHdr = Header::decode(Data))
  88. Swap->Hdr = ExpectedHdr.get();
  89. else
  90. return ExpectedHdr.takeError();
  91. Hdr = &Swap->Hdr;
  92. }
  93. // Detect errors in the header and report any that are found. If we make it
  94. // past this without errors, we know we have a good magic value, a supported
  95. // version number, verified address offset size and a valid UUID size.
  96. if (Error Err = Hdr->checkForError())
  97. return Err;
  98. if (!Swap) {
  99. // This is the native endianness case that is most common and optimized for
  100. // efficient lookups. Here we just grab pointers to the native data and
  101. // use ArrayRef objects to allow efficient read only access.
  102. // Read the address offsets.
  103. if (FileData.padToAlignment(Hdr->AddrOffSize) ||
  104. FileData.readArray(AddrOffsets,
  105. Hdr->NumAddresses * Hdr->AddrOffSize))
  106. return createStringError(std::errc::invalid_argument,
  107. "failed to read address table");
  108. // Read the address info offsets.
  109. if (FileData.padToAlignment(4) ||
  110. FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses))
  111. return createStringError(std::errc::invalid_argument,
  112. "failed to read address info offsets table");
  113. // Read the file table.
  114. uint32_t NumFiles = 0;
  115. if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles))
  116. return createStringError(std::errc::invalid_argument,
  117. "failed to read file table");
  118. // Get the string table.
  119. FileData.setOffset(Hdr->StrtabOffset);
  120. if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize))
  121. return createStringError(std::errc::invalid_argument,
  122. "failed to read string table");
  123. } else {
  124. // This is the non native endianness case that is not common and not
  125. // optimized for lookups. Here we decode the important tables into local
  126. // storage and then set the ArrayRef objects to point to these swapped
  127. // copies of the read only data so lookups can be as efficient as possible.
  128. DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
  129. // Read the address offsets.
  130. uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize);
  131. Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize);
  132. switch (Hdr->AddrOffSize) {
  133. case 1:
  134. if (!Data.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses))
  135. return createStringError(std::errc::invalid_argument,
  136. "failed to read address table");
  137. break;
  138. case 2:
  139. if (!Data.getU16(&Offset,
  140. reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
  141. Hdr->NumAddresses))
  142. return createStringError(std::errc::invalid_argument,
  143. "failed to read address table");
  144. break;
  145. case 4:
  146. if (!Data.getU32(&Offset,
  147. reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
  148. Hdr->NumAddresses))
  149. return createStringError(std::errc::invalid_argument,
  150. "failed to read address table");
  151. break;
  152. case 8:
  153. if (!Data.getU64(&Offset,
  154. reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
  155. Hdr->NumAddresses))
  156. return createStringError(std::errc::invalid_argument,
  157. "failed to read address table");
  158. }
  159. AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
  160. // Read the address info offsets.
  161. Offset = alignTo(Offset, 4);
  162. Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
  163. if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses))
  164. AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets);
  165. else
  166. return createStringError(std::errc::invalid_argument,
  167. "failed to read address table");
  168. // Read the file table.
  169. const uint32_t NumFiles = Data.getU32(&Offset);
  170. if (NumFiles > 0) {
  171. Swap->Files.resize(NumFiles);
  172. if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2))
  173. Files = ArrayRef<FileEntry>(Swap->Files);
  174. else
  175. return createStringError(std::errc::invalid_argument,
  176. "failed to read file table");
  177. }
  178. // Get the string table.
  179. StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset,
  180. Hdr->StrtabSize);
  181. if (StrTab.Data.empty())
  182. return createStringError(std::errc::invalid_argument,
  183. "failed to read string table");
  184. }
  185. return Error::success();
  186. }
  187. const Header &GsymReader::getHeader() const {
  188. // The only way to get a GsymReader is from GsymReader::openFile(...) or
  189. // GsymReader::copyBuffer() and the header must be valid and initialized to
  190. // a valid pointer value, so the assert below should not trigger.
  191. assert(Hdr);
  192. return *Hdr;
  193. }
  194. Optional<uint64_t> GsymReader::getAddress(size_t Index) const {
  195. switch (Hdr->AddrOffSize) {
  196. case 1: return addressForIndex<uint8_t>(Index);
  197. case 2: return addressForIndex<uint16_t>(Index);
  198. case 4: return addressForIndex<uint32_t>(Index);
  199. case 8: return addressForIndex<uint64_t>(Index);
  200. }
  201. return llvm::None;
  202. }
  203. Optional<uint64_t> GsymReader::getAddressInfoOffset(size_t Index) const {
  204. const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
  205. if (Index < NumAddrInfoOffsets)
  206. return AddrInfoOffsets[Index];
  207. return llvm::None;
  208. }
  209. Expected<uint64_t>
  210. GsymReader::getAddressIndex(const uint64_t Addr) const {
  211. if (Addr < Hdr->BaseAddress)
  212. return createStringError(std::errc::invalid_argument,
  213. "address 0x%" PRIx64 " not in GSYM", Addr);
  214. const uint64_t AddrOffset = Addr - Hdr->BaseAddress;
  215. switch (Hdr->AddrOffSize) {
  216. case 1: return getAddressOffsetIndex<uint8_t>(AddrOffset);
  217. case 2: return getAddressOffsetIndex<uint16_t>(AddrOffset);
  218. case 4: return getAddressOffsetIndex<uint32_t>(AddrOffset);
  219. case 8: return getAddressOffsetIndex<uint64_t>(AddrOffset);
  220. default: break;
  221. }
  222. return createStringError(std::errc::invalid_argument,
  223. "unsupported address offset size %u",
  224. Hdr->AddrOffSize);
  225. }
  226. llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
  227. Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
  228. if (!AddressIndex)
  229. return AddressIndex.takeError();
  230. // Address info offsets size should have been checked in parse().
  231. assert(*AddressIndex < AddrInfoOffsets.size());
  232. auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
  233. DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
  234. if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex)) {
  235. auto ExpectedFI = FunctionInfo::decode(Data, *OptAddr);
  236. if (ExpectedFI) {
  237. if (ExpectedFI->Range.contains(Addr) || ExpectedFI->Range.size() == 0)
  238. return ExpectedFI;
  239. return createStringError(std::errc::invalid_argument,
  240. "address 0x%" PRIx64 " not in GSYM", Addr);
  241. }
  242. }
  243. return createStringError(std::errc::invalid_argument,
  244. "failed to extract address[%" PRIu64 "]",
  245. *AddressIndex);
  246. }