172208a82SEugene Zelenko //===- CoverageMappingReader.cpp - Code coverage mapping reader -----------===// 2dc707122SEaswaran Raman // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6dc707122SEaswaran Raman // 7dc707122SEaswaran Raman //===----------------------------------------------------------------------===// 8dc707122SEaswaran Raman // 9dc707122SEaswaran Raman // This file contains support for reading coverage mapping data for 10dc707122SEaswaran Raman // instrumentation based coverage. 11dc707122SEaswaran Raman // 12dc707122SEaswaran Raman //===----------------------------------------------------------------------===// 13dc707122SEaswaran Raman 144a5ddf80SXinliang David Li #include "llvm/ProfileData/Coverage/CoverageMappingReader.h" 15e78d131aSEugene Zelenko #include "llvm/ADT/ArrayRef.h" 16ac40e819SIgor Kudrin #include "llvm/ADT/DenseMap.h" 17e78d131aSEugene Zelenko #include "llvm/ADT/STLExtras.h" 184a5ddf80SXinliang David Li #include "llvm/ADT/SmallVector.h" 19dd1ea9deSVedant Kumar #include "llvm/ADT/Statistic.h" 20e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h" 21e78d131aSEugene Zelenko #include "llvm/ADT/Triple.h" 22e78d131aSEugene Zelenko #include "llvm/Object/Binary.h" 23e78d131aSEugene Zelenko #include "llvm/Object/Error.h" 24dc707122SEaswaran Raman #include "llvm/Object/MachOUniversal.h" 25dc707122SEaswaran Raman #include "llvm/Object/ObjectFile.h" 268b6af001SReid Kleckner #include "llvm/Object/COFF.h" 27e78d131aSEugene Zelenko #include "llvm/ProfileData/InstrProf.h" 28e78d131aSEugene Zelenko #include "llvm/Support/Casting.h" 29dd1ea9deSVedant Kumar #include "llvm/Support/Compression.h" 30dc707122SEaswaran Raman #include "llvm/Support/Debug.h" 314a5ddf80SXinliang David Li #include "llvm/Support/Endian.h" 32e78d131aSEugene Zelenko #include "llvm/Support/Error.h" 33e78d131aSEugene Zelenko #include "llvm/Support/ErrorHandling.h" 34dc707122SEaswaran Raman #include "llvm/Support/LEB128.h" 35dc707122SEaswaran Raman #include "llvm/Support/MathExtras.h" 36dc707122SEaswaran Raman #include "llvm/Support/raw_ostream.h" 37e78d131aSEugene Zelenko #include <vector> 38dc707122SEaswaran Raman 39dc707122SEaswaran Raman using namespace llvm; 40dc707122SEaswaran Raman using namespace coverage; 41dc707122SEaswaran Raman using namespace object; 42dc707122SEaswaran Raman 43dc707122SEaswaran Raman #define DEBUG_TYPE "coverage-mapping" 44dc707122SEaswaran Raman 45dd1ea9deSVedant Kumar STATISTIC(CovMapNumRecords, "The # of coverage function records"); 46dd1ea9deSVedant Kumar STATISTIC(CovMapNumUsedRecords, "The # of used coverage function records"); 47dd1ea9deSVedant Kumar 48dc707122SEaswaran Raman void CoverageMappingIterator::increment() { 49bae83970SVedant Kumar if (ReadErr != coveragemap_error::success) 50bae83970SVedant Kumar return; 51bae83970SVedant Kumar 52dc707122SEaswaran Raman // Check if all the records were read or if an error occurred while reading 53dc707122SEaswaran Raman // the next record. 54bae83970SVedant Kumar if (auto E = Reader->readNextRecord(Record)) 559152fd17SVedant Kumar handleAllErrors(std::move(E), [&](const CoverageMapError &CME) { 569152fd17SVedant Kumar if (CME.get() == coveragemap_error::eof) 57dc707122SEaswaran Raman *this = CoverageMappingIterator(); 589152fd17SVedant Kumar else 59bae83970SVedant Kumar ReadErr = CME.get(); 609152fd17SVedant Kumar }); 619152fd17SVedant Kumar } 62dc707122SEaswaran Raman 639152fd17SVedant Kumar Error RawCoverageReader::readULEB128(uint64_t &Result) { 6472208a82SEugene Zelenko if (Data.empty()) 659152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::truncated); 66dc707122SEaswaran Raman unsigned N = 0; 676a0746a9SFangrui Song Result = decodeULEB128(Data.bytes_begin(), &N); 68dc707122SEaswaran Raman if (N > Data.size()) 699152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 70dc707122SEaswaran Raman Data = Data.substr(N); 719152fd17SVedant Kumar return Error::success(); 72dc707122SEaswaran Raman } 73dc707122SEaswaran Raman 749152fd17SVedant Kumar Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) { 75dc707122SEaswaran Raman if (auto Err = readULEB128(Result)) 76dc707122SEaswaran Raman return Err; 77dc707122SEaswaran Raman if (Result >= MaxPlus1) 789152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 799152fd17SVedant Kumar return Error::success(); 80dc707122SEaswaran Raman } 81dc707122SEaswaran Raman 829152fd17SVedant Kumar Error RawCoverageReader::readSize(uint64_t &Result) { 83dc707122SEaswaran Raman if (auto Err = readULEB128(Result)) 84dc707122SEaswaran Raman return Err; 85dc707122SEaswaran Raman // Sanity check the number. 86dc707122SEaswaran Raman if (Result > Data.size()) 879152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 889152fd17SVedant Kumar return Error::success(); 89dc707122SEaswaran Raman } 90dc707122SEaswaran Raman 919152fd17SVedant Kumar Error RawCoverageReader::readString(StringRef &Result) { 92dc707122SEaswaran Raman uint64_t Length; 93dc707122SEaswaran Raman if (auto Err = readSize(Length)) 94dc707122SEaswaran Raman return Err; 95dc707122SEaswaran Raman Result = Data.substr(0, Length); 96dc707122SEaswaran Raman Data = Data.substr(Length); 979152fd17SVedant Kumar return Error::success(); 98dc707122SEaswaran Raman } 99dc707122SEaswaran Raman 100*5fbd1a33SPetr Hosek Error RawCoverageFilenamesReader::read(CovMapVersion Version) { 101dc707122SEaswaran Raman uint64_t NumFilenames; 102dc707122SEaswaran Raman if (auto Err = readSize(NumFilenames)) 103dc707122SEaswaran Raman return Err; 104dd1ea9deSVedant Kumar if (!NumFilenames) 105dd1ea9deSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 106dd1ea9deSVedant Kumar 107dd1ea9deSVedant Kumar if (Version < CovMapVersion::Version4) 108*5fbd1a33SPetr Hosek return readUncompressed(Version, NumFilenames); 109dd1ea9deSVedant Kumar 110dd1ea9deSVedant Kumar // The uncompressed length may exceed the size of the encoded filenames. 111dd1ea9deSVedant Kumar // Skip size validation. 112dd1ea9deSVedant Kumar uint64_t UncompressedLen; 113dd1ea9deSVedant Kumar if (auto Err = readULEB128(UncompressedLen)) 114dd1ea9deSVedant Kumar return Err; 115dd1ea9deSVedant Kumar 116dd1ea9deSVedant Kumar uint64_t CompressedLen; 117dd1ea9deSVedant Kumar if (auto Err = readSize(CompressedLen)) 118dd1ea9deSVedant Kumar return Err; 119dd1ea9deSVedant Kumar 120dd1ea9deSVedant Kumar if (CompressedLen > 0) { 121dd1ea9deSVedant Kumar if (!zlib::isAvailable()) 122dd1ea9deSVedant Kumar return make_error<CoverageMapError>( 123dd1ea9deSVedant Kumar coveragemap_error::decompression_failed); 124dd1ea9deSVedant Kumar 125*5fbd1a33SPetr Hosek // Allocate memory for the decompressed filenames. 126*5fbd1a33SPetr Hosek SmallVector<char, 0> StorageBuf; 127dd1ea9deSVedant Kumar 128dd1ea9deSVedant Kumar // Read compressed filenames. 129dd1ea9deSVedant Kumar StringRef CompressedFilenames = Data.substr(0, CompressedLen); 130dd1ea9deSVedant Kumar Data = Data.substr(CompressedLen); 131dd1ea9deSVedant Kumar auto Err = 132dd1ea9deSVedant Kumar zlib::uncompress(CompressedFilenames, StorageBuf, UncompressedLen); 133dd1ea9deSVedant Kumar if (Err) { 134dd1ea9deSVedant Kumar consumeError(std::move(Err)); 135dd1ea9deSVedant Kumar return make_error<CoverageMapError>( 136dd1ea9deSVedant Kumar coveragemap_error::decompression_failed); 137dd1ea9deSVedant Kumar } 138dd1ea9deSVedant Kumar 139dd1ea9deSVedant Kumar StringRef UncompressedFilenames(StorageBuf.data(), StorageBuf.size()); 140dd1ea9deSVedant Kumar RawCoverageFilenamesReader Delegate(UncompressedFilenames, Filenames); 141*5fbd1a33SPetr Hosek return Delegate.readUncompressed(Version, NumFilenames); 142dd1ea9deSVedant Kumar } 143dd1ea9deSVedant Kumar 144*5fbd1a33SPetr Hosek return readUncompressed(Version, NumFilenames); 145dd1ea9deSVedant Kumar } 146dd1ea9deSVedant Kumar 147*5fbd1a33SPetr Hosek Error RawCoverageFilenamesReader::readUncompressed(CovMapVersion Version, 148*5fbd1a33SPetr Hosek uint64_t NumFilenames) { 149dd1ea9deSVedant Kumar // Read uncompressed filenames. 150*5fbd1a33SPetr Hosek if (Version < CovMapVersion::Version6) { 151dc707122SEaswaran Raman for (size_t I = 0; I < NumFilenames; ++I) { 152dc707122SEaswaran Raman StringRef Filename; 153dc707122SEaswaran Raman if (auto Err = readString(Filename)) 154dc707122SEaswaran Raman return Err; 155*5fbd1a33SPetr Hosek Filenames.push_back(Filename.str()); 156*5fbd1a33SPetr Hosek } 157*5fbd1a33SPetr Hosek } else { 158*5fbd1a33SPetr Hosek StringRef CWD; 159*5fbd1a33SPetr Hosek if (auto Err = readString(CWD)) 160*5fbd1a33SPetr Hosek return Err; 161*5fbd1a33SPetr Hosek Filenames.push_back(CWD.str()); 162*5fbd1a33SPetr Hosek 163*5fbd1a33SPetr Hosek for (size_t I = 1; I < NumFilenames; ++I) { 164*5fbd1a33SPetr Hosek StringRef Filename; 165*5fbd1a33SPetr Hosek if (auto Err = readString(Filename)) 166*5fbd1a33SPetr Hosek return Err; 167*5fbd1a33SPetr Hosek if (sys::path::is_absolute(Filename)) { 168*5fbd1a33SPetr Hosek Filenames.push_back(Filename.str()); 169*5fbd1a33SPetr Hosek } else { 170*5fbd1a33SPetr Hosek SmallString<256> P(CWD); 171*5fbd1a33SPetr Hosek llvm::sys::path::append(P, Filename); 172*5fbd1a33SPetr Hosek Filenames.push_back(static_cast<std::string>(P)); 173*5fbd1a33SPetr Hosek } 174*5fbd1a33SPetr Hosek } 175dc707122SEaswaran Raman } 1769152fd17SVedant Kumar return Error::success(); 177dc707122SEaswaran Raman } 178dc707122SEaswaran Raman 1799152fd17SVedant Kumar Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) { 180dc707122SEaswaran Raman auto Tag = Value & Counter::EncodingTagMask; 181dc707122SEaswaran Raman switch (Tag) { 182dc707122SEaswaran Raman case Counter::Zero: 183dc707122SEaswaran Raman C = Counter::getZero(); 1849152fd17SVedant Kumar return Error::success(); 185dc707122SEaswaran Raman case Counter::CounterValueReference: 186dc707122SEaswaran Raman C = Counter::getCounter(Value >> Counter::EncodingTagBits); 1879152fd17SVedant Kumar return Error::success(); 188dc707122SEaswaran Raman default: 189dc707122SEaswaran Raman break; 190dc707122SEaswaran Raman } 191dc707122SEaswaran Raman Tag -= Counter::Expression; 192dc707122SEaswaran Raman switch (Tag) { 193dc707122SEaswaran Raman case CounterExpression::Subtract: 194dc707122SEaswaran Raman case CounterExpression::Add: { 195dc707122SEaswaran Raman auto ID = Value >> Counter::EncodingTagBits; 196dc707122SEaswaran Raman if (ID >= Expressions.size()) 1979152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 198dc707122SEaswaran Raman Expressions[ID].Kind = CounterExpression::ExprKind(Tag); 199dc707122SEaswaran Raman C = Counter::getExpression(ID); 200dc707122SEaswaran Raman break; 201dc707122SEaswaran Raman } 202dc707122SEaswaran Raman default: 2039152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 204dc707122SEaswaran Raman } 2059152fd17SVedant Kumar return Error::success(); 206dc707122SEaswaran Raman } 207dc707122SEaswaran Raman 2089152fd17SVedant Kumar Error RawCoverageMappingReader::readCounter(Counter &C) { 209dc707122SEaswaran Raman uint64_t EncodedCounter; 210dc707122SEaswaran Raman if (auto Err = 211dc707122SEaswaran Raman readIntMax(EncodedCounter, std::numeric_limits<unsigned>::max())) 212dc707122SEaswaran Raman return Err; 213dc707122SEaswaran Raman if (auto Err = decodeCounter(EncodedCounter, C)) 214dc707122SEaswaran Raman return Err; 2159152fd17SVedant Kumar return Error::success(); 216dc707122SEaswaran Raman } 217dc707122SEaswaran Raman 218dc707122SEaswaran Raman static const unsigned EncodingExpansionRegionBit = 1 219dc707122SEaswaran Raman << Counter::EncodingTagBits; 220dc707122SEaswaran Raman 2215f8f34e4SAdrian Prantl /// Read the sub-array of regions for the given inferred file id. 222dc707122SEaswaran Raman /// \param NumFileIDs the number of file ids that are defined for this 223dc707122SEaswaran Raman /// function. 2249152fd17SVedant Kumar Error RawCoverageMappingReader::readMappingRegionsSubArray( 225dc707122SEaswaran Raman std::vector<CounterMappingRegion> &MappingRegions, unsigned InferredFileID, 226dc707122SEaswaran Raman size_t NumFileIDs) { 227dc707122SEaswaran Raman uint64_t NumRegions; 228dc707122SEaswaran Raman if (auto Err = readSize(NumRegions)) 229dc707122SEaswaran Raman return Err; 230dc707122SEaswaran Raman unsigned LineStart = 0; 231dc707122SEaswaran Raman for (size_t I = 0; I < NumRegions; ++I) { 2329f2967bcSAlan Phipps Counter C, C2; 233dc707122SEaswaran Raman CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion; 234dc707122SEaswaran Raman 235dc707122SEaswaran Raman // Read the combined counter + region kind. 236dc707122SEaswaran Raman uint64_t EncodedCounterAndRegion; 237dc707122SEaswaran Raman if (auto Err = readIntMax(EncodedCounterAndRegion, 238dc707122SEaswaran Raman std::numeric_limits<unsigned>::max())) 239dc707122SEaswaran Raman return Err; 240dc707122SEaswaran Raman unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask; 241dc707122SEaswaran Raman uint64_t ExpandedFileID = 0; 2429f2967bcSAlan Phipps 2439f2967bcSAlan Phipps // If Tag does not represent a ZeroCounter, then it is understood to refer 2449f2967bcSAlan Phipps // to a counter or counter expression with region kind assumed to be 2459f2967bcSAlan Phipps // "CodeRegion". In that case, EncodedCounterAndRegion actually encodes the 2469f2967bcSAlan Phipps // referenced counter or counter expression (and nothing else). 2479f2967bcSAlan Phipps // 2489f2967bcSAlan Phipps // If Tag represents a ZeroCounter and EncodingExpansionRegionBit is set, 2499f2967bcSAlan Phipps // then EncodedCounterAndRegion is interpreted to represent an 2509f2967bcSAlan Phipps // ExpansionRegion. In all other cases, EncodedCounterAndRegion is 2519f2967bcSAlan Phipps // interpreted to refer to a specific region kind, after which additional 2529f2967bcSAlan Phipps // fields may be read (e.g. BranchRegions have two encoded counters that 2539f2967bcSAlan Phipps // follow an encoded region kind value). 254dc707122SEaswaran Raman if (Tag != Counter::Zero) { 255dc707122SEaswaran Raman if (auto Err = decodeCounter(EncodedCounterAndRegion, C)) 256dc707122SEaswaran Raman return Err; 257dc707122SEaswaran Raman } else { 258dc707122SEaswaran Raman // Is it an expansion region? 259dc707122SEaswaran Raman if (EncodedCounterAndRegion & EncodingExpansionRegionBit) { 260dc707122SEaswaran Raman Kind = CounterMappingRegion::ExpansionRegion; 261dc707122SEaswaran Raman ExpandedFileID = EncodedCounterAndRegion >> 262dc707122SEaswaran Raman Counter::EncodingCounterTagAndExpansionRegionTagBits; 263dc707122SEaswaran Raman if (ExpandedFileID >= NumFileIDs) 2649152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 265dc707122SEaswaran Raman } else { 266dc707122SEaswaran Raman switch (EncodedCounterAndRegion >> 267dc707122SEaswaran Raman Counter::EncodingCounterTagAndExpansionRegionTagBits) { 268dc707122SEaswaran Raman case CounterMappingRegion::CodeRegion: 269dc707122SEaswaran Raman // Don't do anything when we have a code region with a zero counter. 270dc707122SEaswaran Raman break; 271dc707122SEaswaran Raman case CounterMappingRegion::SkippedRegion: 272dc707122SEaswaran Raman Kind = CounterMappingRegion::SkippedRegion; 273dc707122SEaswaran Raman break; 2749f2967bcSAlan Phipps case CounterMappingRegion::BranchRegion: 2759f2967bcSAlan Phipps // For a Branch Region, read two successive counters. 2769f2967bcSAlan Phipps Kind = CounterMappingRegion::BranchRegion; 2779f2967bcSAlan Phipps if (auto Err = readCounter(C)) 2789f2967bcSAlan Phipps return Err; 2799f2967bcSAlan Phipps if (auto Err = readCounter(C2)) 2809f2967bcSAlan Phipps return Err; 2819f2967bcSAlan Phipps break; 282dc707122SEaswaran Raman default: 2839152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 284dc707122SEaswaran Raman } 285dc707122SEaswaran Raman } 286dc707122SEaswaran Raman } 287dc707122SEaswaran Raman 288dc707122SEaswaran Raman // Read the source range. 289dc707122SEaswaran Raman uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd; 290dc707122SEaswaran Raman if (auto Err = 291dc707122SEaswaran Raman readIntMax(LineStartDelta, std::numeric_limits<unsigned>::max())) 292dc707122SEaswaran Raman return Err; 293dc707122SEaswaran Raman if (auto Err = readULEB128(ColumnStart)) 294dc707122SEaswaran Raman return Err; 295dc707122SEaswaran Raman if (ColumnStart > std::numeric_limits<unsigned>::max()) 2969152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 297dc707122SEaswaran Raman if (auto Err = readIntMax(NumLines, std::numeric_limits<unsigned>::max())) 298dc707122SEaswaran Raman return Err; 299dc707122SEaswaran Raman if (auto Err = readIntMax(ColumnEnd, std::numeric_limits<unsigned>::max())) 300dc707122SEaswaran Raman return Err; 301dc707122SEaswaran Raman LineStart += LineStartDelta; 302ad8f637bSVedant Kumar 303ad8f637bSVedant Kumar // If the high bit of ColumnEnd is set, this is a gap region. 304ad8f637bSVedant Kumar if (ColumnEnd & (1U << 31)) { 305ad8f637bSVedant Kumar Kind = CounterMappingRegion::GapRegion; 306ad8f637bSVedant Kumar ColumnEnd &= ~(1U << 31); 307ad8f637bSVedant Kumar } 308ad8f637bSVedant Kumar 309dc707122SEaswaran Raman // Adjust the column locations for the empty regions that are supposed to 310dc707122SEaswaran Raman // cover whole lines. Those regions should be encoded with the 311dc707122SEaswaran Raman // column range (1 -> std::numeric_limits<unsigned>::max()), but because 312dc707122SEaswaran Raman // the encoded std::numeric_limits<unsigned>::max() is several bytes long, 313dc707122SEaswaran Raman // we set the column range to (0 -> 0) to ensure that the column start and 314dc707122SEaswaran Raman // column end take up one byte each. 315dc707122SEaswaran Raman // The std::numeric_limits<unsigned>::max() is used to represent a column 316dc707122SEaswaran Raman // position at the end of the line without knowing the length of that line. 317dc707122SEaswaran Raman if (ColumnStart == 0 && ColumnEnd == 0) { 318dc707122SEaswaran Raman ColumnStart = 1; 319dc707122SEaswaran Raman ColumnEnd = std::numeric_limits<unsigned>::max(); 320dc707122SEaswaran Raman } 321dc707122SEaswaran Raman 322d34e60caSNicola Zaghen LLVM_DEBUG({ 323dc707122SEaswaran Raman dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" 324dc707122SEaswaran Raman << ColumnStart << " -> " << (LineStart + NumLines) << ":" 325dc707122SEaswaran Raman << ColumnEnd << ", "; 326dc707122SEaswaran Raman if (Kind == CounterMappingRegion::ExpansionRegion) 327dc707122SEaswaran Raman dbgs() << "Expands to file " << ExpandedFileID; 328dc707122SEaswaran Raman else 329dc707122SEaswaran Raman CounterMappingContext(Expressions).dump(C, dbgs()); 330dc707122SEaswaran Raman dbgs() << "\n"; 331dc707122SEaswaran Raman }); 332dc707122SEaswaran Raman 3339f2967bcSAlan Phipps auto CMR = CounterMappingRegion(C, C2, InferredFileID, ExpandedFileID, 334bae83970SVedant Kumar LineStart, ColumnStart, 335bae83970SVedant Kumar LineStart + NumLines, ColumnEnd, Kind); 336bae83970SVedant Kumar if (CMR.startLoc() > CMR.endLoc()) 337bae83970SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 338bae83970SVedant Kumar MappingRegions.push_back(CMR); 339dc707122SEaswaran Raman } 3409152fd17SVedant Kumar return Error::success(); 341dc707122SEaswaran Raman } 342dc707122SEaswaran Raman 3439152fd17SVedant Kumar Error RawCoverageMappingReader::read() { 344dc707122SEaswaran Raman // Read the virtual file mapping. 345e78d131aSEugene Zelenko SmallVector<unsigned, 8> VirtualFileMapping; 346dc707122SEaswaran Raman uint64_t NumFileMappings; 347dc707122SEaswaran Raman if (auto Err = readSize(NumFileMappings)) 348dc707122SEaswaran Raman return Err; 349dc707122SEaswaran Raman for (size_t I = 0; I < NumFileMappings; ++I) { 350dc707122SEaswaran Raman uint64_t FilenameIndex; 351dc707122SEaswaran Raman if (auto Err = readIntMax(FilenameIndex, TranslationUnitFilenames.size())) 352dc707122SEaswaran Raman return Err; 353dc707122SEaswaran Raman VirtualFileMapping.push_back(FilenameIndex); 354dc707122SEaswaran Raman } 355dc707122SEaswaran Raman 356dc707122SEaswaran Raman // Construct the files using unique filenames and virtual file mapping. 357dc707122SEaswaran Raman for (auto I : VirtualFileMapping) { 358dc707122SEaswaran Raman Filenames.push_back(TranslationUnitFilenames[I]); 359dc707122SEaswaran Raman } 360dc707122SEaswaran Raman 361dc707122SEaswaran Raman // Read the expressions. 362dc707122SEaswaran Raman uint64_t NumExpressions; 363dc707122SEaswaran Raman if (auto Err = readSize(NumExpressions)) 364dc707122SEaswaran Raman return Err; 365dc707122SEaswaran Raman // Create an array of dummy expressions that get the proper counters 366dc707122SEaswaran Raman // when the expressions are read, and the proper kinds when the counters 367dc707122SEaswaran Raman // are decoded. 368dc707122SEaswaran Raman Expressions.resize( 369dc707122SEaswaran Raman NumExpressions, 370dc707122SEaswaran Raman CounterExpression(CounterExpression::Subtract, Counter(), Counter())); 371dc707122SEaswaran Raman for (size_t I = 0; I < NumExpressions; ++I) { 372dc707122SEaswaran Raman if (auto Err = readCounter(Expressions[I].LHS)) 373dc707122SEaswaran Raman return Err; 374dc707122SEaswaran Raman if (auto Err = readCounter(Expressions[I].RHS)) 375dc707122SEaswaran Raman return Err; 376dc707122SEaswaran Raman } 377dc707122SEaswaran Raman 378dc707122SEaswaran Raman // Read the mapping regions sub-arrays. 379dc707122SEaswaran Raman for (unsigned InferredFileID = 0, S = VirtualFileMapping.size(); 380dc707122SEaswaran Raman InferredFileID < S; ++InferredFileID) { 381dc707122SEaswaran Raman if (auto Err = readMappingRegionsSubArray(MappingRegions, InferredFileID, 382dc707122SEaswaran Raman VirtualFileMapping.size())) 383dc707122SEaswaran Raman return Err; 384dc707122SEaswaran Raman } 385dc707122SEaswaran Raman 386dc707122SEaswaran Raman // Set the counters for the expansion regions. 387dc707122SEaswaran Raman // i.e. Counter of expansion region = counter of the first region 388dc707122SEaswaran Raman // from the expanded file. 389dc707122SEaswaran Raman // Perform multiple passes to correctly propagate the counters through 390dc707122SEaswaran Raman // all the nested expansion regions. 391dc707122SEaswaran Raman SmallVector<CounterMappingRegion *, 8> FileIDExpansionRegionMapping; 392dc707122SEaswaran Raman FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr); 393dc707122SEaswaran Raman for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) { 394dc707122SEaswaran Raman for (auto &R : MappingRegions) { 395dc707122SEaswaran Raman if (R.Kind != CounterMappingRegion::ExpansionRegion) 396dc707122SEaswaran Raman continue; 397dc707122SEaswaran Raman assert(!FileIDExpansionRegionMapping[R.ExpandedFileID]); 398dc707122SEaswaran Raman FileIDExpansionRegionMapping[R.ExpandedFileID] = &R; 399dc707122SEaswaran Raman } 400dc707122SEaswaran Raman for (auto &R : MappingRegions) { 401dc707122SEaswaran Raman if (FileIDExpansionRegionMapping[R.FileID]) { 402dc707122SEaswaran Raman FileIDExpansionRegionMapping[R.FileID]->Count = R.Count; 403dc707122SEaswaran Raman FileIDExpansionRegionMapping[R.FileID] = nullptr; 404dc707122SEaswaran Raman } 405dc707122SEaswaran Raman } 406dc707122SEaswaran Raman } 407dc707122SEaswaran Raman 4089152fd17SVedant Kumar return Error::success(); 409dc707122SEaswaran Raman } 410dc707122SEaswaran Raman 411ac40e819SIgor Kudrin Expected<bool> RawCoverageMappingDummyChecker::isDummy() { 412ac40e819SIgor Kudrin // A dummy coverage mapping data consists of just one region with zero count. 413ac40e819SIgor Kudrin uint64_t NumFileMappings; 414ac40e819SIgor Kudrin if (Error Err = readSize(NumFileMappings)) 415c55cf4afSBill Wendling return std::move(Err); 416ac40e819SIgor Kudrin if (NumFileMappings != 1) 417ac40e819SIgor Kudrin return false; 418ac40e819SIgor Kudrin // We don't expect any specific value for the filename index, just skip it. 419ac40e819SIgor Kudrin uint64_t FilenameIndex; 420ac40e819SIgor Kudrin if (Error Err = 421ac40e819SIgor Kudrin readIntMax(FilenameIndex, std::numeric_limits<unsigned>::max())) 422c55cf4afSBill Wendling return std::move(Err); 423ac40e819SIgor Kudrin uint64_t NumExpressions; 424ac40e819SIgor Kudrin if (Error Err = readSize(NumExpressions)) 425c55cf4afSBill Wendling return std::move(Err); 426ac40e819SIgor Kudrin if (NumExpressions != 0) 427ac40e819SIgor Kudrin return false; 428ac40e819SIgor Kudrin uint64_t NumRegions; 429ac40e819SIgor Kudrin if (Error Err = readSize(NumRegions)) 430c55cf4afSBill Wendling return std::move(Err); 431ac40e819SIgor Kudrin if (NumRegions != 1) 432ac40e819SIgor Kudrin return false; 433ac40e819SIgor Kudrin uint64_t EncodedCounterAndRegion; 434ac40e819SIgor Kudrin if (Error Err = readIntMax(EncodedCounterAndRegion, 435ac40e819SIgor Kudrin std::numeric_limits<unsigned>::max())) 436c55cf4afSBill Wendling return std::move(Err); 437ac40e819SIgor Kudrin unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask; 438ac40e819SIgor Kudrin return Tag == Counter::Zero; 439ac40e819SIgor Kudrin } 440ac40e819SIgor Kudrin 4419152fd17SVedant Kumar Error InstrProfSymtab::create(SectionRef &Section) { 442e183340cSFangrui Song Expected<StringRef> DataOrErr = Section.getContents(); 443e183340cSFangrui Song if (!DataOrErr) 444e183340cSFangrui Song return DataOrErr.takeError(); 445e183340cSFangrui Song Data = *DataOrErr; 446dc707122SEaswaran Raman Address = Section.getAddress(); 4478b6af001SReid Kleckner 4488b6af001SReid Kleckner // If this is a linked PE/COFF file, then we have to skip over the null byte 4498b6af001SReid Kleckner // that is allocated in the .lprfn$A section in the LLVM profiling runtime. 4508b6af001SReid Kleckner const ObjectFile *Obj = Section.getObject(); 4518b6af001SReid Kleckner if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject()) 4528b6af001SReid Kleckner Data = Data.drop_front(1); 4538b6af001SReid Kleckner 4549152fd17SVedant Kumar return Error::success(); 455dc707122SEaswaran Raman } 456dc707122SEaswaran Raman 457dc707122SEaswaran Raman StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) { 458dc707122SEaswaran Raman if (Pointer < Address) 459dc707122SEaswaran Raman return StringRef(); 460dc707122SEaswaran Raman auto Offset = Pointer - Address; 461dc707122SEaswaran Raman if (Offset + Size > Data.size()) 462dc707122SEaswaran Raman return StringRef(); 463dc707122SEaswaran Raman return Data.substr(Pointer - Address, Size); 464dc707122SEaswaran Raman } 465dc707122SEaswaran Raman 466ac40e819SIgor Kudrin // Check if the mapping data is a dummy, i.e. is emitted for an unused function. 467ac40e819SIgor Kudrin static Expected<bool> isCoverageMappingDummy(uint64_t Hash, StringRef Mapping) { 468ac40e819SIgor Kudrin // The hash value of dummy mapping records is always zero. 469ac40e819SIgor Kudrin if (Hash) 470ac40e819SIgor Kudrin return false; 471ac40e819SIgor Kudrin return RawCoverageMappingDummyChecker(Mapping).isDummy(); 472ac40e819SIgor Kudrin } 473ac40e819SIgor Kudrin 474dd1ea9deSVedant Kumar /// A range of filename indices. Used to specify the location of a batch of 475dd1ea9deSVedant Kumar /// filenames in a vector-like container. 476dd1ea9deSVedant Kumar struct FilenameRange { 477dd1ea9deSVedant Kumar unsigned StartingIndex; 478dd1ea9deSVedant Kumar unsigned Length; 479dd1ea9deSVedant Kumar 480dd1ea9deSVedant Kumar FilenameRange(unsigned StartingIndex, unsigned Length) 481dd1ea9deSVedant Kumar : StartingIndex(StartingIndex), Length(Length) {} 482dd1ea9deSVedant Kumar 483dd1ea9deSVedant Kumar void markInvalid() { Length = 0; } 484dd1ea9deSVedant Kumar bool isInvalid() const { return Length == 0; } 485dd1ea9deSVedant Kumar }; 486dd1ea9deSVedant Kumar 487dc707122SEaswaran Raman namespace { 488e78d131aSEugene Zelenko 489dd1ea9deSVedant Kumar /// The interface to read coverage mapping function records for a module. 490dc707122SEaswaran Raman struct CovMapFuncRecordReader { 491e78d131aSEugene Zelenko virtual ~CovMapFuncRecordReader() = default; 492e78d131aSEugene Zelenko 493dd1ea9deSVedant Kumar // Read a coverage header. 4943739b95dSVedant Kumar // 495dd1ea9deSVedant Kumar // \p CovBuf points to the buffer containing the \c CovHeader of the coverage 4963739b95dSVedant Kumar // mapping data associated with the module. 4973739b95dSVedant Kumar // 498dd1ea9deSVedant Kumar // Returns a pointer to the next \c CovHeader if it exists, or to an address 499dd1ea9deSVedant Kumar // greater than \p CovEnd if not. 500*5fbd1a33SPetr Hosek virtual Expected<const char *> readCoverageHeader(const char *CovBuf, 501*5fbd1a33SPetr Hosek const char *CovBufEnd) = 0; 502dd1ea9deSVedant Kumar 503dd1ea9deSVedant Kumar // Read function records. 504dd1ea9deSVedant Kumar // 505dd1ea9deSVedant Kumar // \p FuncRecBuf points to the buffer containing a batch of function records. 506dd1ea9deSVedant Kumar // \p FuncRecBufEnd points past the end of the batch of records. 507dd1ea9deSVedant Kumar // 508dd1ea9deSVedant Kumar // Prior to Version4, \p OutOfLineFileRange points to a sequence of filenames 509dd1ea9deSVedant Kumar // associated with the function records. It is unused in Version4. 510dd1ea9deSVedant Kumar // 511dd1ea9deSVedant Kumar // Prior to Version4, \p OutOfLineMappingBuf points to a sequence of coverage 512dd1ea9deSVedant Kumar // mappings associated with the function records. It is unused in Version4. 513dd1ea9deSVedant Kumar virtual Error readFunctionRecords(const char *FuncRecBuf, 514dd1ea9deSVedant Kumar const char *FuncRecBufEnd, 515dd1ea9deSVedant Kumar Optional<FilenameRange> OutOfLineFileRange, 516dd1ea9deSVedant Kumar const char *OutOfLineMappingBuf, 517dd1ea9deSVedant Kumar const char *OutOfLineMappingBufEnd) = 0; 518e78d131aSEugene Zelenko 519dc707122SEaswaran Raman template <class IntPtrT, support::endianness Endian> 5209152fd17SVedant Kumar static Expected<std::unique_ptr<CovMapFuncRecordReader>> 521e78d131aSEugene Zelenko get(CovMapVersion Version, InstrProfSymtab &P, 522dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, 523*5fbd1a33SPetr Hosek std::vector<std::string> &F); 524dc707122SEaswaran Raman }; 525dc707122SEaswaran Raman 526dc707122SEaswaran Raman // A class for reading coverage mapping function records for a module. 527e78d131aSEugene Zelenko template <CovMapVersion Version, class IntPtrT, support::endianness Endian> 528dc707122SEaswaran Raman class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { 52972208a82SEugene Zelenko using FuncRecordType = 53072208a82SEugene Zelenko typename CovMapTraits<Version, IntPtrT>::CovMapFuncRecordType; 53172208a82SEugene Zelenko using NameRefType = typename CovMapTraits<Version, IntPtrT>::NameRefType; 532dc707122SEaswaran Raman 533ac40e819SIgor Kudrin // Maps function's name references to the indexes of their records 534ac40e819SIgor Kudrin // in \c Records. 535e78d131aSEugene Zelenko DenseMap<NameRefType, size_t> FunctionRecords; 536dc707122SEaswaran Raman InstrProfSymtab &ProfileNames; 537*5fbd1a33SPetr Hosek std::vector<std::string> &Filenames; 538dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records; 539dc707122SEaswaran Raman 540dd1ea9deSVedant Kumar // Maps a hash of the filenames in a TU to a \c FileRange. The range 541dd1ea9deSVedant Kumar // specifies the location of the hashed filenames in \c Filenames. 542dd1ea9deSVedant Kumar DenseMap<uint64_t, FilenameRange> FileRangeMap; 543dd1ea9deSVedant Kumar 544ac40e819SIgor Kudrin // Add the record to the collection if we don't already have a record that 545ac40e819SIgor Kudrin // points to the same function name. This is useful to ignore the redundant 546ac40e819SIgor Kudrin // records for the functions with ODR linkage. 547ac40e819SIgor Kudrin // In addition, prefer records with real coverage mapping data to dummy 548ac40e819SIgor Kudrin // records, which were emitted for inline functions which were seen but 549ac40e819SIgor Kudrin // not used in the corresponding translation unit. 550ac40e819SIgor Kudrin Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR, 551dd1ea9deSVedant Kumar StringRef Mapping, 552dd1ea9deSVedant Kumar FilenameRange FileRange) { 553dd1ea9deSVedant Kumar ++CovMapNumRecords; 554ac40e819SIgor Kudrin uint64_t FuncHash = CFR->template getFuncHash<Endian>(); 555ac40e819SIgor Kudrin NameRefType NameRef = CFR->template getFuncNameRef<Endian>(); 556ac40e819SIgor Kudrin auto InsertResult = 557ac40e819SIgor Kudrin FunctionRecords.insert(std::make_pair(NameRef, Records.size())); 558ac40e819SIgor Kudrin if (InsertResult.second) { 559ac40e819SIgor Kudrin StringRef FuncName; 560ac40e819SIgor Kudrin if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName)) 561ac40e819SIgor Kudrin return Err; 562b5794ca9SVedant Kumar if (FuncName.empty()) 563b5794ca9SVedant Kumar return make_error<InstrProfError>(instrprof_error::malformed); 564dd1ea9deSVedant Kumar ++CovMapNumUsedRecords; 565dd1ea9deSVedant Kumar Records.emplace_back(Version, FuncName, FuncHash, Mapping, 566dd1ea9deSVedant Kumar FileRange.StartingIndex, FileRange.Length); 567ac40e819SIgor Kudrin return Error::success(); 568ac40e819SIgor Kudrin } 569ac40e819SIgor Kudrin // Update the existing record if it's a dummy and the new record is real. 570ac40e819SIgor Kudrin size_t OldRecordIndex = InsertResult.first->second; 571ac40e819SIgor Kudrin BinaryCoverageReader::ProfileMappingRecord &OldRecord = 572ac40e819SIgor Kudrin Records[OldRecordIndex]; 573ac40e819SIgor Kudrin Expected<bool> OldIsDummyExpected = isCoverageMappingDummy( 574ac40e819SIgor Kudrin OldRecord.FunctionHash, OldRecord.CoverageMapping); 575ac40e819SIgor Kudrin if (Error Err = OldIsDummyExpected.takeError()) 576ac40e819SIgor Kudrin return Err; 577ac40e819SIgor Kudrin if (!*OldIsDummyExpected) 578ac40e819SIgor Kudrin return Error::success(); 579ac40e819SIgor Kudrin Expected<bool> NewIsDummyExpected = 580ac40e819SIgor Kudrin isCoverageMappingDummy(FuncHash, Mapping); 581ac40e819SIgor Kudrin if (Error Err = NewIsDummyExpected.takeError()) 582ac40e819SIgor Kudrin return Err; 583ac40e819SIgor Kudrin if (*NewIsDummyExpected) 584ac40e819SIgor Kudrin return Error::success(); 585dd1ea9deSVedant Kumar ++CovMapNumUsedRecords; 586ac40e819SIgor Kudrin OldRecord.FunctionHash = FuncHash; 587ac40e819SIgor Kudrin OldRecord.CoverageMapping = Mapping; 588dd1ea9deSVedant Kumar OldRecord.FilenamesBegin = FileRange.StartingIndex; 589dd1ea9deSVedant Kumar OldRecord.FilenamesSize = FileRange.Length; 590ac40e819SIgor Kudrin return Error::success(); 591ac40e819SIgor Kudrin } 592ac40e819SIgor Kudrin 593dc707122SEaswaran Raman public: 594dc707122SEaswaran Raman VersionedCovMapFuncRecordReader( 595dc707122SEaswaran Raman InstrProfSymtab &P, 596dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, 597*5fbd1a33SPetr Hosek std::vector<std::string> &F) 598dc707122SEaswaran Raman : ProfileNames(P), Filenames(F), Records(R) {} 599e78d131aSEugene Zelenko 600e78d131aSEugene Zelenko ~VersionedCovMapFuncRecordReader() override = default; 601dc707122SEaswaran Raman 602*5fbd1a33SPetr Hosek Expected<const char *> readCoverageHeader(const char *CovBuf, 603*5fbd1a33SPetr Hosek const char *CovBufEnd) override { 604dc707122SEaswaran Raman using namespace support; 605e78d131aSEugene Zelenko 606dd1ea9deSVedant Kumar if (CovBuf + sizeof(CovMapHeader) > CovBufEnd) 6079152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 608dd1ea9deSVedant Kumar auto CovHeader = reinterpret_cast<const CovMapHeader *>(CovBuf); 609dc707122SEaswaran Raman uint32_t NRecords = CovHeader->getNRecords<Endian>(); 610dc707122SEaswaran Raman uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>(); 611dc707122SEaswaran Raman uint32_t CoverageSize = CovHeader->getCoverageSize<Endian>(); 612dc707122SEaswaran Raman assert((CovMapVersion)CovHeader->getVersion<Endian>() == Version); 613dd1ea9deSVedant Kumar CovBuf = reinterpret_cast<const char *>(CovHeader + 1); 614dc707122SEaswaran Raman 615dc707122SEaswaran Raman // Skip past the function records, saving the start and end for later. 616dd1ea9deSVedant Kumar // This is a no-op in Version4 (function records are read after all headers 617dd1ea9deSVedant Kumar // are read). 618dd1ea9deSVedant Kumar const char *FuncRecBuf = nullptr; 619dd1ea9deSVedant Kumar const char *FuncRecBufEnd = nullptr; 620dd1ea9deSVedant Kumar if (Version < CovMapVersion::Version4) 621dd1ea9deSVedant Kumar FuncRecBuf = CovBuf; 622dd1ea9deSVedant Kumar CovBuf += NRecords * sizeof(FuncRecordType); 623dd1ea9deSVedant Kumar if (Version < CovMapVersion::Version4) 624dd1ea9deSVedant Kumar FuncRecBufEnd = CovBuf; 625dc707122SEaswaran Raman 626dc707122SEaswaran Raman // Get the filenames. 627dd1ea9deSVedant Kumar if (CovBuf + FilenamesSize > CovBufEnd) 6289152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 629dc707122SEaswaran Raman size_t FilenamesBegin = Filenames.size(); 630dd1ea9deSVedant Kumar StringRef FilenameRegion(CovBuf, FilenamesSize); 631dd1ea9deSVedant Kumar RawCoverageFilenamesReader Reader(FilenameRegion, Filenames); 632*5fbd1a33SPetr Hosek if (auto Err = Reader.read(Version)) 633c55cf4afSBill Wendling return std::move(Err); 634dd1ea9deSVedant Kumar CovBuf += FilenamesSize; 635dd1ea9deSVedant Kumar FilenameRange FileRange(FilenamesBegin, Filenames.size() - FilenamesBegin); 636dd1ea9deSVedant Kumar 6379f2967bcSAlan Phipps if (Version >= CovMapVersion::Version4) { 638dd1ea9deSVedant Kumar // Map a hash of the filenames region to the filename range associated 639dd1ea9deSVedant Kumar // with this coverage header. 640dd1ea9deSVedant Kumar int64_t FilenamesRef = 641dd1ea9deSVedant Kumar llvm::IndexedInstrProf::ComputeHash(FilenameRegion); 642dd1ea9deSVedant Kumar auto Insert = 643dd1ea9deSVedant Kumar FileRangeMap.insert(std::make_pair(FilenamesRef, FileRange)); 644dd1ea9deSVedant Kumar if (!Insert.second) { 645dd1ea9deSVedant Kumar // The same filenames ref was encountered twice. It's possible that 646dd1ea9deSVedant Kumar // the associated filenames are the same. 647dd1ea9deSVedant Kumar auto It = Filenames.begin(); 648dd1ea9deSVedant Kumar FilenameRange &OrigRange = Insert.first->getSecond(); 649dd1ea9deSVedant Kumar if (std::equal(It + OrigRange.StartingIndex, 650dd1ea9deSVedant Kumar It + OrigRange.StartingIndex + OrigRange.Length, 651dd1ea9deSVedant Kumar It + FileRange.StartingIndex, 652dd1ea9deSVedant Kumar It + FileRange.StartingIndex + FileRange.Length)) 653dd1ea9deSVedant Kumar // Map the new range to the original one. 654dd1ea9deSVedant Kumar FileRange = OrigRange; 655dd1ea9deSVedant Kumar else 656dd1ea9deSVedant Kumar // This is a hash collision. Mark the filenames ref invalid. 657dd1ea9deSVedant Kumar OrigRange.markInvalid(); 658dd1ea9deSVedant Kumar } 659dd1ea9deSVedant Kumar } 660dc707122SEaswaran Raman 661dc707122SEaswaran Raman // We'll read the coverage mapping records in the loop below. 662dd1ea9deSVedant Kumar // This is a no-op in Version4 (coverage mappings are not affixed to the 663dd1ea9deSVedant Kumar // coverage header). 664dd1ea9deSVedant Kumar const char *MappingBuf = CovBuf; 6659f2967bcSAlan Phipps if (Version >= CovMapVersion::Version4 && CoverageSize != 0) 6669152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 667dd1ea9deSVedant Kumar CovBuf += CoverageSize; 668dd1ea9deSVedant Kumar const char *MappingEnd = CovBuf; 669dd1ea9deSVedant Kumar 670dd1ea9deSVedant Kumar if (CovBuf > CovBufEnd) 671dd1ea9deSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 672dd1ea9deSVedant Kumar 673dd1ea9deSVedant Kumar if (Version < CovMapVersion::Version4) { 674dd1ea9deSVedant Kumar // Read each function record. 675dd1ea9deSVedant Kumar if (Error E = readFunctionRecords(FuncRecBuf, FuncRecBufEnd, FileRange, 676dd1ea9deSVedant Kumar MappingBuf, MappingEnd)) 677dd1ea9deSVedant Kumar return std::move(E); 678dd1ea9deSVedant Kumar } 679dd1ea9deSVedant Kumar 680dc707122SEaswaran Raman // Each coverage map has an alignment of 8, so we need to adjust alignment 681dc707122SEaswaran Raman // before reading the next map. 682dd1ea9deSVedant Kumar CovBuf += offsetToAlignedAddr(CovBuf, Align(8)); 683dc707122SEaswaran Raman 684dd1ea9deSVedant Kumar return CovBuf; 68599317124SVedant Kumar } 686dd1ea9deSVedant Kumar 687dd1ea9deSVedant Kumar Error readFunctionRecords(const char *FuncRecBuf, const char *FuncRecBufEnd, 688dd1ea9deSVedant Kumar Optional<FilenameRange> OutOfLineFileRange, 689dd1ea9deSVedant Kumar const char *OutOfLineMappingBuf, 690dd1ea9deSVedant Kumar const char *OutOfLineMappingBufEnd) override { 691dd1ea9deSVedant Kumar auto CFR = reinterpret_cast<const FuncRecordType *>(FuncRecBuf); 692dd1ea9deSVedant Kumar while ((const char *)CFR < FuncRecBufEnd) { 693dd1ea9deSVedant Kumar // Validate the length of the coverage mapping for this function. 694dd1ea9deSVedant Kumar const char *NextMappingBuf; 695dd1ea9deSVedant Kumar const FuncRecordType *NextCFR; 696dd1ea9deSVedant Kumar std::tie(NextMappingBuf, NextCFR) = 697dd1ea9deSVedant Kumar CFR->template advanceByOne<Endian>(OutOfLineMappingBuf); 698dd1ea9deSVedant Kumar if (Version < CovMapVersion::Version4) 699dd1ea9deSVedant Kumar if (NextMappingBuf > OutOfLineMappingBufEnd) 700dd1ea9deSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 701dd1ea9deSVedant Kumar 702dd1ea9deSVedant Kumar // Look up the set of filenames associated with this function record. 703dd1ea9deSVedant Kumar Optional<FilenameRange> FileRange; 704dd1ea9deSVedant Kumar if (Version < CovMapVersion::Version4) { 705dd1ea9deSVedant Kumar FileRange = OutOfLineFileRange; 706dd1ea9deSVedant Kumar } else { 707dd1ea9deSVedant Kumar uint64_t FilenamesRef = CFR->template getFilenamesRef<Endian>(); 708dd1ea9deSVedant Kumar auto It = FileRangeMap.find(FilenamesRef); 709dd1ea9deSVedant Kumar if (It == FileRangeMap.end()) 710dd1ea9deSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 711dd1ea9deSVedant Kumar else 712dd1ea9deSVedant Kumar FileRange = It->getSecond(); 713dd1ea9deSVedant Kumar } 714dd1ea9deSVedant Kumar 715dd1ea9deSVedant Kumar // Now, read the coverage data. 716dd1ea9deSVedant Kumar if (FileRange && !FileRange->isInvalid()) { 717dd1ea9deSVedant Kumar StringRef Mapping = 718dd1ea9deSVedant Kumar CFR->template getCoverageMapping<Endian>(OutOfLineMappingBuf); 7199f2967bcSAlan Phipps if (Version >= CovMapVersion::Version4 && 720dd1ea9deSVedant Kumar Mapping.data() + Mapping.size() > FuncRecBufEnd) 721dd1ea9deSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 722dd1ea9deSVedant Kumar if (Error Err = insertFunctionRecordIfNeeded(CFR, Mapping, *FileRange)) 723dd1ea9deSVedant Kumar return Err; 724dd1ea9deSVedant Kumar } 725dd1ea9deSVedant Kumar 726dd1ea9deSVedant Kumar std::tie(OutOfLineMappingBuf, CFR) = std::tie(NextMappingBuf, NextCFR); 727dd1ea9deSVedant Kumar } 728dd1ea9deSVedant Kumar return Error::success(); 729dc707122SEaswaran Raman } 730dc707122SEaswaran Raman }; 731e78d131aSEugene Zelenko 732dc707122SEaswaran Raman } // end anonymous namespace 733dc707122SEaswaran Raman 734dc707122SEaswaran Raman template <class IntPtrT, support::endianness Endian> 7359152fd17SVedant Kumar Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get( 736e78d131aSEugene Zelenko CovMapVersion Version, InstrProfSymtab &P, 737dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, 738*5fbd1a33SPetr Hosek std::vector<std::string> &F) { 739dc707122SEaswaran Raman using namespace coverage; 740e78d131aSEugene Zelenko 741dc707122SEaswaran Raman switch (Version) { 742dc707122SEaswaran Raman case CovMapVersion::Version1: 7430eaee545SJonas Devlieghere return std::make_unique<VersionedCovMapFuncRecordReader< 744dc707122SEaswaran Raman CovMapVersion::Version1, IntPtrT, Endian>>(P, R, F); 745dc707122SEaswaran Raman case CovMapVersion::Version2: 746ad8f637bSVedant Kumar case CovMapVersion::Version3: 747dd1ea9deSVedant Kumar case CovMapVersion::Version4: 7489f2967bcSAlan Phipps case CovMapVersion::Version5: 749*5fbd1a33SPetr Hosek case CovMapVersion::Version6: 750dc707122SEaswaran Raman // Decompress the name data. 7519152fd17SVedant Kumar if (Error E = P.create(P.getNameData())) 752c55cf4afSBill Wendling return std::move(E); 753ad8f637bSVedant Kumar if (Version == CovMapVersion::Version2) 7540eaee545SJonas Devlieghere return std::make_unique<VersionedCovMapFuncRecordReader< 755dc707122SEaswaran Raman CovMapVersion::Version2, IntPtrT, Endian>>(P, R, F); 756dd1ea9deSVedant Kumar else if (Version == CovMapVersion::Version3) 7570eaee545SJonas Devlieghere return std::make_unique<VersionedCovMapFuncRecordReader< 758ad8f637bSVedant Kumar CovMapVersion::Version3, IntPtrT, Endian>>(P, R, F); 759dd1ea9deSVedant Kumar else if (Version == CovMapVersion::Version4) 760dd1ea9deSVedant Kumar return std::make_unique<VersionedCovMapFuncRecordReader< 761dd1ea9deSVedant Kumar CovMapVersion::Version4, IntPtrT, Endian>>(P, R, F); 7629f2967bcSAlan Phipps else if (Version == CovMapVersion::Version5) 7639f2967bcSAlan Phipps return std::make_unique<VersionedCovMapFuncRecordReader< 7649f2967bcSAlan Phipps CovMapVersion::Version5, IntPtrT, Endian>>(P, R, F); 765*5fbd1a33SPetr Hosek else if (Version == CovMapVersion::Version6) 766*5fbd1a33SPetr Hosek return std::make_unique<VersionedCovMapFuncRecordReader< 767*5fbd1a33SPetr Hosek CovMapVersion::Version6, IntPtrT, Endian>>(P, R, F); 768dc707122SEaswaran Raman } 769dc707122SEaswaran Raman llvm_unreachable("Unsupported version"); 770dc707122SEaswaran Raman } 771dc707122SEaswaran Raman 772dc707122SEaswaran Raman template <typename T, support::endianness Endian> 7739152fd17SVedant Kumar static Error readCoverageMappingData( 774dd1ea9deSVedant Kumar InstrProfSymtab &ProfileNames, StringRef CovMap, StringRef FuncRecords, 775dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records, 776*5fbd1a33SPetr Hosek std::vector<std::string> &Filenames) { 777dc707122SEaswaran Raman using namespace coverage; 778e78d131aSEugene Zelenko 779dc707122SEaswaran Raman // Read the records in the coverage data section. 780dc707122SEaswaran Raman auto CovHeader = 781dd1ea9deSVedant Kumar reinterpret_cast<const CovMapHeader *>(CovMap.data()); 782dc707122SEaswaran Raman CovMapVersion Version = (CovMapVersion)CovHeader->getVersion<Endian>(); 783e78d131aSEugene Zelenko if (Version > CovMapVersion::CurrentVersion) 7849152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::unsupported_version); 7859152fd17SVedant Kumar Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected = 786dc707122SEaswaran Raman CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records, 787dc707122SEaswaran Raman Filenames); 7889152fd17SVedant Kumar if (Error E = ReaderExpected.takeError()) 7899152fd17SVedant Kumar return E; 7909152fd17SVedant Kumar auto Reader = std::move(ReaderExpected.get()); 791dd1ea9deSVedant Kumar const char *CovBuf = CovMap.data(); 792dd1ea9deSVedant Kumar const char *CovBufEnd = CovBuf + CovMap.size(); 793dd1ea9deSVedant Kumar const char *FuncRecBuf = FuncRecords.data(); 794dd1ea9deSVedant Kumar const char *FuncRecBufEnd = FuncRecords.data() + FuncRecords.size(); 795dd1ea9deSVedant Kumar while (CovBuf < CovBufEnd) { 796dd1ea9deSVedant Kumar // Read the current coverage header & filename data. 797dd1ea9deSVedant Kumar // 798dd1ea9deSVedant Kumar // Prior to Version4, this also reads all function records affixed to the 799dd1ea9deSVedant Kumar // header. 800dd1ea9deSVedant Kumar // 801dd1ea9deSVedant Kumar // Return a pointer to the next coverage header. 802*5fbd1a33SPetr Hosek auto NextOrErr = Reader->readCoverageHeader(CovBuf, CovBufEnd); 803dd1ea9deSVedant Kumar if (auto E = NextOrErr.takeError()) 8049152fd17SVedant Kumar return E; 805dd1ea9deSVedant Kumar CovBuf = NextOrErr.get(); 806dc707122SEaswaran Raman } 807dd1ea9deSVedant Kumar // In Version4, function records are not affixed to coverage headers. Read 808dd1ea9deSVedant Kumar // the records from their dedicated section. 8099f2967bcSAlan Phipps if (Version >= CovMapVersion::Version4) 810dd1ea9deSVedant Kumar return Reader->readFunctionRecords(FuncRecBuf, FuncRecBufEnd, None, nullptr, 811dd1ea9deSVedant Kumar nullptr); 8129152fd17SVedant Kumar return Error::success(); 813dc707122SEaswaran Raman } 814e78d131aSEugene Zelenko 815dc707122SEaswaran Raman static const char *TestingFormatMagic = "llvmcovmtestdata"; 816dc707122SEaswaran Raman 817901d04fcSVedant Kumar Expected<std::unique_ptr<BinaryCoverageReader>> 818901d04fcSVedant Kumar BinaryCoverageReader::createCoverageReaderFromBuffer( 81980cd518bSVedant Kumar StringRef Coverage, std::string &&FuncRecords, InstrProfSymtab &&ProfileNames, 820dd1ea9deSVedant Kumar uint8_t BytesInAddress, support::endianness Endian) { 82180cd518bSVedant Kumar std::unique_ptr<BinaryCoverageReader> Reader( 82280cd518bSVedant Kumar new BinaryCoverageReader(std::move(FuncRecords))); 823901d04fcSVedant Kumar Reader->ProfileNames = std::move(ProfileNames); 82480cd518bSVedant Kumar StringRef FuncRecordsRef = Reader->FuncRecords; 825901d04fcSVedant Kumar if (BytesInAddress == 4 && Endian == support::endianness::little) { 826901d04fcSVedant Kumar if (Error E = 827901d04fcSVedant Kumar readCoverageMappingData<uint32_t, support::endianness::little>( 82880cd518bSVedant Kumar Reader->ProfileNames, Coverage, FuncRecordsRef, 829*5fbd1a33SPetr Hosek Reader->MappingRecords, Reader->Filenames)) 830c55cf4afSBill Wendling return std::move(E); 831901d04fcSVedant Kumar } else if (BytesInAddress == 4 && Endian == support::endianness::big) { 832901d04fcSVedant Kumar if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>( 83380cd518bSVedant Kumar Reader->ProfileNames, Coverage, FuncRecordsRef, 834*5fbd1a33SPetr Hosek Reader->MappingRecords, Reader->Filenames)) 835c55cf4afSBill Wendling return std::move(E); 836901d04fcSVedant Kumar } else if (BytesInAddress == 8 && Endian == support::endianness::little) { 837901d04fcSVedant Kumar if (Error E = 838901d04fcSVedant Kumar readCoverageMappingData<uint64_t, support::endianness::little>( 83980cd518bSVedant Kumar Reader->ProfileNames, Coverage, FuncRecordsRef, 840*5fbd1a33SPetr Hosek Reader->MappingRecords, Reader->Filenames)) 841c55cf4afSBill Wendling return std::move(E); 842901d04fcSVedant Kumar } else if (BytesInAddress == 8 && Endian == support::endianness::big) { 843901d04fcSVedant Kumar if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>( 84480cd518bSVedant Kumar Reader->ProfileNames, Coverage, FuncRecordsRef, 845*5fbd1a33SPetr Hosek Reader->MappingRecords, Reader->Filenames)) 846c55cf4afSBill Wendling return std::move(E); 847901d04fcSVedant Kumar } else 848901d04fcSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 849c55cf4afSBill Wendling return std::move(Reader); 850901d04fcSVedant Kumar } 851901d04fcSVedant Kumar 852901d04fcSVedant Kumar static Expected<std::unique_ptr<BinaryCoverageReader>> 853901d04fcSVedant Kumar loadTestingFormat(StringRef Data) { 854901d04fcSVedant Kumar uint8_t BytesInAddress = 8; 855901d04fcSVedant Kumar support::endianness Endian = support::endianness::little; 856dc707122SEaswaran Raman 857dc707122SEaswaran Raman Data = Data.substr(StringRef(TestingFormatMagic).size()); 85872208a82SEugene Zelenko if (Data.empty()) 8599152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::truncated); 860dc707122SEaswaran Raman unsigned N = 0; 8616a0746a9SFangrui Song uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N); 862dc707122SEaswaran Raman if (N > Data.size()) 8639152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 864dc707122SEaswaran Raman Data = Data.substr(N); 86572208a82SEugene Zelenko if (Data.empty()) 8669152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::truncated); 867dc707122SEaswaran Raman N = 0; 8686a0746a9SFangrui Song uint64_t Address = decodeULEB128(Data.bytes_begin(), &N); 869dc707122SEaswaran Raman if (N > Data.size()) 8709152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 871dc707122SEaswaran Raman Data = Data.substr(N); 872dc707122SEaswaran Raman if (Data.size() < ProfileNamesSize) 8739152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 874901d04fcSVedant Kumar InstrProfSymtab ProfileNames; 8759152fd17SVedant Kumar if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address)) 876c55cf4afSBill Wendling return std::move(E); 877901d04fcSVedant Kumar StringRef CoverageMapping = Data.substr(ProfileNamesSize); 878eb103073SIgor Kudrin // Skip the padding bytes because coverage map data has an alignment of 8. 87972208a82SEugene Zelenko if (CoverageMapping.empty()) 8809152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::truncated); 881ce56e1a1SGuillaume Chatelet size_t Pad = offsetToAlignedAddr(CoverageMapping.data(), Align(8)); 882eb103073SIgor Kudrin if (CoverageMapping.size() < Pad) 8839152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 884eb103073SIgor Kudrin CoverageMapping = CoverageMapping.substr(Pad); 885901d04fcSVedant Kumar return BinaryCoverageReader::createCoverageReaderFromBuffer( 886dd1ea9deSVedant Kumar CoverageMapping, "", std::move(ProfileNames), BytesInAddress, Endian); 887dc707122SEaswaran Raman } 888dc707122SEaswaran Raman 88980cd518bSVedant Kumar /// Find all sections that match \p Name. There may be more than one if comdats 89080cd518bSVedant Kumar /// are in use, e.g. for the __llvm_covfun section on ELF. 89180cd518bSVedant Kumar static Expected<std::vector<SectionRef>> lookupSections(ObjectFile &OF, 89280cd518bSVedant Kumar StringRef Name) { 8938b6af001SReid Kleckner // On COFF, the object file section name may end in "$M". This tells the 8948b6af001SReid Kleckner // linker to sort these sections between "$A" and "$Z". The linker removes the 8958b6af001SReid Kleckner // dollar and everything after it in the final binary. Do the same to match. 8968b6af001SReid Kleckner bool IsCOFF = isa<COFFObjectFile>(OF); 8978b6af001SReid Kleckner auto stripSuffix = [IsCOFF](StringRef N) { 8988b6af001SReid Kleckner return IsCOFF ? N.split('$').first : N; 8998b6af001SReid Kleckner }; 9008b6af001SReid Kleckner Name = stripSuffix(Name); 9018b6af001SReid Kleckner 90280cd518bSVedant Kumar std::vector<SectionRef> Sections; 903dc707122SEaswaran Raman for (const auto &Section : OF.sections()) { 904bcc00e1aSGeorge Rimar Expected<StringRef> NameOrErr = Section.getName(); 905bcc00e1aSGeorge Rimar if (!NameOrErr) 906bcc00e1aSGeorge Rimar return NameOrErr.takeError(); 907bcc00e1aSGeorge Rimar if (stripSuffix(*NameOrErr) == Name) 90880cd518bSVedant Kumar Sections.push_back(Section); 909dc707122SEaswaran Raman } 91080cd518bSVedant Kumar if (Sections.empty()) 9119152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::no_data_found); 91280cd518bSVedant Kumar return Sections; 913dc707122SEaswaran Raman } 914dc707122SEaswaran Raman 915901d04fcSVedant Kumar static Expected<std::unique_ptr<BinaryCoverageReader>> 916901d04fcSVedant Kumar loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch) { 917dc707122SEaswaran Raman std::unique_ptr<ObjectFile> OF; 918e78d131aSEugene Zelenko if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { 919dc707122SEaswaran Raman // If we have a universal binary, try to look up the object for the 920dc707122SEaswaran Raman // appropriate architecture. 9214fd11c1eSAlexander Shaposhnikov auto ObjectFileOrErr = Universal->getMachOObjectForArch(Arch); 9229acb1099SKevin Enderby if (!ObjectFileOrErr) 9239acb1099SKevin Enderby return ObjectFileOrErr.takeError(); 924dc707122SEaswaran Raman OF = std::move(ObjectFileOrErr.get()); 925e78d131aSEugene Zelenko } else if (isa<ObjectFile>(Bin.get())) { 926dc707122SEaswaran Raman // For any other object file, upcast and take ownership. 927e78d131aSEugene Zelenko OF.reset(cast<ObjectFile>(Bin.release())); 928dc707122SEaswaran Raman // If we've asked for a particular arch, make sure they match. 929dc707122SEaswaran Raman if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch()) 9309152fd17SVedant Kumar return errorCodeToError(object_error::arch_not_found); 931dc707122SEaswaran Raman } else 932dc707122SEaswaran Raman // We can only handle object files. 9339152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 934dc707122SEaswaran Raman 935dc707122SEaswaran Raman // The coverage uses native pointer sizes for the object it's written in. 936901d04fcSVedant Kumar uint8_t BytesInAddress = OF->getBytesInAddress(); 937901d04fcSVedant Kumar support::endianness Endian = OF->isLittleEndian() 938901d04fcSVedant Kumar ? support::endianness::little 939dc707122SEaswaran Raman : support::endianness::big; 940dc707122SEaswaran Raman 941dc707122SEaswaran Raman // Look for the sections that we are interested in. 9421a6a2b64SVedant Kumar auto ObjFormat = OF->getTripleObjectFormat(); 9434a5ddf80SXinliang David Li auto NamesSection = 94480cd518bSVedant Kumar lookupSections(*OF, getInstrProfSectionName(IPSK_name, ObjFormat, 9451a6a2b64SVedant Kumar /*AddSegmentInfo=*/false)); 9469152fd17SVedant Kumar if (auto E = NamesSection.takeError()) 947c55cf4afSBill Wendling return std::move(E); 9484a5ddf80SXinliang David Li auto CoverageSection = 94980cd518bSVedant Kumar lookupSections(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat, 9501a6a2b64SVedant Kumar /*AddSegmentInfo=*/false)); 9519152fd17SVedant Kumar if (auto E = CoverageSection.takeError()) 952c55cf4afSBill Wendling return std::move(E); 95380cd518bSVedant Kumar std::vector<SectionRef> CoverageSectionRefs = *CoverageSection; 95480cd518bSVedant Kumar if (CoverageSectionRefs.size() != 1) 95580cd518bSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 95680cd518bSVedant Kumar auto CoverageMappingOrErr = CoverageSectionRefs.back().getContents(); 957901d04fcSVedant Kumar if (!CoverageMappingOrErr) 958901d04fcSVedant Kumar return CoverageMappingOrErr.takeError(); 959dd1ea9deSVedant Kumar StringRef CoverageMapping = CoverageMappingOrErr.get(); 960e183340cSFangrui Song 961901d04fcSVedant Kumar InstrProfSymtab ProfileNames; 96280cd518bSVedant Kumar std::vector<SectionRef> NamesSectionRefs = *NamesSection; 96380cd518bSVedant Kumar if (NamesSectionRefs.size() != 1) 96480cd518bSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 96580cd518bSVedant Kumar if (Error E = ProfileNames.create(NamesSectionRefs.back())) 966c55cf4afSBill Wendling return std::move(E); 967dc707122SEaswaran Raman 968dd1ea9deSVedant Kumar // Look for the coverage records section (Version4 only). 96980cd518bSVedant Kumar std::string FuncRecords; 97080cd518bSVedant Kumar auto CoverageRecordsSections = 97180cd518bSVedant Kumar lookupSections(*OF, getInstrProfSectionName(IPSK_covfun, ObjFormat, 972dd1ea9deSVedant Kumar /*AddSegmentInfo=*/false)); 97380cd518bSVedant Kumar if (auto E = CoverageRecordsSections.takeError()) 974dd1ea9deSVedant Kumar consumeError(std::move(E)); 975dd1ea9deSVedant Kumar else { 97680cd518bSVedant Kumar for (SectionRef Section : *CoverageRecordsSections) { 97780cd518bSVedant Kumar auto CoverageRecordsOrErr = Section.getContents(); 978dd1ea9deSVedant Kumar if (!CoverageRecordsOrErr) 979dd1ea9deSVedant Kumar return CoverageRecordsOrErr.takeError(); 98080cd518bSVedant Kumar FuncRecords += CoverageRecordsOrErr.get(); 98180cd518bSVedant Kumar while (FuncRecords.size() % 8 != 0) 98280cd518bSVedant Kumar FuncRecords += '\0'; 98380cd518bSVedant Kumar } 984dd1ea9deSVedant Kumar } 985dd1ea9deSVedant Kumar 986901d04fcSVedant Kumar return BinaryCoverageReader::createCoverageReaderFromBuffer( 98780cd518bSVedant Kumar CoverageMapping, std::move(FuncRecords), std::move(ProfileNames), 98880cd518bSVedant Kumar BytesInAddress, Endian); 989dc707122SEaswaran Raman } 990dc707122SEaswaran Raman 9917fafaa07SVedant Kumar /// Determine whether \p Arch is invalid or empty, given \p Bin. 9927fafaa07SVedant Kumar static bool isArchSpecifierInvalidOrMissing(Binary *Bin, StringRef Arch) { 9937fafaa07SVedant Kumar // If we have a universal binary and Arch doesn't identify any of its slices, 9947fafaa07SVedant Kumar // it's user error. 9957fafaa07SVedant Kumar if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin)) { 9967fafaa07SVedant Kumar for (auto &ObjForArch : Universal->objects()) 9977fafaa07SVedant Kumar if (Arch == ObjForArch.getArchFlagName()) 9987fafaa07SVedant Kumar return false; 9997fafaa07SVedant Kumar return true; 10007fafaa07SVedant Kumar } 10017fafaa07SVedant Kumar return false; 10027fafaa07SVedant Kumar } 10037fafaa07SVedant Kumar 1004901d04fcSVedant Kumar Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>> 1005901d04fcSVedant Kumar BinaryCoverageReader::create( 1006901d04fcSVedant Kumar MemoryBufferRef ObjectBuffer, StringRef Arch, 1007901d04fcSVedant Kumar SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers) { 1008901d04fcSVedant Kumar std::vector<std::unique_ptr<BinaryCoverageReader>> Readers; 1009dc707122SEaswaran Raman 1010901d04fcSVedant Kumar if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) { 1011dc707122SEaswaran Raman // This is a special format used for testing. 1012901d04fcSVedant Kumar auto ReaderOrErr = loadTestingFormat(ObjectBuffer.getBuffer()); 1013901d04fcSVedant Kumar if (!ReaderOrErr) 1014901d04fcSVedant Kumar return ReaderOrErr.takeError(); 1015901d04fcSVedant Kumar Readers.push_back(std::move(ReaderOrErr.get())); 1016c55cf4afSBill Wendling return std::move(Readers); 1017901d04fcSVedant Kumar } 1018dc707122SEaswaran Raman 1019901d04fcSVedant Kumar auto BinOrErr = createBinary(ObjectBuffer); 1020901d04fcSVedant Kumar if (!BinOrErr) 1021901d04fcSVedant Kumar return BinOrErr.takeError(); 1022901d04fcSVedant Kumar std::unique_ptr<Binary> Bin = std::move(BinOrErr.get()); 1023901d04fcSVedant Kumar 10247fafaa07SVedant Kumar if (isArchSpecifierInvalidOrMissing(Bin.get(), Arch)) 10257fafaa07SVedant Kumar return make_error<CoverageMapError>( 10267fafaa07SVedant Kumar coveragemap_error::invalid_or_missing_arch_specifier); 10277fafaa07SVedant Kumar 1028901d04fcSVedant Kumar // MachO universal binaries which contain archives need to be treated as 1029901d04fcSVedant Kumar // archives, not as regular binaries. 1030901d04fcSVedant Kumar if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { 1031901d04fcSVedant Kumar for (auto &ObjForArch : Universal->objects()) { 1032901d04fcSVedant Kumar // Skip slices within the universal binary which target the wrong arch. 1033901d04fcSVedant Kumar std::string ObjArch = ObjForArch.getArchFlagName(); 1034901d04fcSVedant Kumar if (Arch != ObjArch) 1035901d04fcSVedant Kumar continue; 1036901d04fcSVedant Kumar 1037901d04fcSVedant Kumar auto ArchiveOrErr = ObjForArch.getAsArchive(); 1038901d04fcSVedant Kumar if (!ArchiveOrErr) { 1039901d04fcSVedant Kumar // If this is not an archive, try treating it as a regular object. 1040901d04fcSVedant Kumar consumeError(ArchiveOrErr.takeError()); 1041901d04fcSVedant Kumar break; 1042901d04fcSVedant Kumar } 1043901d04fcSVedant Kumar 1044901d04fcSVedant Kumar return BinaryCoverageReader::create( 1045901d04fcSVedant Kumar ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers); 1046901d04fcSVedant Kumar } 1047901d04fcSVedant Kumar } 1048901d04fcSVedant Kumar 1049901d04fcSVedant Kumar // Load coverage out of archive members. 1050901d04fcSVedant Kumar if (auto *Ar = dyn_cast<Archive>(Bin.get())) { 1051901d04fcSVedant Kumar Error Err = Error::success(); 1052901d04fcSVedant Kumar for (auto &Child : Ar->children(Err)) { 1053901d04fcSVedant Kumar Expected<MemoryBufferRef> ChildBufOrErr = Child.getMemoryBufferRef(); 1054901d04fcSVedant Kumar if (!ChildBufOrErr) 1055901d04fcSVedant Kumar return ChildBufOrErr.takeError(); 1056901d04fcSVedant Kumar 1057901d04fcSVedant Kumar auto ChildReadersOrErr = BinaryCoverageReader::create( 1058901d04fcSVedant Kumar ChildBufOrErr.get(), Arch, ObjectFileBuffers); 1059901d04fcSVedant Kumar if (!ChildReadersOrErr) 1060901d04fcSVedant Kumar return ChildReadersOrErr.takeError(); 1061901d04fcSVedant Kumar for (auto &Reader : ChildReadersOrErr.get()) 1062901d04fcSVedant Kumar Readers.push_back(std::move(Reader)); 1063901d04fcSVedant Kumar } 1064901d04fcSVedant Kumar if (Err) 1065c55cf4afSBill Wendling return std::move(Err); 1066901d04fcSVedant Kumar 1067901d04fcSVedant Kumar // Thin archives reference object files outside of the archive file, i.e. 1068901d04fcSVedant Kumar // files which reside in memory not owned by the caller. Transfer ownership 1069901d04fcSVedant Kumar // to the caller. 1070901d04fcSVedant Kumar if (Ar->isThin()) 1071901d04fcSVedant Kumar for (auto &Buffer : Ar->takeThinBuffers()) 1072901d04fcSVedant Kumar ObjectFileBuffers.push_back(std::move(Buffer)); 1073901d04fcSVedant Kumar 1074c55cf4afSBill Wendling return std::move(Readers); 1075901d04fcSVedant Kumar } 1076901d04fcSVedant Kumar 1077901d04fcSVedant Kumar auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch); 1078901d04fcSVedant Kumar if (!ReaderOrErr) 1079901d04fcSVedant Kumar return ReaderOrErr.takeError(); 1080901d04fcSVedant Kumar Readers.push_back(std::move(ReaderOrErr.get())); 1081c55cf4afSBill Wendling return std::move(Readers); 1082dc707122SEaswaran Raman } 1083dc707122SEaswaran Raman 10849152fd17SVedant Kumar Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { 1085dc707122SEaswaran Raman if (CurrentRecord >= MappingRecords.size()) 10869152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::eof); 1087dc707122SEaswaran Raman 1088dc707122SEaswaran Raman FunctionsFilenames.clear(); 1089dc707122SEaswaran Raman Expressions.clear(); 1090dc707122SEaswaran Raman MappingRegions.clear(); 1091dc707122SEaswaran Raman auto &R = MappingRecords[CurrentRecord]; 1092*5fbd1a33SPetr Hosek auto F = makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize); 1093*5fbd1a33SPetr Hosek RawCoverageMappingReader Reader(R.CoverageMapping, F, FunctionsFilenames, 1094*5fbd1a33SPetr Hosek Expressions, MappingRegions); 1095dc707122SEaswaran Raman if (auto Err = Reader.read()) 1096dc707122SEaswaran Raman return Err; 1097dc707122SEaswaran Raman 1098dc707122SEaswaran Raman Record.FunctionName = R.FunctionName; 1099dc707122SEaswaran Raman Record.FunctionHash = R.FunctionHash; 1100dc707122SEaswaran Raman Record.Filenames = FunctionsFilenames; 1101dc707122SEaswaran Raman Record.Expressions = Expressions; 1102dc707122SEaswaran Raman Record.MappingRegions = MappingRegions; 1103dc707122SEaswaran Raman 1104dc707122SEaswaran Raman ++CurrentRecord; 11059152fd17SVedant Kumar return Error::success(); 1106dc707122SEaswaran Raman } 1107