[InstCombine] Signed saturation patterns
[llvm-complete.git] / lib / DebugInfo / GSYM / GsymReader.cpp
blob1b448cf80b70df173a29b3c91f031b0f24009af6
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 //===----------------------------------------------------------------------===//
10 #include "llvm/DebugInfo/GSYM/GsymReader.h"
12 #include <assert.h>
13 #include <inttypes.h>
14 #include <stdio.h>
15 #include <stdlib.h>
17 #include "llvm/DebugInfo/GSYM/GsymCreator.h"
18 #include "llvm/DebugInfo/GSYM/InlineInfo.h"
19 #include "llvm/DebugInfo/GSYM/LineTable.h"
20 #include "llvm/Support/BinaryStreamReader.h"
21 #include "llvm/Support/DataExtractor.h"
22 #include "llvm/Support/MemoryBuffer.h"
24 using namespace llvm;
25 using namespace gsym;
27 GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) :
28 MemBuffer(std::move(Buffer)),
29 Endian(support::endian::system_endianness()) {}
31 GsymReader::GsymReader(GsymReader &&RHS) = default;
33 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());
45 llvm::Expected<GsymReader> GsymReader::copyBuffer(StringRef Bytes) {
46 auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes");
47 return create(MemBuffer);
50 llvm::Expected<llvm::gsym::GsymReader>
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);
62 llvm::Error
63 GsymReader::parse() {
64 BinaryStreamReader FileData(MemBuffer->getBuffer(),
65 support::endian::system_endianness());
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");
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.
80 Endian = sys::IsBigEndianHost ? support::little : support::big;
81 Swap.reset(new SwappedData);
82 break;
83 default:
84 return createStringError(std::errc::invalid_argument,
85 "not a GSYM file");
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;
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;
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.
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");
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");
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");
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);
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");
171 AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
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");
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");
198 return Error::success();
202 const Header &GsymReader::getHeader() const {
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;
210 Optional<uint64_t> GsymReader::getAddress(size_t Index) const {
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);
217 return llvm::None;
220 Optional<uint64_t> GsymReader::getAddressInfoOffset(size_t Index) const {
221 const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
222 if (Index < NumAddrInfoOffsets)
223 return AddrInfoOffsets[Index];
224 return llvm::None;
227 Expected<uint64_t>
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;
240 return createStringError(std::errc::invalid_argument,
241 "unsupported address offset size %u",
242 Hdr->AddrOffSize);
245 llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
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);
262 return createStringError(std::errc::invalid_argument,
263 "failed to extract address[%" PRIu64 "]",
264 *AddressIndex);