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" 19e78d131aSEugene Zelenko #include "llvm/ADT/StringRef.h" 20e78d131aSEugene Zelenko #include "llvm/ADT/Triple.h" 21e78d131aSEugene Zelenko #include "llvm/Object/Binary.h" 22e78d131aSEugene Zelenko #include "llvm/Object/Error.h" 23dc707122SEaswaran Raman #include "llvm/Object/MachOUniversal.h" 24dc707122SEaswaran Raman #include "llvm/Object/ObjectFile.h" 258b6af001SReid Kleckner #include "llvm/Object/COFF.h" 26e78d131aSEugene Zelenko #include "llvm/ProfileData/InstrProf.h" 27e78d131aSEugene Zelenko #include "llvm/Support/Casting.h" 28dc707122SEaswaran Raman #include "llvm/Support/Debug.h" 294a5ddf80SXinliang David Li #include "llvm/Support/Endian.h" 30e78d131aSEugene Zelenko #include "llvm/Support/Error.h" 31e78d131aSEugene Zelenko #include "llvm/Support/ErrorHandling.h" 32dc707122SEaswaran Raman #include "llvm/Support/LEB128.h" 33dc707122SEaswaran Raman #include "llvm/Support/MathExtras.h" 34dc707122SEaswaran Raman #include "llvm/Support/raw_ostream.h" 35e78d131aSEugene Zelenko #include <vector> 36dc707122SEaswaran Raman 37dc707122SEaswaran Raman using namespace llvm; 38dc707122SEaswaran Raman using namespace coverage; 39dc707122SEaswaran Raman using namespace object; 40dc707122SEaswaran Raman 41dc707122SEaswaran Raman #define DEBUG_TYPE "coverage-mapping" 42dc707122SEaswaran Raman 43dc707122SEaswaran Raman void CoverageMappingIterator::increment() { 44bae83970SVedant Kumar if (ReadErr != coveragemap_error::success) 45bae83970SVedant Kumar return; 46bae83970SVedant Kumar 47dc707122SEaswaran Raman // Check if all the records were read or if an error occurred while reading 48dc707122SEaswaran Raman // the next record. 49bae83970SVedant Kumar if (auto E = Reader->readNextRecord(Record)) 509152fd17SVedant Kumar handleAllErrors(std::move(E), [&](const CoverageMapError &CME) { 519152fd17SVedant Kumar if (CME.get() == coveragemap_error::eof) 52dc707122SEaswaran Raman *this = CoverageMappingIterator(); 539152fd17SVedant Kumar else 54bae83970SVedant Kumar ReadErr = CME.get(); 559152fd17SVedant Kumar }); 569152fd17SVedant Kumar } 57dc707122SEaswaran Raman 589152fd17SVedant Kumar Error RawCoverageReader::readULEB128(uint64_t &Result) { 5972208a82SEugene Zelenko if (Data.empty()) 609152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::truncated); 61dc707122SEaswaran Raman unsigned N = 0; 626a0746a9SFangrui Song Result = decodeULEB128(Data.bytes_begin(), &N); 63dc707122SEaswaran Raman if (N > Data.size()) 649152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 65dc707122SEaswaran Raman Data = Data.substr(N); 669152fd17SVedant Kumar return Error::success(); 67dc707122SEaswaran Raman } 68dc707122SEaswaran Raman 699152fd17SVedant Kumar Error RawCoverageReader::readIntMax(uint64_t &Result, uint64_t MaxPlus1) { 70dc707122SEaswaran Raman if (auto Err = readULEB128(Result)) 71dc707122SEaswaran Raman return Err; 72dc707122SEaswaran Raman if (Result >= MaxPlus1) 739152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 749152fd17SVedant Kumar return Error::success(); 75dc707122SEaswaran Raman } 76dc707122SEaswaran Raman 779152fd17SVedant Kumar Error RawCoverageReader::readSize(uint64_t &Result) { 78dc707122SEaswaran Raman if (auto Err = readULEB128(Result)) 79dc707122SEaswaran Raman return Err; 80dc707122SEaswaran Raman // Sanity check the number. 81dc707122SEaswaran Raman if (Result > Data.size()) 829152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 839152fd17SVedant Kumar return Error::success(); 84dc707122SEaswaran Raman } 85dc707122SEaswaran Raman 869152fd17SVedant Kumar Error RawCoverageReader::readString(StringRef &Result) { 87dc707122SEaswaran Raman uint64_t Length; 88dc707122SEaswaran Raman if (auto Err = readSize(Length)) 89dc707122SEaswaran Raman return Err; 90dc707122SEaswaran Raman Result = Data.substr(0, Length); 91dc707122SEaswaran Raman Data = Data.substr(Length); 929152fd17SVedant Kumar return Error::success(); 93dc707122SEaswaran Raman } 94dc707122SEaswaran Raman 959152fd17SVedant Kumar Error RawCoverageFilenamesReader::read() { 96dc707122SEaswaran Raman uint64_t NumFilenames; 97dc707122SEaswaran Raman if (auto Err = readSize(NumFilenames)) 98dc707122SEaswaran Raman return Err; 99dc707122SEaswaran Raman for (size_t I = 0; I < NumFilenames; ++I) { 100dc707122SEaswaran Raman StringRef Filename; 101dc707122SEaswaran Raman if (auto Err = readString(Filename)) 102dc707122SEaswaran Raman return Err; 103dc707122SEaswaran Raman Filenames.push_back(Filename); 104dc707122SEaswaran Raman } 1059152fd17SVedant Kumar return Error::success(); 106dc707122SEaswaran Raman } 107dc707122SEaswaran Raman 1089152fd17SVedant Kumar Error RawCoverageMappingReader::decodeCounter(unsigned Value, Counter &C) { 109dc707122SEaswaran Raman auto Tag = Value & Counter::EncodingTagMask; 110dc707122SEaswaran Raman switch (Tag) { 111dc707122SEaswaran Raman case Counter::Zero: 112dc707122SEaswaran Raman C = Counter::getZero(); 1139152fd17SVedant Kumar return Error::success(); 114dc707122SEaswaran Raman case Counter::CounterValueReference: 115dc707122SEaswaran Raman C = Counter::getCounter(Value >> Counter::EncodingTagBits); 1169152fd17SVedant Kumar return Error::success(); 117dc707122SEaswaran Raman default: 118dc707122SEaswaran Raman break; 119dc707122SEaswaran Raman } 120dc707122SEaswaran Raman Tag -= Counter::Expression; 121dc707122SEaswaran Raman switch (Tag) { 122dc707122SEaswaran Raman case CounterExpression::Subtract: 123dc707122SEaswaran Raman case CounterExpression::Add: { 124dc707122SEaswaran Raman auto ID = Value >> Counter::EncodingTagBits; 125dc707122SEaswaran Raman if (ID >= Expressions.size()) 1269152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 127dc707122SEaswaran Raman Expressions[ID].Kind = CounterExpression::ExprKind(Tag); 128dc707122SEaswaran Raman C = Counter::getExpression(ID); 129dc707122SEaswaran Raman break; 130dc707122SEaswaran Raman } 131dc707122SEaswaran Raman default: 1329152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 133dc707122SEaswaran Raman } 1349152fd17SVedant Kumar return Error::success(); 135dc707122SEaswaran Raman } 136dc707122SEaswaran Raman 1379152fd17SVedant Kumar Error RawCoverageMappingReader::readCounter(Counter &C) { 138dc707122SEaswaran Raman uint64_t EncodedCounter; 139dc707122SEaswaran Raman if (auto Err = 140dc707122SEaswaran Raman readIntMax(EncodedCounter, std::numeric_limits<unsigned>::max())) 141dc707122SEaswaran Raman return Err; 142dc707122SEaswaran Raman if (auto Err = decodeCounter(EncodedCounter, C)) 143dc707122SEaswaran Raman return Err; 1449152fd17SVedant Kumar return Error::success(); 145dc707122SEaswaran Raman } 146dc707122SEaswaran Raman 147dc707122SEaswaran Raman static const unsigned EncodingExpansionRegionBit = 1 148dc707122SEaswaran Raman << Counter::EncodingTagBits; 149dc707122SEaswaran Raman 1505f8f34e4SAdrian Prantl /// Read the sub-array of regions for the given inferred file id. 151dc707122SEaswaran Raman /// \param NumFileIDs the number of file ids that are defined for this 152dc707122SEaswaran Raman /// function. 1539152fd17SVedant Kumar Error RawCoverageMappingReader::readMappingRegionsSubArray( 154dc707122SEaswaran Raman std::vector<CounterMappingRegion> &MappingRegions, unsigned InferredFileID, 155dc707122SEaswaran Raman size_t NumFileIDs) { 156dc707122SEaswaran Raman uint64_t NumRegions; 157dc707122SEaswaran Raman if (auto Err = readSize(NumRegions)) 158dc707122SEaswaran Raman return Err; 159dc707122SEaswaran Raman unsigned LineStart = 0; 160dc707122SEaswaran Raman for (size_t I = 0; I < NumRegions; ++I) { 161dc707122SEaswaran Raman Counter C; 162dc707122SEaswaran Raman CounterMappingRegion::RegionKind Kind = CounterMappingRegion::CodeRegion; 163dc707122SEaswaran Raman 164dc707122SEaswaran Raman // Read the combined counter + region kind. 165dc707122SEaswaran Raman uint64_t EncodedCounterAndRegion; 166dc707122SEaswaran Raman if (auto Err = readIntMax(EncodedCounterAndRegion, 167dc707122SEaswaran Raman std::numeric_limits<unsigned>::max())) 168dc707122SEaswaran Raman return Err; 169dc707122SEaswaran Raman unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask; 170dc707122SEaswaran Raman uint64_t ExpandedFileID = 0; 171dc707122SEaswaran Raman if (Tag != Counter::Zero) { 172dc707122SEaswaran Raman if (auto Err = decodeCounter(EncodedCounterAndRegion, C)) 173dc707122SEaswaran Raman return Err; 174dc707122SEaswaran Raman } else { 175dc707122SEaswaran Raman // Is it an expansion region? 176dc707122SEaswaran Raman if (EncodedCounterAndRegion & EncodingExpansionRegionBit) { 177dc707122SEaswaran Raman Kind = CounterMappingRegion::ExpansionRegion; 178dc707122SEaswaran Raman ExpandedFileID = EncodedCounterAndRegion >> 179dc707122SEaswaran Raman Counter::EncodingCounterTagAndExpansionRegionTagBits; 180dc707122SEaswaran Raman if (ExpandedFileID >= NumFileIDs) 1819152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 182dc707122SEaswaran Raman } else { 183dc707122SEaswaran Raman switch (EncodedCounterAndRegion >> 184dc707122SEaswaran Raman Counter::EncodingCounterTagAndExpansionRegionTagBits) { 185dc707122SEaswaran Raman case CounterMappingRegion::CodeRegion: 186dc707122SEaswaran Raman // Don't do anything when we have a code region with a zero counter. 187dc707122SEaswaran Raman break; 188dc707122SEaswaran Raman case CounterMappingRegion::SkippedRegion: 189dc707122SEaswaran Raman Kind = CounterMappingRegion::SkippedRegion; 190dc707122SEaswaran Raman break; 191dc707122SEaswaran Raman default: 1929152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 193dc707122SEaswaran Raman } 194dc707122SEaswaran Raman } 195dc707122SEaswaran Raman } 196dc707122SEaswaran Raman 197dc707122SEaswaran Raman // Read the source range. 198dc707122SEaswaran Raman uint64_t LineStartDelta, ColumnStart, NumLines, ColumnEnd; 199dc707122SEaswaran Raman if (auto Err = 200dc707122SEaswaran Raman readIntMax(LineStartDelta, std::numeric_limits<unsigned>::max())) 201dc707122SEaswaran Raman return Err; 202dc707122SEaswaran Raman if (auto Err = readULEB128(ColumnStart)) 203dc707122SEaswaran Raman return Err; 204dc707122SEaswaran Raman if (ColumnStart > std::numeric_limits<unsigned>::max()) 2059152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 206dc707122SEaswaran Raman if (auto Err = readIntMax(NumLines, std::numeric_limits<unsigned>::max())) 207dc707122SEaswaran Raman return Err; 208dc707122SEaswaran Raman if (auto Err = readIntMax(ColumnEnd, std::numeric_limits<unsigned>::max())) 209dc707122SEaswaran Raman return Err; 210dc707122SEaswaran Raman LineStart += LineStartDelta; 211ad8f637bSVedant Kumar 212ad8f637bSVedant Kumar // If the high bit of ColumnEnd is set, this is a gap region. 213ad8f637bSVedant Kumar if (ColumnEnd & (1U << 31)) { 214ad8f637bSVedant Kumar Kind = CounterMappingRegion::GapRegion; 215ad8f637bSVedant Kumar ColumnEnd &= ~(1U << 31); 216ad8f637bSVedant Kumar } 217ad8f637bSVedant Kumar 218dc707122SEaswaran Raman // Adjust the column locations for the empty regions that are supposed to 219dc707122SEaswaran Raman // cover whole lines. Those regions should be encoded with the 220dc707122SEaswaran Raman // column range (1 -> std::numeric_limits<unsigned>::max()), but because 221dc707122SEaswaran Raman // the encoded std::numeric_limits<unsigned>::max() is several bytes long, 222dc707122SEaswaran Raman // we set the column range to (0 -> 0) to ensure that the column start and 223dc707122SEaswaran Raman // column end take up one byte each. 224dc707122SEaswaran Raman // The std::numeric_limits<unsigned>::max() is used to represent a column 225dc707122SEaswaran Raman // position at the end of the line without knowing the length of that line. 226dc707122SEaswaran Raman if (ColumnStart == 0 && ColumnEnd == 0) { 227dc707122SEaswaran Raman ColumnStart = 1; 228dc707122SEaswaran Raman ColumnEnd = std::numeric_limits<unsigned>::max(); 229dc707122SEaswaran Raman } 230dc707122SEaswaran Raman 231d34e60caSNicola Zaghen LLVM_DEBUG({ 232dc707122SEaswaran Raman dbgs() << "Counter in file " << InferredFileID << " " << LineStart << ":" 233dc707122SEaswaran Raman << ColumnStart << " -> " << (LineStart + NumLines) << ":" 234dc707122SEaswaran Raman << ColumnEnd << ", "; 235dc707122SEaswaran Raman if (Kind == CounterMappingRegion::ExpansionRegion) 236dc707122SEaswaran Raman dbgs() << "Expands to file " << ExpandedFileID; 237dc707122SEaswaran Raman else 238dc707122SEaswaran Raman CounterMappingContext(Expressions).dump(C, dbgs()); 239dc707122SEaswaran Raman dbgs() << "\n"; 240dc707122SEaswaran Raman }); 241dc707122SEaswaran Raman 242bae83970SVedant Kumar auto CMR = CounterMappingRegion(C, InferredFileID, ExpandedFileID, 243bae83970SVedant Kumar LineStart, ColumnStart, 244bae83970SVedant Kumar LineStart + NumLines, ColumnEnd, Kind); 245bae83970SVedant Kumar if (CMR.startLoc() > CMR.endLoc()) 246bae83970SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 247bae83970SVedant Kumar MappingRegions.push_back(CMR); 248dc707122SEaswaran Raman } 2499152fd17SVedant Kumar return Error::success(); 250dc707122SEaswaran Raman } 251dc707122SEaswaran Raman 2529152fd17SVedant Kumar Error RawCoverageMappingReader::read() { 253dc707122SEaswaran Raman // Read the virtual file mapping. 254e78d131aSEugene Zelenko SmallVector<unsigned, 8> VirtualFileMapping; 255dc707122SEaswaran Raman uint64_t NumFileMappings; 256dc707122SEaswaran Raman if (auto Err = readSize(NumFileMappings)) 257dc707122SEaswaran Raman return Err; 258dc707122SEaswaran Raman for (size_t I = 0; I < NumFileMappings; ++I) { 259dc707122SEaswaran Raman uint64_t FilenameIndex; 260dc707122SEaswaran Raman if (auto Err = readIntMax(FilenameIndex, TranslationUnitFilenames.size())) 261dc707122SEaswaran Raman return Err; 262dc707122SEaswaran Raman VirtualFileMapping.push_back(FilenameIndex); 263dc707122SEaswaran Raman } 264dc707122SEaswaran Raman 265dc707122SEaswaran Raman // Construct the files using unique filenames and virtual file mapping. 266dc707122SEaswaran Raman for (auto I : VirtualFileMapping) { 267dc707122SEaswaran Raman Filenames.push_back(TranslationUnitFilenames[I]); 268dc707122SEaswaran Raman } 269dc707122SEaswaran Raman 270dc707122SEaswaran Raman // Read the expressions. 271dc707122SEaswaran Raman uint64_t NumExpressions; 272dc707122SEaswaran Raman if (auto Err = readSize(NumExpressions)) 273dc707122SEaswaran Raman return Err; 274dc707122SEaswaran Raman // Create an array of dummy expressions that get the proper counters 275dc707122SEaswaran Raman // when the expressions are read, and the proper kinds when the counters 276dc707122SEaswaran Raman // are decoded. 277dc707122SEaswaran Raman Expressions.resize( 278dc707122SEaswaran Raman NumExpressions, 279dc707122SEaswaran Raman CounterExpression(CounterExpression::Subtract, Counter(), Counter())); 280dc707122SEaswaran Raman for (size_t I = 0; I < NumExpressions; ++I) { 281dc707122SEaswaran Raman if (auto Err = readCounter(Expressions[I].LHS)) 282dc707122SEaswaran Raman return Err; 283dc707122SEaswaran Raman if (auto Err = readCounter(Expressions[I].RHS)) 284dc707122SEaswaran Raman return Err; 285dc707122SEaswaran Raman } 286dc707122SEaswaran Raman 287dc707122SEaswaran Raman // Read the mapping regions sub-arrays. 288dc707122SEaswaran Raman for (unsigned InferredFileID = 0, S = VirtualFileMapping.size(); 289dc707122SEaswaran Raman InferredFileID < S; ++InferredFileID) { 290dc707122SEaswaran Raman if (auto Err = readMappingRegionsSubArray(MappingRegions, InferredFileID, 291dc707122SEaswaran Raman VirtualFileMapping.size())) 292dc707122SEaswaran Raman return Err; 293dc707122SEaswaran Raman } 294dc707122SEaswaran Raman 295dc707122SEaswaran Raman // Set the counters for the expansion regions. 296dc707122SEaswaran Raman // i.e. Counter of expansion region = counter of the first region 297dc707122SEaswaran Raman // from the expanded file. 298dc707122SEaswaran Raman // Perform multiple passes to correctly propagate the counters through 299dc707122SEaswaran Raman // all the nested expansion regions. 300dc707122SEaswaran Raman SmallVector<CounterMappingRegion *, 8> FileIDExpansionRegionMapping; 301dc707122SEaswaran Raman FileIDExpansionRegionMapping.resize(VirtualFileMapping.size(), nullptr); 302dc707122SEaswaran Raman for (unsigned Pass = 1, S = VirtualFileMapping.size(); Pass < S; ++Pass) { 303dc707122SEaswaran Raman for (auto &R : MappingRegions) { 304dc707122SEaswaran Raman if (R.Kind != CounterMappingRegion::ExpansionRegion) 305dc707122SEaswaran Raman continue; 306dc707122SEaswaran Raman assert(!FileIDExpansionRegionMapping[R.ExpandedFileID]); 307dc707122SEaswaran Raman FileIDExpansionRegionMapping[R.ExpandedFileID] = &R; 308dc707122SEaswaran Raman } 309dc707122SEaswaran Raman for (auto &R : MappingRegions) { 310dc707122SEaswaran Raman if (FileIDExpansionRegionMapping[R.FileID]) { 311dc707122SEaswaran Raman FileIDExpansionRegionMapping[R.FileID]->Count = R.Count; 312dc707122SEaswaran Raman FileIDExpansionRegionMapping[R.FileID] = nullptr; 313dc707122SEaswaran Raman } 314dc707122SEaswaran Raman } 315dc707122SEaswaran Raman } 316dc707122SEaswaran Raman 3179152fd17SVedant Kumar return Error::success(); 318dc707122SEaswaran Raman } 319dc707122SEaswaran Raman 320ac40e819SIgor Kudrin Expected<bool> RawCoverageMappingDummyChecker::isDummy() { 321ac40e819SIgor Kudrin // A dummy coverage mapping data consists of just one region with zero count. 322ac40e819SIgor Kudrin uint64_t NumFileMappings; 323ac40e819SIgor Kudrin if (Error Err = readSize(NumFileMappings)) 324ac40e819SIgor Kudrin return std::move(Err); 325ac40e819SIgor Kudrin if (NumFileMappings != 1) 326ac40e819SIgor Kudrin return false; 327ac40e819SIgor Kudrin // We don't expect any specific value for the filename index, just skip it. 328ac40e819SIgor Kudrin uint64_t FilenameIndex; 329ac40e819SIgor Kudrin if (Error Err = 330ac40e819SIgor Kudrin readIntMax(FilenameIndex, std::numeric_limits<unsigned>::max())) 331ac40e819SIgor Kudrin return std::move(Err); 332ac40e819SIgor Kudrin uint64_t NumExpressions; 333ac40e819SIgor Kudrin if (Error Err = readSize(NumExpressions)) 334ac40e819SIgor Kudrin return std::move(Err); 335ac40e819SIgor Kudrin if (NumExpressions != 0) 336ac40e819SIgor Kudrin return false; 337ac40e819SIgor Kudrin uint64_t NumRegions; 338ac40e819SIgor Kudrin if (Error Err = readSize(NumRegions)) 339ac40e819SIgor Kudrin return std::move(Err); 340ac40e819SIgor Kudrin if (NumRegions != 1) 341ac40e819SIgor Kudrin return false; 342ac40e819SIgor Kudrin uint64_t EncodedCounterAndRegion; 343ac40e819SIgor Kudrin if (Error Err = readIntMax(EncodedCounterAndRegion, 344ac40e819SIgor Kudrin std::numeric_limits<unsigned>::max())) 345ac40e819SIgor Kudrin return std::move(Err); 346ac40e819SIgor Kudrin unsigned Tag = EncodedCounterAndRegion & Counter::EncodingTagMask; 347ac40e819SIgor Kudrin return Tag == Counter::Zero; 348ac40e819SIgor Kudrin } 349ac40e819SIgor Kudrin 3509152fd17SVedant Kumar Error InstrProfSymtab::create(SectionRef &Section) { 351e183340cSFangrui Song Expected<StringRef> DataOrErr = Section.getContents(); 352e183340cSFangrui Song if (!DataOrErr) 353e183340cSFangrui Song return DataOrErr.takeError(); 354e183340cSFangrui Song Data = *DataOrErr; 355dc707122SEaswaran Raman Address = Section.getAddress(); 3568b6af001SReid Kleckner 3578b6af001SReid Kleckner // If this is a linked PE/COFF file, then we have to skip over the null byte 3588b6af001SReid Kleckner // that is allocated in the .lprfn$A section in the LLVM profiling runtime. 3598b6af001SReid Kleckner const ObjectFile *Obj = Section.getObject(); 3608b6af001SReid Kleckner if (isa<COFFObjectFile>(Obj) && !Obj->isRelocatableObject()) 3618b6af001SReid Kleckner Data = Data.drop_front(1); 3628b6af001SReid Kleckner 3639152fd17SVedant Kumar return Error::success(); 364dc707122SEaswaran Raman } 365dc707122SEaswaran Raman 366dc707122SEaswaran Raman StringRef InstrProfSymtab::getFuncName(uint64_t Pointer, size_t Size) { 367dc707122SEaswaran Raman if (Pointer < Address) 368dc707122SEaswaran Raman return StringRef(); 369dc707122SEaswaran Raman auto Offset = Pointer - Address; 370dc707122SEaswaran Raman if (Offset + Size > Data.size()) 371dc707122SEaswaran Raman return StringRef(); 372dc707122SEaswaran Raman return Data.substr(Pointer - Address, Size); 373dc707122SEaswaran Raman } 374dc707122SEaswaran Raman 375ac40e819SIgor Kudrin // Check if the mapping data is a dummy, i.e. is emitted for an unused function. 376ac40e819SIgor Kudrin static Expected<bool> isCoverageMappingDummy(uint64_t Hash, StringRef Mapping) { 377ac40e819SIgor Kudrin // The hash value of dummy mapping records is always zero. 378ac40e819SIgor Kudrin if (Hash) 379ac40e819SIgor Kudrin return false; 380ac40e819SIgor Kudrin return RawCoverageMappingDummyChecker(Mapping).isDummy(); 381ac40e819SIgor Kudrin } 382ac40e819SIgor Kudrin 383dc707122SEaswaran Raman namespace { 384e78d131aSEugene Zelenko 385dc707122SEaswaran Raman struct CovMapFuncRecordReader { 386e78d131aSEugene Zelenko virtual ~CovMapFuncRecordReader() = default; 387e78d131aSEugene Zelenko 3883739b95dSVedant Kumar // The interface to read coverage mapping function records for a module. 3893739b95dSVedant Kumar // 3903739b95dSVedant Kumar // \p Buf points to the buffer containing the \c CovHeader of the coverage 3913739b95dSVedant Kumar // mapping data associated with the module. 3923739b95dSVedant Kumar // 3933739b95dSVedant Kumar // Returns a pointer to the next \c CovHeader if it exists, or a pointer 3943739b95dSVedant Kumar // greater than \p End if not. 3953739b95dSVedant Kumar virtual Expected<const char *> readFunctionRecords(const char *Buf, 3963739b95dSVedant Kumar const char *End) = 0; 397e78d131aSEugene Zelenko 398dc707122SEaswaran Raman template <class IntPtrT, support::endianness Endian> 3999152fd17SVedant Kumar static Expected<std::unique_ptr<CovMapFuncRecordReader>> 400e78d131aSEugene Zelenko get(CovMapVersion Version, InstrProfSymtab &P, 401dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, 402dc707122SEaswaran Raman std::vector<StringRef> &F); 403dc707122SEaswaran Raman }; 404dc707122SEaswaran Raman 405dc707122SEaswaran Raman // A class for reading coverage mapping function records for a module. 406e78d131aSEugene Zelenko template <CovMapVersion Version, class IntPtrT, support::endianness Endian> 407dc707122SEaswaran Raman class VersionedCovMapFuncRecordReader : public CovMapFuncRecordReader { 40872208a82SEugene Zelenko using FuncRecordType = 40972208a82SEugene Zelenko typename CovMapTraits<Version, IntPtrT>::CovMapFuncRecordType; 41072208a82SEugene Zelenko using NameRefType = typename CovMapTraits<Version, IntPtrT>::NameRefType; 411dc707122SEaswaran Raman 412ac40e819SIgor Kudrin // Maps function's name references to the indexes of their records 413ac40e819SIgor Kudrin // in \c Records. 414e78d131aSEugene Zelenko DenseMap<NameRefType, size_t> FunctionRecords; 415dc707122SEaswaran Raman InstrProfSymtab &ProfileNames; 416dc707122SEaswaran Raman std::vector<StringRef> &Filenames; 417dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records; 418dc707122SEaswaran Raman 419ac40e819SIgor Kudrin // Add the record to the collection if we don't already have a record that 420ac40e819SIgor Kudrin // points to the same function name. This is useful to ignore the redundant 421ac40e819SIgor Kudrin // records for the functions with ODR linkage. 422ac40e819SIgor Kudrin // In addition, prefer records with real coverage mapping data to dummy 423ac40e819SIgor Kudrin // records, which were emitted for inline functions which were seen but 424ac40e819SIgor Kudrin // not used in the corresponding translation unit. 425ac40e819SIgor Kudrin Error insertFunctionRecordIfNeeded(const FuncRecordType *CFR, 426ac40e819SIgor Kudrin StringRef Mapping, size_t FilenamesBegin) { 427ac40e819SIgor Kudrin uint64_t FuncHash = CFR->template getFuncHash<Endian>(); 428ac40e819SIgor Kudrin NameRefType NameRef = CFR->template getFuncNameRef<Endian>(); 429ac40e819SIgor Kudrin auto InsertResult = 430ac40e819SIgor Kudrin FunctionRecords.insert(std::make_pair(NameRef, Records.size())); 431ac40e819SIgor Kudrin if (InsertResult.second) { 432ac40e819SIgor Kudrin StringRef FuncName; 433ac40e819SIgor Kudrin if (Error Err = CFR->template getFuncName<Endian>(ProfileNames, FuncName)) 434ac40e819SIgor Kudrin return Err; 435b5794ca9SVedant Kumar if (FuncName.empty()) 436b5794ca9SVedant Kumar return make_error<InstrProfError>(instrprof_error::malformed); 437ac40e819SIgor Kudrin Records.emplace_back(Version, FuncName, FuncHash, Mapping, FilenamesBegin, 438ac40e819SIgor Kudrin Filenames.size() - FilenamesBegin); 439ac40e819SIgor Kudrin return Error::success(); 440ac40e819SIgor Kudrin } 441ac40e819SIgor Kudrin // Update the existing record if it's a dummy and the new record is real. 442ac40e819SIgor Kudrin size_t OldRecordIndex = InsertResult.first->second; 443ac40e819SIgor Kudrin BinaryCoverageReader::ProfileMappingRecord &OldRecord = 444ac40e819SIgor Kudrin Records[OldRecordIndex]; 445ac40e819SIgor Kudrin Expected<bool> OldIsDummyExpected = isCoverageMappingDummy( 446ac40e819SIgor Kudrin OldRecord.FunctionHash, OldRecord.CoverageMapping); 447ac40e819SIgor Kudrin if (Error Err = OldIsDummyExpected.takeError()) 448ac40e819SIgor Kudrin return Err; 449ac40e819SIgor Kudrin if (!*OldIsDummyExpected) 450ac40e819SIgor Kudrin return Error::success(); 451ac40e819SIgor Kudrin Expected<bool> NewIsDummyExpected = 452ac40e819SIgor Kudrin isCoverageMappingDummy(FuncHash, Mapping); 453ac40e819SIgor Kudrin if (Error Err = NewIsDummyExpected.takeError()) 454ac40e819SIgor Kudrin return Err; 455ac40e819SIgor Kudrin if (*NewIsDummyExpected) 456ac40e819SIgor Kudrin return Error::success(); 457ac40e819SIgor Kudrin OldRecord.FunctionHash = FuncHash; 458ac40e819SIgor Kudrin OldRecord.CoverageMapping = Mapping; 459ac40e819SIgor Kudrin OldRecord.FilenamesBegin = FilenamesBegin; 460ac40e819SIgor Kudrin OldRecord.FilenamesSize = Filenames.size() - FilenamesBegin; 461ac40e819SIgor Kudrin return Error::success(); 462ac40e819SIgor Kudrin } 463ac40e819SIgor Kudrin 464dc707122SEaswaran Raman public: 465dc707122SEaswaran Raman VersionedCovMapFuncRecordReader( 466dc707122SEaswaran Raman InstrProfSymtab &P, 467dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, 468dc707122SEaswaran Raman std::vector<StringRef> &F) 469dc707122SEaswaran Raman : ProfileNames(P), Filenames(F), Records(R) {} 470e78d131aSEugene Zelenko 471e78d131aSEugene Zelenko ~VersionedCovMapFuncRecordReader() override = default; 472dc707122SEaswaran Raman 4733739b95dSVedant Kumar Expected<const char *> readFunctionRecords(const char *Buf, 4743739b95dSVedant Kumar const char *End) override { 475dc707122SEaswaran Raman using namespace support; 476e78d131aSEugene Zelenko 477dc707122SEaswaran Raman if (Buf + sizeof(CovMapHeader) > End) 4789152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 479e78d131aSEugene Zelenko auto CovHeader = reinterpret_cast<const CovMapHeader *>(Buf); 480dc707122SEaswaran Raman uint32_t NRecords = CovHeader->getNRecords<Endian>(); 481dc707122SEaswaran Raman uint32_t FilenamesSize = CovHeader->getFilenamesSize<Endian>(); 482dc707122SEaswaran Raman uint32_t CoverageSize = CovHeader->getCoverageSize<Endian>(); 483dc707122SEaswaran Raman assert((CovMapVersion)CovHeader->getVersion<Endian>() == Version); 484dc707122SEaswaran Raman Buf = reinterpret_cast<const char *>(CovHeader + 1); 485dc707122SEaswaran Raman 486dc707122SEaswaran Raman // Skip past the function records, saving the start and end for later. 487dc707122SEaswaran Raman const char *FunBuf = Buf; 488dc707122SEaswaran Raman Buf += NRecords * sizeof(FuncRecordType); 489dc707122SEaswaran Raman const char *FunEnd = Buf; 490dc707122SEaswaran Raman 491dc707122SEaswaran Raman // Get the filenames. 492dc707122SEaswaran Raman if (Buf + FilenamesSize > End) 4939152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 494dc707122SEaswaran Raman size_t FilenamesBegin = Filenames.size(); 495dc707122SEaswaran Raman RawCoverageFilenamesReader Reader(StringRef(Buf, FilenamesSize), Filenames); 496dc707122SEaswaran Raman if (auto Err = Reader.read()) 4973739b95dSVedant Kumar return std::move(Err); 498dc707122SEaswaran Raman Buf += FilenamesSize; 499dc707122SEaswaran Raman 500dc707122SEaswaran Raman // We'll read the coverage mapping records in the loop below. 501dc707122SEaswaran Raman const char *CovBuf = Buf; 502dc707122SEaswaran Raman Buf += CoverageSize; 503dc707122SEaswaran Raman const char *CovEnd = Buf; 504dc707122SEaswaran Raman 505dc707122SEaswaran Raman if (Buf > End) 5069152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 507dc707122SEaswaran Raman // Each coverage map has an alignment of 8, so we need to adjust alignment 508dc707122SEaswaran Raman // before reading the next map. 509dc707122SEaswaran Raman Buf += alignmentAdjustment(Buf, 8); 510dc707122SEaswaran Raman 511dc707122SEaswaran Raman auto CFR = reinterpret_cast<const FuncRecordType *>(FunBuf); 512dc707122SEaswaran Raman while ((const char *)CFR < FunEnd) { 513dc707122SEaswaran Raman // Read the function information 514dc707122SEaswaran Raman uint32_t DataSize = CFR->template getDataSize<Endian>(); 515dc707122SEaswaran Raman 516dc707122SEaswaran Raman // Now use that to read the coverage data. 517dc707122SEaswaran Raman if (CovBuf + DataSize > CovEnd) 5189152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 519dc707122SEaswaran Raman auto Mapping = StringRef(CovBuf, DataSize); 520dc707122SEaswaran Raman CovBuf += DataSize; 521dc707122SEaswaran Raman 522ac40e819SIgor Kudrin if (Error Err = 523ac40e819SIgor Kudrin insertFunctionRecordIfNeeded(CFR, Mapping, FilenamesBegin)) 5243739b95dSVedant Kumar return std::move(Err); 525dc707122SEaswaran Raman CFR++; 526dc707122SEaswaran Raman } 5273739b95dSVedant Kumar return Buf; 528dc707122SEaswaran Raman } 529dc707122SEaswaran Raman }; 530e78d131aSEugene Zelenko 531dc707122SEaswaran Raman } // end anonymous namespace 532dc707122SEaswaran Raman 533dc707122SEaswaran Raman template <class IntPtrT, support::endianness Endian> 5349152fd17SVedant Kumar Expected<std::unique_ptr<CovMapFuncRecordReader>> CovMapFuncRecordReader::get( 535e78d131aSEugene Zelenko CovMapVersion Version, InstrProfSymtab &P, 536dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &R, 537dc707122SEaswaran Raman std::vector<StringRef> &F) { 538dc707122SEaswaran Raman using namespace coverage; 539e78d131aSEugene Zelenko 540dc707122SEaswaran Raman switch (Version) { 541dc707122SEaswaran Raman case CovMapVersion::Version1: 542*0eaee545SJonas Devlieghere return std::make_unique<VersionedCovMapFuncRecordReader< 543dc707122SEaswaran Raman CovMapVersion::Version1, IntPtrT, Endian>>(P, R, F); 544dc707122SEaswaran Raman case CovMapVersion::Version2: 545ad8f637bSVedant Kumar case CovMapVersion::Version3: 546dc707122SEaswaran Raman // Decompress the name data. 5479152fd17SVedant Kumar if (Error E = P.create(P.getNameData())) 5489152fd17SVedant Kumar return std::move(E); 549ad8f637bSVedant Kumar if (Version == CovMapVersion::Version2) 550*0eaee545SJonas Devlieghere return std::make_unique<VersionedCovMapFuncRecordReader< 551dc707122SEaswaran Raman CovMapVersion::Version2, IntPtrT, Endian>>(P, R, F); 552ad8f637bSVedant Kumar else 553*0eaee545SJonas Devlieghere return std::make_unique<VersionedCovMapFuncRecordReader< 554ad8f637bSVedant Kumar CovMapVersion::Version3, IntPtrT, Endian>>(P, R, F); 555dc707122SEaswaran Raman } 556dc707122SEaswaran Raman llvm_unreachable("Unsupported version"); 557dc707122SEaswaran Raman } 558dc707122SEaswaran Raman 559dc707122SEaswaran Raman template <typename T, support::endianness Endian> 5609152fd17SVedant Kumar static Error readCoverageMappingData( 561dc707122SEaswaran Raman InstrProfSymtab &ProfileNames, StringRef Data, 562dc707122SEaswaran Raman std::vector<BinaryCoverageReader::ProfileMappingRecord> &Records, 563dc707122SEaswaran Raman std::vector<StringRef> &Filenames) { 564dc707122SEaswaran Raman using namespace coverage; 565e78d131aSEugene Zelenko 566dc707122SEaswaran Raman // Read the records in the coverage data section. 567dc707122SEaswaran Raman auto CovHeader = 568e78d131aSEugene Zelenko reinterpret_cast<const CovMapHeader *>(Data.data()); 569dc707122SEaswaran Raman CovMapVersion Version = (CovMapVersion)CovHeader->getVersion<Endian>(); 570e78d131aSEugene Zelenko if (Version > CovMapVersion::CurrentVersion) 5719152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::unsupported_version); 5729152fd17SVedant Kumar Expected<std::unique_ptr<CovMapFuncRecordReader>> ReaderExpected = 573dc707122SEaswaran Raman CovMapFuncRecordReader::get<T, Endian>(Version, ProfileNames, Records, 574dc707122SEaswaran Raman Filenames); 5759152fd17SVedant Kumar if (Error E = ReaderExpected.takeError()) 5769152fd17SVedant Kumar return E; 5779152fd17SVedant Kumar auto Reader = std::move(ReaderExpected.get()); 578dc707122SEaswaran Raman for (const char *Buf = Data.data(), *End = Buf + Data.size(); Buf < End;) { 5793739b95dSVedant Kumar auto NextHeaderOrErr = Reader->readFunctionRecords(Buf, End); 5803739b95dSVedant Kumar if (auto E = NextHeaderOrErr.takeError()) 5819152fd17SVedant Kumar return E; 5823739b95dSVedant Kumar Buf = NextHeaderOrErr.get(); 583dc707122SEaswaran Raman } 5849152fd17SVedant Kumar return Error::success(); 585dc707122SEaswaran Raman } 586e78d131aSEugene Zelenko 587dc707122SEaswaran Raman static const char *TestingFormatMagic = "llvmcovmtestdata"; 588dc707122SEaswaran Raman 589901d04fcSVedant Kumar Expected<std::unique_ptr<BinaryCoverageReader>> 590901d04fcSVedant Kumar BinaryCoverageReader::createCoverageReaderFromBuffer( 591901d04fcSVedant Kumar StringRef Coverage, InstrProfSymtab &&ProfileNames, uint8_t BytesInAddress, 592901d04fcSVedant Kumar support::endianness Endian) { 593901d04fcSVedant Kumar std::unique_ptr<BinaryCoverageReader> Reader(new BinaryCoverageReader()); 594901d04fcSVedant Kumar Reader->ProfileNames = std::move(ProfileNames); 595901d04fcSVedant Kumar if (BytesInAddress == 4 && Endian == support::endianness::little) { 596901d04fcSVedant Kumar if (Error E = 597901d04fcSVedant Kumar readCoverageMappingData<uint32_t, support::endianness::little>( 598901d04fcSVedant Kumar Reader->ProfileNames, Coverage, Reader->MappingRecords, 599901d04fcSVedant Kumar Reader->Filenames)) 600901d04fcSVedant Kumar return std::move(E); 601901d04fcSVedant Kumar } else if (BytesInAddress == 4 && Endian == support::endianness::big) { 602901d04fcSVedant Kumar if (Error E = readCoverageMappingData<uint32_t, support::endianness::big>( 603901d04fcSVedant Kumar Reader->ProfileNames, Coverage, Reader->MappingRecords, 604901d04fcSVedant Kumar Reader->Filenames)) 605901d04fcSVedant Kumar return std::move(E); 606901d04fcSVedant Kumar } else if (BytesInAddress == 8 && Endian == support::endianness::little) { 607901d04fcSVedant Kumar if (Error E = 608901d04fcSVedant Kumar readCoverageMappingData<uint64_t, support::endianness::little>( 609901d04fcSVedant Kumar Reader->ProfileNames, Coverage, Reader->MappingRecords, 610901d04fcSVedant Kumar Reader->Filenames)) 611901d04fcSVedant Kumar return std::move(E); 612901d04fcSVedant Kumar } else if (BytesInAddress == 8 && Endian == support::endianness::big) { 613901d04fcSVedant Kumar if (Error E = readCoverageMappingData<uint64_t, support::endianness::big>( 614901d04fcSVedant Kumar Reader->ProfileNames, Coverage, Reader->MappingRecords, 615901d04fcSVedant Kumar Reader->Filenames)) 616901d04fcSVedant Kumar return std::move(E); 617901d04fcSVedant Kumar } else 618901d04fcSVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 6191e4882c8SVedant Kumar return std::move(Reader); 620901d04fcSVedant Kumar } 621901d04fcSVedant Kumar 622901d04fcSVedant Kumar static Expected<std::unique_ptr<BinaryCoverageReader>> 623901d04fcSVedant Kumar loadTestingFormat(StringRef Data) { 624901d04fcSVedant Kumar uint8_t BytesInAddress = 8; 625901d04fcSVedant Kumar support::endianness Endian = support::endianness::little; 626dc707122SEaswaran Raman 627dc707122SEaswaran Raman Data = Data.substr(StringRef(TestingFormatMagic).size()); 62872208a82SEugene Zelenko if (Data.empty()) 6299152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::truncated); 630dc707122SEaswaran Raman unsigned N = 0; 6316a0746a9SFangrui Song uint64_t ProfileNamesSize = decodeULEB128(Data.bytes_begin(), &N); 632dc707122SEaswaran Raman if (N > Data.size()) 6339152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 634dc707122SEaswaran Raman Data = Data.substr(N); 63572208a82SEugene Zelenko if (Data.empty()) 6369152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::truncated); 637dc707122SEaswaran Raman N = 0; 6386a0746a9SFangrui Song uint64_t Address = decodeULEB128(Data.bytes_begin(), &N); 639dc707122SEaswaran Raman if (N > Data.size()) 6409152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 641dc707122SEaswaran Raman Data = Data.substr(N); 642dc707122SEaswaran Raman if (Data.size() < ProfileNamesSize) 6439152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 644901d04fcSVedant Kumar InstrProfSymtab ProfileNames; 6459152fd17SVedant Kumar if (Error E = ProfileNames.create(Data.substr(0, ProfileNamesSize), Address)) 646901d04fcSVedant Kumar return std::move(E); 647901d04fcSVedant Kumar StringRef CoverageMapping = Data.substr(ProfileNamesSize); 648eb103073SIgor Kudrin // Skip the padding bytes because coverage map data has an alignment of 8. 64972208a82SEugene Zelenko if (CoverageMapping.empty()) 6509152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::truncated); 651eb103073SIgor Kudrin size_t Pad = alignmentAdjustment(CoverageMapping.data(), 8); 652eb103073SIgor Kudrin if (CoverageMapping.size() < Pad) 6539152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 654eb103073SIgor Kudrin CoverageMapping = CoverageMapping.substr(Pad); 655901d04fcSVedant Kumar return BinaryCoverageReader::createCoverageReaderFromBuffer( 656901d04fcSVedant Kumar CoverageMapping, std::move(ProfileNames), BytesInAddress, Endian); 657dc707122SEaswaran Raman } 658dc707122SEaswaran Raman 6599152fd17SVedant Kumar static Expected<SectionRef> lookupSection(ObjectFile &OF, StringRef Name) { 6608b6af001SReid Kleckner // On COFF, the object file section name may end in "$M". This tells the 6618b6af001SReid Kleckner // linker to sort these sections between "$A" and "$Z". The linker removes the 6628b6af001SReid Kleckner // dollar and everything after it in the final binary. Do the same to match. 6638b6af001SReid Kleckner bool IsCOFF = isa<COFFObjectFile>(OF); 6648b6af001SReid Kleckner auto stripSuffix = [IsCOFF](StringRef N) { 6658b6af001SReid Kleckner return IsCOFF ? N.split('$').first : N; 6668b6af001SReid Kleckner }; 6678b6af001SReid Kleckner Name = stripSuffix(Name); 6688b6af001SReid Kleckner 669dc707122SEaswaran Raman for (const auto &Section : OF.sections()) { 670bcc00e1aSGeorge Rimar Expected<StringRef> NameOrErr = Section.getName(); 671bcc00e1aSGeorge Rimar if (!NameOrErr) 672bcc00e1aSGeorge Rimar return NameOrErr.takeError(); 673bcc00e1aSGeorge Rimar if (stripSuffix(*NameOrErr) == Name) 674dc707122SEaswaran Raman return Section; 675dc707122SEaswaran Raman } 6769152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::no_data_found); 677dc707122SEaswaran Raman } 678dc707122SEaswaran Raman 679901d04fcSVedant Kumar static Expected<std::unique_ptr<BinaryCoverageReader>> 680901d04fcSVedant Kumar loadBinaryFormat(std::unique_ptr<Binary> Bin, StringRef Arch) { 681dc707122SEaswaran Raman std::unique_ptr<ObjectFile> OF; 682e78d131aSEugene Zelenko if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { 683dc707122SEaswaran Raman // If we have a universal binary, try to look up the object for the 684dc707122SEaswaran Raman // appropriate architecture. 685dc707122SEaswaran Raman auto ObjectFileOrErr = Universal->getObjectForArch(Arch); 6869acb1099SKevin Enderby if (!ObjectFileOrErr) 6879acb1099SKevin Enderby return ObjectFileOrErr.takeError(); 688dc707122SEaswaran Raman OF = std::move(ObjectFileOrErr.get()); 689e78d131aSEugene Zelenko } else if (isa<ObjectFile>(Bin.get())) { 690dc707122SEaswaran Raman // For any other object file, upcast and take ownership. 691e78d131aSEugene Zelenko OF.reset(cast<ObjectFile>(Bin.release())); 692dc707122SEaswaran Raman // If we've asked for a particular arch, make sure they match. 693dc707122SEaswaran Raman if (!Arch.empty() && OF->getArch() != Triple(Arch).getArch()) 6949152fd17SVedant Kumar return errorCodeToError(object_error::arch_not_found); 695dc707122SEaswaran Raman } else 696dc707122SEaswaran Raman // We can only handle object files. 6979152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::malformed); 698dc707122SEaswaran Raman 699dc707122SEaswaran Raman // The coverage uses native pointer sizes for the object it's written in. 700901d04fcSVedant Kumar uint8_t BytesInAddress = OF->getBytesInAddress(); 701901d04fcSVedant Kumar support::endianness Endian = OF->isLittleEndian() 702901d04fcSVedant Kumar ? support::endianness::little 703dc707122SEaswaran Raman : support::endianness::big; 704dc707122SEaswaran Raman 705dc707122SEaswaran Raman // Look for the sections that we are interested in. 7061a6a2b64SVedant Kumar auto ObjFormat = OF->getTripleObjectFormat(); 7074a5ddf80SXinliang David Li auto NamesSection = 7081a6a2b64SVedant Kumar lookupSection(*OF, getInstrProfSectionName(IPSK_name, ObjFormat, 7091a6a2b64SVedant Kumar /*AddSegmentInfo=*/false)); 7109152fd17SVedant Kumar if (auto E = NamesSection.takeError()) 711901d04fcSVedant Kumar return std::move(E); 7124a5ddf80SXinliang David Li auto CoverageSection = 7131a6a2b64SVedant Kumar lookupSection(*OF, getInstrProfSectionName(IPSK_covmap, ObjFormat, 7141a6a2b64SVedant Kumar /*AddSegmentInfo=*/false)); 7159152fd17SVedant Kumar if (auto E = CoverageSection.takeError()) 716901d04fcSVedant Kumar return std::move(E); 717dc707122SEaswaran Raman 718dc707122SEaswaran Raman // Get the contents of the given sections. 719901d04fcSVedant Kumar auto CoverageMappingOrErr = CoverageSection->getContents(); 720901d04fcSVedant Kumar if (!CoverageMappingOrErr) 721901d04fcSVedant Kumar return CoverageMappingOrErr.takeError(); 722e183340cSFangrui Song 723901d04fcSVedant Kumar InstrProfSymtab ProfileNames; 7249152fd17SVedant Kumar if (Error E = ProfileNames.create(*NamesSection)) 725901d04fcSVedant Kumar return std::move(E); 726dc707122SEaswaran Raman 727901d04fcSVedant Kumar return BinaryCoverageReader::createCoverageReaderFromBuffer( 728901d04fcSVedant Kumar CoverageMappingOrErr.get(), std::move(ProfileNames), BytesInAddress, 729901d04fcSVedant Kumar Endian); 730dc707122SEaswaran Raman } 731dc707122SEaswaran Raman 732901d04fcSVedant Kumar Expected<std::vector<std::unique_ptr<BinaryCoverageReader>>> 733901d04fcSVedant Kumar BinaryCoverageReader::create( 734901d04fcSVedant Kumar MemoryBufferRef ObjectBuffer, StringRef Arch, 735901d04fcSVedant Kumar SmallVectorImpl<std::unique_ptr<MemoryBuffer>> &ObjectFileBuffers) { 736901d04fcSVedant Kumar std::vector<std::unique_ptr<BinaryCoverageReader>> Readers; 737dc707122SEaswaran Raman 738901d04fcSVedant Kumar if (ObjectBuffer.getBuffer().startswith(TestingFormatMagic)) { 739dc707122SEaswaran Raman // This is a special format used for testing. 740901d04fcSVedant Kumar auto ReaderOrErr = loadTestingFormat(ObjectBuffer.getBuffer()); 741901d04fcSVedant Kumar if (!ReaderOrErr) 742901d04fcSVedant Kumar return ReaderOrErr.takeError(); 743901d04fcSVedant Kumar Readers.push_back(std::move(ReaderOrErr.get())); 7441e4882c8SVedant Kumar return std::move(Readers); 745901d04fcSVedant Kumar } 746dc707122SEaswaran Raman 747901d04fcSVedant Kumar auto BinOrErr = createBinary(ObjectBuffer); 748901d04fcSVedant Kumar if (!BinOrErr) 749901d04fcSVedant Kumar return BinOrErr.takeError(); 750901d04fcSVedant Kumar std::unique_ptr<Binary> Bin = std::move(BinOrErr.get()); 751901d04fcSVedant Kumar 752901d04fcSVedant Kumar // MachO universal binaries which contain archives need to be treated as 753901d04fcSVedant Kumar // archives, not as regular binaries. 754901d04fcSVedant Kumar if (auto *Universal = dyn_cast<MachOUniversalBinary>(Bin.get())) { 755901d04fcSVedant Kumar for (auto &ObjForArch : Universal->objects()) { 756901d04fcSVedant Kumar // Skip slices within the universal binary which target the wrong arch. 757901d04fcSVedant Kumar std::string ObjArch = ObjForArch.getArchFlagName(); 758901d04fcSVedant Kumar if (Arch != ObjArch) 759901d04fcSVedant Kumar continue; 760901d04fcSVedant Kumar 761901d04fcSVedant Kumar auto ArchiveOrErr = ObjForArch.getAsArchive(); 762901d04fcSVedant Kumar if (!ArchiveOrErr) { 763901d04fcSVedant Kumar // If this is not an archive, try treating it as a regular object. 764901d04fcSVedant Kumar consumeError(ArchiveOrErr.takeError()); 765901d04fcSVedant Kumar break; 766901d04fcSVedant Kumar } 767901d04fcSVedant Kumar 768901d04fcSVedant Kumar return BinaryCoverageReader::create( 769901d04fcSVedant Kumar ArchiveOrErr.get()->getMemoryBufferRef(), Arch, ObjectFileBuffers); 770901d04fcSVedant Kumar } 771901d04fcSVedant Kumar } 772901d04fcSVedant Kumar 773901d04fcSVedant Kumar // Load coverage out of archive members. 774901d04fcSVedant Kumar if (auto *Ar = dyn_cast<Archive>(Bin.get())) { 775901d04fcSVedant Kumar Error Err = Error::success(); 776901d04fcSVedant Kumar for (auto &Child : Ar->children(Err)) { 777901d04fcSVedant Kumar Expected<MemoryBufferRef> ChildBufOrErr = Child.getMemoryBufferRef(); 778901d04fcSVedant Kumar if (!ChildBufOrErr) 779901d04fcSVedant Kumar return ChildBufOrErr.takeError(); 780901d04fcSVedant Kumar 781901d04fcSVedant Kumar auto ChildReadersOrErr = BinaryCoverageReader::create( 782901d04fcSVedant Kumar ChildBufOrErr.get(), Arch, ObjectFileBuffers); 783901d04fcSVedant Kumar if (!ChildReadersOrErr) 784901d04fcSVedant Kumar return ChildReadersOrErr.takeError(); 785901d04fcSVedant Kumar for (auto &Reader : ChildReadersOrErr.get()) 786901d04fcSVedant Kumar Readers.push_back(std::move(Reader)); 787901d04fcSVedant Kumar } 788901d04fcSVedant Kumar if (Err) 789901d04fcSVedant Kumar return std::move(Err); 790901d04fcSVedant Kumar 791901d04fcSVedant Kumar // Thin archives reference object files outside of the archive file, i.e. 792901d04fcSVedant Kumar // files which reside in memory not owned by the caller. Transfer ownership 793901d04fcSVedant Kumar // to the caller. 794901d04fcSVedant Kumar if (Ar->isThin()) 795901d04fcSVedant Kumar for (auto &Buffer : Ar->takeThinBuffers()) 796901d04fcSVedant Kumar ObjectFileBuffers.push_back(std::move(Buffer)); 797901d04fcSVedant Kumar 7981e4882c8SVedant Kumar return std::move(Readers); 799901d04fcSVedant Kumar } 800901d04fcSVedant Kumar 801901d04fcSVedant Kumar auto ReaderOrErr = loadBinaryFormat(std::move(Bin), Arch); 802901d04fcSVedant Kumar if (!ReaderOrErr) 803901d04fcSVedant Kumar return ReaderOrErr.takeError(); 804901d04fcSVedant Kumar Readers.push_back(std::move(ReaderOrErr.get())); 8051e4882c8SVedant Kumar return std::move(Readers); 806dc707122SEaswaran Raman } 807dc707122SEaswaran Raman 8089152fd17SVedant Kumar Error BinaryCoverageReader::readNextRecord(CoverageMappingRecord &Record) { 809dc707122SEaswaran Raman if (CurrentRecord >= MappingRecords.size()) 8109152fd17SVedant Kumar return make_error<CoverageMapError>(coveragemap_error::eof); 811dc707122SEaswaran Raman 812dc707122SEaswaran Raman FunctionsFilenames.clear(); 813dc707122SEaswaran Raman Expressions.clear(); 814dc707122SEaswaran Raman MappingRegions.clear(); 815dc707122SEaswaran Raman auto &R = MappingRecords[CurrentRecord]; 816dc707122SEaswaran Raman RawCoverageMappingReader Reader( 817dc707122SEaswaran Raman R.CoverageMapping, 818dc707122SEaswaran Raman makeArrayRef(Filenames).slice(R.FilenamesBegin, R.FilenamesSize), 819dc707122SEaswaran Raman FunctionsFilenames, Expressions, MappingRegions); 820dc707122SEaswaran Raman if (auto Err = Reader.read()) 821dc707122SEaswaran Raman return Err; 822dc707122SEaswaran Raman 823dc707122SEaswaran Raman Record.FunctionName = R.FunctionName; 824dc707122SEaswaran Raman Record.FunctionHash = R.FunctionHash; 825dc707122SEaswaran Raman Record.Filenames = FunctionsFilenames; 826dc707122SEaswaran Raman Record.Expressions = Expressions; 827dc707122SEaswaran Raman Record.MappingRegions = MappingRegions; 828dc707122SEaswaran Raman 829dc707122SEaswaran Raman ++CurrentRecord; 8309152fd17SVedant Kumar return Error::success(); 831dc707122SEaswaran Raman } 832