Home | History | Annotate | Download | only in sancov
      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 
    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 
    115 template <typename T> static void FailIfError(const ErrorOr<T> &E) {
    116   FailIfError(E.getError());
    117 }
    118 
    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>
    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>
    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 {
    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 
    152 struct 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 
    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>
    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.
    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>
    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'.
    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 
    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'.
    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 
    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 
    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 
    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.
    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 
    494 private:
    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 
    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