LLVM  10.0.0svn
GsymReader.cpp
Go to the documentation of this file.
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 
11 
12 #include <assert.h>
13 #include <inttypes.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 
23 
24 using namespace llvm;
25 using namespace gsym;
26 
27 GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) :
28  MemBuffer(std::move(Buffer)),
29  Endian(support::endian::system_endianness()) {}
30 
31  GsymReader::GsymReader(GsymReader &&RHS) = default;
32 
33 GsymReader::~GsymReader() = default;
34 
36  // Open the input file and return an appropriate error if needed.
39  auto Err = BuffOrErr.getError();
40  if (Err)
41  return llvm::errorCodeToError(Err);
42  return create(BuffOrErr.get());
43 }
44 
46  auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes");
47  return create(MemBuffer);
48 }
49 
51 GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) {
52  if (!MemBuffer.get())
53  return createStringError(std::errc::invalid_argument,
54  "invalid memory buffer");
55  GsymReader GR(std::move(MemBuffer));
56  llvm::Error Err = GR.parse();
57  if (Err)
58  return std::move(Err);
59  return std::move(GR);
60 }
61 
63 GsymReader::parse() {
64  BinaryStreamReader FileData(MemBuffer->getBuffer(),
66  // Check for the magic bytes. This file format is designed to be mmap'ed
67  // into a process and accessed as read only. This is done for performance
68  // and efficiency for symbolicating and parsing GSYM data.
69  if (FileData.readObject(Hdr))
70  return createStringError(std::errc::invalid_argument,
71  "not enough data for a GSYM header");
72 
73  const auto HostByteOrder = support::endian::system_endianness();
74  switch (Hdr->Magic) {
75  case GSYM_MAGIC:
76  Endian = HostByteOrder;
77  break;
78  case GSYM_CIGAM:
79  // This is a GSYM file, but not native endianness.
81  Swap.reset(new SwappedData);
82  break;
83  default:
84  return createStringError(std::errc::invalid_argument,
85  "not a GSYM file");
86  }
87 
88  bool DataIsLittleEndian = HostByteOrder != support::little;
89  // Read a correctly byte swapped header if we need to.
90  if (Swap) {
91  DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
92  if (auto ExpectedHdr = Header::decode(Data))
93  Swap->Hdr = ExpectedHdr.get();
94  else
95  return ExpectedHdr.takeError();
96  Hdr = &Swap->Hdr;
97  }
98 
99  // Detect errors in the header and report any that are found. If we make it
100  // past this without errors, we know we have a good magic value, a supported
101  // version number, verified address offset size and a valid UUID size.
102  if (Error Err = Hdr->checkForError())
103  return Err;
104 
105  if (!Swap) {
106  // This is the native endianness case that is most common and optimized for
107  // efficient lookups. Here we just grab pointers to the native data and
108  // use ArrayRef objects to allow efficient read only access.
109 
110  // Read the address offsets.
111  if (FileData.padToAlignment(Hdr->AddrOffSize) ||
112  FileData.readArray(AddrOffsets,
113  Hdr->NumAddresses * Hdr->AddrOffSize))
114  return createStringError(std::errc::invalid_argument,
115  "failed to read address table");
116 
117  // Read the address info offsets.
118  if (FileData.padToAlignment(4) ||
119  FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses))
120  return createStringError(std::errc::invalid_argument,
121  "failed to read address info offsets table");
122 
123  // Read the file table.
124  uint32_t NumFiles = 0;
125  if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles))
126  return createStringError(std::errc::invalid_argument,
127  "failed to read file table");
128 
129  // Get the string table.
130  FileData.setOffset(Hdr->StrtabOffset);
131  if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize))
132  return createStringError(std::errc::invalid_argument,
133  "failed to read string table");
134 } else {
135  // This is the non native endianness case that is not common and not
136  // optimized for lookups. Here we decode the important tables into local
137  // storage and then set the ArrayRef objects to point to these swapped
138  // copies of the read only data so lookups can be as efficient as possible.
139  DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
140 
141  // Read the address offsets.
142  uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize);
143  Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize);
144  switch (Hdr->AddrOffSize) {
145  case 1:
146  if (!Data.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses))
147  return createStringError(std::errc::invalid_argument,
148  "failed to read address table");
149  break;
150  case 2:
151  if (!Data.getU16(&Offset,
152  reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
153  Hdr->NumAddresses))
154  return createStringError(std::errc::invalid_argument,
155  "failed to read address table");
156  break;
157  case 4:
158  if (!Data.getU32(&Offset,
159  reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
160  Hdr->NumAddresses))
161  return createStringError(std::errc::invalid_argument,
162  "failed to read address table");
163  break;
164  case 8:
165  if (!Data.getU64(&Offset,
166  reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
167  Hdr->NumAddresses))
168  return createStringError(std::errc::invalid_argument,
169  "failed to read address table");
170  }
171  AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
172 
173  // Read the address info offsets.
174  Offset = alignTo(Offset, 4);
175  Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
176  if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses))
177  AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets);
178  else
179  return createStringError(std::errc::invalid_argument,
180  "failed to read address table");
181  // Read the file table.
182  const uint32_t NumFiles = Data.getU32(&Offset);
183  if (NumFiles > 0) {
184  Swap->Files.resize(NumFiles);
185  if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2))
186  Files = ArrayRef<FileEntry>(Swap->Files);
187  else
188  return createStringError(std::errc::invalid_argument,
189  "failed to read file table");
190  }
191  // Get the string table.
192  StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset,
193  Hdr->StrtabSize);
194  if (StrTab.Data.empty())
195  return createStringError(std::errc::invalid_argument,
196  "failed to read string table");
197  }
198  return Error::success();
199 
200 }
201 
203  // The only way to get a GsymReader is from GsymReader::openFile(...) or
204  // GsymReader::copyBuffer() and the header must be valid and initialized to
205  // a valid pointer value, so the assert below should not trigger.
206  assert(Hdr);
207  return *Hdr;
208 }
209 
211  switch (Hdr->AddrOffSize) {
212  case 1: return addressForIndex<uint8_t>(Index);
213  case 2: return addressForIndex<uint16_t>(Index);
214  case 4: return addressForIndex<uint32_t>(Index);
215  case 8: return addressForIndex<uint64_t>(Index);
216  }
217  return llvm::None;
218 }
219 
221  const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
222  if (Index < NumAddrInfoOffsets)
223  return AddrInfoOffsets[Index];
224  return llvm::None;
225 }
226 
228 GsymReader::getAddressIndex(const uint64_t Addr) const {
229  if (Addr < Hdr->BaseAddress)
230  return createStringError(std::errc::invalid_argument,
231  "address 0x%" PRIx64 " not in GSYM", Addr);
232  const uint64_t AddrOffset = Addr - Hdr->BaseAddress;
233  switch (Hdr->AddrOffSize) {
234  case 1: return getAddressOffsetIndex<uint8_t>(AddrOffset);
235  case 2: return getAddressOffsetIndex<uint16_t>(AddrOffset);
236  case 4: return getAddressOffsetIndex<uint32_t>(AddrOffset);
237  case 8: return getAddressOffsetIndex<uint64_t>(AddrOffset);
238  default: break;
239  }
240  return createStringError(std::errc::invalid_argument,
241  "unsupported address offset size %u",
242  Hdr->AddrOffSize);
243 }
244 
246  Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
247  if (!AddressIndex)
248  return AddressIndex.takeError();
249  // Address info offsets size should have been checked in parse().
250  assert(*AddressIndex < AddrInfoOffsets.size());
251  auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
252  DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
253  if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex)) {
254  auto ExpectedFI = FunctionInfo::decode(Data, *OptAddr);
255  if (ExpectedFI) {
256  if (ExpectedFI->Range.contains(Addr) || ExpectedFI->Range.size() == 0)
257  return ExpectedFI;
258  return createStringError(std::errc::invalid_argument,
259  "address 0x%" PRIx64 " not in GSYM", Addr);
260  }
261  }
262  return createStringError(std::errc::invalid_argument,
263  "failed to extract address[%" PRIu64 "]",
264  *AddressIndex);
265 }
GsymReader is used to read GSYM data from a file or buffer.
Definition: GsymReader.h:48
static llvm::Expected< GsymReader > copyBuffer(StringRef Bytes)
Construct a GsymReader from a buffer.
Definition: GsymReader.cpp:45
Represents either an error or a value T.
Definition: ErrorOr.h:56
const Header & getHeader() const
Access the GSYM header.
Definition: GsymReader.cpp:202
This class represents lattice values for constants.
Definition: AllocatorList.h:23
Error takeError()
Take ownership of the stored error.
Definition: Error.h:552
constexpr bool IsBigEndianHost
Definition: SwapByteOrder.h:51
constexpr uint32_t GSYM_CIGAM
Definition: Header.h:25
Definition: BitVector.h:937
Tagged union holding either a T or a Error.
Definition: yaml2obj.h:21
llvm::Expected< FunctionInfo > getFunctionInfo(uint64_t Addr) const
Get the full function info for an address.
Definition: GsymReader.cpp:245
Expected< uint64_t > getAddressIndex(const uint64_t Addr) const
Given an address, find the address index.
Definition: GsymReader.cpp:228
Optional< uint64_t > getAddress(size_t Index) const
Gets an address from the address table.
Definition: GsymReader.cpp:210
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition: Error.cpp:87
std::error_code getError() const
Definition: ErrorOr.h:159
static llvm::Expected< GsymReader > openFile(StringRef Path)
Construct a GsymReader from a file on disk.
Definition: GsymReader.cpp:35
const T * data() const
Definition: ArrayRef.h:145
static ErrorSuccess success()
Create a success value.
Definition: Error.h:326
The GSYM header.
Definition: Header.h:45
static llvm::Expected< llvm::gsym::GsymReader > create(std::unique_ptr< MemoryBuffer > &MemBuffer)
Create a GSYM from a memory buffer.
Definition: GsymReader.cpp:51
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, int64_t FileSize=-1, bool RequiresNullTerminator=true)
Open the specified file as a MemoryBuffer, or open stdin if the Filename is "-".
constexpr endianness system_endianness()
Definition: Endian.h:46
uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition: Alignment.h:163
static llvm::Expected< FunctionInfo > decode(DataExtractor &Data, uint64_t BaseAddr)
Decode an object from a binary data stream.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
static llvm::Expected< Header > decode(DataExtractor &Data)
Decode an object from a binary data stream.
Definition: Header.cpp:64
constexpr uint32_t GSYM_MAGIC
Definition: Header.h:24
Provides read only access to a subclass of BinaryStream.
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:48
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1197
reference get()
Definition: ErrorOr.h:156
Optional< uint64_t > getAddressInfoOffset(size_t Index) const
Given an address index, get the offset for the FunctionInfo.
Definition: GsymReader.cpp:220