1 //===- GCOV.h - LLVM coverage tool ------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This header provides the interface to read and write coverage files that 10 // use 'gcov' format. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_PROFILEDATA_GCOV_H 15 #define LLVM_PROFILEDATA_GCOV_H 16 17 #include "llvm/ADT/DenseSet.h" 18 #include "llvm/ADT/SmallString.h" 19 #include "llvm/ADT/SmallVector.h" 20 #include "llvm/ADT/StringMap.h" 21 #include "llvm/ADT/StringRef.h" 22 #include "llvm/ADT/iterator.h" 23 #include "llvm/ADT/iterator_range.h" 24 #include "llvm/Support/Compiler.h" 25 #include "llvm/Support/DataExtractor.h" 26 #include "llvm/Support/MemoryBuffer.h" 27 #include "llvm/Support/raw_ostream.h" 28 #include <algorithm> 29 #include <cstddef> 30 #include <cstdint> 31 #include <map> 32 #include <memory> 33 #include <string> 34 #include <utility> 35 36 namespace llvm { 37 38 class GCOVFunction; 39 class GCOVBlock; 40 41 namespace GCOV { 42 43 enum GCOVVersion { V304, V407, V408, V800, V900, V1200 }; 44 45 /// A struct for passing gcov options between functions. 46 struct Options { OptionsOptions47 Options(bool A, bool B, bool C, bool F, bool P, bool U, bool I, bool L, 48 bool M, bool N, bool R, bool T, bool X, std::string SourcePrefix) 49 : AllBlocks(A), BranchInfo(B), BranchCount(C), FuncCoverage(F), 50 PreservePaths(P), UncondBranch(U), Intermediate(I), LongFileNames(L), 51 Demangle(M), NoOutput(N), RelativeOnly(R), UseStdout(T), 52 HashFilenames(X), SourcePrefix(std::move(SourcePrefix)) {} 53 54 bool AllBlocks; 55 bool BranchInfo; 56 bool BranchCount; 57 bool FuncCoverage; 58 bool PreservePaths; 59 bool UncondBranch; 60 bool Intermediate; 61 bool LongFileNames; 62 bool Demangle; 63 bool NoOutput; 64 bool RelativeOnly; 65 bool UseStdout; 66 bool HashFilenames; 67 std::string SourcePrefix; 68 }; 69 70 } // end namespace GCOV 71 72 /// GCOVBuffer - A wrapper around MemoryBuffer to provide GCOV specific 73 /// read operations. 74 class GCOVBuffer { 75 public: GCOVBuffer(MemoryBuffer * B)76 GCOVBuffer(MemoryBuffer *B) : Buffer(B) {} ~GCOVBuffer()77 ~GCOVBuffer() { consumeError(cursor.takeError()); } 78 79 /// readGCNOFormat - Check GCNO signature is valid at the beginning of buffer. readGCNOFormat()80 bool readGCNOFormat() { 81 StringRef buf = Buffer->getBuffer(); 82 StringRef magic = buf.substr(0, 4); 83 if (magic == "gcno") { 84 de = DataExtractor(buf.substr(4), false, 0); 85 } else if (magic == "oncg") { 86 de = DataExtractor(buf.substr(4), true, 0); 87 } else { 88 errs() << "unexpected magic: " << magic << "\n"; 89 return false; 90 } 91 return true; 92 } 93 94 /// readGCDAFormat - Check GCDA signature is valid at the beginning of buffer. readGCDAFormat()95 bool readGCDAFormat() { 96 StringRef buf = Buffer->getBuffer(); 97 StringRef magic = buf.substr(0, 4); 98 if (magic == "gcda") { 99 de = DataExtractor(buf.substr(4), false, 0); 100 } else if (magic == "adcg") { 101 de = DataExtractor(buf.substr(4), true, 0); 102 } else { 103 return false; 104 } 105 return true; 106 } 107 108 /// readGCOVVersion - Read GCOV version. readGCOVVersion(GCOV::GCOVVersion & version)109 bool readGCOVVersion(GCOV::GCOVVersion &version) { 110 std::string str(de.getBytes(cursor, 4)); 111 if (str.size() != 4) 112 return false; 113 if (de.isLittleEndian()) 114 std::reverse(str.begin(), str.end()); 115 int ver = str[0] >= 'A' 116 ? (str[0] - 'A') * 100 + (str[1] - '0') * 10 + str[2] - '0' 117 : (str[0] - '0') * 10 + str[2] - '0'; 118 if (ver >= 120) { 119 this->version = version = GCOV::V1200; 120 return true; 121 } else if (ver >= 90) { 122 // PR gcov-profile/84846, r269678 123 this->version = version = GCOV::V900; 124 return true; 125 } else if (ver >= 80) { 126 // PR gcov-profile/48463 127 this->version = version = GCOV::V800; 128 return true; 129 } else if (ver >= 48) { 130 // r189778: the exit block moved from the last to the second. 131 this->version = version = GCOV::V408; 132 return true; 133 } else if (ver >= 47) { 134 // r173147: split checksum into cfg checksum and line checksum. 135 this->version = version = GCOV::V407; 136 return true; 137 } else if (ver >= 34) { 138 this->version = version = GCOV::V304; 139 return true; 140 } 141 errs() << "unexpected version: " << str << "\n"; 142 return false; 143 } 144 getWord()145 uint32_t getWord() { return de.getU32(cursor); } getString()146 StringRef getString() { 147 uint32_t len; 148 if (!readInt(len) || len == 0) 149 return {}; 150 return de.getBytes(cursor, len * 4).split('\0').first; 151 } 152 readInt(uint32_t & Val)153 bool readInt(uint32_t &Val) { 154 if (cursor.tell() + 4 > de.size()) { 155 Val = 0; 156 errs() << "unexpected end of memory buffer: " << cursor.tell() << "\n"; 157 return false; 158 } 159 Val = de.getU32(cursor); 160 return true; 161 } 162 readInt64(uint64_t & Val)163 bool readInt64(uint64_t &Val) { 164 uint32_t Lo, Hi; 165 if (!readInt(Lo) || !readInt(Hi)) 166 return false; 167 Val = ((uint64_t)Hi << 32) | Lo; 168 return true; 169 } 170 readString(StringRef & str)171 bool readString(StringRef &str) { 172 uint32_t len; 173 if (!readInt(len) || len == 0) 174 return false; 175 if (version >= GCOV::V1200) 176 str = de.getBytes(cursor, len).drop_back(); 177 else 178 str = de.getBytes(cursor, len * 4).split('\0').first; 179 return bool(cursor); 180 } 181 182 DataExtractor de{ArrayRef<uint8_t>{}, false, 0}; 183 DataExtractor::Cursor cursor{0}; 184 185 private: 186 MemoryBuffer *Buffer; 187 GCOV::GCOVVersion version{}; 188 }; 189 190 /// GCOVFile - Collects coverage information for one pair of coverage file 191 /// (.gcno and .gcda). 192 class GCOVFile { 193 public: 194 GCOVFile() = default; 195 196 LLVM_ABI bool readGCNO(GCOVBuffer &Buffer); 197 LLVM_ABI bool readGCDA(GCOVBuffer &Buffer); getVersion()198 GCOV::GCOVVersion getVersion() const { return version; } 199 LLVM_ABI void print(raw_ostream &OS) const; 200 LLVM_ABI void dump() const; 201 202 std::vector<std::string> filenames; 203 StringMap<unsigned> filenameToIdx; 204 205 public: 206 bool GCNOInitialized = false; 207 GCOV::GCOVVersion version{}; 208 uint32_t checksum = 0; 209 StringRef cwd; 210 SmallVector<std::unique_ptr<GCOVFunction>, 16> functions; 211 std::map<uint32_t, GCOVFunction *> identToFunction; 212 uint32_t runCount = 0; 213 uint32_t programCount = 0; 214 215 using iterator = pointee_iterator< 216 SmallVectorImpl<std::unique_ptr<GCOVFunction>>::const_iterator>; begin()217 iterator begin() const { return iterator(functions.begin()); } end()218 iterator end() const { return iterator(functions.end()); } 219 220 private: 221 unsigned addNormalizedPathToMap(StringRef filename); 222 }; 223 224 struct GCOVArc { GCOVArcGCOVArc225 GCOVArc(GCOVBlock &src, GCOVBlock &dst, uint32_t flags) 226 : src(src), dst(dst), flags(flags) {} 227 LLVM_ABI bool onTree() const; 228 229 GCOVBlock &src; 230 GCOVBlock &dst; 231 uint32_t flags; 232 uint64_t count = 0; 233 uint64_t cycleCount = 0; 234 }; 235 236 /// GCOVFunction - Collects function information. 237 class GCOVFunction { 238 public: 239 using BlockIterator = pointee_iterator< 240 SmallVectorImpl<std::unique_ptr<GCOVBlock>>::const_iterator>; 241 GCOVFunction(GCOVFile & file)242 GCOVFunction(GCOVFile &file) : file(file) {} 243 244 LLVM_ABI StringRef getName(bool demangle) const; 245 LLVM_ABI StringRef getFilename() const; 246 LLVM_ABI uint64_t getEntryCount() const; 247 LLVM_ABI GCOVBlock &getExitBlock() const; 248 blocksRange()249 iterator_range<BlockIterator> blocksRange() const { 250 return make_range(blocks.begin(), blocks.end()); 251 } 252 253 LLVM_ABI void propagateCounts(const GCOVBlock &v, GCOVArc *pred); 254 LLVM_ABI void print(raw_ostream &OS) const; 255 LLVM_ABI void dump() const; 256 257 GCOVFile &file; 258 uint32_t ident = 0; 259 uint32_t linenoChecksum; 260 uint32_t cfgChecksum = 0; 261 uint32_t startLine = 0; 262 uint32_t startColumn = 0; 263 uint32_t endLine = 0; 264 uint32_t endColumn = 0; 265 uint8_t artificial = 0; 266 StringRef Name; 267 mutable SmallString<0> demangled; 268 unsigned srcIdx; 269 SmallVector<std::unique_ptr<GCOVBlock>, 0> blocks; 270 SmallVector<std::unique_ptr<GCOVArc>, 0> arcs, treeArcs; 271 DenseSet<const GCOVBlock *> visited; 272 }; 273 274 /// Represent file of lines same with block_location_info in gcc. 275 struct GCOVBlockLocation { GCOVBlockLocationGCOVBlockLocation276 GCOVBlockLocation(unsigned idx) : srcIdx(idx) {} 277 278 unsigned srcIdx; 279 SmallVector<uint32_t, 4> lines; 280 }; 281 282 /// GCOVBlock - Collects block information. 283 class GCOVBlock { 284 public: 285 using EdgeIterator = SmallVectorImpl<GCOVArc *>::const_iterator; 286 using BlockVector = SmallVector<const GCOVBlock *, 1>; 287 using BlockVectorLists = SmallVector<BlockVector, 4>; 288 using Edges = SmallVector<GCOVArc *, 4>; 289 GCOVBlock(uint32_t N)290 GCOVBlock(uint32_t N) : number(N) {} 291 addLine(uint32_t N)292 void addLine(uint32_t N) { 293 locations.back().lines.push_back(N); 294 lastLine = N; 295 } addFile(unsigned fileIdx)296 void addFile(unsigned fileIdx) { locations.emplace_back(fileIdx); } 297 getLastLine()298 uint32_t getLastLine() const { return lastLine; } getCount()299 uint64_t getCount() const { return count; } 300 addSrcEdge(GCOVArc * Edge)301 void addSrcEdge(GCOVArc *Edge) { pred.push_back(Edge); } 302 addDstEdge(GCOVArc * Edge)303 void addDstEdge(GCOVArc *Edge) { succ.push_back(Edge); } 304 srcs()305 iterator_range<EdgeIterator> srcs() const { 306 return make_range(pred.begin(), pred.end()); 307 } 308 dsts()309 iterator_range<EdgeIterator> dsts() const { 310 return make_range(succ.begin(), succ.end()); 311 } 312 313 LLVM_ABI void print(raw_ostream &OS) const; 314 LLVM_ABI void dump() const; 315 316 LLVM_ABI static uint64_t 317 augmentOneCycle(GCOVBlock *src, 318 std::vector<std::pair<GCOVBlock *, size_t>> &stack); 319 LLVM_ABI static uint64_t getCyclesCount(const BlockVector &blocks); 320 LLVM_ABI static uint64_t getLineCount(const BlockVector &Blocks); 321 322 public: 323 uint32_t number; 324 uint64_t count = 0; 325 SmallVector<GCOVArc *, 2> pred; 326 SmallVector<GCOVArc *, 2> succ; 327 SmallVector<GCOVBlockLocation> locations; 328 uint32_t lastLine = 0; 329 bool traversable = false; 330 GCOVArc *incoming = nullptr; 331 }; 332 333 LLVM_ABI void gcovOneInput(const GCOV::Options &options, StringRef filename, 334 StringRef gcno, StringRef gcda, GCOVFile &file); 335 336 } // end namespace llvm 337 338 #endif // LLVM_PROFILEDATA_GCOV_H 339