diff options
Diffstat (limited to 'contrib/llvm/lib/ProfileData/CoverageMappingReader.cpp')
-rw-r--r-- | contrib/llvm/lib/ProfileData/CoverageMappingReader.cpp | 402 |
1 files changed, 204 insertions, 198 deletions
diff --git a/contrib/llvm/lib/ProfileData/CoverageMappingReader.cpp b/contrib/llvm/lib/ProfileData/CoverageMappingReader.cpp index 6476d28..ec531c3 100644 --- a/contrib/llvm/lib/ProfileData/CoverageMappingReader.cpp +++ b/contrib/llvm/lib/ProfileData/CoverageMappingReader.cpp @@ -14,9 +14,13 @@ #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/MathExtras.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace coverage; @@ -33,13 +37,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 +51,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 +60,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 +70,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 +83,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 +92,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 +105,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 +123,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 +160,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 +171,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 +215,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 +287,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 +302,258 @@ 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; + // Each coverage map has an alignment of 8, so we need to adjust alignment + // before reading the next map. + Buf += alignmentAdjustment(Buf, 8); + + 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(); } |