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