OSDN Git Service

efeb46a1faacdd7714cc6eb80935082eebf682b5
[android-x86/external-llvm.git] / tools / sancov / sancov.cc
1 //===-- sancov.cc --------------------------------------------===//
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 // This file is a command-line tool for reading and analyzing sanitizer
11 // coverage.
12 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/ADT/Twine.h"
15 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
16 #include "llvm/MC/MCAsmInfo.h"
17 #include "llvm/MC/MCContext.h"
18 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
19 #include "llvm/MC/MCInst.h"
20 #include "llvm/MC/MCInstPrinter.h"
21 #include "llvm/MC/MCInstrAnalysis.h"
22 #include "llvm/MC/MCInstrInfo.h"
23 #include "llvm/MC/MCObjectFileInfo.h"
24 #include "llvm/MC/MCRegisterInfo.h"
25 #include "llvm/MC/MCSubtargetInfo.h"
26 #include "llvm/Object/Archive.h"
27 #include "llvm/Object/Binary.h"
28 #include "llvm/Object/ELFObjectFile.h"
29 #include "llvm/Object/ObjectFile.h"
30 #include "llvm/Support/Casting.h"
31 #include "llvm/Support/CommandLine.h"
32 #include "llvm/Support/Errc.h"
33 #include "llvm/Support/ErrorOr.h"
34 #include "llvm/Support/FileSystem.h"
35 #include "llvm/Support/LineIterator.h"
36 #include "llvm/Support/MD5.h"
37 #include "llvm/Support/ManagedStatic.h"
38 #include "llvm/Support/MemoryBuffer.h"
39 #include "llvm/Support/Path.h"
40 #include "llvm/Support/PrettyStackTrace.h"
41 #include "llvm/Support/Regex.h"
42 #include "llvm/Support/Signals.h"
43 #include "llvm/Support/SpecialCaseList.h"
44 #include "llvm/Support/TargetRegistry.h"
45 #include "llvm/Support/TargetSelect.h"
46 #include "llvm/Support/ToolOutputFile.h"
47 #include "llvm/Support/raw_ostream.h"
48
49 #include <algorithm>
50 #include <set>
51 #include <stdio.h>
52 #include <string>
53 #include <utility>
54 #include <vector>
55
56 using namespace llvm;
57
58 namespace {
59
60 // --------- COMMAND LINE FLAGS ---------
61
62 enum ActionType {
63   PrintAction,
64   PrintCovPointsAction,
65   CoveredFunctionsAction,
66   NotCoveredFunctionsAction,
67   HtmlReportAction,
68   StatsAction
69 };
70
71 cl::opt<ActionType> Action(
72     cl::desc("Action (required)"), cl::Required,
73     cl::values(clEnumValN(PrintAction, "print", "Print coverage addresses"),
74                clEnumValN(PrintCovPointsAction, "print-coverage-pcs",
75                           "Print coverage instrumentation points addresses."),
76                clEnumValN(CoveredFunctionsAction, "covered-functions",
77                           "Print all covered funcions."),
78                clEnumValN(NotCoveredFunctionsAction, "not-covered-functions",
79                           "Print all not covered funcions."),
80                clEnumValN(HtmlReportAction, "html-report",
81                           "Print HTML coverage report."),
82                clEnumValN(StatsAction, "print-coverage-stats",
83                           "Print coverage statistics."),
84                clEnumValEnd));
85
86 static cl::list<std::string>
87     ClInputFiles(cl::Positional, cl::OneOrMore,
88                  cl::desc("(<binary file>|<.sancov file>)..."));
89
90 static cl::opt<bool> ClDemangle("demangle", cl::init(true),
91                                 cl::desc("Print demangled function name."));
92
93 static cl::opt<std::string> ClStripPathPrefix(
94     "strip_path_prefix", cl::init(""),
95     cl::desc("Strip this prefix from file paths in reports."));
96
97 static cl::opt<std::string>
98     ClBlacklist("blacklist", cl::init(""),
99                 cl::desc("Blacklist file (sanitizer blacklist format)."));
100
101 static cl::opt<bool> ClUseDefaultBlacklist(
102     "use_default_blacklist", cl::init(true), cl::Hidden,
103     cl::desc("Controls if default blacklist should be used."));
104
105 static const char *const DefaultBlacklistStr = "fun:__sanitizer_.*\n"
106                                                "src:/usr/include/.*\n"
107                                                "src:.*/libc\\+\\+/.*\n";
108
109 // --------- FORMAT SPECIFICATION ---------
110
111 struct FileHeader {
112   uint32_t Bitness;
113   uint32_t Magic;
114 };
115
116 static const uint32_t BinCoverageMagic = 0xC0BFFFFF;
117 static const uint32_t Bitness32 = 0xFFFFFF32;
118 static const uint32_t Bitness64 = 0xFFFFFF64;
119
120 // --------- ERROR HANDLING ---------
121
122 static void Fail(const llvm::Twine &E) {
123   errs() << "Error: " << E << "\n";
124   exit(1);
125 }
126
127 static void FailIfError(std::error_code Error) {
128   if (!Error)
129     return;
130   errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n";
131   exit(1);
132 }
133
134 template <typename T> static void FailIfError(const ErrorOr<T> &E) {
135   FailIfError(E.getError());
136 }
137
138 static void FailIfNotEmpty(const llvm::Twine &E) {
139   if (E.str().empty())
140     return;
141   Fail(E);
142 }
143
144 template <typename T>
145 static void FailIfEmpty(const std::unique_ptr<T> &Ptr,
146                         const std::string &Message) {
147   if (Ptr.get())
148     return;
149   Fail(Message);
150 }
151
152 // ---------
153
154 // Produces std::map<K, std::vector<E>> grouping input
155 // elements by FuncTy result.
156 template <class RangeTy, class FuncTy>
157 static inline auto group_by(const RangeTy &R, FuncTy F)
158     -> std::map<typename std::decay<decltype(F(*R.begin()))>::type,
159                 std::vector<typename std::decay<decltype(*R.begin())>::type>> {
160   std::map<typename std::decay<decltype(F(*R.begin()))>::type,
161            std::vector<typename std::decay<decltype(*R.begin())>::type>>
162       Result;
163   for (const auto &E : R) {
164     Result[F(E)].push_back(E);
165   }
166   return Result;
167 }
168
169 template <typename T>
170 static void readInts(const char *Start, const char *End,
171                      std::set<uint64_t> *Ints) {
172   const T *S = reinterpret_cast<const T *>(Start);
173   const T *E = reinterpret_cast<const T *>(End);
174   std::copy(S, E, std::inserter(*Ints, Ints->end()));
175 }
176
177 struct FileLoc {
178   bool operator<(const FileLoc &RHS) const {
179     return std::tie(FileName, Line) < std::tie(RHS.FileName, RHS.Line);
180   }
181
182   std::string FileName;
183   uint32_t Line;
184 };
185
186 struct FileFn {
187   bool operator<(const FileFn &RHS) const {
188     return std::tie(FileName, FunctionName) <
189            std::tie(RHS.FileName, RHS.FunctionName);
190   }
191
192   std::string FileName;
193   std::string FunctionName;
194 };
195
196 struct FnLoc {
197   bool operator<(const FnLoc &RHS) const {
198     return std::tie(Loc, FunctionName) < std::tie(RHS.Loc, RHS.FunctionName);
199   }
200
201   FileLoc Loc;
202   std::string FunctionName;
203 };
204
205 std::string stripPathPrefix(std::string Path) {
206   if (ClStripPathPrefix.empty())
207     return Path;
208   size_t Pos = Path.find(ClStripPathPrefix);
209   if (Pos == std::string::npos)
210     return Path;
211   return Path.substr(Pos + ClStripPathPrefix.size());
212 }
213
214 static std::unique_ptr<symbolize::LLVMSymbolizer> createSymbolizer() {
215   symbolize::LLVMSymbolizer::Options SymbolizerOptions;
216   SymbolizerOptions.Demangle = ClDemangle;
217   SymbolizerOptions.UseSymbolTable = true;
218   return std::unique_ptr<symbolize::LLVMSymbolizer>(
219       new symbolize::LLVMSymbolizer(SymbolizerOptions));
220 }
221
222 // A DILineInfo with address.
223 struct AddrInfo : public DILineInfo {
224   uint64_t Addr;
225
226   AddrInfo(const DILineInfo &DI, uint64_t Addr) : DILineInfo(DI), Addr(Addr) {
227     FileName = normalizeFilename(FileName);
228   }
229
230 private:
231   static std::string normalizeFilename(std::string FileName) {
232     SmallString<256> S(FileName);
233     sys::path::remove_dots(S, /* remove_dot_dot */ true);
234     return S.str().str();
235   }
236 };
237
238 class Blacklists {
239 public:
240   Blacklists()
241       : DefaultBlacklist(createDefaultBlacklist()),
242         UserBlacklist(createUserBlacklist()) {}
243
244   // AddrInfo contains normalized filename. It is important to check it rather
245   // than DILineInfo.
246   bool isBlacklisted(const AddrInfo &AI) {
247     if (DefaultBlacklist && DefaultBlacklist->inSection("fun", AI.FunctionName))
248       return true;
249     if (DefaultBlacklist && DefaultBlacklist->inSection("src", AI.FileName))
250       return true;
251     if (UserBlacklist && UserBlacklist->inSection("fun", AI.FunctionName))
252       return true;
253     if (UserBlacklist && UserBlacklist->inSection("src", AI.FileName))
254       return true;
255     return false;
256   }
257
258 private:
259   static std::unique_ptr<SpecialCaseList> createDefaultBlacklist() {
260     if (!ClUseDefaultBlacklist)
261       return std::unique_ptr<SpecialCaseList>();
262     std::unique_ptr<MemoryBuffer> MB =
263         MemoryBuffer::getMemBuffer(DefaultBlacklistStr);
264     std::string Error;
265     auto Blacklist = SpecialCaseList::create(MB.get(), Error);
266     FailIfNotEmpty(Error);
267     return Blacklist;
268   }
269
270   static std::unique_ptr<SpecialCaseList> createUserBlacklist() {
271     if (ClBlacklist.empty())
272       return std::unique_ptr<SpecialCaseList>();
273
274     return SpecialCaseList::createOrDie({{ClBlacklist}});
275   }
276   std::unique_ptr<SpecialCaseList> DefaultBlacklist;
277   std::unique_ptr<SpecialCaseList> UserBlacklist;
278 };
279
280 // Collect all debug info for given addresses.
281 static std::vector<AddrInfo> getAddrInfo(std::string ObjectFile,
282                                          const std::set<uint64_t> &Addrs,
283                                          bool InlinedCode) {
284   std::vector<AddrInfo> Result;
285   auto Symbolizer(createSymbolizer());
286   Blacklists B;
287
288   for (auto Addr : Addrs) {
289     auto LineInfo = Symbolizer->symbolizeCode(ObjectFile, Addr);
290     FailIfError(LineInfo);
291     auto LineAddrInfo = AddrInfo(*LineInfo, Addr);
292     if (B.isBlacklisted(LineAddrInfo))
293       continue;
294     Result.push_back(LineAddrInfo);
295     if (InlinedCode) {
296       auto InliningInfo = Symbolizer->symbolizeInlinedCode(ObjectFile, Addr);
297       FailIfError(InliningInfo);
298       for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) {
299         auto FrameInfo = InliningInfo->getFrame(I);
300         auto FrameAddrInfo = AddrInfo(FrameInfo, Addr);
301         if (B.isBlacklisted(FrameAddrInfo))
302           continue;
303         Result.push_back(FrameAddrInfo);
304       }
305     }
306   }
307
308   return Result;
309 }
310
311 // Locate __sanitizer_cov* function addresses that are used for coverage
312 // reporting.
313 static std::set<uint64_t>
314 findSanitizerCovFunctions(const object::ObjectFile &O) {
315   std::set<uint64_t> Result;
316
317   for (const object::SymbolRef &Symbol : O.symbols()) {
318     ErrorOr<uint64_t> AddressOrErr = Symbol.getAddress();
319     FailIfError(AddressOrErr);
320
321     Expected<StringRef> NameOrErr = Symbol.getName();
322     FailIfError(errorToErrorCode(NameOrErr.takeError()));
323     StringRef Name = NameOrErr.get();
324
325     if (Name == "__sanitizer_cov" || Name == "__sanitizer_cov_with_check" ||
326         Name == "__sanitizer_cov_trace_func_enter") {
327       if (!(Symbol.getFlags() & object::BasicSymbolRef::SF_Undefined))
328         Result.insert(AddressOrErr.get());
329     }
330   }
331
332   return Result;
333 }
334
335 // Locate addresses of all coverage points in a file. Coverage point
336 // is defined as the 'address of instruction following __sanitizer_cov
337 // call - 1'.
338 static void getObjectCoveragePoints(const object::ObjectFile &O,
339                                     std::set<uint64_t> *Addrs) {
340   Triple TheTriple("unknown-unknown-unknown");
341   TheTriple.setArch(Triple::ArchType(O.getArch()));
342   auto TripleName = TheTriple.getTriple();
343
344   std::string Error;
345   const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
346   FailIfNotEmpty(Error);
347
348   std::unique_ptr<const MCSubtargetInfo> STI(
349       TheTarget->createMCSubtargetInfo(TripleName, "", ""));
350   FailIfEmpty(STI, "no subtarget info for target " + TripleName);
351
352   std::unique_ptr<const MCRegisterInfo> MRI(
353       TheTarget->createMCRegInfo(TripleName));
354   FailIfEmpty(MRI, "no register info for target " + TripleName);
355
356   std::unique_ptr<const MCAsmInfo> AsmInfo(
357       TheTarget->createMCAsmInfo(*MRI, TripleName));
358   FailIfEmpty(AsmInfo, "no asm info for target " + TripleName);
359
360   std::unique_ptr<const MCObjectFileInfo> MOFI(new MCObjectFileInfo);
361   MCContext Ctx(AsmInfo.get(), MRI.get(), MOFI.get());
362   std::unique_ptr<MCDisassembler> DisAsm(
363       TheTarget->createMCDisassembler(*STI, Ctx));
364   FailIfEmpty(DisAsm, "no disassembler info for target " + TripleName);
365
366   std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
367   FailIfEmpty(MII, "no instruction info for target " + TripleName);
368
369   std::unique_ptr<const MCInstrAnalysis> MIA(
370       TheTarget->createMCInstrAnalysis(MII.get()));
371   FailIfEmpty(MIA, "no instruction analysis info for target " + TripleName);
372
373   auto SanCovAddrs = findSanitizerCovFunctions(O);
374   if (SanCovAddrs.empty())
375     Fail("__sanitizer_cov* functions not found");
376
377   for (object::SectionRef Section : O.sections()) {
378     if (Section.isVirtual() || !Section.isText()) // llvm-objdump does the same.
379       continue;
380     uint64_t SectionAddr = Section.getAddress();
381     uint64_t SectSize = Section.getSize();
382     if (!SectSize)
383       continue;
384
385     StringRef BytesStr;
386     FailIfError(Section.getContents(BytesStr));
387     ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
388                             BytesStr.size());
389
390     for (uint64_t Index = 0, Size = 0; Index < Section.getSize();
391          Index += Size) {
392       MCInst Inst;
393       if (!DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
394                                   SectionAddr + Index, nulls(), nulls())) {
395         if (Size == 0)
396           Size = 1;
397         continue;
398       }
399       uint64_t Addr = Index + SectionAddr;
400       // Sanitizer coverage uses the address of the next instruction - 1.
401       uint64_t CovPoint = Addr + Size - 1;
402       uint64_t Target;
403       if (MIA->isCall(Inst) &&
404           MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target) &&
405           SanCovAddrs.find(Target) != SanCovAddrs.end())
406         Addrs->insert(CovPoint);
407     }
408   }
409 }
410
411 static void
412 visitObjectFiles(const object::Archive &A,
413                  std::function<void(const object::ObjectFile &)> Fn) {
414   for (auto &ErrorOrChild : A.children()) {
415     FailIfError(ErrorOrChild);
416     const object::Archive::Child &C = *ErrorOrChild;
417     Expected<std::unique_ptr<object::Binary>> ChildOrErr = C.getAsBinary();
418     FailIfError(errorToErrorCode(ChildOrErr.takeError()));
419     if (auto *O = dyn_cast<object::ObjectFile>(&*ChildOrErr.get()))
420       Fn(*O);
421     else
422       FailIfError(object::object_error::invalid_file_type);
423   }
424 }
425
426 static void
427 visitObjectFiles(std::string FileName,
428                  std::function<void(const object::ObjectFile &)> Fn) {
429   Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
430       object::createBinary(FileName);
431   if (!BinaryOrErr)
432     FailIfError(errorToErrorCode(BinaryOrErr.takeError()));
433
434   object::Binary &Binary = *BinaryOrErr.get().getBinary();
435   if (object::Archive *A = dyn_cast<object::Archive>(&Binary))
436     visitObjectFiles(*A, Fn);
437   else if (object::ObjectFile *O = dyn_cast<object::ObjectFile>(&Binary))
438     Fn(*O);
439   else
440     FailIfError(object::object_error::invalid_file_type);
441 }
442
443 std::set<uint64_t> findSanitizerCovFunctions(std::string FileName) {
444   std::set<uint64_t> Result;
445   visitObjectFiles(FileName, [&](const object::ObjectFile &O) {
446     auto Addrs = findSanitizerCovFunctions(O);
447     Result.insert(Addrs.begin(), Addrs.end());
448   });
449   return Result;
450 }
451
452 // Locate addresses of all coverage points in a file. Coverage point
453 // is defined as the 'address of instruction following __sanitizer_cov
454 // call - 1'.
455 std::set<uint64_t> getCoveragePoints(std::string FileName) {
456   std::set<uint64_t> Result;
457   visitObjectFiles(FileName, [&](const object::ObjectFile &O) {
458     getObjectCoveragePoints(O, &Result);
459   });
460   return Result;
461 }
462
463 static void printCovPoints(std::string ObjFile, raw_ostream &OS) {
464   for (uint64_t Addr : getCoveragePoints(ObjFile)) {
465     OS << "0x";
466     OS.write_hex(Addr);
467     OS << "\n";
468   }
469 }
470
471 static std::string escapeHtml(const std::string &S) {
472   std::string Result;
473   Result.reserve(S.size());
474   for (char Ch : S) {
475     switch (Ch) {
476     case '&':
477       Result.append("&amp;");
478       break;
479     case '\'':
480       Result.append("&apos;");
481       break;
482     case '"':
483       Result.append("&quot;");
484       break;
485     case '<':
486       Result.append("&lt;");
487       break;
488     case '>':
489       Result.append("&gt;");
490       break;
491     default:
492       Result.push_back(Ch);
493       break;
494     }
495   }
496   return Result;
497 }
498
499 // Adds leading zeroes wrapped in 'lz' style.
500 // Leading zeroes help locate 000% coverage.
501 static std::string formatHtmlPct(size_t Pct) {
502   Pct = std::max(std::size_t{0}, std::min(std::size_t{100}, Pct));
503
504   std::string Num = std::to_string(Pct);
505   std::string Zeroes(3 - Num.size(), '0');
506   if (!Zeroes.empty())
507     Zeroes = "<span class='lz'>" + Zeroes + "</span>";
508
509   return Zeroes + Num;
510 }
511
512 static std::string anchorName(std::string Anchor) {
513   llvm::MD5 Hasher;
514   llvm::MD5::MD5Result Hash;
515   Hasher.update(Anchor);
516   Hasher.final(Hash);
517
518   SmallString<32> HexString;
519   llvm::MD5::stringifyResult(Hash, HexString);
520   return HexString.str().str();
521 }
522
523 static ErrorOr<bool> isCoverageFile(std::string FileName) {
524   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
525       MemoryBuffer::getFile(FileName);
526   if (!BufOrErr) {
527     errs() << "Warning: " << BufOrErr.getError().message() << "("
528            << BufOrErr.getError().value()
529            << "), filename: " << llvm::sys::path::filename(FileName) << "\n";
530     return BufOrErr.getError();
531   }
532   std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
533   if (Buf->getBufferSize() < 8) {
534     return false;
535   }
536   const FileHeader *Header =
537       reinterpret_cast<const FileHeader *>(Buf->getBufferStart());
538   return Header->Magic == BinCoverageMagic;
539 }
540
541 struct CoverageStats {
542   CoverageStats() : AllPoints(0), CovPoints(0), AllFns(0), CovFns(0) {}
543
544   size_t AllPoints;
545   size_t CovPoints;
546   size_t AllFns;
547   size_t CovFns;
548 };
549
550 static raw_ostream &operator<<(raw_ostream &OS, const CoverageStats &Stats) {
551   OS << "all-edges: " << Stats.AllPoints << "\n";
552   OS << "cov-edges: " << Stats.CovPoints << "\n";
553   OS << "all-functions: " << Stats.AllFns << "\n";
554   OS << "cov-functions: " << Stats.CovFns << "\n";
555   return OS;
556 }
557
558 class CoverageData {
559 public:
560   // Read single file coverage data.
561   static ErrorOr<std::unique_ptr<CoverageData>> read(std::string FileName) {
562     ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
563         MemoryBuffer::getFile(FileName);
564     if (!BufOrErr)
565       return BufOrErr.getError();
566     std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
567     if (Buf->getBufferSize() < 8) {
568       errs() << "File too small (<8): " << Buf->getBufferSize();
569       return make_error_code(errc::illegal_byte_sequence);
570     }
571     const FileHeader *Header =
572         reinterpret_cast<const FileHeader *>(Buf->getBufferStart());
573
574     if (Header->Magic != BinCoverageMagic) {
575       errs() << "Wrong magic: " << Header->Magic;
576       return make_error_code(errc::illegal_byte_sequence);
577     }
578
579     auto Addrs = llvm::make_unique<std::set<uint64_t>>();
580
581     switch (Header->Bitness) {
582     case Bitness64:
583       readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
584                          Addrs.get());
585       break;
586     case Bitness32:
587       readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
588                          Addrs.get());
589       break;
590     default:
591       errs() << "Unsupported bitness: " << Header->Bitness;
592       return make_error_code(errc::illegal_byte_sequence);
593     }
594
595     return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));
596   }
597
598   // Merge multiple coverage data together.
599   static std::unique_ptr<CoverageData>
600   merge(const std::vector<std::unique_ptr<CoverageData>> &Covs) {
601     auto Addrs = llvm::make_unique<std::set<uint64_t>>();
602
603     for (const auto &Cov : Covs)
604       Addrs->insert(Cov->Addrs->begin(), Cov->Addrs->end());
605
606     return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));
607   }
608
609   // Read list of files and merges their coverage info.
610   static ErrorOr<std::unique_ptr<CoverageData>>
611   readAndMerge(const std::vector<std::string> &FileNames) {
612     std::vector<std::unique_ptr<CoverageData>> Covs;
613     for (const auto &FileName : FileNames) {
614       auto Cov = read(FileName);
615       if (!Cov)
616         return Cov.getError();
617       Covs.push_back(std::move(Cov.get()));
618     }
619     return merge(Covs);
620   }
621
622   // Print coverage addresses.
623   void printAddrs(raw_ostream &OS) {
624     for (auto Addr : *Addrs) {
625       OS << "0x";
626       OS.write_hex(Addr);
627       OS << "\n";
628     }
629   }
630
631 protected:
632   explicit CoverageData(std::unique_ptr<std::set<uint64_t>> Addrs)
633       : Addrs(std::move(Addrs)) {}
634
635   friend class CoverageDataWithObjectFile;
636
637   std::unique_ptr<std::set<uint64_t>> Addrs;
638 };
639
640 // Coverage data translated into source code line-level information.
641 // Fetches debug info in constructor and calculates various information per
642 // request.
643 class SourceCoverageData {
644 public:
645   enum LineStatus {
646     // coverage information for the line is not available.
647     // default value in maps.
648     UNKNOWN = 0,
649     // the line is fully covered.
650     COVERED = 1,
651     // the line is fully uncovered.
652     NOT_COVERED = 2,
653     // some points in the line a covered, some are not.
654     MIXED = 3
655   };
656
657   SourceCoverageData(std::string ObjectFile, const std::set<uint64_t> &Addrs)
658       : AllCovPoints(getCoveragePoints(ObjectFile)) {
659     if (!std::includes(AllCovPoints.begin(), AllCovPoints.end(), Addrs.begin(),
660                        Addrs.end())) {
661       Fail("Coverage points in binary and .sancov file do not match.");
662     }
663
664     AllAddrInfo = getAddrInfo(ObjectFile, AllCovPoints, true);
665     CovAddrInfo = getAddrInfo(ObjectFile, Addrs, true);
666   }
667
668   // Compute number of coverage points hit/total in a file.
669   // file_name -> <coverage, all_coverage>
670   std::map<std::string, std::pair<size_t, size_t>> computeFileCoverage() {
671     std::map<std::string, std::pair<size_t, size_t>> FileCoverage;
672     auto AllCovPointsByFile =
673         group_by(AllAddrInfo, [](const AddrInfo &AI) { return AI.FileName; });
674     auto CovPointsByFile =
675         group_by(CovAddrInfo, [](const AddrInfo &AI) { return AI.FileName; });
676
677     for (const auto &P : AllCovPointsByFile) {
678       const std::string &FileName = P.first;
679
680       FileCoverage[FileName] =
681           std::make_pair(CovPointsByFile[FileName].size(),
682                          AllCovPointsByFile[FileName].size());
683     }
684     return FileCoverage;
685   }
686
687   // line_number -> line_status.
688   typedef std::map<int, LineStatus> LineStatusMap;
689   // file_name -> LineStatusMap
690   typedef std::map<std::string, LineStatusMap> FileLineStatusMap;
691
692   // fills in the {file_name -> {line_no -> status}} map.
693   FileLineStatusMap computeLineStatusMap() {
694     FileLineStatusMap StatusMap;
695
696     auto AllLocs = group_by(AllAddrInfo, [](const AddrInfo &AI) {
697       return FileLoc{AI.FileName, AI.Line};
698     });
699     auto CovLocs = group_by(CovAddrInfo, [](const AddrInfo &AI) {
700       return FileLoc{AI.FileName, AI.Line};
701     });
702
703     for (const auto &P : AllLocs) {
704       const FileLoc &Loc = P.first;
705       auto I = CovLocs.find(Loc);
706
707       if (I == CovLocs.end()) {
708         StatusMap[Loc.FileName][Loc.Line] = NOT_COVERED;
709       } else {
710         StatusMap[Loc.FileName][Loc.Line] =
711             (I->second.size() == P.second.size()) ? COVERED : MIXED;
712       }
713     }
714     return StatusMap;
715   }
716
717   std::set<FileFn> computeAllFunctions() const {
718     std::set<FileFn> Fns;
719     for (const auto &AI : AllAddrInfo) {
720       Fns.insert(FileFn{AI.FileName, AI.FunctionName});
721     }
722     return Fns;
723   }
724
725   std::set<FileFn> computeCoveredFunctions() const {
726     std::set<FileFn> Fns;
727     auto CovFns = group_by(CovAddrInfo, [](const AddrInfo &AI) {
728       return FileFn{AI.FileName, AI.FunctionName};
729     });
730
731     for (const auto &P : CovFns) {
732       Fns.insert(P.first);
733     }
734     return Fns;
735   }
736
737   std::set<FileFn> computeNotCoveredFunctions() const {
738     std::set<FileFn> Fns;
739
740     auto AllFns = group_by(AllAddrInfo, [](const AddrInfo &AI) {
741       return FileFn{AI.FileName, AI.FunctionName};
742     });
743     auto CovFns = group_by(CovAddrInfo, [](const AddrInfo &AI) {
744       return FileFn{AI.FileName, AI.FunctionName};
745     });
746
747     for (const auto &P : AllFns) {
748       if (CovFns.find(P.first) == CovFns.end()) {
749         Fns.insert(P.first);
750       }
751     }
752     return Fns;
753   }
754
755   // Compute % coverage for each function.
756   std::map<FileFn, int> computeFunctionsCoverage() const {
757     std::map<FileFn, int> FnCoverage;
758     auto AllFns = group_by(AllAddrInfo, [](const AddrInfo &AI) {
759       return FileFn{AI.FileName, AI.FunctionName};
760     });
761
762     auto CovFns = group_by(CovAddrInfo, [](const AddrInfo &AI) {
763       return FileFn{AI.FileName, AI.FunctionName};
764     });
765
766     for (const auto &P : AllFns) {
767       FileFn F = P.first;
768       FnCoverage[F] = CovFns[F].size() * 100 / P.second.size();
769     }
770
771     return FnCoverage;
772   }
773
774   typedef std::map<FileLoc, std::set<std::string>> FunctionLocs;
775   // finds first line number in a file for each function.
776   FunctionLocs resolveFunctions(const std::set<FileFn> &Fns) const {
777     std::vector<AddrInfo> FnAddrs;
778     for (const auto &AI : AllAddrInfo) {
779       if (Fns.find(FileFn{AI.FileName, AI.FunctionName}) != Fns.end())
780         FnAddrs.push_back(AI);
781     }
782
783     auto GroupedAddrs = group_by(FnAddrs, [](const AddrInfo &AI) {
784       return FnLoc{FileLoc{AI.FileName, AI.Line}, AI.FunctionName};
785     });
786
787     FunctionLocs Result;
788     std::string LastFileName;
789     std::set<std::string> ProcessedFunctions;
790
791     for (const auto &P : GroupedAddrs) {
792       const FnLoc &Loc = P.first;
793       std::string FileName = Loc.Loc.FileName;
794       std::string FunctionName = Loc.FunctionName;
795
796       if (LastFileName != FileName)
797         ProcessedFunctions.clear();
798       LastFileName = FileName;
799
800       if (!ProcessedFunctions.insert(FunctionName).second)
801         continue;
802
803       auto FLoc = FileLoc{FileName, Loc.Loc.Line};
804       Result[FLoc].insert(FunctionName);
805     }
806     return Result;
807   }
808
809   std::set<std::string> files() const {
810     std::set<std::string> Files;
811     for (const auto &AI : AllAddrInfo) {
812       Files.insert(AI.FileName);
813     }
814     return Files;
815   }
816
817   void collectStats(CoverageStats *Stats) const {
818     Stats->AllPoints += AllCovPoints.size();
819     Stats->AllFns += computeAllFunctions().size();
820     Stats->CovFns += computeCoveredFunctions().size();
821   }
822
823 private:
824   const std::set<uint64_t> AllCovPoints;
825
826   std::vector<AddrInfo> AllAddrInfo;
827   std::vector<AddrInfo> CovAddrInfo;
828 };
829
830 static void printFunctionLocs(const SourceCoverageData::FunctionLocs &FnLocs,
831                               raw_ostream &OS) {
832   for (const auto &Fns : FnLocs) {
833     for (const auto &Fn : Fns.second) {
834       OS << stripPathPrefix(Fns.first.FileName) << ":" << Fns.first.Line << " "
835          << Fn << "\n";
836     }
837   }
838 }
839
840 // Holder for coverage data + filename of corresponding object file.
841 class CoverageDataWithObjectFile : public CoverageData {
842 public:
843   static ErrorOr<std::unique_ptr<CoverageDataWithObjectFile>>
844   readAndMerge(std::string ObjectFile,
845                const std::vector<std::string> &FileNames) {
846     auto MergedDataOrError = CoverageData::readAndMerge(FileNames);
847     if (!MergedDataOrError)
848       return MergedDataOrError.getError();
849     return std::unique_ptr<CoverageDataWithObjectFile>(
850         new CoverageDataWithObjectFile(ObjectFile,
851                                        std::move(MergedDataOrError.get())));
852   }
853
854   std::string object_file() const { return ObjectFile; }
855
856   // Print list of covered functions.
857   // Line format: <file_name>:<line> <function_name>
858   void printCoveredFunctions(raw_ostream &OS) const {
859     SourceCoverageData SCovData(ObjectFile, *Addrs);
860     auto CoveredFns = SCovData.computeCoveredFunctions();
861     printFunctionLocs(SCovData.resolveFunctions(CoveredFns), OS);
862   }
863
864   // Print list of not covered functions.
865   // Line format: <file_name>:<line> <function_name>
866   void printNotCoveredFunctions(raw_ostream &OS) const {
867     SourceCoverageData SCovData(ObjectFile, *Addrs);
868     auto NotCoveredFns = SCovData.computeNotCoveredFunctions();
869     printFunctionLocs(SCovData.resolveFunctions(NotCoveredFns), OS);
870   }
871
872   void printReport(raw_ostream &OS) const {
873     SourceCoverageData SCovData(ObjectFile, *Addrs);
874     auto LineStatusMap = SCovData.computeLineStatusMap();
875
876     std::set<FileFn> AllFns = SCovData.computeAllFunctions();
877     // file_loc -> set[function_name]
878     auto AllFnsByLoc = SCovData.resolveFunctions(AllFns);
879     auto FileCoverage = SCovData.computeFileCoverage();
880
881     auto FnCoverage = SCovData.computeFunctionsCoverage();
882     auto FnCoverageByFile =
883         group_by(FnCoverage, [](const std::pair<FileFn, int> &FileFn) {
884           return FileFn.first.FileName;
885         });
886
887     // TOC
888
889     size_t NotCoveredFilesCount = 0;
890     std::set<std::string> Files = SCovData.files();
891
892     // Covered Files.
893     OS << "<details open><summary>Touched Files</summary>\n";
894     OS << "<table>\n";
895     OS << "<tr><th>File</th><th>Coverage %</th>";
896     OS << "<th>Hit (Total) Fns</th></tr>\n";
897     for (const auto &FileName : Files) {
898       std::pair<size_t, size_t> FC = FileCoverage[FileName];
899       if (FC.first == 0) {
900         NotCoveredFilesCount++;
901         continue;
902       }
903       size_t CovPct = FC.second == 0 ? 100 : 100 * FC.first / FC.second;
904
905       OS << "<tr><td><a href=\"#" << anchorName(FileName) << "\">"
906          << stripPathPrefix(FileName) << "</a></td>"
907          << "<td>" << formatHtmlPct(CovPct) << "%</td>"
908          << "<td>" << FC.first << " (" << FC.second << ")"
909          << "</tr>\n";
910     }
911     OS << "</table>\n";
912     OS << "</details>\n";
913
914     // Not covered files.
915     if (NotCoveredFilesCount) {
916       OS << "<details><summary>Not Touched Files</summary>\n";
917       OS << "<table>\n";
918       for (const auto &FileName : Files) {
919         std::pair<size_t, size_t> FC = FileCoverage[FileName];
920         if (FC.first == 0)
921           OS << "<tr><td>" << stripPathPrefix(FileName) << "</td>\n";
922       }
923       OS << "</table>\n";
924       OS << "</details>\n";
925     } else {
926       OS << "<p>Congratulations! All source files are touched.</p>\n";
927     }
928
929     // Source
930     for (const auto &FileName : Files) {
931       std::pair<size_t, size_t> FC = FileCoverage[FileName];
932       if (FC.first == 0)
933         continue;
934       OS << "<a name=\"" << anchorName(FileName) << "\"></a>\n";
935       OS << "<h2>" << stripPathPrefix(FileName) << "</h2>\n";
936       OS << "<details open><summary>Function Coverage</summary>";
937       OS << "<div class='fnlist'>\n";
938
939       auto &FileFnCoverage = FnCoverageByFile[FileName];
940
941       for (const auto &P : FileFnCoverage) {
942         std::string FunctionName = P.first.FunctionName;
943
944         OS << "<div class='fn' style='order: " << P.second << "'>";
945         OS << "<span class='pct'>" << formatHtmlPct(P.second)
946            << "%</span>&nbsp;";
947         OS << "<span class='name'><a href=\"#"
948            << anchorName(FileName + "::" + FunctionName) << "\">";
949         OS << escapeHtml(FunctionName) << "</a></span>";
950         OS << "</div>\n";
951       }
952       OS << "</div></details>\n";
953
954       ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
955           MemoryBuffer::getFile(FileName);
956       if (!BufOrErr) {
957         OS << "Error reading file: " << FileName << " : "
958            << BufOrErr.getError().message() << "("
959            << BufOrErr.getError().value() << ")\n";
960         continue;
961       }
962
963       OS << "<pre>\n";
964       const auto &LineStatuses = LineStatusMap[FileName];
965       for (line_iterator I = line_iterator(*BufOrErr.get(), false);
966            !I.is_at_eof(); ++I) {
967         uint32_t Line = I.line_number();
968         { // generate anchors (if any);
969           FileLoc Loc = FileLoc{FileName, Line};
970           auto It = AllFnsByLoc.find(Loc);
971           if (It != AllFnsByLoc.end()) {
972             for (const std::string &Fn : It->second) {
973               OS << "<a name=\"" << anchorName(FileName + "::" + Fn)
974                  << "\"></a>";
975             };
976           }
977         }
978
979         OS << "<span ";
980         auto LIT = LineStatuses.find(I.line_number());
981         auto Status = (LIT != LineStatuses.end()) ? LIT->second
982                                                   : SourceCoverageData::UNKNOWN;
983         switch (Status) {
984         case SourceCoverageData::UNKNOWN:
985           OS << "class=unknown";
986           break;
987         case SourceCoverageData::COVERED:
988           OS << "class=covered";
989           break;
990         case SourceCoverageData::NOT_COVERED:
991           OS << "class=notcovered";
992           break;
993         case SourceCoverageData::MIXED:
994           OS << "class=mixed";
995           break;
996         }
997         OS << ">";
998         OS << escapeHtml(*I) << "</span>\n";
999       }
1000       OS << "</pre>\n";
1001     }
1002   }
1003
1004   void collectStats(CoverageStats *Stats) const {
1005     Stats->CovPoints += Addrs->size();
1006
1007     SourceCoverageData SCovData(ObjectFile, *Addrs);
1008     SCovData.collectStats(Stats);
1009   }
1010
1011 private:
1012   CoverageDataWithObjectFile(std::string ObjectFile,
1013                              std::unique_ptr<CoverageData> Coverage)
1014       : CoverageData(std::move(Coverage->Addrs)),
1015         ObjectFile(std::move(ObjectFile)) {}
1016   const std::string ObjectFile;
1017 };
1018
1019 // Multiple coverage files data organized by object file.
1020 class CoverageDataSet {
1021 public:
1022   static ErrorOr<std::unique_ptr<CoverageDataSet>>
1023   readCmdArguments(std::vector<std::string> FileNames) {
1024     // Short name => file name.
1025     std::map<std::string, std::string> ObjFiles;
1026     std::string FirstObjFile;
1027     std::set<std::string> CovFiles;
1028
1029     // Partition input values into coverage/object files.
1030     for (const auto &FileName : FileNames) {
1031       auto ErrorOrIsCoverage = isCoverageFile(FileName);
1032       if (!ErrorOrIsCoverage)
1033         continue;
1034       if (ErrorOrIsCoverage.get()) {
1035         CovFiles.insert(FileName);
1036       } else {
1037         auto ShortFileName = llvm::sys::path::filename(FileName);
1038         if (ObjFiles.find(ShortFileName) != ObjFiles.end()) {
1039           Fail("Duplicate binary file with a short name: " + ShortFileName);
1040         }
1041
1042         ObjFiles[ShortFileName] = FileName;
1043         if (FirstObjFile.empty())
1044           FirstObjFile = FileName;
1045       }
1046     }
1047
1048     Regex SancovRegex("(.*)\\.[0-9]+\\.sancov");
1049     SmallVector<StringRef, 2> Components;
1050
1051     // Object file => list of corresponding coverage file names.
1052     auto CoverageByObjFile = group_by(CovFiles, [&](std::string FileName) {
1053       auto ShortFileName = llvm::sys::path::filename(FileName);
1054       auto Ok = SancovRegex.match(ShortFileName, &Components);
1055       if (!Ok) {
1056         Fail("Can't match coverage file name against "
1057              "<module_name>.<pid>.sancov pattern: " +
1058              FileName);
1059       }
1060
1061       auto Iter = ObjFiles.find(Components[1]);
1062       if (Iter == ObjFiles.end()) {
1063         Fail("Object file for coverage not found: " + FileName);
1064       }
1065       return Iter->second;
1066     });
1067
1068     // Read coverage.
1069     std::vector<std::unique_ptr<CoverageDataWithObjectFile>> MergedCoverage;
1070     for (const auto &Pair : CoverageByObjFile) {
1071       if (findSanitizerCovFunctions(Pair.first).empty()) {
1072         for (const auto &FileName : Pair.second) {
1073           CovFiles.erase(FileName);
1074         }
1075
1076         errs()
1077             << "Ignoring " << Pair.first
1078             << " and its coverage because  __sanitizer_cov* functions were not "
1079                "found.\n";
1080         continue;
1081       }
1082
1083       auto DataOrError =
1084           CoverageDataWithObjectFile::readAndMerge(Pair.first, Pair.second);
1085       FailIfError(DataOrError);
1086       MergedCoverage.push_back(std::move(DataOrError.get()));
1087     }
1088
1089     return std::unique_ptr<CoverageDataSet>(
1090         new CoverageDataSet(FirstObjFile, &MergedCoverage, CovFiles));
1091   }
1092
1093   void printCoveredFunctions(raw_ostream &OS) const {
1094     for (const auto &Cov : Coverage) {
1095       Cov->printCoveredFunctions(OS);
1096     }
1097   }
1098
1099   void printNotCoveredFunctions(raw_ostream &OS) const {
1100     for (const auto &Cov : Coverage) {
1101       Cov->printNotCoveredFunctions(OS);
1102     }
1103   }
1104
1105   void printStats(raw_ostream &OS) const {
1106     CoverageStats Stats;
1107     for (const auto &Cov : Coverage) {
1108       Cov->collectStats(&Stats);
1109     }
1110     OS << Stats;
1111   }
1112
1113   void printReport(raw_ostream &OS) const {
1114     auto Title =
1115         (llvm::sys::path::filename(MainObjFile) + " Coverage Report").str();
1116
1117     OS << "<html>\n";
1118     OS << "<head>\n";
1119
1120     // Stylesheet
1121     OS << "<style>\n";
1122     OS << ".covered { background: #7F7; }\n";
1123     OS << ".notcovered { background: #F77; }\n";
1124     OS << ".mixed { background: #FF7; }\n";
1125     OS << "summary { font-weight: bold; }\n";
1126     OS << "details > summary + * { margin-left: 1em; }\n";
1127     OS << ".fnlist { display: flex; flex-flow: column nowrap; }\n";
1128     OS << ".fn { display: flex; flex-flow: row nowrap; }\n";
1129     OS << ".pct { width: 3em; text-align: right; margin-right: 1em; }\n";
1130     OS << ".name { flex: 2; }\n";
1131     OS << ".lz { color: lightgray; }\n";
1132     OS << "</style>\n";
1133     OS << "<title>" << Title << "</title>\n";
1134     OS << "</head>\n";
1135     OS << "<body>\n";
1136
1137     // Title
1138     OS << "<h1>" << Title << "</h1>\n";
1139
1140     // Modules TOC.
1141     if (Coverage.size() > 1) {
1142       for (const auto &CovData : Coverage) {
1143         OS << "<li><a href=\"#module_" << anchorName(CovData->object_file())
1144            << "\">" << llvm::sys::path::filename(CovData->object_file())
1145            << "</a></li>\n";
1146       }
1147     }
1148
1149     for (const auto &CovData : Coverage) {
1150       if (Coverage.size() > 1) {
1151         OS << "<h2>" << llvm::sys::path::filename(CovData->object_file())
1152            << "</h2>\n";
1153       }
1154       OS << "<a name=\"module_" << anchorName(CovData->object_file())
1155          << "\"></a>\n";
1156       CovData->printReport(OS);
1157     }
1158
1159     // About
1160     OS << "<details><summary>About</summary>\n";
1161     OS << "Coverage files:<ul>";
1162     for (const auto &InputFile : CoverageFiles) {
1163       llvm::sys::fs::file_status Status;
1164       llvm::sys::fs::status(InputFile, Status);
1165       OS << "<li>" << stripPathPrefix(InputFile) << " ("
1166          << Status.getLastModificationTime().str() << ")</li>\n";
1167     }
1168     OS << "</ul></details>\n";
1169
1170     OS << "</body>\n";
1171     OS << "</html>\n";
1172   }
1173
1174   bool empty() const { return Coverage.empty(); }
1175
1176 private:
1177   explicit CoverageDataSet(
1178       const std::string &MainObjFile,
1179       std::vector<std::unique_ptr<CoverageDataWithObjectFile>> *Data,
1180       const std::set<std::string> &CoverageFiles)
1181       : MainObjFile(MainObjFile), CoverageFiles(CoverageFiles) {
1182     Data->swap(this->Coverage);
1183   }
1184
1185   const std::string MainObjFile;
1186   std::vector<std::unique_ptr<CoverageDataWithObjectFile>> Coverage;
1187   const std::set<std::string> CoverageFiles;
1188 };
1189
1190 } // namespace
1191
1192 int main(int argc, char **argv) {
1193   // Print stack trace if we signal out.
1194   sys::PrintStackTraceOnErrorSignal();
1195   PrettyStackTraceProgram X(argc, argv);
1196   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
1197
1198   llvm::InitializeAllTargetInfos();
1199   llvm::InitializeAllTargetMCs();
1200   llvm::InitializeAllDisassemblers();
1201
1202   cl::ParseCommandLineOptions(argc, argv, "Sanitizer Coverage Processing Tool");
1203
1204   // -print doesn't need object files.
1205   if (Action == PrintAction) {
1206     auto CovData = CoverageData::readAndMerge(ClInputFiles);
1207     FailIfError(CovData);
1208     CovData.get()->printAddrs(outs());
1209     return 0;
1210   } else if (Action == PrintCovPointsAction) {
1211     // -print-coverage-points doesn't need coverage files.
1212     for (const std::string &ObjFile : ClInputFiles) {
1213       printCovPoints(ObjFile, outs());
1214     }
1215     return 0;
1216   }
1217
1218   auto CovDataSet = CoverageDataSet::readCmdArguments(ClInputFiles);
1219   FailIfError(CovDataSet);
1220
1221   if (CovDataSet.get()->empty()) {
1222     Fail("No coverage files specified.");
1223   }
1224
1225   switch (Action) {
1226   case CoveredFunctionsAction: {
1227     CovDataSet.get()->printCoveredFunctions(outs());
1228     return 0;
1229   }
1230   case NotCoveredFunctionsAction: {
1231     CovDataSet.get()->printNotCoveredFunctions(outs());
1232     return 0;
1233   }
1234   case HtmlReportAction: {
1235     CovDataSet.get()->printReport(outs());
1236     return 0;
1237   }
1238   case StatsAction: {
1239     CovDataSet.get()->printStats(outs());
1240     return 0;
1241   }
1242   case PrintAction:
1243   case PrintCovPointsAction:
1244     llvm_unreachable("unsupported action");
1245   }
1246 }