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
49using namespace llvm;
50
51namespace {
52
53// --------- COMMAND LINE FLAGS ---------
54
55enum ActionType {
56  PrintAction,
57  CoveredFunctionsAction,
58  NotCoveredFunctionsAction
59};
60
61cl::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
70static cl::list<std::string> ClInputFiles(cl::Positional, cl::OneOrMore,
71                                          cl::desc("<filenames...>"));
72
73static cl::opt<std::string>
74    ClBinaryName("obj", cl::Required,
75                 cl::desc("Path to object file to be symbolized"));
76
77static cl::opt<bool>
78    ClDemangle("demangle", cl::init(true),
79        cl::desc("Print demangled function name."));
80
81static cl::opt<std::string> ClStripPathPrefix(
82    "strip_path_prefix", cl::init(""),
83    cl::desc("Strip this prefix from file paths in reports."));
84
85static cl::opt<std::string>
86    ClBlacklist("blacklist", cl::init(""),
87                cl::desc("Blacklist file (sanitizer blacklist format)."));
88
89static cl::opt<bool> ClUseDefaultBlacklist(
90    "use_default_blacklist", cl::init(true), cl::Hidden,
91    cl::desc("Controls if default blacklist should be used."));
92
93static const char *const DefaultBlacklist = "fun:__sanitizer_*";
94
95// --------- FORMAT SPECIFICATION ---------
96
97struct FileHeader {
98  uint32_t Bitness;
99  uint32_t Magic;
100};
101
102static const uint32_t BinCoverageMagic = 0xC0BFFFFF;
103static const uint32_t Bitness32 = 0xFFFFFF32;
104static const uint32_t Bitness64 = 0xFFFFFF64;
105
106// ---------
107
108static void FailIfError(std::error_code Error) {
109  if (!Error)
110    return;
111  errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n";
112  exit(1);
113}
114
115template <typename T> static void FailIfError(const ErrorOr<T> &E) {
116  FailIfError(E.getError());
117}
118
119static void FailIfNotEmpty(const std::string &E) {
120  if (E.empty())
121    return;
122  errs() << "Error: " << E << "\n";
123  exit(1);
124}
125
126template <typename T>
127static 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
135template <typename T>
136static 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
143struct FileLoc {
144  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
152struct FunctionLoc {
153  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
161std::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.
171static std::map<FileLoc, std::string>
172computeFunctionsMap(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.
198std::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.
224static std::set<uint64_t>
225findSanitizerCovFunctions(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'.
251static 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
325static 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'.
343std::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
361static 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
372static std::unique_ptr<SpecialCaseList> createUserBlacklist() {
373  if (ClBlacklist.empty())
374    return std::unique_ptr<SpecialCaseList>();
375
376  return SpecialCaseList::createOrDie({{ClBlacklist}});
377}
378
379static 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
401class CoverageData {
402 public:
403  // Read single file coverage data.
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>
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>>
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.
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>
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>
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
494private:
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
502int 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