1 //===-- sancov.cpp --------------------------------------------------------===//
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 // This file is a command-line tool for reading and analyzing sanitizer
9 // coverage.
10 //===----------------------------------------------------------------------===//
11 #include "llvm/ADT/STLExtras.h"
12 #include "llvm/ADT/StringExtras.h"
13 #include "llvm/ADT/Twine.h"
14 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
15 #include "llvm/MC/MCAsmInfo.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCInstrAnalysis.h"
20 #include "llvm/MC/MCInstrInfo.h"
21 #include "llvm/MC/MCObjectFileInfo.h"
22 #include "llvm/MC/MCRegisterInfo.h"
23 #include "llvm/MC/MCSubtargetInfo.h"
24 #include "llvm/MC/MCTargetOptions.h"
25 #include "llvm/Object/Archive.h"
26 #include "llvm/Object/Binary.h"
27 #include "llvm/Object/COFF.h"
28 #include "llvm/Object/MachO.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/JSON.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/SHA1.h"
43 #include "llvm/Support/Signals.h"
44 #include "llvm/Support/SourceMgr.h"
45 #include "llvm/Support/SpecialCaseList.h"
46 #include "llvm/Support/TargetRegistry.h"
47 #include "llvm/Support/TargetSelect.h"
48 #include "llvm/Support/VirtualFileSystem.h"
49 #include "llvm/Support/YAMLParser.h"
50 #include "llvm/Support/raw_ostream.h"
51 
52 #include <set>
53 #include <vector>
54 
55 using namespace llvm;
56 
57 namespace {
58 
59 // --------- COMMAND LINE FLAGS ---------
60 
61 enum ActionType {
62   CoveredFunctionsAction,
63   HtmlReportAction,
64   MergeAction,
65   NotCoveredFunctionsAction,
66   PrintAction,
67   PrintCovPointsAction,
68   StatsAction,
69   SymbolizeAction
70 };
71 
72 cl::opt<ActionType> Action(
73     cl::desc("Action (required)"), cl::Required,
74     cl::values(
75         clEnumValN(PrintAction, "print", "Print coverage addresses"),
76         clEnumValN(PrintCovPointsAction, "print-coverage-pcs",
77                    "Print coverage instrumentation points addresses."),
78         clEnumValN(CoveredFunctionsAction, "covered-functions",
79                    "Print all covered funcions."),
80         clEnumValN(NotCoveredFunctionsAction, "not-covered-functions",
81                    "Print all not covered funcions."),
82         clEnumValN(StatsAction, "print-coverage-stats",
83                    "Print coverage statistics."),
84         clEnumValN(HtmlReportAction, "html-report",
85                    "REMOVED. Use -symbolize & coverage-report-server.py."),
86         clEnumValN(SymbolizeAction, "symbolize",
87                    "Produces a symbolized JSON report from binary report."),
88         clEnumValN(MergeAction, "merge", "Merges reports.")));
89 
90 static cl::list<std::string>
91     ClInputFiles(cl::Positional, cl::OneOrMore,
92                  cl::desc("<action> <binary files...> <.sancov files...> "
93                           "<.symcov files...>"));
94 
95 static cl::opt<bool> ClDemangle("demangle", cl::init(true),
96                                 cl::desc("Print demangled function name."));
97 
98 static cl::opt<bool>
99     ClSkipDeadFiles("skip-dead-files", cl::init(true),
100                     cl::desc("Do not list dead source files in reports."));
101 
102 static cl::opt<std::string> ClStripPathPrefix(
103     "strip_path_prefix", cl::init(""),
104     cl::desc("Strip this prefix from file paths in reports."));
105 
106 static cl::opt<std::string>
107     ClBlacklist("blacklist", cl::init(""),
108                 cl::desc("Blacklist file (sanitizer blacklist format)."));
109 
110 static cl::opt<bool> ClUseDefaultBlacklist(
111     "use_default_blacklist", cl::init(true), cl::Hidden,
112     cl::desc("Controls if default blacklist should be used."));
113 
114 static const char *const DefaultBlacklistStr = "fun:__sanitizer_.*\n"
115                                                "src:/usr/include/.*\n"
116                                                "src:.*/libc\\+\\+/.*\n";
117 
118 // --------- FORMAT SPECIFICATION ---------
119 
120 struct FileHeader {
121   uint32_t Bitness;
122   uint32_t Magic;
123 };
124 
125 static const uint32_t BinCoverageMagic = 0xC0BFFFFF;
126 static const uint32_t Bitness32 = 0xFFFFFF32;
127 static const uint32_t Bitness64 = 0xFFFFFF64;
128 
129 static const Regex SancovFileRegex("(.*)\\.[0-9]+\\.sancov");
130 static const Regex SymcovFileRegex(".*\\.symcov");
131 
132 // --------- MAIN DATASTRUCTURES ----------
133 
134 // Contents of .sancov file: list of coverage point addresses that were
135 // executed.
136 struct RawCoverage {
RawCoverage__anonf5a75d5b0111::RawCoverage137   explicit RawCoverage(std::unique_ptr<std::set<uint64_t>> Addrs)
138       : Addrs(std::move(Addrs)) {}
139 
140   // Read binary .sancov file.
141   static ErrorOr<std::unique_ptr<RawCoverage>>
142   read(const std::string &FileName);
143 
144   std::unique_ptr<std::set<uint64_t>> Addrs;
145 };
146 
147 // Coverage point has an opaque Id and corresponds to multiple source locations.
148 struct CoveragePoint {
CoveragePoint__anonf5a75d5b0111::CoveragePoint149   explicit CoveragePoint(const std::string &Id) : Id(Id) {}
150 
151   std::string Id;
152   SmallVector<DILineInfo, 1> Locs;
153 };
154 
155 // Symcov file content: set of covered Ids plus information about all available
156 // coverage points.
157 struct SymbolizedCoverage {
158   // Read json .symcov file.
159   static std::unique_ptr<SymbolizedCoverage> read(const std::string &InputFile);
160 
161   std::set<std::string> CoveredIds;
162   std::string BinaryHash;
163   std::vector<CoveragePoint> Points;
164 };
165 
166 struct CoverageStats {
167   size_t AllPoints;
168   size_t CovPoints;
169   size_t AllFns;
170   size_t CovFns;
171 };
172 
173 // --------- ERROR HANDLING ---------
174 
fail(const llvm::Twine & E)175 static void fail(const llvm::Twine &E) {
176   errs() << "ERROR: " << E << "\n";
177   exit(1);
178 }
179 
failIf(bool B,const llvm::Twine & E)180 static void failIf(bool B, const llvm::Twine &E) {
181   if (B)
182     fail(E);
183 }
184 
failIfError(std::error_code Error)185 static void failIfError(std::error_code Error) {
186   if (!Error)
187     return;
188   errs() << "ERROR: " << Error.message() << "(" << Error.value() << ")\n";
189   exit(1);
190 }
191 
failIfError(const ErrorOr<T> & E)192 template <typename T> static void failIfError(const ErrorOr<T> &E) {
193   failIfError(E.getError());
194 }
195 
failIfError(Error Err)196 static void failIfError(Error Err) {
197   if (Err) {
198     logAllUnhandledErrors(std::move(Err), errs(), "ERROR: ");
199     exit(1);
200   }
201 }
202 
failIfError(Expected<T> & E)203 template <typename T> static void failIfError(Expected<T> &E) {
204   failIfError(E.takeError());
205 }
206 
failIfNotEmpty(const llvm::Twine & E)207 static void failIfNotEmpty(const llvm::Twine &E) {
208   if (E.str().empty())
209     return;
210   fail(E);
211 }
212 
213 template <typename T>
failIfEmpty(const std::unique_ptr<T> & Ptr,const std::string & Message)214 static void failIfEmpty(const std::unique_ptr<T> &Ptr,
215                         const std::string &Message) {
216   if (Ptr.get())
217     return;
218   fail(Message);
219 }
220 
221 // ----------- Coverage I/O ----------
222 template <typename T>
readInts(const char * Start,const char * End,std::set<uint64_t> * Ints)223 static void readInts(const char *Start, const char *End,
224                      std::set<uint64_t> *Ints) {
225   const T *S = reinterpret_cast<const T *>(Start);
226   const T *E = reinterpret_cast<const T *>(End);
227   std::copy(S, E, std::inserter(*Ints, Ints->end()));
228 }
229 
230 ErrorOr<std::unique_ptr<RawCoverage>>
read(const std::string & FileName)231 RawCoverage::read(const std::string &FileName) {
232   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
233       MemoryBuffer::getFile(FileName);
234   if (!BufOrErr)
235     return BufOrErr.getError();
236   std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
237   if (Buf->getBufferSize() < 8) {
238     errs() << "File too small (<8): " << Buf->getBufferSize() << '\n';
239     return make_error_code(errc::illegal_byte_sequence);
240   }
241   const FileHeader *Header =
242       reinterpret_cast<const FileHeader *>(Buf->getBufferStart());
243 
244   if (Header->Magic != BinCoverageMagic) {
245     errs() << "Wrong magic: " << Header->Magic << '\n';
246     return make_error_code(errc::illegal_byte_sequence);
247   }
248 
249   auto Addrs = std::make_unique<std::set<uint64_t>>();
250 
251   switch (Header->Bitness) {
252   case Bitness64:
253     readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
254                        Addrs.get());
255     break;
256   case Bitness32:
257     readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
258                        Addrs.get());
259     break;
260   default:
261     errs() << "Unsupported bitness: " << Header->Bitness << '\n';
262     return make_error_code(errc::illegal_byte_sequence);
263   }
264 
265   // Ignore slots that are zero, so a runtime implementation is not required
266   // to compactify the data.
267   Addrs->erase(0);
268 
269   return std::unique_ptr<RawCoverage>(new RawCoverage(std::move(Addrs)));
270 }
271 
272 // Print coverage addresses.
operator <<(raw_ostream & OS,const RawCoverage & CoverageData)273 raw_ostream &operator<<(raw_ostream &OS, const RawCoverage &CoverageData) {
274   for (auto Addr : *CoverageData.Addrs) {
275     OS << "0x";
276     OS.write_hex(Addr);
277     OS << "\n";
278   }
279   return OS;
280 }
281 
operator <<(raw_ostream & OS,const CoverageStats & Stats)282 static raw_ostream &operator<<(raw_ostream &OS, const CoverageStats &Stats) {
283   OS << "all-edges: " << Stats.AllPoints << "\n";
284   OS << "cov-edges: " << Stats.CovPoints << "\n";
285   OS << "all-functions: " << Stats.AllFns << "\n";
286   OS << "cov-functions: " << Stats.CovFns << "\n";
287   return OS;
288 }
289 
290 // Output symbolized information for coverage points in JSON.
291 // Format:
292 // {
293 //   '<file_name>' : {
294 //     '<function_name>' : {
295 //       '<point_id'> : '<line_number>:'<column_number'.
296 //          ....
297 //       }
298 //    }
299 // }
operator <<(json::OStream & W,const std::vector<CoveragePoint> & Points)300 static void operator<<(json::OStream &W,
301                        const std::vector<CoveragePoint> &Points) {
302   // Group points by file.
303   std::map<std::string, std::vector<const CoveragePoint *>> PointsByFile;
304   for (const auto &Point : Points) {
305     for (const DILineInfo &Loc : Point.Locs) {
306       PointsByFile[Loc.FileName].push_back(&Point);
307     }
308   }
309 
310   for (const auto &P : PointsByFile) {
311     std::string FileName = P.first;
312     std::map<std::string, std::vector<const CoveragePoint *>> PointsByFn;
313     for (auto PointPtr : P.second) {
314       for (const DILineInfo &Loc : PointPtr->Locs) {
315         PointsByFn[Loc.FunctionName].push_back(PointPtr);
316       }
317     }
318 
319     W.attributeObject(P.first, [&] {
320       // Group points by function.
321       for (const auto &P : PointsByFn) {
322         std::string FunctionName = P.first;
323         std::set<std::string> WrittenIds;
324 
325         W.attributeObject(FunctionName, [&] {
326           for (const CoveragePoint *Point : P.second) {
327             for (const auto &Loc : Point->Locs) {
328               if (Loc.FileName != FileName || Loc.FunctionName != FunctionName)
329                 continue;
330               if (WrittenIds.find(Point->Id) != WrittenIds.end())
331                 continue;
332 
333               // Output <point_id> : "<line>:<col>".
334               WrittenIds.insert(Point->Id);
335               W.attribute(Point->Id,
336                           (utostr(Loc.Line) + ":" + utostr(Loc.Column)));
337             }
338           }
339         });
340       }
341     });
342   }
343 }
344 
operator <<(json::OStream & W,const SymbolizedCoverage & C)345 static void operator<<(json::OStream &W, const SymbolizedCoverage &C) {
346   W.object([&] {
347     W.attributeArray("covered-points", [&] {
348       for (const std::string &P : C.CoveredIds) {
349         W.value(P);
350       }
351     });
352     W.attribute("binary-hash", C.BinaryHash);
353     W.attributeObject("point-symbol-info", [&] { W << C.Points; });
354   });
355 }
356 
parseScalarString(yaml::Node * N)357 static std::string parseScalarString(yaml::Node *N) {
358   SmallString<64> StringStorage;
359   yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);
360   failIf(!S, "expected string");
361   return std::string(S->getValue(StringStorage));
362 }
363 
364 std::unique_ptr<SymbolizedCoverage>
read(const std::string & InputFile)365 SymbolizedCoverage::read(const std::string &InputFile) {
366   auto Coverage(std::make_unique<SymbolizedCoverage>());
367 
368   std::map<std::string, CoveragePoint> Points;
369   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
370       MemoryBuffer::getFile(InputFile);
371   failIfError(BufOrErr);
372 
373   SourceMgr SM;
374   yaml::Stream S(**BufOrErr, SM);
375 
376   yaml::document_iterator DI = S.begin();
377   failIf(DI == S.end(), "empty document: " + InputFile);
378   yaml::Node *Root = DI->getRoot();
379   failIf(!Root, "expecting root node: " + InputFile);
380   yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);
381   failIf(!Top, "expecting mapping node: " + InputFile);
382 
383   for (auto &KVNode : *Top) {
384     auto Key = parseScalarString(KVNode.getKey());
385 
386     if (Key == "covered-points") {
387       yaml::SequenceNode *Points =
388           dyn_cast<yaml::SequenceNode>(KVNode.getValue());
389       failIf(!Points, "expected array: " + InputFile);
390 
391       for (auto I = Points->begin(), E = Points->end(); I != E; ++I) {
392         Coverage->CoveredIds.insert(parseScalarString(&*I));
393       }
394     } else if (Key == "binary-hash") {
395       Coverage->BinaryHash = parseScalarString(KVNode.getValue());
396     } else if (Key == "point-symbol-info") {
397       yaml::MappingNode *PointSymbolInfo =
398           dyn_cast<yaml::MappingNode>(KVNode.getValue());
399       failIf(!PointSymbolInfo, "expected mapping node: " + InputFile);
400 
401       for (auto &FileKVNode : *PointSymbolInfo) {
402         auto Filename = parseScalarString(FileKVNode.getKey());
403 
404         yaml::MappingNode *FileInfo =
405             dyn_cast<yaml::MappingNode>(FileKVNode.getValue());
406         failIf(!FileInfo, "expected mapping node: " + InputFile);
407 
408         for (auto &FunctionKVNode : *FileInfo) {
409           auto FunctionName = parseScalarString(FunctionKVNode.getKey());
410 
411           yaml::MappingNode *FunctionInfo =
412               dyn_cast<yaml::MappingNode>(FunctionKVNode.getValue());
413           failIf(!FunctionInfo, "expected mapping node: " + InputFile);
414 
415           for (auto &PointKVNode : *FunctionInfo) {
416             auto PointId = parseScalarString(PointKVNode.getKey());
417             auto Loc = parseScalarString(PointKVNode.getValue());
418 
419             size_t ColonPos = Loc.find(':');
420             failIf(ColonPos == std::string::npos, "expected ':': " + InputFile);
421 
422             auto LineStr = Loc.substr(0, ColonPos);
423             auto ColStr = Loc.substr(ColonPos + 1, Loc.size());
424 
425             if (Points.find(PointId) == Points.end())
426               Points.insert(std::make_pair(PointId, CoveragePoint(PointId)));
427 
428             DILineInfo LineInfo;
429             LineInfo.FileName = Filename;
430             LineInfo.FunctionName = FunctionName;
431             char *End;
432             LineInfo.Line = std::strtoul(LineStr.c_str(), &End, 10);
433             LineInfo.Column = std::strtoul(ColStr.c_str(), &End, 10);
434 
435             CoveragePoint *CoveragePoint = &Points.find(PointId)->second;
436             CoveragePoint->Locs.push_back(LineInfo);
437           }
438         }
439       }
440     } else {
441       errs() << "Ignoring unknown key: " << Key << "\n";
442     }
443   }
444 
445   for (auto &KV : Points) {
446     Coverage->Points.push_back(KV.second);
447   }
448 
449   return Coverage;
450 }
451 
452 // ---------- MAIN FUNCTIONALITY ----------
453 
stripPathPrefix(std::string Path)454 std::string stripPathPrefix(std::string Path) {
455   if (ClStripPathPrefix.empty())
456     return Path;
457   size_t Pos = Path.find(ClStripPathPrefix);
458   if (Pos == std::string::npos)
459     return Path;
460   return Path.substr(Pos + ClStripPathPrefix.size());
461 }
462 
createSymbolizer()463 static std::unique_ptr<symbolize::LLVMSymbolizer> createSymbolizer() {
464   symbolize::LLVMSymbolizer::Options SymbolizerOptions;
465   SymbolizerOptions.Demangle = ClDemangle;
466   SymbolizerOptions.UseSymbolTable = true;
467   return std::unique_ptr<symbolize::LLVMSymbolizer>(
468       new symbolize::LLVMSymbolizer(SymbolizerOptions));
469 }
470 
normalizeFilename(const std::string & FileName)471 static std::string normalizeFilename(const std::string &FileName) {
472   SmallString<256> S(FileName);
473   sys::path::remove_dots(S, /* remove_dot_dot */ true);
474   return stripPathPrefix(sys::path::convert_to_slash(std::string(S)));
475 }
476 
477 class Blacklists {
478 public:
Blacklists()479   Blacklists()
480       : DefaultBlacklist(createDefaultBlacklist()),
481         UserBlacklist(createUserBlacklist()) {}
482 
isBlacklisted(const DILineInfo & I)483   bool isBlacklisted(const DILineInfo &I) {
484     if (DefaultBlacklist &&
485         DefaultBlacklist->inSection("sancov", "fun", I.FunctionName))
486       return true;
487     if (DefaultBlacklist &&
488         DefaultBlacklist->inSection("sancov", "src", I.FileName))
489       return true;
490     if (UserBlacklist &&
491         UserBlacklist->inSection("sancov", "fun", I.FunctionName))
492       return true;
493     if (UserBlacklist && UserBlacklist->inSection("sancov", "src", I.FileName))
494       return true;
495     return false;
496   }
497 
498 private:
createDefaultBlacklist()499   static std::unique_ptr<SpecialCaseList> createDefaultBlacklist() {
500     if (!ClUseDefaultBlacklist)
501       return std::unique_ptr<SpecialCaseList>();
502     std::unique_ptr<MemoryBuffer> MB =
503         MemoryBuffer::getMemBuffer(DefaultBlacklistStr);
504     std::string Error;
505     auto Blacklist = SpecialCaseList::create(MB.get(), Error);
506     failIfNotEmpty(Error);
507     return Blacklist;
508   }
509 
createUserBlacklist()510   static std::unique_ptr<SpecialCaseList> createUserBlacklist() {
511     if (ClBlacklist.empty())
512       return std::unique_ptr<SpecialCaseList>();
513 
514     return SpecialCaseList::createOrDie({{ClBlacklist}},
515                                         *vfs::getRealFileSystem());
516   }
517   std::unique_ptr<SpecialCaseList> DefaultBlacklist;
518   std::unique_ptr<SpecialCaseList> UserBlacklist;
519 };
520 
521 static std::vector<CoveragePoint>
getCoveragePoints(const std::string & ObjectFile,const std::set<uint64_t> & Addrs,const std::set<uint64_t> & CoveredAddrs)522 getCoveragePoints(const std::string &ObjectFile,
523                   const std::set<uint64_t> &Addrs,
524                   const std::set<uint64_t> &CoveredAddrs) {
525   std::vector<CoveragePoint> Result;
526   auto Symbolizer(createSymbolizer());
527   Blacklists B;
528 
529   std::set<std::string> CoveredFiles;
530   if (ClSkipDeadFiles) {
531     for (auto Addr : CoveredAddrs) {
532       // TODO: it would be neccessary to set proper section index here.
533       // object::SectionedAddress::UndefSection works for only absolute
534       // addresses.
535       object::SectionedAddress ModuleAddress = {
536           Addr, object::SectionedAddress::UndefSection};
537 
538       auto LineInfo = Symbolizer->symbolizeCode(ObjectFile, ModuleAddress);
539       failIfError(LineInfo);
540       CoveredFiles.insert(LineInfo->FileName);
541       auto InliningInfo =
542           Symbolizer->symbolizeInlinedCode(ObjectFile, ModuleAddress);
543       failIfError(InliningInfo);
544       for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) {
545         auto FrameInfo = InliningInfo->getFrame(I);
546         CoveredFiles.insert(FrameInfo.FileName);
547       }
548     }
549   }
550 
551   for (auto Addr : Addrs) {
552     std::set<DILineInfo> Infos; // deduplicate debug info.
553 
554     // TODO: it would be neccessary to set proper section index here.
555     // object::SectionedAddress::UndefSection works for only absolute addresses.
556     object::SectionedAddress ModuleAddress = {
557         Addr, object::SectionedAddress::UndefSection};
558 
559     auto LineInfo = Symbolizer->symbolizeCode(ObjectFile, ModuleAddress);
560     failIfError(LineInfo);
561     if (ClSkipDeadFiles &&
562         CoveredFiles.find(LineInfo->FileName) == CoveredFiles.end())
563       continue;
564     LineInfo->FileName = normalizeFilename(LineInfo->FileName);
565     if (B.isBlacklisted(*LineInfo))
566       continue;
567 
568     auto Id = utohexstr(Addr, true);
569     auto Point = CoveragePoint(Id);
570     Infos.insert(*LineInfo);
571     Point.Locs.push_back(*LineInfo);
572 
573     auto InliningInfo =
574         Symbolizer->symbolizeInlinedCode(ObjectFile, ModuleAddress);
575     failIfError(InliningInfo);
576     for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) {
577       auto FrameInfo = InliningInfo->getFrame(I);
578       if (ClSkipDeadFiles &&
579           CoveredFiles.find(FrameInfo.FileName) == CoveredFiles.end())
580         continue;
581       FrameInfo.FileName = normalizeFilename(FrameInfo.FileName);
582       if (B.isBlacklisted(FrameInfo))
583         continue;
584       if (Infos.find(FrameInfo) == Infos.end()) {
585         Infos.insert(FrameInfo);
586         Point.Locs.push_back(FrameInfo);
587       }
588     }
589 
590     Result.push_back(Point);
591   }
592 
593   return Result;
594 }
595 
isCoveragePointSymbol(StringRef Name)596 static bool isCoveragePointSymbol(StringRef Name) {
597   return Name == "__sanitizer_cov" || Name == "__sanitizer_cov_with_check" ||
598          Name == "__sanitizer_cov_trace_func_enter" ||
599          Name == "__sanitizer_cov_trace_pc_guard" ||
600          // Mac has '___' prefix
601          Name == "___sanitizer_cov" || Name == "___sanitizer_cov_with_check" ||
602          Name == "___sanitizer_cov_trace_func_enter" ||
603          Name == "___sanitizer_cov_trace_pc_guard";
604 }
605 
606 // Locate __sanitizer_cov* function addresses inside the stubs table on MachO.
findMachOIndirectCovFunctions(const object::MachOObjectFile & O,std::set<uint64_t> * Result)607 static void findMachOIndirectCovFunctions(const object::MachOObjectFile &O,
608                                           std::set<uint64_t> *Result) {
609   MachO::dysymtab_command Dysymtab = O.getDysymtabLoadCommand();
610   MachO::symtab_command Symtab = O.getSymtabLoadCommand();
611 
612   for (const auto &Load : O.load_commands()) {
613     if (Load.C.cmd == MachO::LC_SEGMENT_64) {
614       MachO::segment_command_64 Seg = O.getSegment64LoadCommand(Load);
615       for (unsigned J = 0; J < Seg.nsects; ++J) {
616         MachO::section_64 Sec = O.getSection64(Load, J);
617 
618         uint32_t SectionType = Sec.flags & MachO::SECTION_TYPE;
619         if (SectionType == MachO::S_SYMBOL_STUBS) {
620           uint32_t Stride = Sec.reserved2;
621           uint32_t Cnt = Sec.size / Stride;
622           uint32_t N = Sec.reserved1;
623           for (uint32_t J = 0; J < Cnt && N + J < Dysymtab.nindirectsyms; J++) {
624             uint32_t IndirectSymbol =
625                 O.getIndirectSymbolTableEntry(Dysymtab, N + J);
626             uint64_t Addr = Sec.addr + J * Stride;
627             if (IndirectSymbol < Symtab.nsyms) {
628               object::SymbolRef Symbol = *(O.getSymbolByIndex(IndirectSymbol));
629               Expected<StringRef> Name = Symbol.getName();
630               failIfError(Name);
631               if (isCoveragePointSymbol(Name.get())) {
632                 Result->insert(Addr);
633               }
634             }
635           }
636         }
637       }
638     }
639     if (Load.C.cmd == MachO::LC_SEGMENT) {
640       errs() << "ERROR: 32 bit MachO binaries not supported\n";
641     }
642   }
643 }
644 
645 // Locate __sanitizer_cov* function addresses that are used for coverage
646 // reporting.
647 static std::set<uint64_t>
findSanitizerCovFunctions(const object::ObjectFile & O)648 findSanitizerCovFunctions(const object::ObjectFile &O) {
649   std::set<uint64_t> Result;
650 
651   for (const object::SymbolRef &Symbol : O.symbols()) {
652     Expected<uint64_t> AddressOrErr = Symbol.getAddress();
653     failIfError(AddressOrErr);
654     uint64_t Address = AddressOrErr.get();
655 
656     Expected<StringRef> NameOrErr = Symbol.getName();
657     failIfError(NameOrErr);
658     StringRef Name = NameOrErr.get();
659 
660     Expected<uint32_t> FlagsOrErr = Symbol.getFlags();
661     // TODO: Test this error.
662     failIfError(FlagsOrErr);
663     uint32_t Flags = FlagsOrErr.get();
664 
665     if (!(Flags & object::BasicSymbolRef::SF_Undefined) &&
666         isCoveragePointSymbol(Name)) {
667       Result.insert(Address);
668     }
669   }
670 
671   if (const auto *CO = dyn_cast<object::COFFObjectFile>(&O)) {
672     for (const object::ExportDirectoryEntryRef &Export :
673          CO->export_directories()) {
674       uint32_t RVA;
675       failIfError(Export.getExportRVA(RVA));
676 
677       StringRef Name;
678       failIfError(Export.getSymbolName(Name));
679 
680       if (isCoveragePointSymbol(Name))
681         Result.insert(CO->getImageBase() + RVA);
682     }
683   }
684 
685   if (const auto *MO = dyn_cast<object::MachOObjectFile>(&O)) {
686     findMachOIndirectCovFunctions(*MO, &Result);
687   }
688 
689   return Result;
690 }
691 
getPreviousInstructionPc(uint64_t PC,Triple TheTriple)692 static uint64_t getPreviousInstructionPc(uint64_t PC,
693                                          Triple TheTriple) {
694   if (TheTriple.isARM()) {
695     return (PC - 3) & (~1);
696   } else if (TheTriple.isAArch64()) {
697     return PC - 4;
698   } else if (TheTriple.isMIPS()) {
699     return PC - 8;
700   } else {
701     return PC - 1;
702   }
703 }
704 
705 // Locate addresses of all coverage points in a file. Coverage point
706 // is defined as the 'address of instruction following __sanitizer_cov
707 // call - 1'.
getObjectCoveragePoints(const object::ObjectFile & O,std::set<uint64_t> * Addrs)708 static void getObjectCoveragePoints(const object::ObjectFile &O,
709                                     std::set<uint64_t> *Addrs) {
710   Triple TheTriple("unknown-unknown-unknown");
711   TheTriple.setArch(Triple::ArchType(O.getArch()));
712   auto TripleName = TheTriple.getTriple();
713 
714   std::string Error;
715   const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
716   failIfNotEmpty(Error);
717 
718   std::unique_ptr<const MCSubtargetInfo> STI(
719       TheTarget->createMCSubtargetInfo(TripleName, "", ""));
720   failIfEmpty(STI, "no subtarget info for target " + TripleName);
721 
722   MCTargetOptions MCOptions;
723   std::unique_ptr<const MCRegisterInfo> MRI(
724       TheTarget->createMCRegInfo(TripleName, MCOptions));
725   failIfEmpty(MRI, "no register info for target " + TripleName);
726 
727   std::unique_ptr<const MCAsmInfo> AsmInfo(
728       TheTarget->createMCAsmInfo(*MRI, TripleName, MCOptions));
729   failIfEmpty(AsmInfo, "no asm info for target " + TripleName);
730 
731   std::unique_ptr<const MCObjectFileInfo> MOFI(new MCObjectFileInfo);
732   MCContext Ctx(AsmInfo.get(), MRI.get(), MOFI.get());
733   std::unique_ptr<MCDisassembler> DisAsm(
734       TheTarget->createMCDisassembler(*STI, Ctx));
735   failIfEmpty(DisAsm, "no disassembler info for target " + TripleName);
736 
737   std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
738   failIfEmpty(MII, "no instruction info for target " + TripleName);
739 
740   std::unique_ptr<const MCInstrAnalysis> MIA(
741       TheTarget->createMCInstrAnalysis(MII.get()));
742   failIfEmpty(MIA, "no instruction analysis info for target " + TripleName);
743 
744   auto SanCovAddrs = findSanitizerCovFunctions(O);
745   if (SanCovAddrs.empty())
746     fail("__sanitizer_cov* functions not found");
747 
748   for (object::SectionRef Section : O.sections()) {
749     if (Section.isVirtual() || !Section.isText()) // llvm-objdump does the same.
750       continue;
751     uint64_t SectionAddr = Section.getAddress();
752     uint64_t SectSize = Section.getSize();
753     if (!SectSize)
754       continue;
755 
756     Expected<StringRef> BytesStr = Section.getContents();
757     failIfError(BytesStr);
758     ArrayRef<uint8_t> Bytes = arrayRefFromStringRef(*BytesStr);
759 
760     for (uint64_t Index = 0, Size = 0; Index < Section.getSize();
761          Index += Size) {
762       MCInst Inst;
763       if (!DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
764                                   SectionAddr + Index, nulls())) {
765         if (Size == 0)
766           Size = 1;
767         continue;
768       }
769       uint64_t Addr = Index + SectionAddr;
770       // Sanitizer coverage uses the address of the next instruction - 1.
771       uint64_t CovPoint = getPreviousInstructionPc(Addr + Size, TheTriple);
772       uint64_t Target;
773       if (MIA->isCall(Inst) &&
774           MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target) &&
775           SanCovAddrs.find(Target) != SanCovAddrs.end())
776         Addrs->insert(CovPoint);
777     }
778   }
779 }
780 
781 static void
visitObjectFiles(const object::Archive & A,function_ref<void (const object::ObjectFile &)> Fn)782 visitObjectFiles(const object::Archive &A,
783                  function_ref<void(const object::ObjectFile &)> Fn) {
784   Error Err = Error::success();
785   for (auto &C : A.children(Err)) {
786     Expected<std::unique_ptr<object::Binary>> ChildOrErr = C.getAsBinary();
787     failIfError(ChildOrErr);
788     if (auto *O = dyn_cast<object::ObjectFile>(&*ChildOrErr.get()))
789       Fn(*O);
790     else
791       failIfError(object::object_error::invalid_file_type);
792   }
793   failIfError(std::move(Err));
794 }
795 
796 static void
visitObjectFiles(const std::string & FileName,function_ref<void (const object::ObjectFile &)> Fn)797 visitObjectFiles(const std::string &FileName,
798                  function_ref<void(const object::ObjectFile &)> Fn) {
799   Expected<object::OwningBinary<object::Binary>> BinaryOrErr =
800       object::createBinary(FileName);
801   if (!BinaryOrErr)
802     failIfError(BinaryOrErr);
803 
804   object::Binary &Binary = *BinaryOrErr.get().getBinary();
805   if (object::Archive *A = dyn_cast<object::Archive>(&Binary))
806     visitObjectFiles(*A, Fn);
807   else if (object::ObjectFile *O = dyn_cast<object::ObjectFile>(&Binary))
808     Fn(*O);
809   else
810     failIfError(object::object_error::invalid_file_type);
811 }
812 
813 static std::set<uint64_t>
findSanitizerCovFunctions(const std::string & FileName)814 findSanitizerCovFunctions(const std::string &FileName) {
815   std::set<uint64_t> Result;
816   visitObjectFiles(FileName, [&](const object::ObjectFile &O) {
817     auto Addrs = findSanitizerCovFunctions(O);
818     Result.insert(Addrs.begin(), Addrs.end());
819   });
820   return Result;
821 }
822 
823 // Locate addresses of all coverage points in a file. Coverage point
824 // is defined as the 'address of instruction following __sanitizer_cov
825 // call - 1'.
findCoveragePointAddrs(const std::string & FileName)826 static std::set<uint64_t> findCoveragePointAddrs(const std::string &FileName) {
827   std::set<uint64_t> Result;
828   visitObjectFiles(FileName, [&](const object::ObjectFile &O) {
829     getObjectCoveragePoints(O, &Result);
830   });
831   return Result;
832 }
833 
printCovPoints(const std::string & ObjFile,raw_ostream & OS)834 static void printCovPoints(const std::string &ObjFile, raw_ostream &OS) {
835   for (uint64_t Addr : findCoveragePointAddrs(ObjFile)) {
836     OS << "0x";
837     OS.write_hex(Addr);
838     OS << "\n";
839   }
840 }
841 
isCoverageFile(const std::string & FileName)842 static ErrorOr<bool> isCoverageFile(const std::string &FileName) {
843   auto ShortFileName = llvm::sys::path::filename(FileName);
844   if (!SancovFileRegex.match(ShortFileName))
845     return false;
846 
847   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
848       MemoryBuffer::getFile(FileName);
849   if (!BufOrErr) {
850     errs() << "Warning: " << BufOrErr.getError().message() << "("
851            << BufOrErr.getError().value()
852            << "), filename: " << llvm::sys::path::filename(FileName) << "\n";
853     return BufOrErr.getError();
854   }
855   std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
856   if (Buf->getBufferSize() < 8) {
857     return false;
858   }
859   const FileHeader *Header =
860       reinterpret_cast<const FileHeader *>(Buf->getBufferStart());
861   return Header->Magic == BinCoverageMagic;
862 }
863 
isSymbolizedCoverageFile(const std::string & FileName)864 static bool isSymbolizedCoverageFile(const std::string &FileName) {
865   auto ShortFileName = llvm::sys::path::filename(FileName);
866   return SymcovFileRegex.match(ShortFileName);
867 }
868 
869 static std::unique_ptr<SymbolizedCoverage>
symbolize(const RawCoverage & Data,const std::string ObjectFile)870 symbolize(const RawCoverage &Data, const std::string ObjectFile) {
871   auto Coverage = std::make_unique<SymbolizedCoverage>();
872 
873   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
874       MemoryBuffer::getFile(ObjectFile);
875   failIfError(BufOrErr);
876   SHA1 Hasher;
877   Hasher.update((*BufOrErr)->getBuffer());
878   Coverage->BinaryHash = toHex(Hasher.final());
879 
880   Blacklists B;
881   auto Symbolizer(createSymbolizer());
882 
883   for (uint64_t Addr : *Data.Addrs) {
884     // TODO: it would be neccessary to set proper section index here.
885     // object::SectionedAddress::UndefSection works for only absolute addresses.
886     auto LineInfo = Symbolizer->symbolizeCode(
887         ObjectFile, {Addr, object::SectionedAddress::UndefSection});
888     failIfError(LineInfo);
889     if (B.isBlacklisted(*LineInfo))
890       continue;
891 
892     Coverage->CoveredIds.insert(utohexstr(Addr, true));
893   }
894 
895   std::set<uint64_t> AllAddrs = findCoveragePointAddrs(ObjectFile);
896   if (!std::includes(AllAddrs.begin(), AllAddrs.end(), Data.Addrs->begin(),
897                      Data.Addrs->end())) {
898     fail("Coverage points in binary and .sancov file do not match.");
899   }
900   Coverage->Points = getCoveragePoints(ObjectFile, AllAddrs, *Data.Addrs);
901   return Coverage;
902 }
903 
904 struct FileFn {
operator <__anonf5a75d5b0111::FileFn905   bool operator<(const FileFn &RHS) const {
906     return std::tie(FileName, FunctionName) <
907            std::tie(RHS.FileName, RHS.FunctionName);
908   }
909 
910   std::string FileName;
911   std::string FunctionName;
912 };
913 
914 static std::set<FileFn>
computeFunctions(const std::vector<CoveragePoint> & Points)915 computeFunctions(const std::vector<CoveragePoint> &Points) {
916   std::set<FileFn> Fns;
917   for (const auto &Point : Points) {
918     for (const auto &Loc : Point.Locs) {
919       Fns.insert(FileFn{Loc.FileName, Loc.FunctionName});
920     }
921   }
922   return Fns;
923 }
924 
925 static std::set<FileFn>
computeNotCoveredFunctions(const SymbolizedCoverage & Coverage)926 computeNotCoveredFunctions(const SymbolizedCoverage &Coverage) {
927   auto Fns = computeFunctions(Coverage.Points);
928 
929   for (const auto &Point : Coverage.Points) {
930     if (Coverage.CoveredIds.find(Point.Id) == Coverage.CoveredIds.end())
931       continue;
932 
933     for (const auto &Loc : Point.Locs) {
934       Fns.erase(FileFn{Loc.FileName, Loc.FunctionName});
935     }
936   }
937 
938   return Fns;
939 }
940 
941 static std::set<FileFn>
computeCoveredFunctions(const SymbolizedCoverage & Coverage)942 computeCoveredFunctions(const SymbolizedCoverage &Coverage) {
943   auto AllFns = computeFunctions(Coverage.Points);
944   std::set<FileFn> Result;
945 
946   for (const auto &Point : Coverage.Points) {
947     if (Coverage.CoveredIds.find(Point.Id) == Coverage.CoveredIds.end())
948       continue;
949 
950     for (const auto &Loc : Point.Locs) {
951       Result.insert(FileFn{Loc.FileName, Loc.FunctionName});
952     }
953   }
954 
955   return Result;
956 }
957 
958 typedef std::map<FileFn, std::pair<uint32_t, uint32_t>> FunctionLocs;
959 // finds first location in a file for each function.
resolveFunctions(const SymbolizedCoverage & Coverage,const std::set<FileFn> & Fns)960 static FunctionLocs resolveFunctions(const SymbolizedCoverage &Coverage,
961                                      const std::set<FileFn> &Fns) {
962   FunctionLocs Result;
963   for (const auto &Point : Coverage.Points) {
964     for (const auto &Loc : Point.Locs) {
965       FileFn Fn = FileFn{Loc.FileName, Loc.FunctionName};
966       if (Fns.find(Fn) == Fns.end())
967         continue;
968 
969       auto P = std::make_pair(Loc.Line, Loc.Column);
970       auto I = Result.find(Fn);
971       if (I == Result.end() || I->second > P) {
972         Result[Fn] = P;
973       }
974     }
975   }
976   return Result;
977 }
978 
printFunctionLocs(const FunctionLocs & FnLocs,raw_ostream & OS)979 static void printFunctionLocs(const FunctionLocs &FnLocs, raw_ostream &OS) {
980   for (const auto &P : FnLocs) {
981     OS << stripPathPrefix(P.first.FileName) << ":" << P.second.first << " "
982        << P.first.FunctionName << "\n";
983   }
984 }
computeStats(const SymbolizedCoverage & Coverage)985 CoverageStats computeStats(const SymbolizedCoverage &Coverage) {
986   CoverageStats Stats = {Coverage.Points.size(), Coverage.CoveredIds.size(),
987                          computeFunctions(Coverage.Points).size(),
988                          computeCoveredFunctions(Coverage).size()};
989   return Stats;
990 }
991 
992 // Print list of covered functions.
993 // Line format: <file_name>:<line> <function_name>
printCoveredFunctions(const SymbolizedCoverage & CovData,raw_ostream & OS)994 static void printCoveredFunctions(const SymbolizedCoverage &CovData,
995                                   raw_ostream &OS) {
996   auto CoveredFns = computeCoveredFunctions(CovData);
997   printFunctionLocs(resolveFunctions(CovData, CoveredFns), OS);
998 }
999 
1000 // Print list of not covered functions.
1001 // Line format: <file_name>:<line> <function_name>
printNotCoveredFunctions(const SymbolizedCoverage & CovData,raw_ostream & OS)1002 static void printNotCoveredFunctions(const SymbolizedCoverage &CovData,
1003                                      raw_ostream &OS) {
1004   auto NotCoveredFns = computeNotCoveredFunctions(CovData);
1005   printFunctionLocs(resolveFunctions(CovData, NotCoveredFns), OS);
1006 }
1007 
1008 // Read list of files and merges their coverage info.
readAndPrintRawCoverage(const std::vector<std::string> & FileNames,raw_ostream & OS)1009 static void readAndPrintRawCoverage(const std::vector<std::string> &FileNames,
1010                                     raw_ostream &OS) {
1011   std::vector<std::unique_ptr<RawCoverage>> Covs;
1012   for (const auto &FileName : FileNames) {
1013     auto Cov = RawCoverage::read(FileName);
1014     if (!Cov)
1015       continue;
1016     OS << *Cov.get();
1017   }
1018 }
1019 
1020 static std::unique_ptr<SymbolizedCoverage>
merge(const std::vector<std::unique_ptr<SymbolizedCoverage>> & Coverages)1021 merge(const std::vector<std::unique_ptr<SymbolizedCoverage>> &Coverages) {
1022   if (Coverages.empty())
1023     return nullptr;
1024 
1025   auto Result = std::make_unique<SymbolizedCoverage>();
1026 
1027   for (size_t I = 0; I < Coverages.size(); ++I) {
1028     const SymbolizedCoverage &Coverage = *Coverages[I];
1029     std::string Prefix;
1030     if (Coverages.size() > 1) {
1031       // prefix is not needed when there's only one file.
1032       Prefix = utostr(I);
1033     }
1034 
1035     for (const auto &Id : Coverage.CoveredIds) {
1036       Result->CoveredIds.insert(Prefix + Id);
1037     }
1038 
1039     for (const auto &CovPoint : Coverage.Points) {
1040       CoveragePoint NewPoint(CovPoint);
1041       NewPoint.Id = Prefix + CovPoint.Id;
1042       Result->Points.push_back(NewPoint);
1043     }
1044   }
1045 
1046   if (Coverages.size() == 1) {
1047     Result->BinaryHash = Coverages[0]->BinaryHash;
1048   }
1049 
1050   return Result;
1051 }
1052 
1053 static std::unique_ptr<SymbolizedCoverage>
readSymbolizeAndMergeCmdArguments(std::vector<std::string> FileNames)1054 readSymbolizeAndMergeCmdArguments(std::vector<std::string> FileNames) {
1055   std::vector<std::unique_ptr<SymbolizedCoverage>> Coverages;
1056 
1057   {
1058     // Short name => file name.
1059     std::map<std::string, std::string> ObjFiles;
1060     std::string FirstObjFile;
1061     std::set<std::string> CovFiles;
1062 
1063     // Partition input values into coverage/object files.
1064     for (const auto &FileName : FileNames) {
1065       if (isSymbolizedCoverageFile(FileName)) {
1066         Coverages.push_back(SymbolizedCoverage::read(FileName));
1067       }
1068 
1069       auto ErrorOrIsCoverage = isCoverageFile(FileName);
1070       if (!ErrorOrIsCoverage)
1071         continue;
1072       if (ErrorOrIsCoverage.get()) {
1073         CovFiles.insert(FileName);
1074       } else {
1075         auto ShortFileName = llvm::sys::path::filename(FileName);
1076         if (ObjFiles.find(std::string(ShortFileName)) != ObjFiles.end()) {
1077           fail("Duplicate binary file with a short name: " + ShortFileName);
1078         }
1079 
1080         ObjFiles[std::string(ShortFileName)] = FileName;
1081         if (FirstObjFile.empty())
1082           FirstObjFile = FileName;
1083       }
1084     }
1085 
1086     SmallVector<StringRef, 2> Components;
1087 
1088     // Object file => list of corresponding coverage file names.
1089     std::map<std::string, std::vector<std::string>> CoverageByObjFile;
1090     for (const auto &FileName : CovFiles) {
1091       auto ShortFileName = llvm::sys::path::filename(FileName);
1092       auto Ok = SancovFileRegex.match(ShortFileName, &Components);
1093       if (!Ok) {
1094         fail("Can't match coverage file name against "
1095              "<module_name>.<pid>.sancov pattern: " +
1096              FileName);
1097       }
1098 
1099       auto Iter = ObjFiles.find(std::string(Components[1]));
1100       if (Iter == ObjFiles.end()) {
1101         fail("Object file for coverage not found: " + FileName);
1102       }
1103 
1104       CoverageByObjFile[Iter->second].push_back(FileName);
1105     };
1106 
1107     for (const auto &Pair : ObjFiles) {
1108       auto FileName = Pair.second;
1109       if (CoverageByObjFile.find(FileName) == CoverageByObjFile.end())
1110         errs() << "WARNING: No coverage file for " << FileName << "\n";
1111     }
1112 
1113     // Read raw coverage and symbolize it.
1114     for (const auto &Pair : CoverageByObjFile) {
1115       if (findSanitizerCovFunctions(Pair.first).empty()) {
1116         errs()
1117             << "WARNING: Ignoring " << Pair.first
1118             << " and its coverage because  __sanitizer_cov* functions were not "
1119                "found.\n";
1120         continue;
1121       }
1122 
1123       for (const std::string &CoverageFile : Pair.second) {
1124         auto DataOrError = RawCoverage::read(CoverageFile);
1125         failIfError(DataOrError);
1126         Coverages.push_back(symbolize(*DataOrError.get(), Pair.first));
1127       }
1128     }
1129   }
1130 
1131   return merge(Coverages);
1132 }
1133 
1134 } // namespace
1135 
main(int Argc,char ** Argv)1136 int main(int Argc, char **Argv) {
1137   // Print stack trace if we signal out.
1138   sys::PrintStackTraceOnErrorSignal(Argv[0]);
1139   PrettyStackTraceProgram X(Argc, Argv);
1140   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
1141 
1142   llvm::InitializeAllTargetInfos();
1143   llvm::InitializeAllTargetMCs();
1144   llvm::InitializeAllDisassemblers();
1145 
1146   cl::ParseCommandLineOptions(Argc, Argv,
1147       "Sanitizer Coverage Processing Tool (sancov)\n\n"
1148       "  This tool can extract various coverage-related information from: \n"
1149       "  coverage-instrumented binary files, raw .sancov files and their "
1150       "symbolized .symcov version.\n"
1151       "  Depending on chosen action the tool expects different input files:\n"
1152       "    -print-coverage-pcs     - coverage-instrumented binary files\n"
1153       "    -print-coverage         - .sancov files\n"
1154       "    <other actions>         - .sancov files & corresponding binary "
1155       "files, .symcov files\n"
1156       );
1157 
1158   // -print doesn't need object files.
1159   if (Action == PrintAction) {
1160     readAndPrintRawCoverage(ClInputFiles, outs());
1161     return 0;
1162   } else if (Action == PrintCovPointsAction) {
1163     // -print-coverage-points doesn't need coverage files.
1164     for (const std::string &ObjFile : ClInputFiles) {
1165       printCovPoints(ObjFile, outs());
1166     }
1167     return 0;
1168   }
1169 
1170   auto Coverage = readSymbolizeAndMergeCmdArguments(ClInputFiles);
1171   failIf(!Coverage, "No valid coverage files given.");
1172 
1173   switch (Action) {
1174   case CoveredFunctionsAction: {
1175     printCoveredFunctions(*Coverage, outs());
1176     return 0;
1177   }
1178   case NotCoveredFunctionsAction: {
1179     printNotCoveredFunctions(*Coverage, outs());
1180     return 0;
1181   }
1182   case StatsAction: {
1183     outs() << computeStats(*Coverage);
1184     return 0;
1185   }
1186   case MergeAction:
1187   case SymbolizeAction: { // merge & symbolize are synonims.
1188     json::OStream W(outs(), 2);
1189     W << *Coverage;
1190     return 0;
1191   }
1192   case HtmlReportAction:
1193     errs() << "-html-report option is removed: "
1194               "use -symbolize & coverage-report-server.py instead\n";
1195     return 1;
1196   case PrintAction:
1197   case PrintCovPointsAction:
1198     llvm_unreachable("unsupported action");
1199   }
1200 }
1201