CoverageMapping.h revision 314564
1//=-- CoverageMapping.h - Code coverage mapping support ---------*- C++ -*-=// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Code coverage mapping data is generated by clang and read by 11// llvm-cov to show code coverage statistics for a file. 12// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_PROFILEDATA_COVERAGEMAPPING_H_ 16#define LLVM_PROFILEDATA_COVERAGEMAPPING_H_ 17 18#include "llvm/ADT/ArrayRef.h" 19#include "llvm/ADT/DenseMap.h" 20#include "llvm/ADT/Hashing.h" 21#include "llvm/ADT/StringSet.h" 22#include "llvm/ADT/Triple.h" 23#include "llvm/ADT/iterator.h" 24#include "llvm/ProfileData/InstrProf.h" 25#include "llvm/Support/Debug.h" 26#include "llvm/Support/Endian.h" 27#include "llvm/Support/raw_ostream.h" 28#include <system_error> 29#include <tuple> 30 31namespace llvm { 32namespace coverage { 33 34enum class coveragemap_error { 35 success = 0, 36 eof, 37 no_data_found, 38 unsupported_version, 39 truncated, 40 malformed 41}; 42 43const std::error_category &coveragemap_category(); 44 45inline std::error_code make_error_code(coveragemap_error E) { 46 return std::error_code(static_cast<int>(E), coveragemap_category()); 47} 48 49class CoverageMapError : public ErrorInfo<CoverageMapError> { 50public: 51 CoverageMapError(coveragemap_error Err) : Err(Err) { 52 assert(Err != coveragemap_error::success && "Not an error"); 53 } 54 55 std::string message() const override; 56 57 void log(raw_ostream &OS) const override { OS << message(); } 58 59 std::error_code convertToErrorCode() const override { 60 return make_error_code(Err); 61 } 62 63 coveragemap_error get() const { return Err; } 64 65 static char ID; 66 67private: 68 coveragemap_error Err; 69}; 70 71} // end of coverage namespace. 72} // end of llvm namespace 73 74namespace llvm { 75class IndexedInstrProfReader; 76namespace coverage { 77 78class CoverageMappingReader; 79struct CoverageMappingRecord; 80 81class CoverageMapping; 82struct CounterExpressions; 83 84/// \brief A Counter is an abstract value that describes how to compute the 85/// execution count for a region of code using the collected profile count data. 86struct Counter { 87 enum CounterKind { Zero, CounterValueReference, Expression }; 88 static const unsigned EncodingTagBits = 2; 89 static const unsigned EncodingTagMask = 0x3; 90 static const unsigned EncodingCounterTagAndExpansionRegionTagBits = 91 EncodingTagBits + 1; 92 93private: 94 CounterKind Kind; 95 unsigned ID; 96 97 Counter(CounterKind Kind, unsigned ID) : Kind(Kind), ID(ID) {} 98 99public: 100 Counter() : Kind(Zero), ID(0) {} 101 102 CounterKind getKind() const { return Kind; } 103 104 bool isZero() const { return Kind == Zero; } 105 106 bool isExpression() const { return Kind == Expression; } 107 108 unsigned getCounterID() const { return ID; } 109 110 unsigned getExpressionID() const { return ID; } 111 112 friend bool operator==(const Counter &LHS, const Counter &RHS) { 113 return LHS.Kind == RHS.Kind && LHS.ID == RHS.ID; 114 } 115 116 friend bool operator!=(const Counter &LHS, const Counter &RHS) { 117 return !(LHS == RHS); 118 } 119 120 friend bool operator<(const Counter &LHS, const Counter &RHS) { 121 return std::tie(LHS.Kind, LHS.ID) < std::tie(RHS.Kind, RHS.ID); 122 } 123 124 /// \brief Return the counter that represents the number zero. 125 static Counter getZero() { return Counter(); } 126 127 /// \brief Return the counter that corresponds to a specific profile counter. 128 static Counter getCounter(unsigned CounterId) { 129 return Counter(CounterValueReference, CounterId); 130 } 131 132 /// \brief Return the counter that corresponds to a specific 133 /// addition counter expression. 134 static Counter getExpression(unsigned ExpressionId) { 135 return Counter(Expression, ExpressionId); 136 } 137}; 138 139/// \brief A Counter expression is a value that represents an arithmetic 140/// operation with two counters. 141struct CounterExpression { 142 enum ExprKind { Subtract, Add }; 143 ExprKind Kind; 144 Counter LHS, RHS; 145 146 CounterExpression(ExprKind Kind, Counter LHS, Counter RHS) 147 : Kind(Kind), LHS(LHS), RHS(RHS) {} 148}; 149 150/// \brief A Counter expression builder is used to construct the 151/// counter expressions. It avoids unnecessary duplication 152/// and simplifies algebraic expressions. 153class CounterExpressionBuilder { 154 /// \brief A list of all the counter expressions 155 std::vector<CounterExpression> Expressions; 156 /// \brief A lookup table for the index of a given expression. 157 llvm::DenseMap<CounterExpression, unsigned> ExpressionIndices; 158 159 /// \brief Return the counter which corresponds to the given expression. 160 /// 161 /// If the given expression is already stored in the builder, a counter 162 /// that references that expression is returned. Otherwise, the given 163 /// expression is added to the builder's collection of expressions. 164 Counter get(const CounterExpression &E); 165 166 /// \brief Gather the terms of the expression tree for processing. 167 /// 168 /// This collects each addition and subtraction referenced by the counter into 169 /// a sequence that can be sorted and combined to build a simplified counter 170 /// expression. 171 void extractTerms(Counter C, int Sign, 172 SmallVectorImpl<std::pair<unsigned, int>> &Terms); 173 174 /// \brief Simplifies the given expression tree 175 /// by getting rid of algebraically redundant operations. 176 Counter simplify(Counter ExpressionTree); 177 178public: 179 ArrayRef<CounterExpression> getExpressions() const { return Expressions; } 180 181 /// \brief Return a counter that represents the expression 182 /// that adds LHS and RHS. 183 Counter add(Counter LHS, Counter RHS); 184 185 /// \brief Return a counter that represents the expression 186 /// that subtracts RHS from LHS. 187 Counter subtract(Counter LHS, Counter RHS); 188}; 189 190/// \brief A Counter mapping region associates a source range with 191/// a specific counter. 192struct CounterMappingRegion { 193 enum RegionKind { 194 /// \brief A CodeRegion associates some code with a counter 195 CodeRegion, 196 197 /// \brief An ExpansionRegion represents a file expansion region that 198 /// associates a source range with the expansion of a virtual source file, 199 /// such as for a macro instantiation or #include file. 200 ExpansionRegion, 201 202 /// \brief A SkippedRegion represents a source range with code that 203 /// was skipped by a preprocessor or similar means. 204 SkippedRegion 205 }; 206 207 Counter Count; 208 unsigned FileID, ExpandedFileID; 209 unsigned LineStart, ColumnStart, LineEnd, ColumnEnd; 210 RegionKind Kind; 211 212 CounterMappingRegion(Counter Count, unsigned FileID, unsigned ExpandedFileID, 213 unsigned LineStart, unsigned ColumnStart, 214 unsigned LineEnd, unsigned ColumnEnd, RegionKind Kind) 215 : Count(Count), FileID(FileID), ExpandedFileID(ExpandedFileID), 216 LineStart(LineStart), ColumnStart(ColumnStart), LineEnd(LineEnd), 217 ColumnEnd(ColumnEnd), Kind(Kind) {} 218 219 static CounterMappingRegion 220 makeRegion(Counter Count, unsigned FileID, unsigned LineStart, 221 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { 222 return CounterMappingRegion(Count, FileID, 0, LineStart, ColumnStart, 223 LineEnd, ColumnEnd, CodeRegion); 224 } 225 226 static CounterMappingRegion 227 makeExpansion(unsigned FileID, unsigned ExpandedFileID, unsigned LineStart, 228 unsigned ColumnStart, unsigned LineEnd, unsigned ColumnEnd) { 229 return CounterMappingRegion(Counter(), FileID, ExpandedFileID, LineStart, 230 ColumnStart, LineEnd, ColumnEnd, 231 ExpansionRegion); 232 } 233 234 static CounterMappingRegion 235 makeSkipped(unsigned FileID, unsigned LineStart, unsigned ColumnStart, 236 unsigned LineEnd, unsigned ColumnEnd) { 237 return CounterMappingRegion(Counter(), FileID, 0, LineStart, ColumnStart, 238 LineEnd, ColumnEnd, SkippedRegion); 239 } 240 241 242 inline std::pair<unsigned, unsigned> startLoc() const { 243 return std::pair<unsigned, unsigned>(LineStart, ColumnStart); 244 } 245 246 inline std::pair<unsigned, unsigned> endLoc() const { 247 return std::pair<unsigned, unsigned>(LineEnd, ColumnEnd); 248 } 249}; 250 251/// \brief Associates a source range with an execution count. 252struct CountedRegion : public CounterMappingRegion { 253 uint64_t ExecutionCount; 254 255 CountedRegion(const CounterMappingRegion &R, uint64_t ExecutionCount) 256 : CounterMappingRegion(R), ExecutionCount(ExecutionCount) {} 257}; 258 259/// \brief A Counter mapping context is used to connect the counters, 260/// expressions and the obtained counter values. 261class CounterMappingContext { 262 ArrayRef<CounterExpression> Expressions; 263 ArrayRef<uint64_t> CounterValues; 264 265public: 266 CounterMappingContext(ArrayRef<CounterExpression> Expressions, 267 ArrayRef<uint64_t> CounterValues = None) 268 : Expressions(Expressions), CounterValues(CounterValues) {} 269 270 void setCounts(ArrayRef<uint64_t> Counts) { CounterValues = Counts; } 271 272 void dump(const Counter &C, llvm::raw_ostream &OS) const; 273 void dump(const Counter &C) const { dump(C, dbgs()); } 274 275 /// \brief Return the number of times that a region of code associated with 276 /// this counter was executed. 277 Expected<int64_t> evaluate(const Counter &C) const; 278}; 279 280/// \brief Code coverage information for a single function. 281struct FunctionRecord { 282 /// \brief Raw function name. 283 std::string Name; 284 /// \brief Associated files. 285 std::vector<std::string> Filenames; 286 /// \brief Regions in the function along with their counts. 287 std::vector<CountedRegion> CountedRegions; 288 /// \brief The number of times this function was executed. 289 uint64_t ExecutionCount; 290 291 FunctionRecord(StringRef Name, ArrayRef<StringRef> Filenames) 292 : Name(Name), Filenames(Filenames.begin(), Filenames.end()) {} 293 294 FunctionRecord(FunctionRecord &&FR) = default; 295 FunctionRecord &operator=(FunctionRecord &&) = default; 296 297 void pushRegion(CounterMappingRegion Region, uint64_t Count) { 298 if (CountedRegions.empty()) 299 ExecutionCount = Count; 300 CountedRegions.emplace_back(Region, Count); 301 } 302}; 303 304/// \brief Iterator over Functions, optionally filtered to a single file. 305class FunctionRecordIterator 306 : public iterator_facade_base<FunctionRecordIterator, 307 std::forward_iterator_tag, FunctionRecord> { 308 ArrayRef<FunctionRecord> Records; 309 ArrayRef<FunctionRecord>::iterator Current; 310 StringRef Filename; 311 312 /// \brief Skip records whose primary file is not \c Filename. 313 void skipOtherFiles(); 314 315public: 316 FunctionRecordIterator(ArrayRef<FunctionRecord> Records_, 317 StringRef Filename = "") 318 : Records(Records_), Current(Records.begin()), Filename(Filename) { 319 skipOtherFiles(); 320 } 321 322 FunctionRecordIterator() : Current(Records.begin()) {} 323 324 bool operator==(const FunctionRecordIterator &RHS) const { 325 return Current == RHS.Current && Filename == RHS.Filename; 326 } 327 328 const FunctionRecord &operator*() const { return *Current; } 329 330 FunctionRecordIterator &operator++() { 331 assert(Current != Records.end() && "incremented past end"); 332 ++Current; 333 skipOtherFiles(); 334 return *this; 335 } 336}; 337 338/// \brief Coverage information for a macro expansion or #included file. 339/// 340/// When covered code has pieces that can be expanded for more detail, such as a 341/// preprocessor macro use and its definition, these are represented as 342/// expansions whose coverage can be looked up independently. 343struct ExpansionRecord { 344 /// \brief The abstract file this expansion covers. 345 unsigned FileID; 346 /// \brief The region that expands to this record. 347 const CountedRegion &Region; 348 /// \brief Coverage for the expansion. 349 const FunctionRecord &Function; 350 351 ExpansionRecord(const CountedRegion &Region, 352 const FunctionRecord &Function) 353 : FileID(Region.ExpandedFileID), Region(Region), Function(Function) {} 354}; 355 356/// \brief The execution count information starting at a point in a file. 357/// 358/// A sequence of CoverageSegments gives execution counts for a file in format 359/// that's simple to iterate through for processing. 360struct CoverageSegment { 361 /// \brief The line where this segment begins. 362 unsigned Line; 363 /// \brief The column where this segment begins. 364 unsigned Col; 365 /// \brief The execution count, or zero if no count was recorded. 366 uint64_t Count; 367 /// \brief When false, the segment was uninstrumented or skipped. 368 bool HasCount; 369 /// \brief Whether this enters a new region or returns to a previous count. 370 bool IsRegionEntry; 371 372 CoverageSegment(unsigned Line, unsigned Col, bool IsRegionEntry) 373 : Line(Line), Col(Col), Count(0), HasCount(false), 374 IsRegionEntry(IsRegionEntry) {} 375 376 CoverageSegment(unsigned Line, unsigned Col, uint64_t Count, 377 bool IsRegionEntry) 378 : Line(Line), Col(Col), Count(Count), HasCount(true), 379 IsRegionEntry(IsRegionEntry) {} 380 381 friend bool operator==(const CoverageSegment &L, const CoverageSegment &R) { 382 return std::tie(L.Line, L.Col, L.Count, L.HasCount, L.IsRegionEntry) == 383 std::tie(R.Line, R.Col, R.Count, R.HasCount, R.IsRegionEntry); 384 } 385}; 386 387/// \brief Coverage information to be processed or displayed. 388/// 389/// This represents the coverage of an entire file, expansion, or function. It 390/// provides a sequence of CoverageSegments to iterate through, as well as the 391/// list of expansions that can be further processed. 392class CoverageData { 393 std::string Filename; 394 std::vector<CoverageSegment> Segments; 395 std::vector<ExpansionRecord> Expansions; 396 friend class CoverageMapping; 397 398public: 399 CoverageData() {} 400 401 CoverageData(StringRef Filename) : Filename(Filename) {} 402 403 /// \brief Get the name of the file this data covers. 404 StringRef getFilename() const { return Filename; } 405 406 std::vector<CoverageSegment>::const_iterator begin() const { 407 return Segments.begin(); 408 } 409 std::vector<CoverageSegment>::const_iterator end() const { 410 return Segments.end(); 411 } 412 bool empty() const { return Segments.empty(); } 413 414 /// \brief Expansions that can be further processed. 415 ArrayRef<ExpansionRecord> getExpansions() const { return Expansions; } 416}; 417 418/// \brief The mapping of profile information to coverage data. 419/// 420/// This is the main interface to get coverage information, using a profile to 421/// fill out execution counts. 422class CoverageMapping { 423 StringSet<> FunctionNames; 424 std::vector<FunctionRecord> Functions; 425 unsigned MismatchedFunctionCount; 426 427 CoverageMapping() : MismatchedFunctionCount(0) {} 428 429 CoverageMapping(const CoverageMapping &) = delete; 430 const CoverageMapping &operator=(const CoverageMapping &) = delete; 431 432 /// \brief Add a function record corresponding to \p Record. 433 Error loadFunctionRecord(const CoverageMappingRecord &Record, 434 IndexedInstrProfReader &ProfileReader); 435 436public: 437 /// \brief Load the coverage mapping using the given readers. 438 static Expected<std::unique_ptr<CoverageMapping>> 439 load(CoverageMappingReader &CoverageReader, 440 IndexedInstrProfReader &ProfileReader); 441 442 static Expected<std::unique_ptr<CoverageMapping>> 443 load(ArrayRef<std::unique_ptr<CoverageMappingReader>> CoverageReaders, 444 IndexedInstrProfReader &ProfileReader); 445 446 /// \brief Load the coverage mapping from the given files. 447 static Expected<std::unique_ptr<CoverageMapping>> 448 load(StringRef ObjectFilename, StringRef ProfileFilename, 449 StringRef Arch = StringRef()) { 450 return load(ArrayRef<StringRef>(ObjectFilename), ProfileFilename, Arch); 451 } 452 453 static Expected<std::unique_ptr<CoverageMapping>> 454 load(ArrayRef<StringRef> ObjectFilenames, StringRef ProfileFilename, 455 StringRef Arch = StringRef()); 456 457 /// \brief The number of functions that couldn't have their profiles mapped. 458 /// 459 /// This is a count of functions whose profile is out of date or otherwise 460 /// can't be associated with any coverage information. 461 unsigned getMismatchedCount() { return MismatchedFunctionCount; } 462 463 /// \brief Returns a lexicographically sorted, unique list of files that are 464 /// covered. 465 std::vector<StringRef> getUniqueSourceFiles() const; 466 467 /// \brief Get the coverage for a particular file. 468 /// 469 /// The given filename must be the name as recorded in the coverage 470 /// information. That is, only names returned from getUniqueSourceFiles will 471 /// yield a result. 472 CoverageData getCoverageForFile(StringRef Filename) const; 473 474 /// \brief Gets all of the functions covered by this profile. 475 iterator_range<FunctionRecordIterator> getCoveredFunctions() const { 476 return make_range(FunctionRecordIterator(Functions), 477 FunctionRecordIterator()); 478 } 479 480 /// \brief Gets all of the functions in a particular file. 481 iterator_range<FunctionRecordIterator> 482 getCoveredFunctions(StringRef Filename) const { 483 return make_range(FunctionRecordIterator(Functions, Filename), 484 FunctionRecordIterator()); 485 } 486 487 /// \brief Get the list of function instantiations in the file. 488 /// 489 /// Functions that are instantiated more than once, such as C++ template 490 /// specializations, have distinct coverage records for each instantiation. 491 std::vector<const FunctionRecord *> 492 getInstantiations(StringRef Filename) const; 493 494 /// \brief Get the coverage for a particular function. 495 CoverageData getCoverageForFunction(const FunctionRecord &Function) const; 496 497 /// \brief Get the coverage for an expansion within a coverage set. 498 CoverageData getCoverageForExpansion(const ExpansionRecord &Expansion) const; 499}; 500 501// Profile coverage map has the following layout: 502// [CoverageMapFileHeader] 503// [ArrayStart] 504// [CovMapFunctionRecord] 505// [CovMapFunctionRecord] 506// ... 507// [ArrayEnd] 508// [Encoded Region Mapping Data] 509LLVM_PACKED_START 510template <class IntPtrT> struct CovMapFunctionRecordV1 { 511#define COVMAP_V1 512#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; 513#include "llvm/ProfileData/InstrProfData.inc" 514#undef COVMAP_V1 515 516 // Return the structural hash associated with the function. 517 template <support::endianness Endian> uint64_t getFuncHash() const { 518 return support::endian::byte_swap<uint64_t, Endian>(FuncHash); 519 } 520 // Return the coverage map data size for the funciton. 521 template <support::endianness Endian> uint32_t getDataSize() const { 522 return support::endian::byte_swap<uint32_t, Endian>(DataSize); 523 } 524 // Return function lookup key. The value is consider opaque. 525 template <support::endianness Endian> IntPtrT getFuncNameRef() const { 526 return support::endian::byte_swap<IntPtrT, Endian>(NamePtr); 527 } 528 // Return the PGO name of the function */ 529 template <support::endianness Endian> 530 Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { 531 IntPtrT NameRef = getFuncNameRef<Endian>(); 532 uint32_t NameS = support::endian::byte_swap<uint32_t, Endian>(NameSize); 533 FuncName = ProfileNames.getFuncName(NameRef, NameS); 534 if (NameS && FuncName.empty()) 535 return make_error<CoverageMapError>(coveragemap_error::malformed); 536 return Error::success(); 537 } 538}; 539 540struct CovMapFunctionRecord { 541#define COVMAP_FUNC_RECORD(Type, LLVMType, Name, Init) Type Name; 542#include "llvm/ProfileData/InstrProfData.inc" 543 544 // Return the structural hash associated with the function. 545 template <support::endianness Endian> uint64_t getFuncHash() const { 546 return support::endian::byte_swap<uint64_t, Endian>(FuncHash); 547 } 548 // Return the coverage map data size for the funciton. 549 template <support::endianness Endian> uint32_t getDataSize() const { 550 return support::endian::byte_swap<uint32_t, Endian>(DataSize); 551 } 552 // Return function lookup key. The value is consider opaque. 553 template <support::endianness Endian> uint64_t getFuncNameRef() const { 554 return support::endian::byte_swap<uint64_t, Endian>(NameRef); 555 } 556 // Return the PGO name of the function */ 557 template <support::endianness Endian> 558 Error getFuncName(InstrProfSymtab &ProfileNames, StringRef &FuncName) const { 559 uint64_t NameRef = getFuncNameRef<Endian>(); 560 FuncName = ProfileNames.getFuncName(NameRef); 561 return Error::success(); 562 } 563}; 564 565// Per module coverage mapping data header, i.e. CoverageMapFileHeader 566// documented above. 567struct CovMapHeader { 568#define COVMAP_HEADER(Type, LLVMType, Name, Init) Type Name; 569#include "llvm/ProfileData/InstrProfData.inc" 570 template <support::endianness Endian> uint32_t getNRecords() const { 571 return support::endian::byte_swap<uint32_t, Endian>(NRecords); 572 } 573 template <support::endianness Endian> uint32_t getFilenamesSize() const { 574 return support::endian::byte_swap<uint32_t, Endian>(FilenamesSize); 575 } 576 template <support::endianness Endian> uint32_t getCoverageSize() const { 577 return support::endian::byte_swap<uint32_t, Endian>(CoverageSize); 578 } 579 template <support::endianness Endian> uint32_t getVersion() const { 580 return support::endian::byte_swap<uint32_t, Endian>(Version); 581 } 582}; 583 584LLVM_PACKED_END 585 586enum CovMapVersion { 587 Version1 = 0, 588 // Function's name reference from CovMapFuncRecord is changed from raw 589 // name string pointer to MD5 to support name section compression. Name 590 // section is also compressed. 591 Version2 = 1, 592 // The current version is Version2 593 CurrentVersion = INSTR_PROF_COVMAP_VERSION 594}; 595 596template <int CovMapVersion, class IntPtrT> struct CovMapTraits { 597 typedef CovMapFunctionRecord CovMapFuncRecordType; 598 typedef uint64_t NameRefType; 599}; 600 601template <class IntPtrT> struct CovMapTraits<CovMapVersion::Version1, IntPtrT> { 602 typedef CovMapFunctionRecordV1<IntPtrT> CovMapFuncRecordType; 603 typedef IntPtrT NameRefType; 604}; 605 606} // end namespace coverage 607 608/// \brief Provide DenseMapInfo for CounterExpression 609template<> struct DenseMapInfo<coverage::CounterExpression> { 610 static inline coverage::CounterExpression getEmptyKey() { 611 using namespace coverage; 612 return CounterExpression(CounterExpression::ExprKind::Subtract, 613 Counter::getCounter(~0U), 614 Counter::getCounter(~0U)); 615 } 616 617 static inline coverage::CounterExpression getTombstoneKey() { 618 using namespace coverage; 619 return CounterExpression(CounterExpression::ExprKind::Add, 620 Counter::getCounter(~0U), 621 Counter::getCounter(~0U)); 622 } 623 624 static unsigned getHashValue(const coverage::CounterExpression &V) { 625 return static_cast<unsigned>( 626 hash_combine(V.Kind, V.LHS.getKind(), V.LHS.getCounterID(), 627 V.RHS.getKind(), V.RHS.getCounterID())); 628 } 629 630 static bool isEqual(const coverage::CounterExpression &LHS, 631 const coverage::CounterExpression &RHS) { 632 return LHS.Kind == RHS.Kind && LHS.LHS == RHS.LHS && LHS.RHS == RHS.RHS; 633 } 634}; 635 636} // end namespace llvm 637 638#endif // LLVM_PROFILEDATA_COVERAGEMAPPING_H_ 639