diff options
Diffstat (limited to 'lib/ProfileData/CoverageMappingReader.cpp')
| -rw-r--r-- | lib/ProfileData/CoverageMappingReader.cpp | 397 | 
1 files changed, 199 insertions, 198 deletions
diff --git a/lib/ProfileData/CoverageMappingReader.cpp b/lib/ProfileData/CoverageMappingReader.cpp index 6476d28ec35d2..cf6cd58f95336 100644 --- a/lib/ProfileData/CoverageMappingReader.cpp +++ b/lib/ProfileData/CoverageMappingReader.cpp @@ -14,9 +14,12 @@  #include "llvm/ProfileData/CoverageMappingReader.h"  #include "llvm/ADT/DenseSet.h" +#include "llvm/Object/MachOUniversal.h"  #include "llvm/Object/ObjectFile.h"  #include "llvm/Support/Debug.h" +#include "llvm/Support/Endian.h"  #include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h"  using namespace llvm;  using namespace coverage; @@ -33,13 +36,13 @@ void CoverageMappingIterator::increment() {  std::error_code RawCoverageReader::readULEB128(uint64_t &Result) {    if (Data.size() < 1) -    return error(instrprof_error::truncated); +    return coveragemap_error::truncated;    unsigned N = 0;    Result = decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);    if (N > Data.size()) -    return error(instrprof_error::malformed); +    return coveragemap_error::malformed;    Data = Data.substr(N); -  return success(); +  return std::error_code();  }  std::error_code RawCoverageReader::readIntMax(uint64_t &Result, @@ -47,8 +50,8 @@ std::error_code RawCoverageReader::readIntMax(uint64_t &Result,    if (auto Err = readULEB128(Result))      return Err;    if (Result >= MaxPlus1) -    return error(instrprof_error::malformed); -  return success(); +    return coveragemap_error::malformed; +  return std::error_code();  }  std::error_code RawCoverageReader::readSize(uint64_t &Result) { @@ -56,8 +59,8 @@ std::error_code RawCoverageReader::readSize(uint64_t &Result) {      return Err;    // Sanity check the number.    if (Result > Data.size()) -    return error(instrprof_error::malformed); -  return success(); +    return coveragemap_error::malformed; +  return std::error_code();  }  std::error_code RawCoverageReader::readString(StringRef &Result) { @@ -66,7 +69,7 @@ std::error_code RawCoverageReader::readString(StringRef &Result) {      return Err;    Result = Data.substr(0, Length);    Data = Data.substr(Length); -  return success(); +  return std::error_code();  }  std::error_code RawCoverageFilenamesReader::read() { @@ -79,7 +82,7 @@ std::error_code RawCoverageFilenamesReader::read() {        return Err;      Filenames.push_back(Filename);    } -  return success(); +  return std::error_code();  }  std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value, @@ -88,10 +91,10 @@ std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value,    switch (Tag) {    case Counter::Zero:      C = Counter::getZero(); -    return success(); +    return std::error_code();    case Counter::CounterValueReference:      C = Counter::getCounter(Value >> Counter::EncodingTagBits); -    return success(); +    return std::error_code();    default:      break;    } @@ -101,15 +104,15 @@ std::error_code RawCoverageMappingReader::decodeCounter(unsigned Value,    case CounterExpression::Add: {      auto ID = Value >> Counter::EncodingTagBits;      if (ID >= Expressions.size()) -      return error(instrprof_error::malformed); +      return coveragemap_error::malformed;      Expressions[ID].Kind = CounterExpression::ExprKind(Tag);      C = Counter::getExpression(ID);      break;    }    default: -    return error(instrprof_error::malformed); +    return coveragemap_error::malformed;    } -  return success(); +  return std::error_code();  }  std::error_code RawCoverageMappingReader::readCounter(Counter &C) { @@ -119,7 +122,7 @@ std::error_code RawCoverageMappingReader::readCounter(Counter &C) {      return Err;    if (auto Err = decodeCounter(EncodedCounter, C))      return Err; -  return success(); +  return std::error_code();  }  static const unsigned EncodingExpansionRegionBit = 1 @@ -156,7 +159,7 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(          ExpandedFileID = EncodedCounterAndRegion >>                           Counter::EncodingCounterTagAndExpansionRegionTagBits;          if (ExpandedFileID >= NumFileIDs) -          return error(instrprof_error::malformed); +          return coveragemap_error::malformed;        } else {          switch (EncodedCounterAndRegion >>                  Counter::EncodingCounterTagAndExpansionRegionTagBits) { @@ -167,23 +170,20 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(            Kind = CounterMappingRegion::SkippedRegion;            break;          default: -          return error(instrprof_error::malformed); +          return coveragemap_error::malformed;          }        }      }      // Read the source range. -    uint64_t LineStartDelta, CodeBeforeColumnStart, NumLines, ColumnEnd; +    uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd;      if (auto Err =              readIntMax(LineStartDelta, std::numeric_limits<unsigned>::max()))        return Err; -    if (auto Err = readULEB128(CodeBeforeColumnStart)) +    if (auto Err = readULEB128(ColumnStart))        return Err; -    bool HasCodeBefore = CodeBeforeColumnStart & 1; -    uint64_t ColumnStart = CodeBeforeColumnStart >> -                           CounterMappingRegion::EncodingHasCodeBeforeBits;      if (ColumnStart > std::numeric_limits<unsigned>::max()) -      return error(instrprof_error::malformed); +      return coveragemap_error::malformed;      if (auto Err = readIntMax(NumLines, std::numeric_limits<unsigned>::max()))        return Err;      if (auto Err = readIntMax(ColumnEnd, std::numeric_limits<unsigned>::max())) @@ -214,14 +214,13 @@ std::error_code RawCoverageMappingReader::readMappingRegionsSubArray(      });      MappingRegions.push_back(CounterMappingRegion( -        C, InferredFileID, LineStart, ColumnStart, LineStart + NumLines, -        ColumnEnd, HasCodeBefore, Kind)); -    MappingRegions.back().ExpandedFileID = ExpandedFileID; +        C, InferredFileID, ExpandedFileID, LineStart, ColumnStart, +        LineStart + NumLines, ColumnEnd, Kind));    } -  return success(); +  return std::error_code();  } -std::error_code RawCoverageMappingReader::read(CoverageMappingRecord &Record) { +std::error_code RawCoverageMappingReader::read() {    // Read the virtual file mapping.    llvm::SmallVector<unsigned, 8> VirtualFileMapping; @@ -287,42 +286,10 @@ std::error_code RawCoverageMappingReader::read(CoverageMappingRecord &Record) {      }    } -  Record.FunctionName = FunctionName; -  Record.Filenames = Filenames; -  Record.Expressions = Expressions; -  Record.MappingRegions = MappingRegions; -  return success(); -} - -ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader( -    StringRef FileName) -    : CurrentRecord(0) { -  auto File = llvm::object::ObjectFile::createObjectFile(FileName); -  if (!File) -    error(File.getError()); -  else -    Object = std::move(File.get()); +  return std::error_code();  }  namespace { -/// \brief The coverage mapping data for a single function. -/// It points to the function's name. -template <typename IntPtrT> struct CoverageMappingFunctionRecord { -  IntPtrT FunctionNamePtr; -  uint32_t FunctionNameSize; -  uint32_t CoverageMappingSize; -  uint64_t FunctionHash; -}; - -/// \brief The coverage mapping data for a single translation unit. -/// It points to the array of function coverage mapping records and the encoded -/// filenames array. -template <typename IntPtrT> struct CoverageMappingTURecord { -  uint32_t FunctionRecordsSize; -  uint32_t FilenamesSize; -  uint32_t CoverageMappingsSize; -  uint32_t Version; -};  /// \brief A helper structure to access the data from a section  /// in an object file. @@ -334,220 +301,254 @@ struct SectionData {      if (auto Err = Section.getContents(Data))        return Err;      Address = Section.getAddress(); -    return instrprof_error::success; +    return std::error_code();    }    std::error_code get(uint64_t Pointer, size_t Size, StringRef &Result) {      if (Pointer < Address) -      return instrprof_error::malformed; +      return coveragemap_error::malformed;      auto Offset = Pointer - Address;      if (Offset + Size > Data.size()) -      return instrprof_error::malformed; +      return coveragemap_error::malformed;      Result = Data.substr(Pointer - Address, Size); -    return instrprof_error::success; +    return std::error_code();    }  };  } -template <typename T> +template <typename T, support::endianness Endian>  std::error_code readCoverageMappingData(      SectionData &ProfileNames, StringRef Data, -    std::vector<ObjectFileCoverageMappingReader::ProfileMappingRecord> &Records, +    std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,      std::vector<StringRef> &Filenames) { +  using namespace support;    llvm::DenseSet<T> UniqueFunctionMappingData;    // Read the records in the coverage data section. -  while (!Data.empty()) { -    if (Data.size() < sizeof(CoverageMappingTURecord<T>)) -      return instrprof_error::malformed; -    auto TU = reinterpret_cast<const CoverageMappingTURecord<T> *>(Data.data()); -    Data = Data.substr(sizeof(CoverageMappingTURecord<T>)); -    switch (TU->Version) { +  for (const char *Buf = Data.data(), *End = Buf + Data.size(); Buf < End;) { +    if (Buf + 4 * sizeof(uint32_t) > End) +      return coveragemap_error::malformed; +    uint32_t NRecords = endian::readNext<uint32_t, Endian, unaligned>(Buf); +    uint32_t FilenamesSize = endian::readNext<uint32_t, Endian, unaligned>(Buf); +    uint32_t CoverageSize = endian::readNext<uint32_t, Endian, unaligned>(Buf); +    uint32_t Version = endian::readNext<uint32_t, Endian, unaligned>(Buf); + +    switch (Version) {      case CoverageMappingVersion1:        break;      default: -      return instrprof_error::unsupported_version; +      return coveragemap_error::unsupported_version;      } -    auto Version = CoverageMappingVersion(TU->Version); -    // Get the function records. -    auto FunctionRecords = -        reinterpret_cast<const CoverageMappingFunctionRecord<T> *>(Data.data()); -    if (Data.size() < -        sizeof(CoverageMappingFunctionRecord<T>) * TU->FunctionRecordsSize) -      return instrprof_error::malformed; -    Data = Data.substr(sizeof(CoverageMappingFunctionRecord<T>) * -                       TU->FunctionRecordsSize); +    // Skip past the function records, saving the start and end for later. +    const char *FunBuf = Buf; +    Buf += NRecords * (sizeof(T) + 2 * sizeof(uint32_t) + sizeof(uint64_t)); +    const char *FunEnd = Buf;      // Get the filenames. -    if (Data.size() < TU->FilenamesSize) -      return instrprof_error::malformed; -    auto RawFilenames = Data.substr(0, TU->FilenamesSize); -    Data = Data.substr(TU->FilenamesSize); +    if (Buf + FilenamesSize > End) +      return coveragemap_error::malformed;      size_t FilenamesBegin = Filenames.size(); -    RawCoverageFilenamesReader Reader(RawFilenames, Filenames); +    RawCoverageFilenamesReader Reader(StringRef(Buf, FilenamesSize), Filenames);      if (auto Err = Reader.read())        return Err; - -    // Get the coverage mappings. -    if (Data.size() < TU->CoverageMappingsSize) -      return instrprof_error::malformed; -    auto CoverageMappings = Data.substr(0, TU->CoverageMappingsSize); -    Data = Data.substr(TU->CoverageMappingsSize); - -    for (unsigned I = 0; I < TU->FunctionRecordsSize; ++I) { -      auto &MappingRecord = FunctionRecords[I]; - -      // Get the coverage mapping. -      if (CoverageMappings.size() < MappingRecord.CoverageMappingSize) -        return instrprof_error::malformed; -      auto Mapping = -          CoverageMappings.substr(0, MappingRecord.CoverageMappingSize); -      CoverageMappings = -          CoverageMappings.substr(MappingRecord.CoverageMappingSize); +    Buf += FilenamesSize; + +    // We'll read the coverage mapping records in the loop below. +    const char *CovBuf = Buf; +    Buf += CoverageSize; +    const char *CovEnd = Buf; +    if (Buf > End) +      return coveragemap_error::malformed; + +    while (FunBuf < FunEnd) { +      // Read the function information +      T NamePtr = endian::readNext<T, Endian, unaligned>(FunBuf); +      uint32_t NameSize = endian::readNext<uint32_t, Endian, unaligned>(FunBuf); +      uint32_t DataSize = endian::readNext<uint32_t, Endian, unaligned>(FunBuf); +      uint64_t FuncHash = endian::readNext<uint64_t, Endian, unaligned>(FunBuf); + +      // Now use that to read the coverage data. +      if (CovBuf + DataSize > CovEnd) +        return coveragemap_error::malformed; +      auto Mapping = StringRef(CovBuf, DataSize); +      CovBuf += DataSize;        // Ignore this record if we already have a record that points to the same -      // function name. -      // This is useful to ignore the redundant records for the functions -      // with ODR linkage. -      if (!UniqueFunctionMappingData.insert(MappingRecord.FunctionNamePtr) -               .second) +      // function name. This is useful to ignore the redundant records for the +      // functions with ODR linkage. +      if (!UniqueFunctionMappingData.insert(NamePtr).second)          continue; -      StringRef FunctionName; -      if (auto Err = -              ProfileNames.get(MappingRecord.FunctionNamePtr, -                               MappingRecord.FunctionNameSize, FunctionName)) -        return Err; -      Records.push_back(ObjectFileCoverageMappingReader::ProfileMappingRecord( -          Version, FunctionName, MappingRecord.FunctionHash, Mapping, + +      // Finally, grab the name and create a record. +      StringRef FuncName; +      if (std::error_code EC = ProfileNames.get(NamePtr, NameSize, FuncName)) +        return EC; +      Records.push_back(BinaryCoverageReader::ProfileMappingRecord( +          CoverageMappingVersion(Version), FuncName, FuncHash, Mapping,            FilenamesBegin, Filenames.size() - FilenamesBegin));      }    } -  return instrprof_error::success; +  return std::error_code();  }  static const char *TestingFormatMagic = "llvmcovmtestdata"; -static std::error_code decodeTestingFormat(StringRef Data, -                                           SectionData &ProfileNames, -                                           StringRef &CoverageMapping) { +static std::error_code loadTestingFormat(StringRef Data, +                                         SectionData &ProfileNames, +                                         StringRef &CoverageMapping, +                                         uint8_t &BytesInAddress, +                                         support::endianness &Endian) { +  BytesInAddress = 8; +  Endian = support::endianness::little; +    Data = Data.substr(StringRef(TestingFormatMagic).size());    if (Data.size() < 1) -    return instrprof_error::truncated; +    return coveragemap_error::truncated;    unsigned N = 0;    auto ProfileNamesSize =        decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);    if (N > Data.size()) -    return instrprof_error::malformed; +    return coveragemap_error::malformed;    Data = Data.substr(N);    if (Data.size() < 1) -    return instrprof_error::truncated; +    return coveragemap_error::truncated;    N = 0;    ProfileNames.Address =        decodeULEB128(reinterpret_cast<const uint8_t *>(Data.data()), &N);    if (N > Data.size()) -    return instrprof_error::malformed; +    return coveragemap_error::malformed;    Data = Data.substr(N);    if (Data.size() < ProfileNamesSize) -    return instrprof_error::malformed; +    return coveragemap_error::malformed;    ProfileNames.Data = Data.substr(0, ProfileNamesSize);    CoverageMapping = Data.substr(ProfileNamesSize); -  return instrprof_error::success; +  return std::error_code();  } -ObjectFileCoverageMappingReader::ObjectFileCoverageMappingReader( -    std::unique_ptr<MemoryBuffer> &ObjectBuffer, sys::fs::file_magic Type) -    : CurrentRecord(0) { -  if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) { -    // This is a special format used for testing. -    SectionData ProfileNames; -    StringRef CoverageMapping; -    if (auto Err = decodeTestingFormat(ObjectBuffer->getBuffer(), ProfileNames, -                                       CoverageMapping)) { -      error(Err); -      return; -    } -    error(readCoverageMappingData<uint64_t>(ProfileNames, CoverageMapping, -                                            MappingRecords, Filenames)); -    Object = OwningBinary<ObjectFile>(std::unique_ptr<ObjectFile>(), -                                      std::move(ObjectBuffer)); -    return; +static ErrorOr<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) { +  StringRef FoundName; +  for (const auto &Section : OF.sections()) { +    if (auto EC = Section.getName(FoundName)) +      return EC; +    if (FoundName == Name) +      return Section;    } - -  auto File = object::ObjectFile::createObjectFile( -      ObjectBuffer->getMemBufferRef(), Type); -  if (!File) -    error(File.getError()); -  else -    Object = OwningBinary<ObjectFile>(std::move(File.get()), -                                      std::move(ObjectBuffer)); +  return coveragemap_error::no_data_found;  } -std::error_code ObjectFileCoverageMappingReader::readHeader() { -  const ObjectFile *OF = Object.getBinary(); -  if (!OF) -    return getError(); -  auto BytesInAddress = OF->getBytesInAddress(); -  if (BytesInAddress != 4 && BytesInAddress != 8) -    return error(instrprof_error::malformed); +static std::error_code loadBinaryFormat(MemoryBufferRef ObjectBuffer, +                                        SectionData &ProfileNames, +                                        StringRef &CoverageMapping, +                                        uint8_t &BytesInAddress, +                                        support::endianness &Endian, +                                        Triple::ArchType Arch) { +  auto BinOrErr = object::createBinary(ObjectBuffer); +  if (std::error_code EC = BinOrErr.getError()) +    return EC; +  auto Bin = std::move(BinOrErr.get()); +  std::unique_ptr<ObjectFile> OF; +  if (auto *Universal = dyn_cast<object::MachOUniversalBinary>(Bin.get())) { +    // If we have a universal binary, try to look up the object for the +    // appropriate architecture. +    auto ObjectFileOrErr = Universal->getObjectForArch(Arch); +    if (std::error_code EC = ObjectFileOrErr.getError()) +      return EC; +    OF = std::move(ObjectFileOrErr.get()); +  } else if (isa<object::ObjectFile>(Bin.get())) { +    // For any other object file, upcast and take ownership. +    OF.reset(cast<object::ObjectFile>(Bin.release())); +    // If we've asked for a particular arch, make sure they match. +    if (Arch != Triple::ArchType::UnknownArch && OF->getArch() != Arch) +      return object_error::arch_not_found; +  } else +    // We can only handle object files. +    return 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;    // Look for the sections that we are interested in. -  int FoundSectionCount = 0; -  SectionRef ProfileNames, CoverageMapping; -  for (const auto &Section : OF->sections()) { -    StringRef Name; -    if (auto Err = Section.getName(Name)) -      return Err; -    if (Name == "__llvm_prf_names") { -      ProfileNames = Section; -    } else if (Name == "__llvm_covmap") { -      CoverageMapping = Section; -    } else -      continue; -    ++FoundSectionCount; -  } -  if (FoundSectionCount != 2) -    return error(instrprof_error::bad_header); +  auto NamesSection = lookupSection(*OF, "__llvm_prf_names"); +  if (auto EC = NamesSection.getError()) +    return EC; +  auto CoverageSection = lookupSection(*OF, "__llvm_covmap"); +  if (auto EC = CoverageSection.getError()) +    return EC;    // Get the contents of the given sections. -  StringRef Data; -  if (auto Err = CoverageMapping.getContents(Data)) -    return Err; -  SectionData ProfileNamesData; -  if (auto Err = ProfileNamesData.load(ProfileNames)) -    return Err; +  if (std::error_code EC = CoverageSection->getContents(CoverageMapping)) +    return EC; +  if (std::error_code EC = ProfileNames.load(*NamesSection)) +    return EC; -  // Load the data from the found sections. -  std::error_code Err; -  if (BytesInAddress == 4) -    Err = readCoverageMappingData<uint32_t>(ProfileNamesData, Data, -                                            MappingRecords, Filenames); -  else -    Err = readCoverageMappingData<uint64_t>(ProfileNamesData, Data, -                                            MappingRecords, Filenames); -  if (Err) -    return error(Err); +  return std::error_code(); +} -  return success(); +ErrorOr<std::unique_ptr<BinaryCoverageReader>> +BinaryCoverageReader::create(std::unique_ptr<MemoryBuffer> &ObjectBuffer, +                             Triple::ArchType Arch) { +  std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader()); + +  SectionData Profile; +  StringRef Coverage; +  uint8_t BytesInAddress; +  support::endianness Endian; +  std::error_code EC; +  if (ObjectBuffer->getBuffer().startswith(TestingFormatMagic)) +    // This is a special format used for testing. +    EC = loadTestingFormat(ObjectBuffer->getBuffer(), Profile, Coverage, +                           BytesInAddress, Endian); +  else +    EC = loadBinaryFormat(ObjectBuffer->getMemBufferRef(), Profile, Coverage, +                          BytesInAddress, Endian, Arch); +  if (EC) +    return EC; + +  if (BytesInAddress == 4 && Endian == support::endianness::little) +    EC = readCoverageMappingData<uint32_t, support::endianness::little>( +        Profile, Coverage, Reader->MappingRecords, Reader->Filenames); +  else if (BytesInAddress == 4 && Endian == support::endianness::big) +    EC = readCoverageMappingData<uint32_t, support::endianness::big>( +        Profile, Coverage, Reader->MappingRecords, Reader->Filenames); +  else if (BytesInAddress == 8 && Endian == support::endianness::little) +    EC = readCoverageMappingData<uint64_t, support::endianness::little>( +        Profile, Coverage, Reader->MappingRecords, Reader->Filenames); +  else if (BytesInAddress == 8 && Endian == support::endianness::big) +    EC = readCoverageMappingData<uint64_t, support::endianness::big>( +        Profile, Coverage, Reader->MappingRecords, Reader->Filenames); +  else +    return coveragemap_error::malformed; +  if (EC) +    return EC; +  return std::move(Reader);  }  std::error_code -ObjectFileCoverageMappingReader::readNextRecord(CoverageMappingRecord &Record) { +BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {    if (CurrentRecord >= MappingRecords.size()) -    return error(instrprof_error::eof); +    return coveragemap_error::eof;    FunctionsFilenames.clear();    Expressions.clear();    MappingRegions.clear();    auto &R = MappingRecords[CurrentRecord];    RawCoverageMappingReader Reader( -      R.FunctionName, R.CoverageMapping, -      makeArrayRef(Filenames.data() + R.FilenamesBegin, R.FilenamesSize), +      R.CoverageMapping, +      makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize),        FunctionsFilenames, Expressions, MappingRegions); -  if (auto Err = Reader.read(Record)) +  if (auto Err = Reader.read())      return Err; + +  Record.FunctionName = R.FunctionName;    Record.FunctionHash = R.FunctionHash; +  Record.Filenames = FunctionsFilenames; +  Record.Expressions = Expressions; +  Record.MappingRegions = MappingRegions; +    ++CurrentRecord; -  return success(); +  return std::error_code();  }  | 
