[sancov] blacklist support.
[oota-llvm.git] / tools / sancov / sancov.cc
1 //===-- sancov.cc --------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file is a command-line tool for reading and analyzing sanitizer
11 // coverage.
12 //===----------------------------------------------------------------------===//
13 #include "llvm/ADT/STLExtras.h"
14 #include "llvm/DebugInfo/Symbolize/Symbolize.h"
15 #include "llvm/MC/MCAsmInfo.h"
16 #include "llvm/MC/MCContext.h"
17 #include "llvm/MC/MCDisassembler.h"
18 #include "llvm/MC/MCInst.h"
19 #include "llvm/MC/MCInstPrinter.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/Object/Binary.h"
26 #include "llvm/Object/ObjectFile.h"
27 #include "llvm/Support/CommandLine.h"
28 #include "llvm/Support/Errc.h"
29 #include "llvm/Support/ErrorOr.h"
30 #include "llvm/Support/FileSystem.h"
31 #include "llvm/Support/LineIterator.h"
32 #include "llvm/Support/ManagedStatic.h"
33 #include "llvm/Support/MemoryBuffer.h"
34 #include "llvm/Support/Path.h"
35 #include "llvm/Support/PrettyStackTrace.h"
36 #include "llvm/Support/Signals.h"
37 #include "llvm/Support/SpecialCaseList.h"
38 #include "llvm/Support/TargetRegistry.h"
39 #include "llvm/Support/TargetSelect.h"
40 #include "llvm/Support/ToolOutputFile.h"
41 #include "llvm/Support/raw_ostream.h"
42
43 #include <set>
44 #include <stdio.h>
45 #include <string>
46 #include <vector>
47
48 using namespace llvm;
49
50 namespace {
51
52 // --------- COMMAND LINE FLAGS ---------
53
54 enum ActionType {
55   PrintAction,
56   CoveredFunctionsAction,
57   NotCoveredFunctionsAction
58 };
59
60 cl::opt<ActionType> Action(
61     cl::desc("Action (required)"), cl::Required,
62     cl::values(clEnumValN(PrintAction, "print", "Print coverage addresses"),
63                clEnumValN(CoveredFunctionsAction, "covered-functions",
64                           "Print all covered funcions."),
65                clEnumValN(NotCoveredFunctionsAction, "not-covered-functions",
66                           "Print all not covered funcions."),
67                clEnumValEnd));
68
69 static cl::list<std::string> ClInputFiles(cl::Positional, cl::OneOrMore,
70                                           cl::desc("<filenames...>"));
71
72 static cl::opt<std::string>
73     ClBinaryName("obj", cl::Required,
74                  cl::desc("Path to object file to be symbolized"));
75
76 static cl::opt<bool>
77     ClDemangle("demangle", cl::init(true),
78         cl::desc("Print demangled function name."));
79
80 static cl::opt<std::string> ClStripPathPrefix(
81     "strip_path_prefix", cl::init(""),
82     cl::desc("Strip this prefix from file paths in reports."));
83
84 static cl::opt<std::string>
85     ClBlacklist("blacklist", cl::init(""),
86                 cl::desc("Blacklist file (sanitizer blacklist format)."));
87
88 static cl::opt<bool> ClUseDefaultBlacklist(
89     "use_default_blacklist", cl::init(true), cl::Hidden,
90     cl::desc("Controls if default blacklist should be used."));
91
92 static const char *const DefaultBlacklist = "fun:__sanitizer_*";
93
94 // --------- FORMAT SPECIFICATION ---------
95
96 struct FileHeader {
97   uint32_t Bitness;
98   uint32_t Magic;
99 };
100
101 static const uint32_t BinCoverageMagic = 0xC0BFFFFF;
102 static const uint32_t Bitness32 = 0xFFFFFF32;
103 static const uint32_t Bitness64 = 0xFFFFFF64;
104
105 // ---------
106
107 static void FailIfError(std::error_code Error) {
108   if (!Error)
109     return;
110   errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n";
111   exit(1);
112 }
113
114 template <typename T> static void FailIfError(const ErrorOr<T> &E) {
115   FailIfError(E.getError());
116 }
117
118 static void FailIfNotEmpty(const std::string &E) {
119   if (E.empty())
120     return;
121   errs() << "Error: " << E << "\n";
122   exit(1);
123 }
124
125 template <typename T>
126 static void FailIfEmpty(const std::unique_ptr<T> &Ptr,
127                         const std::string &Message) {
128   if (Ptr.get())
129     return;
130   errs() << "Error: " << Message << "\n";
131   exit(1);
132 }
133
134 template <typename T>
135 static void readInts(const char *Start, const char *End,
136                      std::set<uint64_t> *Ints) {
137   const T *S = reinterpret_cast<const T *>(Start);
138   const T *E = reinterpret_cast<const T *>(End);
139   std::copy(S, E, std::inserter(*Ints, Ints->end()));
140 }
141
142 struct FileLoc {
143   bool operator<(const FileLoc &RHS) const {
144     return std::tie(FileName, Line) < std::tie(RHS.FileName, RHS.Line);
145   }
146
147   std::string FileName;
148   uint32_t Line;
149 };
150
151 struct FunctionLoc {
152   bool operator<(const FunctionLoc &RHS) const {
153     return std::tie(Loc, FunctionName) < std::tie(RHS.Loc, RHS.FunctionName);
154   }
155
156   FileLoc Loc;
157   std::string FunctionName;
158 };
159
160 std::string stripPathPrefix(std::string Path) {
161   if (ClStripPathPrefix.empty())
162     return Path;
163   size_t Pos = Path.find(ClStripPathPrefix);
164   if (Pos == std::string::npos)
165     return Path;
166   return Path.substr(Pos + ClStripPathPrefix.size());
167 }
168
169 // Compute [FileLoc -> FunctionName] map for given addresses.
170 static std::map<FileLoc, std::string>
171 computeFunctionsMap(const std::set<uint64_t> &Addrs) {
172   std::map<FileLoc, std::string> Fns;
173
174   symbolize::LLVMSymbolizer::Options SymbolizerOptions;
175   SymbolizerOptions.Demangle = ClDemangle;
176   SymbolizerOptions.UseSymbolTable = true;
177   symbolize::LLVMSymbolizer Symbolizer(SymbolizerOptions);
178
179   // Fill in Fns map.
180   for (auto Addr : Addrs) {
181     auto InliningInfo = Symbolizer.symbolizeInlinedCode(ClBinaryName, Addr);
182     FailIfError(InliningInfo);
183     for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) {
184       auto FrameInfo = InliningInfo->getFrame(I);
185       SmallString<256> FileName(FrameInfo.FileName);
186       sys::path::remove_dots(FileName, /* remove_dot_dot */ true);
187       FileLoc Loc = {FileName.str(), FrameInfo.Line};
188       Fns[Loc] = FrameInfo.FunctionName;
189     }
190   }
191
192   return Fns;
193 }
194
195 // Compute functions for given addresses. It keeps only the first
196 // occurence of a function within a file.
197 std::set<FunctionLoc> computeFunctionLocs(const std::set<uint64_t> &Addrs) {
198   std::map<FileLoc, std::string> Fns = computeFunctionsMap(Addrs);
199
200   std::set<FunctionLoc> Result;
201   std::string LastFileName;
202   std::set<std::string> ProcessedFunctions;
203
204   for (const auto &P : Fns) {
205     std::string FileName = P.first.FileName;
206     std::string FunctionName = P.second;
207
208     if (LastFileName != FileName)
209       ProcessedFunctions.clear();
210     LastFileName = FileName;
211
212     if (!ProcessedFunctions.insert(FunctionName).second)
213       continue;
214
215     Result.insert(FunctionLoc{P.first, P.second});
216   }
217
218   return Result;
219 }
220
221 // Locate __sanitizer_cov* function addresses that are used for coverage
222 // reporting.
223 static std::set<uint64_t>
224 findSanitizerCovFunctions(const object::ObjectFile &O) {
225   std::set<uint64_t> Result;
226
227   for (const object::SymbolRef &Symbol : O.symbols()) {
228     ErrorOr<uint64_t> AddressOrErr = Symbol.getAddress();
229     FailIfError(AddressOrErr);
230
231     ErrorOr<StringRef> NameOrErr = Symbol.getName();
232     FailIfError(NameOrErr);
233     StringRef Name = NameOrErr.get();
234
235     if (Name == "__sanitizer_cov" || Name == "__sanitizer_cov_with_check" ||
236         Name == "__sanitizer_cov_trace_func_enter") {
237       Result.insert(AddressOrErr.get());
238     }
239   }
240
241   if (Result.empty())
242     FailIfNotEmpty("__sanitizer_cov* functions not found");
243
244   return Result;
245 }
246
247 // Locate addresses of all coverage points in a file. Coverage point
248 // is defined as the 'address of instruction following __sanitizer_cov
249 // call - 1'.
250 static void getObjectCoveragePoints(const object::ObjectFile &O,
251                                     std::set<uint64_t> *Addrs) {
252   Triple TheTriple("unknown-unknown-unknown");
253   TheTriple.setArch(Triple::ArchType(O.getArch()));
254   auto TripleName = TheTriple.getTriple();
255
256   std::string Error;
257   const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);
258   FailIfNotEmpty(Error);
259
260   std::unique_ptr<const MCSubtargetInfo> STI(
261       TheTarget->createMCSubtargetInfo(TripleName, "", ""));
262   FailIfEmpty(STI, "no subtarget info for target " + TripleName);
263
264   std::unique_ptr<const MCRegisterInfo> MRI(
265       TheTarget->createMCRegInfo(TripleName));
266   FailIfEmpty(MRI, "no register info for target " + TripleName);
267
268   std::unique_ptr<const MCAsmInfo> AsmInfo(
269       TheTarget->createMCAsmInfo(*MRI, TripleName));
270   FailIfEmpty(AsmInfo, "no asm info for target " + TripleName);
271
272   std::unique_ptr<const MCObjectFileInfo> MOFI(new MCObjectFileInfo);
273   MCContext Ctx(AsmInfo.get(), MRI.get(), MOFI.get());
274   std::unique_ptr<MCDisassembler> DisAsm(
275       TheTarget->createMCDisassembler(*STI, Ctx));
276   FailIfEmpty(DisAsm, "no disassembler info for target " + TripleName);
277
278   std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());
279   FailIfEmpty(MII, "no instruction info for target " + TripleName);
280
281   std::unique_ptr<const MCInstrAnalysis> MIA(
282       TheTarget->createMCInstrAnalysis(MII.get()));
283   FailIfEmpty(MIA, "no instruction analysis info for target " + TripleName);
284
285   auto SanCovAddrs = findSanitizerCovFunctions(O);
286
287   for (const auto Section : O.sections()) {
288     if (Section.isVirtual() || !Section.isText()) // llvm-objdump does the same.
289       continue;
290     uint64_t SectionAddr = Section.getAddress();
291     uint64_t SectSize = Section.getSize();
292     if (!SectSize)
293       continue;
294
295     StringRef SectionName;
296     FailIfError(Section.getName(SectionName));
297
298     StringRef BytesStr;
299     FailIfError(Section.getContents(BytesStr));
300     ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),
301                             BytesStr.size());
302
303     for (uint64_t Index = 0, Size = 0; Index < Section.getSize();
304          Index += Size) {
305       MCInst Inst;
306       if (!DisAsm->getInstruction(Inst, Size, Bytes.slice(Index),
307                                   SectionAddr + Index, nulls(), nulls())) {
308         if (Size == 0)
309           Size = 1;
310         continue;
311       }
312       uint64_t Target;
313       if (MIA->isCall(Inst) &&
314           MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target)) {
315         if (SanCovAddrs.find(Target) != SanCovAddrs.end()) {
316           // Sanitizer coverage uses the address of the next instruction - 1.
317           Addrs->insert(Index + SectionAddr + Size - 1);
318         }
319       }
320     }
321   }
322 }
323
324 static void getArchiveCoveragePoints(const object::Archive &A,
325                                      std::set<uint64_t> *Addrs) {
326   for (auto &ErrorOrChild : A.children()) {
327     FailIfError(ErrorOrChild);
328     const object::Archive::Child &C = *ErrorOrChild;
329     ErrorOr<std::unique_ptr<object::Binary>> ChildOrErr = C.getAsBinary();
330     FailIfError(ChildOrErr);
331     if (object::ObjectFile *O =
332             dyn_cast<object::ObjectFile>(&*ChildOrErr.get()))
333       getObjectCoveragePoints(*O, Addrs);
334     else
335       FailIfError(object::object_error::invalid_file_type);
336   }
337 }
338
339 // Locate addresses of all coverage points in a file. Coverage point
340 // is defined as the 'address of instruction following __sanitizer_cov
341 // call - 1'.
342 std::set<uint64_t> getCoveragePoints(std::string FileName) {
343   std::set<uint64_t> Result;
344
345   ErrorOr<object::OwningBinary<object::Binary>> BinaryOrErr =
346       object::createBinary(FileName);
347   FailIfError(BinaryOrErr);
348
349   object::Binary &Binary = *BinaryOrErr.get().getBinary();
350   if (object::Archive *A = dyn_cast<object::Archive>(&Binary))
351     getArchiveCoveragePoints(*A, &Result);
352   else if (object::ObjectFile *O = dyn_cast<object::ObjectFile>(&Binary))
353     getObjectCoveragePoints(*O, &Result);
354   else
355     FailIfError(object::object_error::invalid_file_type);
356
357   return Result;
358 }
359
360 static std::unique_ptr<SpecialCaseList> createDefaultBlacklist() {
361   if (!ClUseDefaultBlacklist) 
362     return std::unique_ptr<SpecialCaseList>();
363   std::unique_ptr<MemoryBuffer> MB =
364       MemoryBuffer::getMemBuffer(DefaultBlacklist);
365   std::string Error;
366   auto Blacklist = SpecialCaseList::create(MB.get(), Error);
367   FailIfNotEmpty(Error);
368   return Blacklist;
369 }
370
371 static std::unique_ptr<SpecialCaseList> createUserBlacklist() {
372   if (ClBlacklist.empty())
373     return std::unique_ptr<SpecialCaseList>();
374
375   return SpecialCaseList::createOrDie({{ClBlacklist}});
376 }
377
378 static void printFunctionLocs(const std::set<FunctionLoc> &FnLocs,
379                               raw_ostream &OS) {
380   std::unique_ptr<SpecialCaseList> DefaultBlacklist = createDefaultBlacklist();
381   std::unique_ptr<SpecialCaseList> UserBlacklist = createUserBlacklist();
382
383   for (const FunctionLoc &FnLoc : FnLocs) {
384     if (DefaultBlacklist &&
385         DefaultBlacklist->inSection("fun", FnLoc.FunctionName))
386       continue;
387     if (DefaultBlacklist &&
388         DefaultBlacklist->inSection("src", FnLoc.Loc.FileName))
389       continue;
390     if (UserBlacklist && UserBlacklist->inSection("fun", FnLoc.FunctionName))
391       continue;
392     if (UserBlacklist && UserBlacklist->inSection("src", FnLoc.Loc.FileName))
393       continue;
394
395     OS << stripPathPrefix(FnLoc.Loc.FileName) << ":" << FnLoc.Loc.Line << " "
396        << FnLoc.FunctionName << "\n";
397   }
398 }
399
400 class CoverageData {
401  public:
402   // Read single file coverage data.
403   static ErrorOr<std::unique_ptr<CoverageData>> read(std::string FileName) {
404     ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
405         MemoryBuffer::getFile(FileName);
406     if (!BufOrErr)
407       return BufOrErr.getError();
408     std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
409     if (Buf->getBufferSize() < 8) {
410       errs() << "File too small (<8): " << Buf->getBufferSize();
411       return make_error_code(errc::illegal_byte_sequence);
412     }
413     const FileHeader *Header =
414         reinterpret_cast<const FileHeader *>(Buf->getBufferStart());
415
416     if (Header->Magic != BinCoverageMagic) {
417       errs() << "Wrong magic: " << Header->Magic;
418       return make_error_code(errc::illegal_byte_sequence);
419     }
420
421     auto Addrs = llvm::make_unique<std::set<uint64_t>>();
422
423     switch (Header->Bitness) {
424     case Bitness64:
425       readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
426                          Addrs.get());
427       break;
428     case Bitness32:
429       readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
430                          Addrs.get());
431       break;
432     default:
433       errs() << "Unsupported bitness: " << Header->Bitness;
434       return make_error_code(errc::illegal_byte_sequence);
435     }
436
437     return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));
438   }
439
440   // Merge multiple coverage data together.
441   static std::unique_ptr<CoverageData>
442   merge(const std::vector<std::unique_ptr<CoverageData>> &Covs) {
443     auto Addrs = llvm::make_unique<std::set<uint64_t>>();
444
445     for (const auto &Cov : Covs)
446       Addrs->insert(Cov->Addrs->begin(), Cov->Addrs->end());
447
448     return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));
449   }
450
451   // Read list of files and merges their coverage info.
452   static ErrorOr<std::unique_ptr<CoverageData>>
453   readAndMerge(const std::vector<std::string> &FileNames) {
454     std::vector<std::unique_ptr<CoverageData>> Covs;
455     for (const auto &FileName : FileNames) {
456       auto Cov = read(FileName);
457       if (!Cov)
458         return Cov.getError();
459       Covs.push_back(std::move(Cov.get()));
460     }
461     return merge(Covs);
462   }
463
464   // Print coverage addresses.
465   void printAddrs(raw_ostream &OS) {
466     for (auto Addr : *Addrs) {
467       OS << "0x";
468       OS.write_hex(Addr);
469       OS << "\n";
470     }
471   }
472
473   // Print list of covered functions.
474   // Line format: <file_name>:<line> <function_name>
475   void printCoveredFunctions(raw_ostream &OS) {
476     printFunctionLocs(computeFunctionLocs(*Addrs), OS);
477   }
478
479   // Print list of not covered functions.
480   // Line format: <file_name>:<line> <function_name>
481   void printNotCoveredFunctions(raw_ostream &OS) {
482     std::set<FunctionLoc> AllFns =
483         computeFunctionLocs(getCoveragePoints(ClBinaryName));
484     std::set<FunctionLoc> CoveredFns = computeFunctionLocs(*Addrs);
485
486     std::set<FunctionLoc> NotCoveredFns;
487     std::set_difference(AllFns.begin(), AllFns.end(), CoveredFns.begin(),
488                         CoveredFns.end(),
489                         std::inserter(NotCoveredFns, NotCoveredFns.end()));
490     printFunctionLocs(NotCoveredFns, OS);
491   }
492
493 private:
494   explicit CoverageData(std::unique_ptr<std::set<uint64_t>> Addrs)
495       : Addrs(std::move(Addrs)) {}
496
497   std::unique_ptr<std::set<uint64_t>> Addrs;
498 };
499 } // namespace
500
501 int main(int argc, char **argv) {
502   // Print stack trace if we signal out.
503   sys::PrintStackTraceOnErrorSignal();
504   PrettyStackTraceProgram X(argc, argv);
505   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
506
507   llvm::InitializeAllTargetInfos();
508   llvm::InitializeAllTargetMCs();
509   llvm::InitializeAllDisassemblers();
510
511   cl::ParseCommandLineOptions(argc, argv, "Sanitizer Coverage Processing Tool");
512
513   auto CovData = CoverageData::readAndMerge(ClInputFiles);
514   FailIfError(CovData);
515
516   switch (Action) {
517   case PrintAction: {
518     CovData.get()->printAddrs(outs());
519     return 0;
520   }
521   case CoveredFunctionsAction: {
522     CovData.get()->printCoveredFunctions(outs());
523     return 0;
524   }
525   case NotCoveredFunctionsAction: {
526     CovData.get()->printNotCoveredFunctions(outs());
527     return 0;
528   }
529   }
530
531   llvm_unreachable("unsupported action");
532 }