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