1384 lines · cpp
1//===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains support for reading coverage mapping data for10// instrumentation based coverage.11//12//===----------------------------------------------------------------------===//13 14#include "llvm/ProfileData/Coverage/CoverageMappingReader.h"15#include "llvm/ADT/ArrayRef.h"16#include "llvm/ADT/DenseMap.h"17#include "llvm/ADT/SmallVector.h"18#include "llvm/ADT/Statistic.h"19#include "llvm/ADT/StringRef.h"20#include "llvm/BinaryFormat/Wasm.h"21#include "llvm/Object/Archive.h"22#include "llvm/Object/Binary.h"23#include "llvm/Object/COFF.h"24#include "llvm/Object/Error.h"25#include "llvm/Object/MachOUniversal.h"26#include "llvm/Object/ObjectFile.h"27#include "llvm/Object/Wasm.h"28#include "llvm/ProfileData/InstrProf.h"29#include "llvm/Support/Casting.h"30#include "llvm/Support/Compression.h"31#include "llvm/Support/Debug.h"32#include "llvm/Support/Endian.h"33#include "llvm/Support/Error.h"34#include "llvm/Support/ErrorHandling.h"35#include "llvm/Support/LEB128.h"36#include "llvm/Support/Path.h"37#include "llvm/Support/raw_ostream.h"38#include "llvm/TargetParser/Triple.h"39#include <vector>40 41using namespace llvm;42using namespace coverage;43using namespace object;44 45#define DEBUG_TYPE "coverage-mapping"46 47STATISTIC(CovMapNumRecords, "The # of coverage function records");48STATISTIC(CovMapNumUsedRecords, "The # of used coverage function records");49 50void CoverageMappingIterator::increment() {51 if (ReadErr != coveragemap_error::success)52 return;53 54 // Check if all the records were read or if an error occurred while reading55 // the next record.56 if (auto E = Reader->readNextRecord(Record))57 handleAllErrors(std::move(E), [&](const CoverageMapError &CME) {58 if (CME.get() == coveragemap_error::eof)59 *this = CoverageMappingIterator();60 else61 ReadErr = CME.get();62 });63}64 65Error RawCoverageReader::readULEB128(uint64_t &Result) {66 if (Data.empty())67 return make_error<CoverageMapError>(coveragemap_error::truncated);68 unsigned N = 0;69 Result = decodeULEB128(Data.bytes_begin(), &N);70 if (N > Data.size())71 return make_error<CoverageMapError>(coveragemap_error::malformed,72 "the size of ULEB128 is too big");73 Data = Data.substr(N);74 return Error::success();75}76 77Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) {78 if (auto Err = readULEB128(Result))79 return Err;80 if (Result >= MaxPlus1)81 return make_error<CoverageMapError>(82 coveragemap_error::malformed,83 "the value of ULEB128 is greater than or equal to MaxPlus1");84 return Error::success();85}86 87Error RawCoverageReader::readSize(uint64_t &Result) {88 if (auto Err = readULEB128(Result))89 return Err;90 if (Result > Data.size())91 return make_error<CoverageMapError>(coveragemap_error::malformed,92 "the value of ULEB128 is too big");93 return Error::success();94}95 96Error RawCoverageReader::readString(StringRef &Result) {97 uint64_t Length;98 if (auto Err = readSize(Length))99 return Err;100 Result = Data.substr(0, Length);101 Data = Data.substr(Length);102 return Error::success();103}104 105Error RawCoverageFilenamesReader::read(CovMapVersion Version) {106 uint64_t NumFilenames;107 if (auto Err = readSize(NumFilenames))108 return Err;109 if (!NumFilenames)110 return make_error<CoverageMapError>(coveragemap_error::malformed,111 "number of filenames is zero");112 113 if (Version < CovMapVersion::Version4)114 return readUncompressed(Version, NumFilenames);115 116 // The uncompressed length may exceed the size of the encoded filenames.117 // Skip size validation.118 uint64_t UncompressedLen;119 if (auto Err = readULEB128(UncompressedLen))120 return Err;121 122 uint64_t CompressedLen;123 if (auto Err = readSize(CompressedLen))124 return Err;125 126 if (CompressedLen > 0) {127 if (!compression::zlib::isAvailable())128 return make_error<CoverageMapError>(129 coveragemap_error::decompression_failed);130 131 // Allocate memory for the decompressed filenames.132 SmallVector<uint8_t, 0> StorageBuf;133 134 // Read compressed filenames.135 StringRef CompressedFilenames = Data.substr(0, CompressedLen);136 Data = Data.substr(CompressedLen);137 auto Err = compression::zlib::decompress(138 arrayRefFromStringRef(CompressedFilenames), StorageBuf,139 UncompressedLen);140 if (Err) {141 consumeError(std::move(Err));142 return make_error<CoverageMapError>(143 coveragemap_error::decompression_failed);144 }145 146 RawCoverageFilenamesReader Delegate(toStringRef(StorageBuf), Filenames,147 CompilationDir);148 return Delegate.readUncompressed(Version, NumFilenames);149 }150 151 return readUncompressed(Version, NumFilenames);152}153 154Error RawCoverageFilenamesReader::readUncompressed(CovMapVersion Version,155 uint64_t NumFilenames) {156 // Read uncompressed filenames.157 if (Version < CovMapVersion::Version6) {158 for (size_t I = 0; I < NumFilenames; ++I) {159 StringRef Filename;160 if (auto Err = readString(Filename))161 return Err;162 Filenames.push_back(Filename.str());163 }164 } else {165 StringRef CWD;166 if (auto Err = readString(CWD))167 return Err;168 Filenames.push_back(CWD.str());169 170 for (size_t I = 1; I < NumFilenames; ++I) {171 StringRef Filename;172 if (auto Err = readString(Filename))173 return Err;174 if (sys::path::is_absolute(Filename)) {175 Filenames.push_back(Filename.str());176 } else {177 SmallString<256> P;178 if (!CompilationDir.empty())179 P.assign(CompilationDir);180 else181 P.assign(CWD);182 llvm::sys::path::append(P, Filename);183 sys::path::remove_dots(P, /*remove_dot_dot=*/true);184 Filenames.push_back(static_cast<std::string>(P.str()));185 }186 }187 }188 return Error::success();189}190 191Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) {192 auto Tag = Value & Counter::EncodingTagMask;193 switch (Tag) {194 case Counter::Zero:195 C = Counter::getZero();196 return Error::success();197 case Counter::CounterValueReference:198 C = Counter::getCounter(Value >> Counter::EncodingTagBits);199 return Error::success();200 default:201 break;202 }203 Tag -= Counter::Expression;204 switch (Tag) {205 case CounterExpression::Subtract:206 case CounterExpression::Add: {207 auto ID = Value >> Counter::EncodingTagBits;208 if (ID >= Expressions.size())209 return make_error<CoverageMapError>(coveragemap_error::malformed,210 "counter expression is invalid");211 Expressions[ID].Kind = CounterExpression::ExprKind(Tag);212 C = Counter::getExpression(ID);213 break;214 }215 default:216 return make_error<CoverageMapError>(coveragemap_error::malformed,217 "counter expression kind is invalid");218 }219 return Error::success();220}221 222Error RawCoverageMappingReader::readCounter(Counter &C) {223 uint64_t EncodedCounter;224 if (auto Err =225 readIntMax(EncodedCounter, std::numeric_limits<unsigned>::max()))226 return Err;227 if (auto Err = decodeCounter(EncodedCounter, C))228 return Err;229 return Error::success();230}231 232static const unsigned EncodingExpansionRegionBit = 1233 << Counter::EncodingTagBits;234 235/// Read the sub-array of regions for the given inferred file id.236/// \param NumFileIDs the number of file ids that are defined for this237/// function.238Error RawCoverageMappingReader::readMappingRegionsSubArray(239 std::vector<CounterMappingRegion> &MappingRegions, unsigned InferredFileID,240 size_t NumFileIDs) {241 uint64_t NumRegions;242 if (auto Err = readSize(NumRegions))243 return Err;244 unsigned LineStart = 0;245 for (size_t I = 0; I < NumRegions; ++I) {246 Counter C, C2;247 uint64_t BIDX, NC;248 // They are stored as internal values plus 1 (min is -1)249 uint64_t ID1, TID1, FID1;250 mcdc::Parameters Params;251 CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion;252 253 // Read the combined counter + region kind.254 uint64_t EncodedCounterAndRegion;255 if (auto Err = readIntMax(EncodedCounterAndRegion,256 std::numeric_limits<unsigned>::max()))257 return Err;258 unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask;259 uint64_t ExpandedFileID = 0;260 261 // If Tag does not represent a ZeroCounter, then it is understood to refer262 // to a counter or counter expression with region kind assumed to be263 // "CodeRegion". In that case, EncodedCounterAndRegion actually encodes the264 // referenced counter or counter expression (and nothing else).265 //266 // If Tag represents a ZeroCounter and EncodingExpansionRegionBit is set,267 // then EncodedCounterAndRegion is interpreted to represent an268 // ExpansionRegion. In all other cases, EncodedCounterAndRegion is269 // interpreted to refer to a specific region kind, after which additional270 // fields may be read (e.g. BranchRegions have two encoded counters that271 // follow an encoded region kind value).272 if (Tag != Counter::Zero) {273 if (auto Err = decodeCounter(EncodedCounterAndRegion, C))274 return Err;275 } else {276 // Is it an expansion region?277 if (EncodedCounterAndRegion & EncodingExpansionRegionBit) {278 Kind = CounterMappingRegion::ExpansionRegion;279 ExpandedFileID = EncodedCounterAndRegion >>280 Counter::EncodingCounterTagAndExpansionRegionTagBits;281 if (ExpandedFileID >= NumFileIDs)282 return make_error<CoverageMapError>(coveragemap_error::malformed,283 "ExpandedFileID is invalid");284 } else {285 switch (EncodedCounterAndRegion >>286 Counter::EncodingCounterTagAndExpansionRegionTagBits) {287 case CounterMappingRegion::CodeRegion:288 // Don't do anything when we have a code region with a zero counter.289 break;290 case CounterMappingRegion::SkippedRegion:291 Kind = CounterMappingRegion::SkippedRegion;292 break;293 case CounterMappingRegion::BranchRegion:294 // For a Branch Region, read two successive counters.295 Kind = CounterMappingRegion::BranchRegion;296 if (auto Err = readCounter(C))297 return Err;298 if (auto Err = readCounter(C2))299 return Err;300 break;301 case CounterMappingRegion::MCDCBranchRegion:302 // For a MCDC Branch Region, read two successive counters and 3 IDs.303 Kind = CounterMappingRegion::MCDCBranchRegion;304 if (auto Err = readCounter(C))305 return Err;306 if (auto Err = readCounter(C2))307 return Err;308 if (auto Err = readIntMax(ID1, std::numeric_limits<int16_t>::max()))309 return Err;310 if (auto Err = readIntMax(TID1, std::numeric_limits<int16_t>::max()))311 return Err;312 if (auto Err = readIntMax(FID1, std::numeric_limits<int16_t>::max()))313 return Err;314 if (ID1 == 0)315 return make_error<CoverageMapError>(316 coveragemap_error::malformed,317 "MCDCConditionID shouldn't be zero");318 Params = mcdc::BranchParameters{319 static_cast<int16_t>(static_cast<int16_t>(ID1) - 1),320 {static_cast<int16_t>(static_cast<int16_t>(FID1) - 1),321 static_cast<int16_t>(static_cast<int16_t>(TID1) - 1)}};322 break;323 case CounterMappingRegion::MCDCDecisionRegion:324 Kind = CounterMappingRegion::MCDCDecisionRegion;325 if (auto Err = readIntMax(BIDX, std::numeric_limits<unsigned>::max()))326 return Err;327 if (auto Err = readIntMax(NC, std::numeric_limits<int16_t>::max()))328 return Err;329 Params = mcdc::DecisionParameters{static_cast<unsigned>(BIDX),330 static_cast<uint16_t>(NC)};331 break;332 default:333 return make_error<CoverageMapError>(coveragemap_error::malformed,334 "region kind is incorrect");335 }336 }337 }338 339 // Read the source range.340 uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd;341 if (auto Err =342 readIntMax(LineStartDelta, std::numeric_limits<unsigned>::max()))343 return Err;344 if (auto Err = readULEB128(ColumnStart))345 return Err;346 if (ColumnStart > std::numeric_limits<unsigned>::max())347 return make_error<CoverageMapError>(coveragemap_error::malformed,348 "start column is too big");349 if (auto Err = readIntMax(NumLines, std::numeric_limits<unsigned>::max()))350 return Err;351 if (auto Err = readIntMax(ColumnEnd, std::numeric_limits<unsigned>::max()))352 return Err;353 LineStart += LineStartDelta;354 355 // If the high bit of ColumnEnd is set, this is a gap region.356 if (ColumnEnd & (1U << 31)) {357 Kind = CounterMappingRegion::GapRegion;358 ColumnEnd &= ~(1U << 31);359 }360 361 // Adjust the column locations for the empty regions that are supposed to362 // cover whole lines. Those regions should be encoded with the363 // column range (1 -> std::numeric_limits<unsigned>::max()), but because364 // the encoded std::numeric_limits<unsigned>::max() is several bytes long,365 // we set the column range to (0 -> 0) to ensure that the column start and366 // column end take up one byte each.367 // The std::numeric_limits<unsigned>::max() is used to represent a column368 // position at the end of the line without knowing the length of that line.369 if (ColumnStart == 0 && ColumnEnd == 0) {370 ColumnStart = 1;371 ColumnEnd = std::numeric_limits<unsigned>::max();372 }373 374 LLVM_DEBUG({375 dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":"376 << ColumnStart << " -> " << (LineStart + NumLines) << ":"377 << ColumnEnd << ", ";378 if (Kind == CounterMappingRegion::ExpansionRegion)379 dbgs() << "Expands to file " << ExpandedFileID;380 else381 CounterMappingContext(Expressions).dump(C, dbgs());382 dbgs() << "\n";383 });384 385 auto CMR = CounterMappingRegion(386 C, C2, InferredFileID, ExpandedFileID, LineStart, ColumnStart,387 LineStart + NumLines, ColumnEnd, Kind, Params);388 if (CMR.startLoc() > CMR.endLoc())389 return make_error<CoverageMapError>(390 coveragemap_error::malformed,391 "counter mapping region locations are incorrect");392 MappingRegions.push_back(CMR);393 }394 return Error::success();395}396 397Error RawCoverageMappingReader::read() {398 // Read the virtual file mapping.399 SmallVector<unsigned, 8> VirtualFileMapping;400 uint64_t NumFileMappings;401 if (auto Err = readSize(NumFileMappings))402 return Err;403 for (size_t I = 0; I < NumFileMappings; ++I) {404 uint64_t FilenameIndex;405 if (auto Err = readIntMax(FilenameIndex, TranslationUnitFilenames.size()))406 return Err;407 VirtualFileMapping.push_back(FilenameIndex);408 }409 410 // Construct the files using unique filenames and virtual file mapping.411 for (auto I : VirtualFileMapping) {412 Filenames.push_back(TranslationUnitFilenames[I]);413 }414 415 // Read the expressions.416 uint64_t NumExpressions;417 if (auto Err = readSize(NumExpressions))418 return Err;419 // Create an array of dummy expressions that get the proper counters420 // when the expressions are read, and the proper kinds when the counters421 // are decoded.422 Expressions.resize(423 NumExpressions,424 CounterExpression(CounterExpression::Subtract, Counter(), Counter()));425 for (size_t I = 0; I < NumExpressions; ++I) {426 if (auto Err = readCounter(Expressions[I].LHS))427 return Err;428 if (auto Err = readCounter(Expressions[I].RHS))429 return Err;430 }431 432 // Read the mapping regions sub-arrays.433 for (unsigned InferredFileID = 0, S = VirtualFileMapping.size();434 InferredFileID < S; ++InferredFileID) {435 if (auto Err = readMappingRegionsSubArray(MappingRegions, InferredFileID,436 VirtualFileMapping.size()))437 return Err;438 }439 440 // Set the counters for the expansion regions.441 // i.e. Counter of expansion region = counter of the first region442 // from the expanded file.443 // Perform multiple passes to correctly propagate the counters through444 // all the nested expansion regions.445 SmallVector<CounterMappingRegion *, 8> FileIDExpansionRegionMapping;446 FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr);447 for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) {448 for (auto &R : MappingRegions) {449 if (R.Kind != CounterMappingRegion::ExpansionRegion)450 continue;451 assert(!FileIDExpansionRegionMapping[R.ExpandedFileID]);452 FileIDExpansionRegionMapping[R.ExpandedFileID] = &R;453 }454 for (auto &R : MappingRegions) {455 if (FileIDExpansionRegionMapping[R.FileID]) {456 FileIDExpansionRegionMapping[R.FileID]->Count = R.Count;457 FileIDExpansionRegionMapping[R.FileID] = nullptr;458 }459 }460 }461 462 return Error::success();463}464 465Expected<bool> RawCoverageMappingDummyChecker::isDummy() {466 // A dummy coverage mapping data consists of just one region with zero count.467 uint64_t NumFileMappings;468 if (Error Err = readSize(NumFileMappings))469 return std::move(Err);470 if (NumFileMappings != 1)471 return false;472 // We don't expect any specific value for the filename index, just skip it.473 uint64_t FilenameIndex;474 if (Error Err =475 readIntMax(FilenameIndex, std::numeric_limits<unsigned>::max()))476 return std::move(Err);477 uint64_t NumExpressions;478 if (Error Err = readSize(NumExpressions))479 return std::move(Err);480 if (NumExpressions != 0)481 return false;482 uint64_t NumRegions;483 if (Error Err = readSize(NumRegions))484 return std::move(Err);485 if (NumRegions != 1)486 return false;487 uint64_t EncodedCounterAndRegion;488 if (Error Err = readIntMax(EncodedCounterAndRegion,489 std::numeric_limits<unsigned>::max()))490 return std::move(Err);491 unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask;492 return Tag == Counter::Zero;493}494 495/// Determine if we should skip the first byte of the section content496static bool shouldSkipSectionFirstByte(SectionRef &Section) {497 const ObjectFile *Obj = Section.getObject();498 // If this is a linked PE/COFF file, then we have to skip over the null byte499 // that is allocated in the .lprfn$A section in the LLVM profiling runtime.500 // If the name section is .lprfcovnames, it doesn't have the null byte at the501 // beginning.502 if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject())503 if (Expected<StringRef> NameOrErr = Section.getName())504 if (*NameOrErr != getInstrProfSectionName(IPSK_covname, Triple::COFF))505 return true;506 return false;507}508 509Error InstrProfSymtab::create(SectionRef &Section) {510 Expected<StringRef> DataOrErr = Section.getContents();511 if (!DataOrErr)512 return DataOrErr.takeError();513 Data = *DataOrErr;514 Address = Section.getAddress();515 516 if (shouldSkipSectionFirstByte(Section))517 Data = Data.substr(1);518 519 return Error::success();520}521 522StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) const {523 if (Pointer < Address)524 return StringRef();525 auto Offset = Pointer - Address;526 if (Offset + Size > Data.size())527 return StringRef();528 return Data.substr(Pointer - Address, Size);529}530 531// Check if the mapping data is a dummy, i.e. is emitted for an unused function.532static Expected<bool> isCoverageMappingDummy(uint64_t Hash, StringRef Mapping) {533 // The hash value of dummy mapping records is always zero.534 if (Hash)535 return false;536 return RawCoverageMappingDummyChecker(Mapping).isDummy();537}538 539/// A range of filename indices. Used to specify the location of a batch of540/// filenames in a vector-like container.541struct FilenameRange {542 unsigned StartingIndex;543 unsigned Length;544 545 FilenameRange(unsigned StartingIndex, unsigned Length)546 : StartingIndex(StartingIndex), Length(Length) {}547 548 void markInvalid() { Length = 0; }549 bool isInvalid() const { return Length == 0; }550};551 552namespace {553 554/// The interface to read coverage mapping function records for a module.555struct CovMapFuncRecordReader {556 virtual ~CovMapFuncRecordReader() = default;557 558 // Read a coverage header.559 //560 // \p CovBuf points to the buffer containing the \c CovHeader of the coverage561 // mapping data associated with the module.562 //563 // Returns a pointer to the next \c CovHeader if it exists, or to an address564 // greater than \p CovEnd if not.565 virtual Expected<const char *> readCoverageHeader(const char *CovBuf,566 const char *CovBufEnd) = 0;567 568 // Read function records.569 //570 // \p FuncRecBuf points to the buffer containing a batch of function records.571 // \p FuncRecBufEnd points past the end of the batch of records.572 //573 // Prior to Version4, \p OutOfLineFileRange points to a sequence of filenames574 // associated with the function records. It is unused in Version4.575 //576 // Prior to Version4, \p OutOfLineMappingBuf points to a sequence of coverage577 // mappings associated with the function records. It is unused in Version4.578 virtual Error579 readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,580 std::optional<FilenameRange> OutOfLineFileRange,581 const char *OutOfLineMappingBuf,582 const char *OutOfLineMappingBufEnd) = 0;583 584 template <class IntPtrT, llvm::endianness Endian>585 static Expected<std::unique_ptr<CovMapFuncRecordReader>>586 get(CovMapVersion Version, InstrProfSymtab &P,587 std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,588 std::vector<std::string> &F);589};590 591// A class for reading coverage mapping function records for a module.592template <CovMapVersion Version, class IntPtrT, llvm::endianness Endian>593class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader {594 using FuncRecordType =595 typename CovMapTraits<Version, IntPtrT>::CovMapFuncRecordType;596 using NameRefType = typename CovMapTraits<Version, IntPtrT>::NameRefType;597 598 // Maps function's name references to the indexes of their records599 // in \c Records.600 DenseMap<NameRefType, size_t> FunctionRecords;601 InstrProfSymtab &ProfileNames;602 StringRef CompilationDir;603 std::vector<std::string> &Filenames;604 std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records;605 606 // Maps a hash of the filenames in a TU to a \c FileRange. The range607 // specifies the location of the hashed filenames in \c Filenames.608 DenseMap<uint64_t, FilenameRange> FileRangeMap;609 610 // Add the record to the collection if we don't already have a record that611 // points to the same function name. This is useful to ignore the redundant612 // records for the functions with ODR linkage.613 // In addition, prefer records with real coverage mapping data to dummy614 // records, which were emitted for inline functions which were seen but615 // not used in the corresponding translation unit.616 Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR,617 StringRef Mapping,618 FilenameRange FileRange) {619 ++CovMapNumRecords;620 uint64_t FuncHash = CFR->template getFuncHash<Endian>();621 NameRefType NameRef = CFR->template getFuncNameRef<Endian>();622 auto InsertResult =623 FunctionRecords.insert(std::make_pair(NameRef, Records.size()));624 if (InsertResult.second) {625 StringRef FuncName;626 if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName))627 return Err;628 if (FuncName.empty())629 return make_error<InstrProfError>(instrprof_error::malformed,630 "function name is empty");631 ++CovMapNumUsedRecords;632 Records.emplace_back(Version, FuncName, FuncHash, Mapping,633 FileRange.StartingIndex, FileRange.Length);634 return Error::success();635 }636 // Update the existing record if it's a dummy and the new record is real.637 size_t OldRecordIndex = InsertResult.first->second;638 BinaryCoverageReader::ProfileMappingRecord &OldRecord =639 Records[OldRecordIndex];640 Expected<bool> OldIsDummyExpected = isCoverageMappingDummy(641 OldRecord.FunctionHash, OldRecord.CoverageMapping);642 if (Error Err = OldIsDummyExpected.takeError())643 return Err;644 if (!*OldIsDummyExpected)645 return Error::success();646 Expected<bool> NewIsDummyExpected =647 isCoverageMappingDummy(FuncHash, Mapping);648 if (Error Err = NewIsDummyExpected.takeError())649 return Err;650 if (*NewIsDummyExpected)651 return Error::success();652 ++CovMapNumUsedRecords;653 OldRecord.FunctionHash = FuncHash;654 OldRecord.CoverageMapping = Mapping;655 OldRecord.FilenamesBegin = FileRange.StartingIndex;656 OldRecord.FilenamesSize = FileRange.Length;657 return Error::success();658 }659 660public:661 VersionedCovMapFuncRecordReader(662 InstrProfSymtab &P,663 std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,664 std::vector<std::string> &F)665 : ProfileNames(P), CompilationDir(D), Filenames(F), Records(R) {}666 667 ~VersionedCovMapFuncRecordReader() override = default;668 669 Expected<const char *> readCoverageHeader(const char *CovBuf,670 const char *CovBufEnd) override {671 using namespace support;672 673 if (CovBuf + sizeof(CovMapHeader) > CovBufEnd)674 return make_error<CoverageMapError>(675 coveragemap_error::malformed,676 "coverage mapping header section is larger than buffer size");677 auto CovHeader = reinterpret_cast<const CovMapHeader *>(CovBuf);678 uint32_t NRecords = CovHeader->getNRecords<Endian>();679 uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>();680 uint32_t CoverageSize = CovHeader->getCoverageSize<Endian>();681 assert((CovMapVersion)CovHeader->getVersion<Endian>() == Version);682 CovBuf = reinterpret_cast<const char *>(CovHeader + 1);683 684 // Skip past the function records, saving the start and end for later.685 // This is a no-op in Version4 (function records are read after all headers686 // are read).687 const char *FuncRecBuf = nullptr;688 const char *FuncRecBufEnd = nullptr;689 if (Version < CovMapVersion::Version4)690 FuncRecBuf = CovBuf;691 CovBuf += NRecords * sizeof(FuncRecordType);692 if (Version < CovMapVersion::Version4)693 FuncRecBufEnd = CovBuf;694 695 // Get the filenames.696 if (CovBuf + FilenamesSize > CovBufEnd)697 return make_error<CoverageMapError>(698 coveragemap_error::malformed,699 "filenames section is larger than buffer size");700 size_t FilenamesBegin = Filenames.size();701 StringRef FilenameRegion(CovBuf, FilenamesSize);702 RawCoverageFilenamesReader Reader(FilenameRegion, Filenames,703 CompilationDir);704 if (auto Err = Reader.read(Version))705 return std::move(Err);706 CovBuf += FilenamesSize;707 FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin);708 709 if (Version >= CovMapVersion::Version4) {710 // Map a hash of the filenames region to the filename range associated711 // with this coverage header.712 int64_t FilenamesRef =713 llvm::IndexedInstrProf::ComputeHash(FilenameRegion);714 auto Insert =715 FileRangeMap.insert(std::make_pair(FilenamesRef, FileRange));716 if (!Insert.second) {717 // The same filenames ref was encountered twice. It's possible that718 // the associated filenames are the same.719 auto It = Filenames.begin();720 FilenameRange &OrigRange = Insert.first->getSecond();721 if (std::equal(It + OrigRange.StartingIndex,722 It + OrigRange.StartingIndex + OrigRange.Length,723 It + FileRange.StartingIndex,724 It + FileRange.StartingIndex + FileRange.Length))725 // Map the new range to the original one.726 FileRange = OrigRange;727 else728 // This is a hash collision. Mark the filenames ref invalid.729 OrigRange.markInvalid();730 }731 }732 733 // We'll read the coverage mapping records in the loop below.734 // This is a no-op in Version4 (coverage mappings are not affixed to the735 // coverage header).736 const char *MappingBuf = CovBuf;737 if (Version >= CovMapVersion::Version4 && CoverageSize != 0)738 return make_error<CoverageMapError>(coveragemap_error::malformed,739 "coverage mapping size is not zero");740 CovBuf += CoverageSize;741 const char *MappingEnd = CovBuf;742 743 if (CovBuf > CovBufEnd)744 return make_error<CoverageMapError>(745 coveragemap_error::malformed,746 "function records section is larger than buffer size");747 748 if (Version < CovMapVersion::Version4) {749 // Read each function record.750 if (Error E = readFunctionRecords(FuncRecBuf, FuncRecBufEnd, FileRange,751 MappingBuf, MappingEnd))752 return std::move(E);753 }754 755 // Each coverage map has an alignment of 8, so we need to adjust alignment756 // before reading the next map.757 CovBuf += offsetToAlignedAddr(CovBuf, Align(8));758 759 return CovBuf;760 }761 762 Error readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd,763 std::optional<FilenameRange> OutOfLineFileRange,764 const char *OutOfLineMappingBuf,765 const char *OutOfLineMappingBufEnd) override {766 auto CFR = reinterpret_cast<const FuncRecordType *>(FuncRecBuf);767 while ((const char *)CFR < FuncRecBufEnd) {768 // Validate the length of the coverage mapping for this function.769 const char *NextMappingBuf;770 const FuncRecordType *NextCFR;771 std::tie(NextMappingBuf, NextCFR) =772 CFR->template advanceByOne<Endian>(OutOfLineMappingBuf);773 if (Version < CovMapVersion::Version4)774 if (NextMappingBuf > OutOfLineMappingBufEnd)775 return make_error<CoverageMapError>(776 coveragemap_error::malformed,777 "next mapping buffer is larger than buffer size");778 779 // Look up the set of filenames associated with this function record.780 std::optional<FilenameRange> FileRange;781 if (Version < CovMapVersion::Version4) {782 FileRange = OutOfLineFileRange;783 } else {784 uint64_t FilenamesRef = CFR->template getFilenamesRef<Endian>();785 auto It = FileRangeMap.find(FilenamesRef);786 if (It == FileRangeMap.end())787 return make_error<CoverageMapError>(788 coveragemap_error::malformed,789 "no filename found for function with hash=0x" +790 Twine::utohexstr(FilenamesRef));791 else792 FileRange = It->getSecond();793 }794 795 // Now, read the coverage data.796 if (FileRange && !FileRange->isInvalid()) {797 StringRef Mapping =798 CFR->template getCoverageMapping<Endian>(OutOfLineMappingBuf);799 if (Version >= CovMapVersion::Version4 &&800 Mapping.data() + Mapping.size() > FuncRecBufEnd)801 return make_error<CoverageMapError>(802 coveragemap_error::malformed,803 "coverage mapping data is larger than buffer size");804 if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange))805 return Err;806 }807 808 std::tie(OutOfLineMappingBuf, CFR) = std::tie(NextMappingBuf, NextCFR);809 }810 return Error::success();811 }812};813 814} // end anonymous namespace815 816template <class IntPtrT, llvm::endianness Endian>817Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get(818 CovMapVersion Version, InstrProfSymtab &P,819 std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, StringRef D,820 std::vector<std::string> &F) {821 using namespace coverage;822 823 switch (Version) {824 case CovMapVersion::Version1:825 return std::make_unique<VersionedCovMapFuncRecordReader<826 CovMapVersion::Version1, IntPtrT, Endian>>(P, R, D, F);827 case CovMapVersion::Version2:828 case CovMapVersion::Version3:829 case CovMapVersion::Version4:830 case CovMapVersion::Version5:831 case CovMapVersion::Version6:832 case CovMapVersion::Version7:833 // Decompress the name data.834 if (Error E = P.create(P.getNameData()))835 return std::move(E);836 if (Version == CovMapVersion::Version2)837 return std::make_unique<VersionedCovMapFuncRecordReader<838 CovMapVersion::Version2, IntPtrT, Endian>>(P, R, D, F);839 else if (Version == CovMapVersion::Version3)840 return std::make_unique<VersionedCovMapFuncRecordReader<841 CovMapVersion::Version3, IntPtrT, Endian>>(P, R, D, F);842 else if (Version == CovMapVersion::Version4)843 return std::make_unique<VersionedCovMapFuncRecordReader<844 CovMapVersion::Version4, IntPtrT, Endian>>(P, R, D, F);845 else if (Version == CovMapVersion::Version5)846 return std::make_unique<VersionedCovMapFuncRecordReader<847 CovMapVersion::Version5, IntPtrT, Endian>>(P, R, D, F);848 else if (Version == CovMapVersion::Version6)849 return std::make_unique<VersionedCovMapFuncRecordReader<850 CovMapVersion::Version6, IntPtrT, Endian>>(P, R, D, F);851 else if (Version == CovMapVersion::Version7)852 return std::make_unique<VersionedCovMapFuncRecordReader<853 CovMapVersion::Version7, IntPtrT, Endian>>(P, R, D, F);854 }855 llvm_unreachable("Unsupported version");856}857 858template <typename T, llvm::endianness Endian>859static Error readCoverageMappingData(860 InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords,861 std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records,862 StringRef CompilationDir, std::vector<std::string> &Filenames) {863 using namespace coverage;864 865 // Read the records in the coverage data section.866 auto CovHeader =867 reinterpret_cast<const CovMapHeader *>(CovMap.data());868 CovMapVersion Version = (CovMapVersion)CovHeader->getVersion<Endian>();869 if (Version > CovMapVersion::CurrentVersion)870 return make_error<CoverageMapError>(coveragemap_error::unsupported_version);871 Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected =872 CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records,873 CompilationDir, Filenames);874 if (Error E = ReaderExpected.takeError())875 return E;876 auto Reader = std::move(ReaderExpected.get());877 const char *CovBuf = CovMap.data();878 const char *CovBufEnd = CovBuf + CovMap.size();879 const char *FuncRecBuf = FuncRecords.data();880 const char *FuncRecBufEnd = FuncRecords.data() + FuncRecords.size();881 while (CovBuf < CovBufEnd) {882 // Read the current coverage header & filename data.883 //884 // Prior to Version4, this also reads all function records affixed to the885 // header.886 //887 // Return a pointer to the next coverage header.888 auto NextOrErr = Reader->readCoverageHeader(CovBuf, CovBufEnd);889 if (auto E = NextOrErr.takeError())890 return E;891 CovBuf = NextOrErr.get();892 }893 // In Version4, function records are not affixed to coverage headers. Read894 // the records from their dedicated section.895 if (Version >= CovMapVersion::Version4)896 return Reader->readFunctionRecords(FuncRecBuf, FuncRecBufEnd, std::nullopt,897 nullptr, nullptr);898 return Error::success();899}900 901Expected<std::unique_ptr<BinaryCoverageReader>>902BinaryCoverageReader::createCoverageReaderFromBuffer(903 StringRef Coverage, FuncRecordsStorage &&FuncRecords,904 CoverageMapCopyStorage &&CoverageMap,905 std::unique_ptr<InstrProfSymtab> ProfileNamesPtr, uint8_t BytesInAddress,906 llvm::endianness Endian, StringRef CompilationDir) {907 if (ProfileNamesPtr == nullptr)908 return make_error<CoverageMapError>(coveragemap_error::malformed,909 "Caller must provide ProfileNames");910 std::unique_ptr<BinaryCoverageReader> Reader(911 new BinaryCoverageReader(std::move(ProfileNamesPtr),912 std::move(FuncRecords), std::move(CoverageMap)));913 InstrProfSymtab &ProfileNames = *Reader->ProfileNames;914 StringRef FuncRecordsRef = Reader->FuncRecords->getBuffer();915 if (BytesInAddress == 4 && Endian == llvm::endianness::little) {916 if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::little>(917 ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,918 CompilationDir, Reader->Filenames))919 return std::move(E);920 } else if (BytesInAddress == 4 && Endian == llvm::endianness::big) {921 if (Error E = readCoverageMappingData<uint32_t, llvm::endianness::big>(922 ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,923 CompilationDir, Reader->Filenames))924 return std::move(E);925 } else if (BytesInAddress == 8 && Endian == llvm::endianness::little) {926 if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::little>(927 ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,928 CompilationDir, Reader->Filenames))929 return std::move(E);930 } else if (BytesInAddress == 8 && Endian == llvm::endianness::big) {931 if (Error E = readCoverageMappingData<uint64_t, llvm::endianness::big>(932 ProfileNames, Coverage, FuncRecordsRef, Reader->MappingRecords,933 CompilationDir, Reader->Filenames))934 return std::move(E);935 } else936 return make_error<CoverageMapError>(937 coveragemap_error::malformed,938 "not supported endianness or bytes in address");939 return std::move(Reader);940}941 942static Expected<std::unique_ptr<BinaryCoverageReader>>943loadTestingFormat(StringRef Data, StringRef CompilationDir) {944 uint8_t BytesInAddress = 8;945 llvm::endianness Endian = llvm::endianness::little;946 947 // Read the magic and version.948 Data = Data.substr(sizeof(TestingFormatMagic));949 if (Data.size() < sizeof(uint64_t))950 return make_error<CoverageMapError>(coveragemap_error::malformed,951 "the size of data is too small");952 auto TestingVersion = support::endian::byte_swap<uint64_t>(953 *reinterpret_cast<const uint64_t *>(Data.data()),954 llvm::endianness::little);955 Data = Data.substr(sizeof(uint64_t));956 957 // Read the ProfileNames data.958 if (Data.empty())959 return make_error<CoverageMapError>(coveragemap_error::truncated);960 unsigned N = 0;961 uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N);962 if (N > Data.size())963 return make_error<CoverageMapError>(964 coveragemap_error::malformed,965 "the size of TestingFormatMagic is too big");966 Data = Data.substr(N);967 if (Data.empty())968 return make_error<CoverageMapError>(coveragemap_error::truncated);969 N = 0;970 uint64_t Address = decodeULEB128(Data.bytes_begin(), &N);971 if (N > Data.size())972 return make_error<CoverageMapError>(coveragemap_error::malformed,973 "the size of ULEB128 is too big");974 Data = Data.substr(N);975 if (Data.size() < ProfileNamesSize)976 return make_error<CoverageMapError>(coveragemap_error::malformed,977 "the size of ProfileNames is too big");978 auto ProfileNames = std::make_unique<InstrProfSymtab>();979 if (Error E = ProfileNames->create(Data.substr(0, ProfileNamesSize), Address))980 return std::move(E);981 Data = Data.substr(ProfileNamesSize);982 983 // In Version2, the size of CoverageMapping is stored directly.984 uint64_t CoverageMappingSize;985 if (TestingVersion == uint64_t(TestingFormatVersion::Version2)) {986 N = 0;987 CoverageMappingSize = decodeULEB128(Data.bytes_begin(), &N);988 if (N > Data.size())989 return make_error<CoverageMapError>(coveragemap_error::malformed,990 "the size of ULEB128 is too big");991 Data = Data.substr(N);992 if (CoverageMappingSize < sizeof(CovMapHeader))993 return make_error<CoverageMapError>(994 coveragemap_error::malformed,995 "the size of CoverageMapping is teoo small");996 } else if (TestingVersion != uint64_t(TestingFormatVersion::Version1)) {997 return make_error<CoverageMapError>(coveragemap_error::unsupported_version);998 }999 1000 // Skip the padding bytes because coverage map data has an alignment of 8.1001 auto Pad = offsetToAlignedAddr(Data.data(), Align(8));1002 if (Data.size() < Pad)1003 return make_error<CoverageMapError>(coveragemap_error::malformed,1004 "insufficient padding");1005 Data = Data.substr(Pad);1006 if (Data.size() < sizeof(CovMapHeader))1007 return make_error<CoverageMapError>(1008 coveragemap_error::malformed,1009 "coverage mapping header section is larger than data size");1010 auto const *CovHeader = reinterpret_cast<const CovMapHeader *>(1011 Data.substr(0, sizeof(CovMapHeader)).data());1012 auto Version =1013 CovMapVersion(CovHeader->getVersion<llvm::endianness::little>());1014 1015 // In Version1, the size of CoverageMapping is calculated.1016 if (TestingVersion == uint64_t(TestingFormatVersion::Version1)) {1017 if (Version < CovMapVersion::Version4) {1018 CoverageMappingSize = Data.size();1019 } else {1020 auto FilenamesSize =1021 CovHeader->getFilenamesSize<llvm::endianness::little>();1022 CoverageMappingSize = sizeof(CovMapHeader) + FilenamesSize;1023 }1024 }1025 1026 auto CoverageMapping = Data.substr(0, CoverageMappingSize);1027 Data = Data.substr(CoverageMappingSize);1028 1029 // Read the CoverageRecords data.1030 if (Version < CovMapVersion::Version4) {1031 if (!Data.empty())1032 return make_error<CoverageMapError>(coveragemap_error::malformed,1033 "data is not empty");1034 } else {1035 // Skip the padding bytes because coverage records data has an alignment1036 // of 8.1037 Pad = offsetToAlignedAddr(Data.data(), Align(8));1038 if (Data.size() < Pad)1039 return make_error<CoverageMapError>(coveragemap_error::malformed,1040 "insufficient padding");1041 Data = Data.substr(Pad);1042 }1043 BinaryCoverageReader::FuncRecordsStorage CoverageRecords =1044 MemoryBuffer::getMemBuffer(Data);1045 1046 return BinaryCoverageReader::createCoverageReaderFromBuffer(1047 CoverageMapping, std::move(CoverageRecords), nullptr,1048 std::move(ProfileNames), BytesInAddress, Endian, CompilationDir);1049}1050 1051/// Find all sections that match \p IPSK name. There may be more than one if1052/// comdats are in use, e.g. for the __llvm_covfun section on ELF.1053static Expected<std::vector<SectionRef>>1054lookupSections(ObjectFile &OF, InstrProfSectKind IPSK) {1055 auto ObjFormat = OF.getTripleObjectFormat();1056 auto Name =1057 getInstrProfSectionName(IPSK, ObjFormat, /*AddSegmentInfo=*/false);1058 // On COFF, the object file section name may end in "$M". This tells the1059 // linker to sort these sections between "$A" and "$Z". The linker removes the1060 // dollar and everything after it in the final binary. Do the same to match.1061 bool IsCOFF = isa<COFFObjectFile>(OF);1062 auto stripSuffix = [IsCOFF](StringRef N) {1063 return IsCOFF ? N.split('$').first : N;1064 };1065 Name = stripSuffix(Name);1066 1067 std::vector<SectionRef> Sections;1068 for (const auto &Section : OF.sections()) {1069 Expected<StringRef> NameOrErr = Section.getName();1070 if (!NameOrErr)1071 return NameOrErr.takeError();1072 if (stripSuffix(*NameOrErr) == Name) {1073 // Skip empty profile name section.1074 // COFF profile name section contains two null bytes indicating the1075 // start/end of the section. If its size is 2 bytes, it's empty.1076 if (IPSK == IPSK_name &&1077 (Section.getSize() == 0 || (IsCOFF && Section.getSize() == 2)))1078 continue;1079 Sections.push_back(Section);1080 }1081 }1082 if (Sections.empty())1083 return make_error<CoverageMapError>(coveragemap_error::no_data_found);1084 return Sections;1085}1086 1087/// Find a section that matches \p Name and is allocatable at runtime.1088///1089/// Returns the contents of the section and its start offset in the object file.1090static Expected<std::pair<StringRef, uint64_t>>1091lookupAllocatableSection(ObjectFile &OF, InstrProfSectKind IPSK) {1092 // On Wasm, allocatable sections can live only in data segments.1093 if (auto *WOF = dyn_cast<WasmObjectFile>(&OF)) {1094 std::vector<const WasmSegment *> Segments;1095 auto ObjFormat = OF.getTripleObjectFormat();1096 auto Name =1097 getInstrProfSectionName(IPSK, ObjFormat, /*AddSegmentInfo=*/false);1098 for (const auto &DebugName : WOF->debugNames()) {1099 if (DebugName.Type != wasm::NameType::DATA_SEGMENT ||1100 DebugName.Name != Name)1101 continue;1102 if (DebugName.Index >= WOF->dataSegments().size())1103 return make_error<CoverageMapError>(coveragemap_error::malformed);1104 auto &Segment = WOF->dataSegments()[DebugName.Index];1105 Segments.push_back(&Segment);1106 }1107 if (Segments.empty())1108 return make_error<CoverageMapError>(coveragemap_error::no_data_found);1109 if (Segments.size() != 1)1110 return make_error<CoverageMapError>(coveragemap_error::malformed);1111 1112 const auto &Segment = *Segments.front();1113 auto &Data = Segment.Data;1114 StringRef Content(reinterpret_cast<const char *>(Data.Content.data()),1115 Data.Content.size());1116 return std::make_pair(Content, Segment.SectionOffset);1117 }1118 1119 // On other object file types, delegate to lookupSections to find the section.1120 auto Sections = lookupSections(OF, IPSK);1121 if (!Sections)1122 return Sections.takeError();1123 if (Sections->size() != 1)1124 return make_error<CoverageMapError>(1125 coveragemap_error::malformed,1126 "the size of coverage mapping section is not one");1127 auto &Section = Sections->front();1128 auto ContentsOrErr = Section.getContents();1129 if (!ContentsOrErr)1130 return ContentsOrErr.takeError();1131 auto Content = *ContentsOrErr;1132 if (shouldSkipSectionFirstByte(Section))1133 Content = Content.drop_front(1);1134 return std::make_pair(Content, Section.getAddress());1135}1136 1137static Expected<std::unique_ptr<BinaryCoverageReader>>1138loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch,1139 StringRef CompilationDir = "",1140 object::BuildIDRef *BinaryID = nullptr) {1141 std::unique_ptr<ObjectFile> OF;1142 if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) {1143 // If we have a universal binary, try to look up the object for the1144 // appropriate architecture.1145 auto ObjectFileOrErr = Universal->getMachOObjectForArch(Arch);1146 if (!ObjectFileOrErr)1147 return ObjectFileOrErr.takeError();1148 OF = std::move(ObjectFileOrErr.get());1149 } else if (isa<ObjectFile>(Bin.get())) {1150 // For any other object file, upcast and take ownership.1151 OF.reset(cast<ObjectFile>(Bin.release()));1152 // If we've asked for a particular arch, make sure they match.1153 if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch())1154 return errorCodeToError(object_error::arch_not_found);1155 } else1156 // We can only handle object files.1157 return make_error<CoverageMapError>(coveragemap_error::malformed,1158 "binary is not an object file");1159 1160 // The coverage uses native pointer sizes for the object it's written in.1161 uint8_t BytesInAddress = OF->getBytesInAddress();1162 llvm::endianness Endian =1163 OF->isLittleEndian() ? llvm::endianness::little : llvm::endianness::big;1164 1165 // Look for the sections that we are interested in.1166 auto ProfileNames = std::make_unique<InstrProfSymtab>();1167 // If IPSK_name is not found, fallback to search for IPK_covname, which is1168 // used when binary correlation is enabled.1169 auto NamesSection = lookupAllocatableSection(*OF, IPSK_name);1170 if (auto E = NamesSection.takeError()) {1171 consumeError(std::move(E));1172 NamesSection = lookupAllocatableSection(*OF, IPSK_covname);1173 if (auto E = NamesSection.takeError())1174 return std::move(E);1175 }1176 1177 uint64_t NamesAddress;1178 StringRef NamesContent;1179 std::tie(NamesContent, NamesAddress) = *NamesSection;1180 if (Error E = ProfileNames->create(NamesContent, NamesAddress))1181 return std::move(E);1182 1183 auto CoverageSection = lookupSections(*OF, IPSK_covmap);1184 if (auto E = CoverageSection.takeError())1185 return std::move(E);1186 std::vector<SectionRef> CoverageSectionRefs = *CoverageSection;1187 if (CoverageSectionRefs.size() != 1)1188 return make_error<CoverageMapError>(coveragemap_error::malformed,1189 "the size of name section is not one");1190 auto CoverageMappingOrErr = CoverageSectionRefs.back().getContents();1191 if (!CoverageMappingOrErr)1192 return CoverageMappingOrErr.takeError();1193 StringRef CoverageMapping = CoverageMappingOrErr.get();1194 1195 // If the coverage mapping section is not aligned to 8 bytes, copy it to a1196 // new buffer that is. Wasm format typically has unaligned section contents1197 // because it doesn't have a good way to insert padding bytes.1198 std::unique_ptr<MemoryBuffer> CoverageMapCopy;1199 if (!isAddrAligned(Align(8), CoverageMapping.data())) {1200 CoverageMapCopy = MemoryBuffer::getMemBufferCopy(CoverageMapping);1201 CoverageMapping = CoverageMapCopy->getBuffer();1202 }1203 1204 // Look for the coverage records section (Version4 only).1205 auto CoverageRecordsSections = lookupSections(*OF, IPSK_covfun);1206 1207 BinaryCoverageReader::FuncRecordsStorage FuncRecords;1208 if (auto E = CoverageRecordsSections.takeError()) {1209 consumeError(std::move(E));1210 FuncRecords = MemoryBuffer::getMemBuffer("");1211 } else {1212 // Compute the FuncRecordsBuffer of the buffer, taking into account the1213 // padding between each record, and making sure the first block is aligned1214 // in memory to maintain consistency between buffer address and size1215 // alignment.1216 const Align RecordAlignment(8);1217 uint64_t FuncRecordsSize = 0;1218 for (SectionRef Section : *CoverageRecordsSections) {1219 auto CoverageRecordsOrErr = Section.getContents();1220 if (!CoverageRecordsOrErr)1221 return CoverageRecordsOrErr.takeError();1222 FuncRecordsSize += alignTo(CoverageRecordsOrErr->size(), RecordAlignment);1223 }1224 auto WritableBuffer =1225 WritableMemoryBuffer::getNewUninitMemBuffer(FuncRecordsSize);1226 char *FuncRecordsBuffer = WritableBuffer->getBufferStart();1227 assert(isAddrAligned(RecordAlignment, FuncRecordsBuffer) &&1228 "Allocated memory is correctly aligned");1229 1230 for (SectionRef Section : *CoverageRecordsSections) {1231 auto CoverageRecordsOrErr = Section.getContents();1232 if (!CoverageRecordsOrErr)1233 return CoverageRecordsOrErr.takeError();1234 const auto &CoverageRecords = CoverageRecordsOrErr.get();1235 FuncRecordsBuffer = llvm::copy(CoverageRecords, FuncRecordsBuffer);1236 FuncRecordsBuffer =1237 std::fill_n(FuncRecordsBuffer,1238 alignAddr(FuncRecordsBuffer, RecordAlignment) -1239 (uintptr_t)FuncRecordsBuffer,1240 '\0');1241 }1242 assert(FuncRecordsBuffer == WritableBuffer->getBufferEnd() &&1243 "consistent init");1244 FuncRecords = std::move(WritableBuffer);1245 }1246 1247 if (BinaryID)1248 *BinaryID = getBuildID(OF.get());1249 1250 return BinaryCoverageReader::createCoverageReaderFromBuffer(1251 CoverageMapping, std::move(FuncRecords), std::move(CoverageMapCopy),1252 std::move(ProfileNames), BytesInAddress, Endian, CompilationDir);1253}1254 1255/// Determine whether \p Arch is invalid or empty, given \p Bin.1256static bool isArchSpecifierInvalidOrMissing(Binary *Bin, StringRef Arch) {1257 // If we have a universal binary and Arch doesn't identify any of its slices,1258 // it's user error.1259 if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin)) {1260 for (auto &ObjForArch : Universal->objects())1261 if (Arch == ObjForArch.getArchFlagName())1262 return false;1263 return true;1264 }1265 return false;1266}1267 1268Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>>1269BinaryCoverageReader::create(1270 MemoryBufferRef ObjectBuffer, StringRef Arch,1271 SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers,1272 StringRef CompilationDir, SmallVectorImpl<object::BuildIDRef> *BinaryIDs) {1273 std::vector<std::unique_ptr<BinaryCoverageReader>> Readers;1274 1275 if (ObjectBuffer.getBuffer().size() > sizeof(TestingFormatMagic)) {1276 uint64_t Magic = support::endian::byte_swap<uint64_t>(1277 *reinterpret_cast<const uint64_t *>(ObjectBuffer.getBufferStart()),1278 llvm::endianness::little);1279 if (Magic == TestingFormatMagic) {1280 // This is a special format used for testing.1281 auto ReaderOrErr =1282 loadTestingFormat(ObjectBuffer.getBuffer(), CompilationDir);1283 if (!ReaderOrErr)1284 return ReaderOrErr.takeError();1285 Readers.push_back(std::move(ReaderOrErr.get()));1286 return std::move(Readers);1287 }1288 }1289 1290 auto BinOrErr = createBinary(ObjectBuffer);1291 if (!BinOrErr)1292 return BinOrErr.takeError();1293 std::unique_ptr<Binary> Bin = std::move(BinOrErr.get());1294 1295 if (isArchSpecifierInvalidOrMissing(Bin.get(), Arch))1296 return make_error<CoverageMapError>(1297 coveragemap_error::invalid_or_missing_arch_specifier);1298 1299 // MachO universal binaries which contain archives need to be treated as1300 // archives, not as regular binaries.1301 if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) {1302 for (auto &ObjForArch : Universal->objects()) {1303 // Skip slices within the universal binary which target the wrong arch.1304 std::string ObjArch = ObjForArch.getArchFlagName();1305 if (Arch != ObjArch)1306 continue;1307 1308 auto ArchiveOrErr = ObjForArch.getAsArchive();1309 if (!ArchiveOrErr) {1310 // If this is not an archive, try treating it as a regular object.1311 consumeError(ArchiveOrErr.takeError());1312 break;1313 }1314 1315 return BinaryCoverageReader::create(1316 ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers,1317 CompilationDir, BinaryIDs);1318 }1319 }1320 1321 // Load coverage out of archive members.1322 if (auto *Ar = dyn_cast<Archive>(Bin.get())) {1323 Error Err = Error::success();1324 for (auto &Child : Ar->children(Err)) {1325 Expected<MemoryBufferRef> ChildBufOrErr = Child.getMemoryBufferRef();1326 if (!ChildBufOrErr)1327 return ChildBufOrErr.takeError();1328 1329 auto ChildReadersOrErr = BinaryCoverageReader::create(1330 ChildBufOrErr.get(), Arch, ObjectFileBuffers, CompilationDir,1331 BinaryIDs);1332 if (!ChildReadersOrErr)1333 return ChildReadersOrErr.takeError();1334 for (auto &Reader : ChildReadersOrErr.get())1335 Readers.push_back(std::move(Reader));1336 }1337 if (Err)1338 return std::move(Err);1339 1340 // Thin archives reference object files outside of the archive file, i.e.1341 // files which reside in memory not owned by the caller. Transfer ownership1342 // to the caller.1343 if (Ar->isThin())1344 for (auto &Buffer : Ar->takeThinBuffers())1345 ObjectFileBuffers.push_back(std::move(Buffer));1346 1347 return std::move(Readers);1348 }1349 1350 object::BuildIDRef BinaryID;1351 auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch, CompilationDir,1352 BinaryIDs ? &BinaryID : nullptr);1353 if (!ReaderOrErr)1354 return ReaderOrErr.takeError();1355 Readers.push_back(std::move(ReaderOrErr.get()));1356 if (!BinaryID.empty())1357 BinaryIDs->push_back(BinaryID);1358 return std::move(Readers);1359}1360 1361Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) {1362 if (CurrentRecord >= MappingRecords.size())1363 return make_error<CoverageMapError>(coveragemap_error::eof);1364 1365 FunctionsFilenames.clear();1366 Expressions.clear();1367 MappingRegions.clear();1368 auto &R = MappingRecords[CurrentRecord];1369 auto F = ArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize);1370 RawCoverageMappingReader Reader(R.CoverageMapping, F, FunctionsFilenames,1371 Expressions, MappingRegions);1372 if (auto Err = Reader.read())1373 return Err;1374 1375 Record.FunctionName = R.FunctionName;1376 Record.FunctionHash = R.FunctionHash;1377 Record.Filenames = FunctionsFilenames;1378 Record.Expressions = Expressions;1379 Record.MappingRegions = MappingRegions;1380 1381 ++CurrentRecord;1382 return Error::success();1383}1384