sancov.cpp 39 KB

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