diff options
Diffstat (limited to 'lib/ProfileData/Coverage/CoverageMappingReader.cpp')
| -rw-r--r-- | lib/ProfileData/Coverage/CoverageMappingReader.cpp | 235 | 
1 files changed, 158 insertions, 77 deletions
diff --git a/lib/ProfileData/Coverage/CoverageMappingReader.cpp b/lib/ProfileData/Coverage/CoverageMappingReader.cpp index ee48256bc2e5..e193e10f91d9 100644 --- a/lib/ProfileData/Coverage/CoverageMappingReader.cpp +++ b/lib/ProfileData/Coverage/CoverageMappingReader.cpp @@ -1,9 +1,8 @@  //===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===//  // -//                     The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception  //  //===----------------------------------------------------------------------===//  // @@ -23,6 +22,7 @@  #include "llvm/Object/Error.h"  #include "llvm/Object/MachOUniversal.h"  #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/COFF.h"  #include "llvm/ProfileData/InstrProf.h"  #include "llvm/Support/Casting.h"  #include "llvm/Support/Debug.h" @@ -59,7 +59,7 @@ Error RawCoverageReader::readULEB128(uint64_t &Result) {    if (Data.empty())      return make_error<CoverageMapError>(coveragemap_error::truncated);    unsigned N = 0; -  Result = decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N); +  Result = decodeULEB128(Data.bytes_begin(), &N);    if (N > Data.size())      return make_error<CoverageMapError>(coveragemap_error::malformed);    Data = Data.substr(N); @@ -348,9 +348,18 @@ Expected<bool> RawCoverageMappingDummyChecker::isDummy() {  }  Error InstrProfSymtab::create(SectionRef &Section) { -  if (auto EC = Section.getContents(Data)) -    return errorCodeToError(EC); +  Expected<StringRef> DataOrErr = Section.getContents(); +  if (!DataOrErr) +    return DataOrErr.takeError(); +  Data = *DataOrErr;    Address = Section.getAddress(); + +  // If this is a linked PE/COFF file, then we have to skip over the null byte +  // that is allocated in the .lprfn$A section in the LLVM profiling runtime. +  const ObjectFile *Obj = Section.getObject(); +  if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject()) +    Data = Data.drop_front(1); +    return Error::success();  } @@ -577,35 +586,65 @@ static Error readCoverageMappingData(  static const char *TestingFormatMagic = "llvmcovmtestdata"; -static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames, -                               StringRef &CoverageMapping, -                               uint8_t &BytesInAddress, -                               support::endianness &Endian) { -  BytesInAddress = 8; -  Endian = support::endianness::little; +Expected<std::unique_ptr<BinaryCoverageReader>> +BinaryCoverageReader::createCoverageReaderFromBuffer( +    StringRef Coverage, InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress, +    support::endianness Endian) { +  std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader()); +  Reader->ProfileNames = std::move(ProfileNames); +  if (BytesInAddress == 4 && Endian == support::endianness::little) { +    if (Error E = +            readCoverageMappingData<uint32_t, support::endianness::little>( +                Reader->ProfileNames, Coverage, Reader->MappingRecords, +                Reader->Filenames)) +      return std::move(E); +  } else if (BytesInAddress == 4 && Endian == support::endianness::big) { +    if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>( +            Reader->ProfileNames, Coverage, Reader->MappingRecords, +            Reader->Filenames)) +      return std::move(E); +  } else if (BytesInAddress == 8 && Endian == support::endianness::little) { +    if (Error E = +            readCoverageMappingData<uint64_t, support::endianness::little>( +                Reader->ProfileNames, Coverage, Reader->MappingRecords, +                Reader->Filenames)) +      return std::move(E); +  } else if (BytesInAddress == 8 && Endian == support::endianness::big) { +    if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>( +            Reader->ProfileNames, Coverage, Reader->MappingRecords, +            Reader->Filenames)) +      return std::move(E); +  } else +    return make_error<CoverageMapError>(coveragemap_error::malformed); +  return std::move(Reader); +} + +static Expected<std::unique_ptr<BinaryCoverageReader>> +loadTestingFormat(StringRef Data) { +  uint8_t BytesInAddress = 8; +  support::endianness Endian = support::endianness::little;    Data = Data.substr(StringRef(TestingFormatMagic).size());    if (Data.empty())      return make_error<CoverageMapError>(coveragemap_error::truncated);    unsigned N = 0; -  auto ProfileNamesSize = -      decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N); +  uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N);    if (N > Data.size())      return make_error<CoverageMapError>(coveragemap_error::malformed);    Data = Data.substr(N);    if (Data.empty())      return make_error<CoverageMapError>(coveragemap_error::truncated);    N = 0; -  uint64_t Address = -      decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N); +  uint64_t Address = decodeULEB128(Data.bytes_begin(), &N);    if (N > Data.size())      return make_error<CoverageMapError>(coveragemap_error::malformed);    Data = Data.substr(N);    if (Data.size() < ProfileNamesSize)      return make_error<CoverageMapError>(coveragemap_error::malformed); +  InstrProfSymtab ProfileNames;    if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address)) -    return E; -  CoverageMapping = Data.substr(ProfileNamesSize); +    return std::move(E); +  StringRef CoverageMapping = Data.substr(ProfileNamesSize);    // Skip the padding bytes because coverage map data has an alignment of 8.    if (CoverageMapping.empty())      return make_error<CoverageMapError>(coveragemap_error::truncated); @@ -613,29 +652,32 @@ static Error loadTestingFormat(StringRef Data, InstrProfSymtab &ProfileNames,    if (CoverageMapping.size() < Pad)      return make_error<CoverageMapError>(coveragemap_error::malformed);    CoverageMapping = CoverageMapping.substr(Pad); -  return Error::success(); +  return BinaryCoverageReader::createCoverageReaderFromBuffer( +      CoverageMapping, std::move(ProfileNames), BytesInAddress, Endian);  }  static Expected<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) { +  // On COFF, the object file section name may end in "$M". This tells the +  // linker to sort these sections between "$A" and "$Z". The linker removes the +  // dollar and everything after it in the final binary. Do the same to match. +  bool IsCOFF = isa<COFFObjectFile>(OF); +  auto stripSuffix = [IsCOFF](StringRef N) { +    return IsCOFF ? N.split('$').first : N; +  }; +  Name = stripSuffix(Name); +    StringRef FoundName;    for (const auto &Section : OF.sections()) {      if (auto EC = Section.getName(FoundName))        return errorCodeToError(EC); -    if (FoundName == Name) +    if (stripSuffix(FoundName) == Name)        return Section;    }    return make_error<CoverageMapError>(coveragemap_error::no_data_found);  } -static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer, -                              InstrProfSymtab &ProfileNames, -                              StringRef &CoverageMapping, -                              uint8_t &BytesInAddress, -                              support::endianness &Endian, StringRef Arch) { -  auto BinOrErr = createBinary(ObjectBuffer); -  if (!BinOrErr) -    return BinOrErr.takeError(); -  auto Bin = std::move(BinOrErr.get()); +static Expected<std::unique_ptr<BinaryCoverageReader>> +loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch) {    std::unique_ptr<ObjectFile> OF;    if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) {      // If we have a universal binary, try to look up the object for the @@ -655,9 +697,10 @@ static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer,      return make_error<CoverageMapError>(coveragemap_error::malformed);    // The coverage uses native pointer sizes for the object it's written in. -  BytesInAddress = OF->getBytesInAddress(); -  Endian = OF->isLittleEndian() ? support::endianness::little -                                : support::endianness::big; +  uint8_t BytesInAddress = OF->getBytesInAddress(); +  support::endianness Endian = OF->isLittleEndian() +                                   ? support::endianness::little +                                   : support::endianness::big;    // Look for the sections that we are interested in.    auto ObjFormat = OF->getTripleObjectFormat(); @@ -665,63 +708,101 @@ static Error loadBinaryFormat(MemoryBufferRef ObjectBuffer,        lookupSection(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,                                                   /*AddSegmentInfo=*/false));    if (auto E = NamesSection.takeError()) -    return E; +    return std::move(E);    auto CoverageSection =        lookupSection(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat,                                                   /*AddSegmentInfo=*/false));    if (auto E = CoverageSection.takeError()) -    return E; +    return std::move(E);    // Get the contents of the given sections. -  if (auto EC = CoverageSection->getContents(CoverageMapping)) -    return errorCodeToError(EC); +  auto CoverageMappingOrErr = CoverageSection->getContents(); +  if (!CoverageMappingOrErr) +    return CoverageMappingOrErr.takeError(); + +  InstrProfSymtab ProfileNames;    if (Error E = ProfileNames.create(*NamesSection)) -    return E; +    return std::move(E); -  return Error::success(); +  return BinaryCoverageReader::createCoverageReaderFromBuffer( +      CoverageMappingOrErr.get(), std::move(ProfileNames), BytesInAddress, +      Endian);  } -Expected<std::unique_ptr<BinaryCoverageReader>> -BinaryCoverageReader::create(std::unique_ptr<MemoryBuffer> &ObjectBuffer, -                             StringRef Arch) { -  std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader()); +Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>> +BinaryCoverageReader::create( +    MemoryBufferRef ObjectBuffer, StringRef Arch, +    SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers) { +  std::vector<std::unique_ptr<BinaryCoverageReader>> Readers; -  StringRef Coverage; -  uint8_t BytesInAddress; -  support::endianness Endian; -  Error E = Error::success(); -  consumeError(std::move(E)); -  if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) +  if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) {      // This is a special format used for testing. -    E = loadTestingFormat(ObjectBuffer->getBuffer(), Reader->ProfileNames, -                          Coverage, BytesInAddress, Endian); -  else -    E = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Reader->ProfileNames, -                         Coverage, BytesInAddress, Endian, Arch); -  if (E) -    return std::move(E); +    auto ReaderOrErr = loadTestingFormat(ObjectBuffer.getBuffer()); +    if (!ReaderOrErr) +      return ReaderOrErr.takeError(); +    Readers.push_back(std::move(ReaderOrErr.get())); +    return std::move(Readers); +  } -  if (BytesInAddress == 4 && Endian == support::endianness::little) -    E = readCoverageMappingData<uint32_t, support::endianness::little>( -        Reader->ProfileNames, Coverage, Reader->MappingRecords, -        Reader->Filenames); -  else if (BytesInAddress == 4 && Endian == support::endianness::big) -    E = readCoverageMappingData<uint32_t, support::endianness::big>( -        Reader->ProfileNames, Coverage, Reader->MappingRecords, -        Reader->Filenames); -  else if (BytesInAddress == 8 && Endian == support::endianness::little) -    E = readCoverageMappingData<uint64_t, support::endianness::little>( -        Reader->ProfileNames, Coverage, Reader->MappingRecords, -        Reader->Filenames); -  else if (BytesInAddress == 8 && Endian == support::endianness::big) -    E = readCoverageMappingData<uint64_t, support::endianness::big>( -        Reader->ProfileNames, Coverage, Reader->MappingRecords, -        Reader->Filenames); -  else -    return make_error<CoverageMapError>(coveragemap_error::malformed); -  if (E) -    return std::move(E); -  return std::move(Reader); +  auto BinOrErr = createBinary(ObjectBuffer); +  if (!BinOrErr) +    return BinOrErr.takeError(); +  std::unique_ptr<Binary> Bin = std::move(BinOrErr.get()); + +  // MachO universal binaries which contain archives need to be treated as +  // archives, not as regular binaries. +  if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { +    for (auto &ObjForArch : Universal->objects()) { +      // Skip slices within the universal binary which target the wrong arch. +      std::string ObjArch = ObjForArch.getArchFlagName(); +      if (Arch != ObjArch) +        continue; + +      auto ArchiveOrErr = ObjForArch.getAsArchive(); +      if (!ArchiveOrErr) { +        // If this is not an archive, try treating it as a regular object. +        consumeError(ArchiveOrErr.takeError()); +        break; +      } + +      return BinaryCoverageReader::create( +          ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers); +    } +  } + +  // Load coverage out of archive members. +  if (auto *Ar = dyn_cast<Archive>(Bin.get())) { +    Error Err = Error::success(); +    for (auto &Child : Ar->children(Err)) { +      Expected<MemoryBufferRef> ChildBufOrErr = Child.getMemoryBufferRef(); +      if (!ChildBufOrErr) +        return ChildBufOrErr.takeError(); + +      auto ChildReadersOrErr = BinaryCoverageReader::create( +          ChildBufOrErr.get(), Arch, ObjectFileBuffers); +      if (!ChildReadersOrErr) +        return ChildReadersOrErr.takeError(); +      for (auto &Reader : ChildReadersOrErr.get()) +        Readers.push_back(std::move(Reader)); +    } +    if (Err) +      return std::move(Err); + +    // Thin archives reference object files outside of the archive file, i.e. +    // files which reside in memory not owned by the caller. Transfer ownership +    // to the caller. +    if (Ar->isThin()) +      for (auto &Buffer : Ar->takeThinBuffers()) +        ObjectFileBuffers.push_back(std::move(Buffer)); + +    return std::move(Readers); +  } + +  auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch); +  if (!ReaderOrErr) +    return ReaderOrErr.takeError(); +  Readers.push_back(std::move(ReaderOrErr.get())); +  return std::move(Readers);  }  Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {  | 
