12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187 |
- //===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===//
- //
- // 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
- //
- //===----------------------------------------------------------------------===//
- //
- // This file contains support for reading coverage mapping data for
- // instrumentation based coverage.
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ProfileData/Coverage/CoverageMappingReader.h"
- #include "llvm/ADT/ArrayRef.h"
- #include "llvm/ADT/DenseMap.h"
- #include "llvm/ADT/STLExtras.h"
- #include "llvm/ADT/SmallVector.h"
- #include "llvm/ADT/Statistic.h"
- #include "llvm/ADT/StringRef.h"
- #include "llvm/ADT/Triple.h"
- #include "llvm/Object/Archive.h"
- #include "llvm/Object/Binary.h"
- #include "llvm/Object/COFF.h"
- #include "llvm/Object/Error.h"
- #include "llvm/Object/MachOUniversal.h"
- #include "llvm/Object/ObjectFile.h"
- #include "llvm/ProfileData/InstrProf.h"
- #include "llvm/Support/Casting.h"
- #include "llvm/Support/Compression.h"
- #include "llvm/Support/Debug.h"
- #include "llvm/Support/Endian.h"
- #include "llvm/Support/Error.h"
- #include "llvm/Support/ErrorHandling.h"
- #include "llvm/Support/LEB128.h"
- #include "llvm/Support/MathExtras.h"
- #include "llvm/Support/Path.h"
- #include "llvm/Support/raw_ostream.h"
- #include <vector>
- using namespace llvm;
- using namespace coverage;
- using namespace object;
- #define DEBUG_TYPE "coverage-mapping"
- STATISTIC(CovMapNumRecords, "The # of coverage function records");
- STATISTIC(CovMapNumUsedRecords, "The # of used coverage function records");
- void CoverageMappingIterator::increment() {
- if (ReadErr != coveragemap_error::success)
- return;
- // Check if all the records were read or if an error occurred while reading
- // the next record.
- if (auto E = Reader->readNextRecord(Record))
- handleAllErrors(std::move(E), [&](const CoverageMapError &CME) {
- if (CME.get() == coveragemap_error::eof)
- *this = CoverageMappingIterator();
- else
- ReadErr = CME.get();
- });
- }
- Error RawCoverageReader::readULEB128(uint64_t &Result) {
- if (Data.empty())
- return make_error<CoverageMapError>(coveragemap_error::truncated);
- unsigned N = 0;
- Result = decodeULEB128(Data.bytes_begin(), &N);
- if (N > Data.size())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- Data = Data.substr(N);
- return Error::success();
- }
- Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) {
- if (auto Err = readULEB128(Result))
- return Err;
- if (Result >= MaxPlus1)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- return Error::success();
- }
- Error RawCoverageReader::readSize(uint64_t &Result) {
- if (auto Err = readULEB128(Result))
- return Err;
- if (Result > Data.size())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- return Error::success();
- }
- Error RawCoverageReader::readString(StringRef &Result) {
- uint64_t Length;
- if (auto Err = readSize(Length))
- return Err;
- Result = Data.substr(0, Length);
- Data = Data.substr(Length);
- return Error::success();
- }
- Error RawCoverageFilenamesReader::read(CovMapVersion Version) {
- uint64_t NumFilenames;
- if (auto Err = readSize(NumFilenames))
- return Err;
- if (!NumFilenames)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- if (Version < CovMapVersion::Version4)
- return readUncompressed(Version, NumFilenames);
- // The uncompressed length may exceed the size of the encoded filenames.
- // Skip size validation.
- uint64_t UncompressedLen;
- if (auto Err = readULEB128(UncompressedLen))
- return Err;
- uint64_t CompressedLen;
- if (auto Err = readSize(CompressedLen))
- return Err;
- if (CompressedLen > 0) {
- if (!compression::zlib::isAvailable())
- return make_error<CoverageMapError>(
- coveragemap_error::decompression_failed);
- // Allocate memory for the decompressed filenames.
- SmallVector<uint8_t, 0> StorageBuf;
- // Read compressed filenames.
- StringRef CompressedFilenames = Data.substr(0, CompressedLen);
- Data = Data.substr(CompressedLen);
- auto Err = compression::zlib::decompress(
- arrayRefFromStringRef(CompressedFilenames), StorageBuf,
- UncompressedLen);
- if (Err) {
- consumeError(std::move(Err));
- return make_error<CoverageMapError>(
- coveragemap_error::decompression_failed);
- }
- RawCoverageFilenamesReader Delegate(toStringRef(StorageBuf), Filenames,
- CompilationDir);
- return Delegate.readUncompressed(Version, NumFilenames);
- }
- return readUncompressed(Version, NumFilenames);
- }
- Error RawCoverageFilenamesReader::readUncompressed(CovMapVersion Version,
- uint64_t NumFilenames) {
- // Read uncompressed filenames.
- if (Version < CovMapVersion::Version6) {
- for (size_t I = 0; I < NumFilenames; ++I) {
- StringRef Filename;
- if (auto Err = readString(Filename))
- return Err;
- Filenames.push_back(Filename.str());
- }
- } else {
- StringRef CWD;
- if (auto Err = readString(CWD))
- return Err;
- Filenames.push_back(CWD.str());
- for (size_t I = 1; I < NumFilenames; ++I) {
- StringRef Filename;
- if (auto Err = readString(Filename))
- return Err;
- if (sys::path::is_absolute(Filename)) {
- Filenames.push_back(Filename.str());
- } else {
- SmallString<256> P;
- if (!CompilationDir.empty())
- P.assign(CompilationDir);
- else
- P.assign(CWD);
- llvm::sys::path::append(P, Filename);
- sys::path::remove_dots(P, /*remove_dot_dot=*/true);
- Filenames.push_back(static_cast<std::string>(P.str()));
- }
- }
- }
- return Error::success();
- }
- Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) {
- auto Tag = Value & Counter::EncodingTagMask;
- switch (Tag) {
- case Counter::Zero:
- C = Counter::getZero();
- return Error::success();
- case Counter::CounterValueReference:
- C = Counter::getCounter(Value >> Counter::EncodingTagBits);
- return Error::success();
- default:
- break;
- }
- Tag -= Counter::Expression;
- switch (Tag) {
- case CounterExpression::Subtract:
- case CounterExpression::Add: {
- auto ID = Value >> Counter::EncodingTagBits;
- if (ID >= Expressions.size())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- Expressions[ID].Kind = CounterExpression::ExprKind(Tag);
- C = Counter::getExpression(ID);
- break;
- }
- default:
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- }
- return Error::success();
- }
- Error RawCoverageMappingReader::readCounter(Counter &C) {
- uint64_t EncodedCounter;
- if (auto Err =
- readIntMax(EncodedCounter, std::numeric_limits<unsigned>::max()))
- return Err;
- if (auto Err = decodeCounter(EncodedCounter, C))
- return Err;
- return Error::success();
- }
- static const unsigned EncodingExpansionRegionBit = 1
- << Counter::EncodingTagBits;
- /// Read the sub-array of regions for the given inferred file id.
- /// \param NumFileIDs the number of file ids that are defined for this
- /// function.
- Error RawCoverageMappingReader::readMappingRegionsSubArray(
- std::vector<CounterMappingRegion> &MappingRegions, unsigned InferredFileID,
- size_t NumFileIDs) {
- uint64_t NumRegions;
- if (auto Err = readSize(NumRegions))
- return Err;
- unsigned LineStart = 0;
- for (size_t I = 0; I < NumRegions; ++I) {
- Counter C, C2;
- CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion;
- // Read the combined counter + region kind.
- uint64_t EncodedCounterAndRegion;
- if (auto Err = readIntMax(EncodedCounterAndRegion,
- std::numeric_limits<unsigned>::max()))
- return Err;
- unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask;
- uint64_t ExpandedFileID = 0;
- // If Tag does not represent a ZeroCounter, then it is understood to refer
- // to a counter or counter expression with region kind assumed to be
- // "CodeRegion". In that case, EncodedCounterAndRegion actually encodes the
- // referenced counter or counter expression (and nothing else).
- //
- // If Tag represents a ZeroCounter and EncodingExpansionRegionBit is set,
- // then EncodedCounterAndRegion is interpreted to represent an
- // ExpansionRegion. In all other cases, EncodedCounterAndRegion is
- // interpreted to refer to a specific region kind, after which additional
- // fields may be read (e.g. BranchRegions have two encoded counters that
- // follow an encoded region kind value).
- if (Tag != Counter::Zero) {
- if (auto Err = decodeCounter(EncodedCounterAndRegion, C))
- return Err;
- } else {
- // Is it an expansion region?
- if (EncodedCounterAndRegion & EncodingExpansionRegionBit) {
- Kind = CounterMappingRegion::ExpansionRegion;
- ExpandedFileID = EncodedCounterAndRegion >>
- Counter::EncodingCounterTagAndExpansionRegionTagBits;
- if (ExpandedFileID >= NumFileIDs)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- } else {
- switch (EncodedCounterAndRegion >>
- Counter::EncodingCounterTagAndExpansionRegionTagBits) {
- case CounterMappingRegion::CodeRegion:
- // Don't do anything when we have a code region with a zero counter.
- break;
- case CounterMappingRegion::SkippedRegion:
- Kind = CounterMappingRegion::SkippedRegion;
- break;
- case CounterMappingRegion::BranchRegion:
- // For a Branch Region, read two successive counters.
- Kind = CounterMappingRegion::BranchRegion;
- if (auto Err = readCounter(C))
- return Err;
- if (auto Err = readCounter(C2))
- return Err;
- break;
- default:
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- }
- }
- }
- // Read the source range.
- uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd;
- if (auto Err =
- readIntMax(LineStartDelta, std::numeric_limits<unsigned>::max()))
- return Err;
- if (auto Err = readULEB128(ColumnStart))
- return Err;
- if (ColumnStart > std::numeric_limits<unsigned>::max())
- return make_error<CoverageMapError>(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()))
- return Err;
- LineStart += LineStartDelta;
- // If the high bit of ColumnEnd is set, this is a gap region.
- if (ColumnEnd & (1U << 31)) {
- Kind = CounterMappingRegion::GapRegion;
- ColumnEnd &= ~(1U << 31);
- }
- // Adjust the column locations for the empty regions that are supposed to
- // cover whole lines. Those regions should be encoded with the
- // column range (1 -> std::numeric_limits<unsigned>::max()), but because
- // the encoded std::numeric_limits<unsigned>::max() is several bytes long,
- // we set the column range to (0 -> 0) to ensure that the column start and
- // column end take up one byte each.
- // The std::numeric_limits<unsigned>::max() is used to represent a column
- // position at the end of the line without knowing the length of that line.
- if (ColumnStart == 0 && ColumnEnd == 0) {
- ColumnStart = 1;
- ColumnEnd = std::numeric_limits<unsigned>::max();
- }
- LLVM_DEBUG({
- dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":"
- << ColumnStart << " -> " << (LineStart + NumLines) << ":"
- << ColumnEnd << ", ";
- if (Kind == CounterMappingRegion::ExpansionRegion)
- dbgs() << "Expands to file " << ExpandedFileID;
- else
- CounterMappingContext(Expressions).dump(C, dbgs());
- dbgs() << "\n";
- });
- auto CMR = CounterMappingRegion(C, C2, InferredFileID, ExpandedFileID,
- LineStart, ColumnStart,
- LineStart + NumLines, ColumnEnd, Kind);
- if (CMR.startLoc() > CMR.endLoc())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- MappingRegions.push_back(CMR);
- }
- return Error::success();
- }
- Error RawCoverageMappingReader::read() {
- // Read the virtual file mapping.
- SmallVector<unsigned, 8> VirtualFileMapping;
- uint64_t NumFileMappings;
- if (auto Err = readSize(NumFileMappings))
- return Err;
- for (size_t I = 0; I < NumFileMappings; ++I) {
- uint64_t FilenameIndex;
- if (auto Err = readIntMax(FilenameIndex, TranslationUnitFilenames.size()))
- return Err;
- VirtualFileMapping.push_back(FilenameIndex);
- }
- // Construct the files using unique filenames and virtual file mapping.
- for (auto I : VirtualFileMapping) {
- Filenames.push_back(TranslationUnitFilenames[I]);
- }
- // Read the expressions.
- uint64_t NumExpressions;
- if (auto Err = readSize(NumExpressions))
- return Err;
- // Create an array of dummy expressions that get the proper counters
- // when the expressions are read, and the proper kinds when the counters
- // are decoded.
- Expressions.resize(
- NumExpressions,
- CounterExpression(CounterExpression::Subtract, Counter(), Counter()));
- for (size_t I = 0; I < NumExpressions; ++I) {
- if (auto Err = readCounter(Expressions[I].LHS))
- return Err;
- if (auto Err = readCounter(Expressions[I].RHS))
- return Err;
- }
- // Read the mapping regions sub-arrays.
- for (unsigned InferredFileID = 0, S = VirtualFileMapping.size();
- InferredFileID < S; ++InferredFileID) {
- if (auto Err = readMappingRegionsSubArray(MappingRegions, InferredFileID,
- VirtualFileMapping.size()))
- return Err;
- }
- // Set the counters for the expansion regions.
- // i.e. Counter of expansion region = counter of the first region
- // from the expanded file.
- // Perform multiple passes to correctly propagate the counters through
- // all the nested expansion regions.
- SmallVector<CounterMappingRegion *, 8> FileIDExpansionRegionMapping;
- FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr);
- for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) {
- for (auto &R : MappingRegions) {
- if (R.Kind != CounterMappingRegion::ExpansionRegion)
- continue;
- assert(!FileIDExpansionRegionMapping[R.ExpandedFileID]);
- FileIDExpansionRegionMapping[R.ExpandedFileID] = &R;
- }
- for (auto &R : MappingRegions) {
- if (FileIDExpansionRegionMapping[R.FileID]) {
- FileIDExpansionRegionMapping[R.FileID]->Count = R.Count;
- FileIDExpansionRegionMapping[R.FileID] = nullptr;
- }
- }
- }
- return Error::success();
- }
- Expected<bool> RawCoverageMappingDummyChecker::isDummy() {
- // A dummy coverage mapping data consists of just one region with zero count.
- uint64_t NumFileMappings;
- if (Error Err = readSize(NumFileMappings))
- return std::move(Err);
- if (NumFileMappings != 1)
- return false;
- // We don't expect any specific value for the filename index, just skip it.
- uint64_t FilenameIndex;
- if (Error Err =
- readIntMax(FilenameIndex, std::numeric_limits<unsigned>::max()))
- return std::move(Err);
- uint64_t NumExpressions;
- if (Error Err = readSize(NumExpressions))
- return std::move(Err);
- if (NumExpressions != 0)
- return false;
- uint64_t NumRegions;
- if (Error Err = readSize(NumRegions))
- return std::move(Err);
- if (NumRegions != 1)
- return false;
- uint64_t EncodedCounterAndRegion;
- if (Error Err = readIntMax(EncodedCounterAndRegion,
- std::numeric_limits<unsigned>::max()))
- return std::move(Err);
- unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask;
- return Tag == Counter::Zero;
- }
- Error InstrProfSymtab::create(SectionRef &Section) {
- 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();
- }
- StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) {
- if (Pointer < Address)
- return StringRef();
- auto Offset = Pointer - Address;
- if (Offset + Size > Data.size())
- return StringRef();
- return Data.substr(Pointer - Address, Size);
- }
- // Check if the mapping data is a dummy, i.e. is emitted for an unused function.
- static Expected<bool> isCoverageMappingDummy(uint64_t Hash, StringRef Mapping) {
- // The hash value of dummy mapping records is always zero.
- if (Hash)
- return false;
- return RawCoverageMappingDummyChecker(Mapping).isDummy();
- }
- /// A range of filename indices. Used to specify the location of a batch of
- /// filenames in a vector-like container.
- struct FilenameRange {
- unsigned StartingIndex;
- unsigned Length;
- FilenameRange(unsigned StartingIndex, unsigned Length)
- : StartingIndex(StartingIndex), Length(Length) {}
- void markInvalid() { Length = 0; }
- bool isInvalid() const { return Length == 0; }
- };
- namespace {
- /// The interface to read coverage mapping function records for a module.
- struct CovMapFuncRecordReader {
- virtual ~CovMapFuncRecordReader() = default;
- // Read a coverage header.
- //
- // \p CovBuf points to the buffer containing the \c CovHeader of the coverage
- // mapping data associated with the module.
- //
- // Returns a pointer to the next \c CovHeader if it exists, or to an address
- // greater than \p CovEnd if not.
- virtual Expected<const char *> readCoverageHeader(const char *CovBuf,
- const char *CovBufEnd) = 0;
- // Read function records.
- //
- // \p FuncRecBuf points to the buffer containing a batch of function records.
- // \p FuncRecBufEnd points past the end of the batch of records.
- //
- // Prior to Version4, \p OutOfLineFileRange points to a sequence of filenames
- // associated with the function records. It is unused in Version4.
- //
- // Prior to Version4, \p OutOfLineMappingBuf points to a sequence of coverage
- // mappings associated with the function records. It is unused in Version4.
- virtual Error
- readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
- std::optional<FilenameRange> OutOfLineFileRange,
- const char *OutOfLineMappingBuf,
- const char *OutOfLineMappingBufEnd) = 0;
- template <class IntPtrT, support::endianness Endian>
- static Expected<std::unique_ptr<CovMapFuncRecordReader>>
- get(CovMapVersion Version, InstrProfSymtab &P,
- std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
- std::vector<std::string> &F);
- };
- // A class for reading coverage mapping function records for a module.
- template <CovMapVersion Version, class IntPtrT, support::endianness Endian>
- class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {
- using FuncRecordType =
- typename CovMapTraits<Version, IntPtrT>::CovMapFuncRecordType;
- using NameRefType = typename CovMapTraits<Version, IntPtrT>::NameRefType;
- // Maps function's name references to the indexes of their records
- // in \c Records.
- DenseMap<NameRefType, size_t> FunctionRecords;
- InstrProfSymtab &ProfileNames;
- StringRef CompilationDir;
- std::vector<std::string> &Filenames;
- std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records;
- // Maps a hash of the filenames in a TU to a \c FileRange. The range
- // specifies the location of the hashed filenames in \c Filenames.
- DenseMap<uint64_t, FilenameRange> FileRangeMap;
- // Add the record to the collection if we don't 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.
- // In addition, prefer records with real coverage mapping data to dummy
- // records, which were emitted for inline functions which were seen but
- // not used in the corresponding translation unit.
- Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR,
- StringRef Mapping,
- FilenameRange FileRange) {
- ++CovMapNumRecords;
- uint64_t FuncHash = CFR->template getFuncHash<Endian>();
- NameRefType NameRef = CFR->template getFuncNameRef<Endian>();
- auto InsertResult =
- FunctionRecords.insert(std::make_pair(NameRef, Records.size()));
- if (InsertResult.second) {
- StringRef FuncName;
- if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName))
- return Err;
- if (FuncName.empty())
- return make_error<InstrProfError>(instrprof_error::malformed,
- "function name is empty");
- ++CovMapNumUsedRecords;
- Records.emplace_back(Version, FuncName, FuncHash, Mapping,
- FileRange.StartingIndex, FileRange.Length);
- return Error::success();
- }
- // Update the existing record if it's a dummy and the new record is real.
- size_t OldRecordIndex = InsertResult.first->second;
- BinaryCoverageReader::ProfileMappingRecord &OldRecord =
- Records[OldRecordIndex];
- Expected<bool> OldIsDummyExpected = isCoverageMappingDummy(
- OldRecord.FunctionHash, OldRecord.CoverageMapping);
- if (Error Err = OldIsDummyExpected.takeError())
- return Err;
- if (!*OldIsDummyExpected)
- return Error::success();
- Expected<bool> NewIsDummyExpected =
- isCoverageMappingDummy(FuncHash, Mapping);
- if (Error Err = NewIsDummyExpected.takeError())
- return Err;
- if (*NewIsDummyExpected)
- return Error::success();
- ++CovMapNumUsedRecords;
- OldRecord.FunctionHash = FuncHash;
- OldRecord.CoverageMapping = Mapping;
- OldRecord.FilenamesBegin = FileRange.StartingIndex;
- OldRecord.FilenamesSize = FileRange.Length;
- return Error::success();
- }
- public:
- VersionedCovMapFuncRecordReader(
- InstrProfSymtab &P,
- std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
- std::vector<std::string> &F)
- : ProfileNames(P), CompilationDir(D), Filenames(F), Records(R) {}
- ~VersionedCovMapFuncRecordReader() override = default;
- Expected<const char *> readCoverageHeader(const char *CovBuf,
- const char *CovBufEnd) override {
- using namespace support;
- if (CovBuf + sizeof(CovMapHeader) > CovBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- auto CovHeader = reinterpret_cast<const CovMapHeader *>(CovBuf);
- uint32_t NRecords = CovHeader->getNRecords<Endian>();
- uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>();
- uint32_t CoverageSize = CovHeader->getCoverageSize<Endian>();
- assert((CovMapVersion)CovHeader->getVersion<Endian>() == Version);
- CovBuf = reinterpret_cast<const char *>(CovHeader + 1);
- // Skip past the function records, saving the start and end for later.
- // This is a no-op in Version4 (function records are read after all headers
- // are read).
- const char *FuncRecBuf = nullptr;
- const char *FuncRecBufEnd = nullptr;
- if (Version < CovMapVersion::Version4)
- FuncRecBuf = CovBuf;
- CovBuf += NRecords * sizeof(FuncRecordType);
- if (Version < CovMapVersion::Version4)
- FuncRecBufEnd = CovBuf;
- // Get the filenames.
- if (CovBuf + FilenamesSize > CovBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- size_t FilenamesBegin = Filenames.size();
- StringRef FilenameRegion(CovBuf, FilenamesSize);
- RawCoverageFilenamesReader Reader(FilenameRegion, Filenames,
- CompilationDir);
- if (auto Err = Reader.read(Version))
- return std::move(Err);
- CovBuf += FilenamesSize;
- FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin);
- if (Version >= CovMapVersion::Version4) {
- // Map a hash of the filenames region to the filename range associated
- // with this coverage header.
- int64_t FilenamesRef =
- llvm::IndexedInstrProf::ComputeHash(FilenameRegion);
- auto Insert =
- FileRangeMap.insert(std::make_pair(FilenamesRef, FileRange));
- if (!Insert.second) {
- // The same filenames ref was encountered twice. It's possible that
- // the associated filenames are the same.
- auto It = Filenames.begin();
- FilenameRange &OrigRange = Insert.first->getSecond();
- if (std::equal(It + OrigRange.StartingIndex,
- It + OrigRange.StartingIndex + OrigRange.Length,
- It + FileRange.StartingIndex,
- It + FileRange.StartingIndex + FileRange.Length))
- // Map the new range to the original one.
- FileRange = OrigRange;
- else
- // This is a hash collision. Mark the filenames ref invalid.
- OrigRange.markInvalid();
- }
- }
- // We'll read the coverage mapping records in the loop below.
- // This is a no-op in Version4 (coverage mappings are not affixed to the
- // coverage header).
- const char *MappingBuf = CovBuf;
- if (Version >= CovMapVersion::Version4 && CoverageSize != 0)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- CovBuf += CoverageSize;
- const char *MappingEnd = CovBuf;
- if (CovBuf > CovBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- if (Version < CovMapVersion::Version4) {
- // Read each function record.
- if (Error E = readFunctionRecords(FuncRecBuf, FuncRecBufEnd, FileRange,
- MappingBuf, MappingEnd))
- return std::move(E);
- }
- // Each coverage map has an alignment of 8, so we need to adjust alignment
- // before reading the next map.
- CovBuf += offsetToAlignedAddr(CovBuf, Align(8));
- return CovBuf;
- }
- Error readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,
- std::optional<FilenameRange> OutOfLineFileRange,
- const char *OutOfLineMappingBuf,
- const char *OutOfLineMappingBufEnd) override {
- auto CFR = reinterpret_cast<const FuncRecordType *>(FuncRecBuf);
- while ((const char *)CFR < FuncRecBufEnd) {
- // Validate the length of the coverage mapping for this function.
- const char *NextMappingBuf;
- const FuncRecordType *NextCFR;
- std::tie(NextMappingBuf, NextCFR) =
- CFR->template advanceByOne<Endian>(OutOfLineMappingBuf);
- if (Version < CovMapVersion::Version4)
- if (NextMappingBuf > OutOfLineMappingBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- // Look up the set of filenames associated with this function record.
- std::optional<FilenameRange> FileRange;
- if (Version < CovMapVersion::Version4) {
- FileRange = OutOfLineFileRange;
- } else {
- uint64_t FilenamesRef = CFR->template getFilenamesRef<Endian>();
- auto It = FileRangeMap.find(FilenamesRef);
- if (It == FileRangeMap.end())
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- else
- FileRange = It->getSecond();
- }
- // Now, read the coverage data.
- if (FileRange && !FileRange->isInvalid()) {
- StringRef Mapping =
- CFR->template getCoverageMapping<Endian>(OutOfLineMappingBuf);
- if (Version >= CovMapVersion::Version4 &&
- Mapping.data() + Mapping.size() > FuncRecBufEnd)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange))
- return Err;
- }
- std::tie(OutOfLineMappingBuf, CFR) = std::tie(NextMappingBuf, NextCFR);
- }
- return Error::success();
- }
- };
- } // end anonymous namespace
- template <class IntPtrT, support::endianness Endian>
- Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(
- CovMapVersion Version, InstrProfSymtab &P,
- std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,
- std::vector<std::string> &F) {
- using namespace coverage;
- switch (Version) {
- case CovMapVersion::Version1:
- return std::make_unique<VersionedCovMapFuncRecordReader<
- CovMapVersion::Version1, IntPtrT, Endian>>(P, R, D, F);
- case CovMapVersion::Version2:
- case CovMapVersion::Version3:
- case CovMapVersion::Version4:
- case CovMapVersion::Version5:
- case CovMapVersion::Version6:
- // Decompress the name data.
- if (Error E = P.create(P.getNameData()))
- return std::move(E);
- if (Version == CovMapVersion::Version2)
- return std::make_unique<VersionedCovMapFuncRecordReader<
- CovMapVersion::Version2, IntPtrT, Endian>>(P, R, D, F);
- else if (Version == CovMapVersion::Version3)
- return std::make_unique<VersionedCovMapFuncRecordReader<
- CovMapVersion::Version3, IntPtrT, Endian>>(P, R, D, F);
- else if (Version == CovMapVersion::Version4)
- return std::make_unique<VersionedCovMapFuncRecordReader<
- CovMapVersion::Version4, IntPtrT, Endian>>(P, R, D, F);
- else if (Version == CovMapVersion::Version5)
- return std::make_unique<VersionedCovMapFuncRecordReader<
- CovMapVersion::Version5, IntPtrT, Endian>>(P, R, D, F);
- else if (Version == CovMapVersion::Version6)
- return std::make_unique<VersionedCovMapFuncRecordReader<
- CovMapVersion::Version6, IntPtrT, Endian>>(P, R, D, F);
- }
- llvm_unreachable("Unsupported version");
- }
- template <typename T, support::endianness Endian>
- static Error readCoverageMappingData(
- InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,
- std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,
- StringRef CompilationDir, std::vector<std::string> &Filenames) {
- using namespace coverage;
- // Read the records in the coverage data section.
- auto CovHeader =
- reinterpret_cast<const CovMapHeader *>(CovMap.data());
- CovMapVersion Version = (CovMapVersion)CovHeader->getVersion<Endian>();
- if (Version > CovMapVersion::CurrentVersion)
- return make_error<CoverageMapError>(coveragemap_error::unsupported_version);
- Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected =
- CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records,
- CompilationDir, Filenames);
- if (Error E = ReaderExpected.takeError())
- return E;
- auto Reader = std::move(ReaderExpected.get());
- const char *CovBuf = CovMap.data();
- const char *CovBufEnd = CovBuf + CovMap.size();
- const char *FuncRecBuf = FuncRecords.data();
- const char *FuncRecBufEnd = FuncRecords.data() + FuncRecords.size();
- while (CovBuf < CovBufEnd) {
- // Read the current coverage header & filename data.
- //
- // Prior to Version4, this also reads all function records affixed to the
- // header.
- //
- // Return a pointer to the next coverage header.
- auto NextOrErr = Reader->readCoverageHeader(CovBuf, CovBufEnd);
- if (auto E = NextOrErr.takeError())
- return E;
- CovBuf = NextOrErr.get();
- }
- // In Version4, function records are not affixed to coverage headers. Read
- // the records from their dedicated section.
- if (Version >= CovMapVersion::Version4)
- return Reader->readFunctionRecords(FuncRecBuf, FuncRecBufEnd, std::nullopt,
- nullptr, nullptr);
- return Error::success();
- }
- static const char *TestingFormatMagic = "llvmcovmtestdata";
- Expected<std::unique_ptr<BinaryCoverageReader>>
- BinaryCoverageReader::createCoverageReaderFromBuffer(
- StringRef Coverage, FuncRecordsStorage &&FuncRecords,
- InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress,
- support::endianness Endian, StringRef CompilationDir) {
- std::unique_ptr<BinaryCoverageReader> Reader(
- new BinaryCoverageReader(std::move(FuncRecords)));
- Reader->ProfileNames = std::move(ProfileNames);
- StringRef FuncRecordsRef = Reader->FuncRecords->getBuffer();
- if (BytesInAddress == 4 && Endian == support::endianness::little) {
- if (Error E =
- readCoverageMappingData<uint32_t, support::endianness::little>(
- Reader->ProfileNames, Coverage, FuncRecordsRef,
- Reader->MappingRecords, CompilationDir, 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, FuncRecordsRef,
- Reader->MappingRecords, CompilationDir, 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, FuncRecordsRef,
- Reader->MappingRecords, CompilationDir, 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, FuncRecordsRef,
- Reader->MappingRecords, CompilationDir, 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, StringRef CompilationDir) {
- 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;
- 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(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 std::move(E);
- Data = Data.substr(ProfileNamesSize);
- // Skip the padding bytes because coverage map data has an alignment of 8.
- size_t Pad = offsetToAlignedAddr(Data.data(), Align(8));
- if (Data.size() < Pad)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- Data = Data.substr(Pad);
- if (Data.size() < sizeof(CovMapHeader))
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- auto const *CovHeader = reinterpret_cast<const CovMapHeader *>(
- Data.substr(0, sizeof(CovMapHeader)).data());
- CovMapVersion Version =
- (CovMapVersion)CovHeader->getVersion<support::endianness::little>();
- StringRef CoverageMapping;
- BinaryCoverageReader::FuncRecordsStorage CoverageRecords;
- if (Version < CovMapVersion::Version4) {
- CoverageMapping = Data;
- if (CoverageMapping.empty())
- return make_error<CoverageMapError>(coveragemap_error::truncated);
- CoverageRecords = MemoryBuffer::getMemBuffer("");
- } else {
- uint32_t FilenamesSize =
- CovHeader->getFilenamesSize<support::endianness::little>();
- uint32_t CoverageMappingSize = sizeof(CovMapHeader) + FilenamesSize;
- CoverageMapping = Data.substr(0, CoverageMappingSize);
- if (CoverageMapping.empty())
- return make_error<CoverageMapError>(coveragemap_error::truncated);
- Data = Data.substr(CoverageMappingSize);
- // Skip the padding bytes because coverage records data has an alignment
- // of 8.
- Pad = offsetToAlignedAddr(Data.data(), Align(8));
- if (Data.size() < Pad)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- CoverageRecords = MemoryBuffer::getMemBuffer(Data.substr(Pad));
- if (CoverageRecords->getBufferSize() == 0)
- return make_error<CoverageMapError>(coveragemap_error::truncated);
- }
- return BinaryCoverageReader::createCoverageReaderFromBuffer(
- CoverageMapping, std::move(CoverageRecords), std::move(ProfileNames),
- BytesInAddress, Endian, CompilationDir);
- }
- /// Find all sections that match \p Name. There may be more than one if comdats
- /// are in use, e.g. for the __llvm_covfun section on ELF.
- static Expected<std::vector<SectionRef>> lookupSections(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);
- std::vector<SectionRef> Sections;
- for (const auto &Section : OF.sections()) {
- Expected<StringRef> NameOrErr = Section.getName();
- if (!NameOrErr)
- return NameOrErr.takeError();
- if (stripSuffix(*NameOrErr) == Name)
- Sections.push_back(Section);
- }
- if (Sections.empty())
- return make_error<CoverageMapError>(coveragemap_error::no_data_found);
- return Sections;
- }
- static Expected<std::unique_ptr<BinaryCoverageReader>>
- loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,
- StringRef CompilationDir = "",
- std::optional<object::BuildIDRef> *BinaryID = nullptr) {
- 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
- // appropriate architecture.
- auto ObjectFileOrErr = Universal->getMachOObjectForArch(Arch);
- if (!ObjectFileOrErr)
- return ObjectFileOrErr.takeError();
- OF = std::move(ObjectFileOrErr.get());
- } else if (isa<ObjectFile>(Bin.get())) {
- // For any other object file, upcast and take ownership.
- OF.reset(cast<ObjectFile>(Bin.release()));
- // If we've asked for a particular arch, make sure they match.
- if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch())
- return errorCodeToError(object_error::arch_not_found);
- } else
- // We can only handle object files.
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- // The coverage uses native pointer sizes for the object it's written in.
- 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();
- auto NamesSection =
- lookupSections(*OF, getInstrProfSectionName(IPSK_name, ObjFormat,
- /*AddSegmentInfo=*/false));
- if (auto E = NamesSection.takeError())
- return std::move(E);
- auto CoverageSection =
- lookupSections(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat,
- /*AddSegmentInfo=*/false));
- if (auto E = CoverageSection.takeError())
- return std::move(E);
- std::vector<SectionRef> CoverageSectionRefs = *CoverageSection;
- if (CoverageSectionRefs.size() != 1)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- auto CoverageMappingOrErr = CoverageSectionRefs.back().getContents();
- if (!CoverageMappingOrErr)
- return CoverageMappingOrErr.takeError();
- StringRef CoverageMapping = CoverageMappingOrErr.get();
- InstrProfSymtab ProfileNames;
- std::vector<SectionRef> NamesSectionRefs = *NamesSection;
- if (NamesSectionRefs.size() != 1)
- return make_error<CoverageMapError>(coveragemap_error::malformed);
- if (Error E = ProfileNames.create(NamesSectionRefs.back()))
- return std::move(E);
- // Look for the coverage records section (Version4 only).
- auto CoverageRecordsSections =
- lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat,
- /*AddSegmentInfo=*/false));
- BinaryCoverageReader::FuncRecordsStorage FuncRecords;
- if (auto E = CoverageRecordsSections.takeError()) {
- consumeError(std::move(E));
- FuncRecords = MemoryBuffer::getMemBuffer("");
- } else {
- // Compute the FuncRecordsBuffer of the buffer, taking into account the
- // padding between each record, and making sure the first block is aligned
- // in memory to maintain consistency between buffer address and size
- // alignment.
- const Align RecordAlignment(8);
- uint64_t FuncRecordsSize = 0;
- for (SectionRef Section : *CoverageRecordsSections) {
- auto CoverageRecordsOrErr = Section.getContents();
- if (!CoverageRecordsOrErr)
- return CoverageRecordsOrErr.takeError();
- FuncRecordsSize += alignTo(CoverageRecordsOrErr->size(), RecordAlignment);
- }
- auto WritableBuffer =
- WritableMemoryBuffer::getNewUninitMemBuffer(FuncRecordsSize);
- char *FuncRecordsBuffer = WritableBuffer->getBufferStart();
- assert(isAddrAligned(RecordAlignment, FuncRecordsBuffer) &&
- "Allocated memory is correctly aligned");
- for (SectionRef Section : *CoverageRecordsSections) {
- auto CoverageRecordsOrErr = Section.getContents();
- if (!CoverageRecordsOrErr)
- return CoverageRecordsOrErr.takeError();
- const auto &CoverageRecords = CoverageRecordsOrErr.get();
- FuncRecordsBuffer = std::copy(CoverageRecords.begin(),
- CoverageRecords.end(), FuncRecordsBuffer);
- FuncRecordsBuffer =
- std::fill_n(FuncRecordsBuffer,
- alignAddr(FuncRecordsBuffer, RecordAlignment) -
- (uintptr_t)FuncRecordsBuffer,
- '\0');
- }
- assert(FuncRecordsBuffer == WritableBuffer->getBufferEnd() &&
- "consistent init");
- FuncRecords = std::move(WritableBuffer);
- }
- if (BinaryID)
- *BinaryID = getBuildID(OF.get());
- return BinaryCoverageReader::createCoverageReaderFromBuffer(
- CoverageMapping, std::move(FuncRecords), std::move(ProfileNames),
- BytesInAddress, Endian, CompilationDir);
- }
- /// Determine whether \p Arch is invalid or empty, given \p Bin.
- static bool isArchSpecifierInvalidOrMissing(Binary *Bin, StringRef Arch) {
- // If we have a universal binary and Arch doesn't identify any of its slices,
- // it's user error.
- if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin)) {
- for (auto &ObjForArch : Universal->objects())
- if (Arch == ObjForArch.getArchFlagName())
- return false;
- return true;
- }
- return false;
- }
- Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>
- BinaryCoverageReader::create(
- MemoryBufferRef ObjectBuffer, StringRef Arch,
- SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,
- StringRef CompilationDir, SmallVectorImpl<object::BuildIDRef> *BinaryIDs) {
- std::vector<std::unique_ptr<BinaryCoverageReader>> Readers;
- if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) {
- // This is a special format used for testing.
- auto ReaderOrErr =
- loadTestingFormat(ObjectBuffer.getBuffer(), CompilationDir);
- if (!ReaderOrErr)
- return ReaderOrErr.takeError();
- Readers.push_back(std::move(ReaderOrErr.get()));
- return std::move(Readers);
- }
- auto BinOrErr = createBinary(ObjectBuffer);
- if (!BinOrErr)
- return BinOrErr.takeError();
- std::unique_ptr<Binary> Bin = std::move(BinOrErr.get());
- if (isArchSpecifierInvalidOrMissing(Bin.get(), Arch))
- return make_error<CoverageMapError>(
- coveragemap_error::invalid_or_missing_arch_specifier);
- // 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,
- CompilationDir, BinaryIDs);
- }
- }
- // 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, CompilationDir,
- BinaryIDs);
- 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);
- }
- std::optional<object::BuildIDRef> BinaryID;
- auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch, CompilationDir,
- BinaryIDs ? &BinaryID : nullptr);
- if (!ReaderOrErr)
- return ReaderOrErr.takeError();
- Readers.push_back(std::move(ReaderOrErr.get()));
- if (BinaryID)
- BinaryIDs->push_back(*BinaryID);
- return std::move(Readers);
- }
- Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {
- if (CurrentRecord >= MappingRecords.size())
- return make_error<CoverageMapError>(coveragemap_error::eof);
- FunctionsFilenames.clear();
- Expressions.clear();
- MappingRegions.clear();
- auto &R = MappingRecords[CurrentRecord];
- auto F = ArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize);
- RawCoverageMappingReader Reader(R.CoverageMapping, F, FunctionsFilenames,
- Expressions, MappingRegions);
- 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 Error::success();
- }
|