[llvm] r252801 - sancov tool in c++

Mike Aizatsky via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 11 12:58:20 PST 2015


Author: aizatsky
Date: Wed Nov 11 14:58:20 2015
New Revision: 252801

URL: http://llvm.org/viewvc/llvm-project?rev=252801&view=rev
Log:
sancov tool in c++

First batch of sancov.py rewrite in c++.
Supports "-print" and "-coveredfns" commands.

Followup to http://reviews.llvm.org/D14356 in a better location.

Differential Revision: http://reviews.llvm.org/D14579

Added:
    llvm/trunk/tools/sancov/
    llvm/trunk/tools/sancov/CMakeLists.txt
    llvm/trunk/tools/sancov/Makefile
    llvm/trunk/tools/sancov/sancov.cc

Added: llvm/trunk/tools/sancov/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/sancov/CMakeLists.txt?rev=252801&view=auto
==============================================================================
--- llvm/trunk/tools/sancov/CMakeLists.txt (added)
+++ llvm/trunk/tools/sancov/CMakeLists.txt Wed Nov 11 14:58:20 2015
@@ -0,0 +1,11 @@
+set(LLVM_LINK_COMPONENTS
+  DebugInfoDWARF
+  DebugInfoPDB
+  Object
+  Support
+  Symbolize
+  )
+
+add_llvm_tool(sancov
+  sancov.cc
+  )

Added: llvm/trunk/tools/sancov/Makefile
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/sancov/Makefile?rev=252801&view=auto
==============================================================================
--- llvm/trunk/tools/sancov/Makefile (added)
+++ llvm/trunk/tools/sancov/Makefile Wed Nov 11 14:58:20 2015
@@ -0,0 +1,17 @@
+##===- tools/sancov/Makefile ----------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+LEVEL := ../..
+TOOLNAME := sancov
+LINK_COMPONENTS := DebugInfoDWARF DebugInfoPDB Object Support Symbolize
+
+# This tool has no plugins, optimize startup time.
+TOOL_NO_EXPORTS := 1
+
+include $(LEVEL)/Makefile.common

Added: llvm/trunk/tools/sancov/sancov.cc
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/sancov/sancov.cc?rev=252801&view=auto
==============================================================================
--- llvm/trunk/tools/sancov/sancov.cc (added)
+++ llvm/trunk/tools/sancov/sancov.cc Wed Nov 11 14:58:20 2015
@@ -0,0 +1,264 @@
+//===-- sancov.cc --------------------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a command-line tool for reading and analyzing sanitizer
+// coverage.
+//===----------------------------------------------------------------------===//
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/PrettyStackTrace.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <set>
+#include <stdio.h>
+#include <vector>
+
+using namespace llvm;
+
+namespace {
+
+// --------- COMMAND LINE FLAGS ---------
+
+enum ActionType { PrintAction, CoveredFunctionsAction };
+
+cl::opt<ActionType> Action(
+    cl::desc("Action (required)"), cl::Required,
+    cl::values(clEnumValN(PrintAction, "print", "Print coverage addresses"),
+               clEnumValN(CoveredFunctionsAction, "covered_functions",
+                          "Print all covered funcions."),
+               clEnumValEnd));
+
+static cl::list<std::string> ClInputFiles(cl::Positional, cl::OneOrMore,
+                                          cl::desc("<filenames...>"));
+
+static cl::opt<std::string>
+    ClBinaryName("obj", cl::Required,
+                 cl::desc("Path to object file to be symbolized"));
+
+static cl::opt<bool>
+    ClDemangle("demangle", cl::init(true),
+        cl::desc("Print demangled function name."));
+
+// --------- FORMAT SPECIFICATION ---------
+
+struct FileHeader {
+  uint32_t Bitness;
+  uint32_t Magic;
+};
+
+static const uint32_t BinCoverageMagic = 0xC0BFFFFF;
+static const uint32_t Bitness32 = 0xFFFFFF32;
+static const uint32_t Bitness64 = 0xFFFFFF64;
+
+// ---------
+
+template <typename T> static void FailIfError(const ErrorOr<T> &E) {
+  if (E)
+    return;
+
+  auto Error = E.getError();
+  errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n";
+  exit(-2);
+}
+
+template <typename T>
+static void readInts(const char *Start, const char *End,
+                     std::vector<uint64_t> *V) {
+  const T *S = reinterpret_cast<const T *>(Start);
+  const T *E = reinterpret_cast<const T *>(End);
+  V->reserve(E - S);
+  std::copy(S, E, std::back_inserter(*V));
+}
+
+static std::string CommonPrefix(std::string A, std::string B) {
+  if (A.size() > B.size())
+    return std::string(B.begin(),
+                       std::mismatch(B.begin(), B.end(), A.begin()).first);
+  else
+    return std::string(A.begin(),
+                       std::mismatch(A.begin(), A.end(), B.begin()).first);
+}
+
+class CoverageData {
+ public:
+  // Read single file coverage data.
+  static ErrorOr<std::unique_ptr<CoverageData>> read(std::string FileName) {
+    ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+        MemoryBuffer::getFile(FileName);
+    if (!BufOrErr)
+      return BufOrErr.getError();
+    std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());
+    if (Buf->getBufferSize() < 8) {
+      errs() << "File too small (<8): " << Buf->getBufferSize();
+      return make_error_code(errc::illegal_byte_sequence);
+    }
+    const FileHeader *Header =
+        reinterpret_cast<const FileHeader *>(Buf->getBufferStart());
+
+    if (Header->Magic != BinCoverageMagic) {
+      errs() << "Wrong magic: " << Header->Magic;
+      return make_error_code(errc::illegal_byte_sequence);
+    }
+
+    auto Addrs = make_unique<std::vector<uint64_t>>();
+
+    switch (Header->Bitness) {
+    case Bitness64:
+      readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
+                         Addrs.get());
+      break;
+    case Bitness32:
+      readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),
+                         Addrs.get());
+      break;
+    default:
+      errs() << "Unsupported bitness: " << Header->Bitness;
+      return make_error_code(errc::illegal_byte_sequence);
+    }
+
+    return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));
+  }
+
+  // Merge multiple coverage data together.
+  static std::unique_ptr<CoverageData>
+  merge(const std::vector<std::unique_ptr<CoverageData>> &Covs) {
+    std::set<uint64_t> Addrs;
+
+    for (const auto &Cov : Covs)
+      Addrs.insert(Cov->Addrs->begin(), Cov->Addrs->end());
+
+    auto AddrsVector = make_unique<std::vector<uint64_t>>(
+        Addrs.begin(), Addrs.end());
+    return std::unique_ptr<CoverageData>(
+        new CoverageData(std::move(AddrsVector)));
+  }
+
+  // Read list of files and merges their coverage info.
+  static ErrorOr<std::unique_ptr<CoverageData>>
+  readAndMerge(const std::vector<std::string> &FileNames) {
+    std::vector<std::unique_ptr<CoverageData>> Covs;
+    for (const auto &FileName : FileNames) {
+      auto Cov = read(FileName);
+      if (!Cov)
+        return Cov.getError();
+      Covs.push_back(std::move(Cov.get()));
+    }
+    return merge(Covs);
+  }
+
+  // Print coverage addresses.
+  void printAddrs(raw_ostream &out) {
+    for (auto Addr : *Addrs) {
+      out << "0x";
+      out.write_hex(Addr);
+      out << "\n";
+    }
+  }
+
+  // Print list of covered functions.
+  // Line format: <file_name>:<line> <function_name>
+  void printCoveredFunctions(raw_ostream &out) {
+    if (Addrs->empty())
+      return;
+    symbolize::LLVMSymbolizer::Options SymbolizerOptions;
+    SymbolizerOptions.Demangle = ClDemangle;
+    symbolize::LLVMSymbolizer Symbolizer;
+
+    struct FileLoc {
+      std::string FileName;
+      uint32_t Line;
+      bool operator<(const FileLoc &Rhs) const {
+        return std::tie(FileName, Line) < std::tie(Rhs.FileName, Rhs.Line);
+      }
+    };
+
+    // FileLoc -> FunctionName
+    std::map<FileLoc, std::string> Fns;
+
+    // Fill in Fns map.
+    for (auto Addr : *Addrs) {
+      auto InliningInfo = Symbolizer.symbolizeInlinedCode(ClBinaryName, Addr);
+      FailIfError(InliningInfo);
+      for (uint32_t i = 0; i < InliningInfo->getNumberOfFrames(); ++i) {
+        auto FrameInfo = InliningInfo->getFrame(i);
+        SmallString<256> FileName(FrameInfo.FileName);
+        sys::path::remove_dots(FileName, /* remove_dot_dot */ true);
+        FileLoc Loc = { FileName.str(), FrameInfo.Line };
+        Fns[Loc] = FrameInfo.FunctionName;
+      }
+    }
+
+    // Compute file names common prefix.
+    std::string FilePrefix = Fns.begin()->first.FileName;
+    for (const auto &P : Fns)
+      FilePrefix = CommonPrefix(FilePrefix, P.first.FileName);
+
+    // Print first function occurence in a file.
+    {
+      std::string LastFileName;
+      std::set<std::string> ProcessedFunctions;
+
+      for (const auto &P : Fns) {
+        std::string FileName = P.first.FileName;
+        std::string FunctionName = P.second;
+        uint32_t Line = P.first.Line;
+
+        if (LastFileName != FileName)
+          ProcessedFunctions.clear();
+        LastFileName = FileName;
+
+        if (!ProcessedFunctions.insert(FunctionName).second)
+          continue;
+
+        out << FileName.substr(FilePrefix.size()) << ":" << Line << " "
+            << FunctionName << "\n";
+      }
+    }
+  }
+
+ private:
+  explicit CoverageData(std::unique_ptr<std::vector<uint64_t>> Addrs)
+      : Addrs(std::move(Addrs)) {}
+
+  std::unique_ptr<std::vector<uint64_t>> Addrs;
+};
+} // namespace
+
+int main(int argc, char **argv) {
+  // Print stack trace if we signal out.
+  sys::PrintStackTraceOnErrorSignal();
+  PrettyStackTraceProgram X(argc, argv);
+  llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
+
+  cl::ParseCommandLineOptions(argc, argv, "Sanitizer Coverage Processing Tool");
+
+  auto CovData = CoverageData::readAndMerge(ClInputFiles);
+  FailIfError(CovData);
+
+  switch (Action) {
+  case PrintAction: {
+    CovData.get()->printAddrs(outs());
+    return 0;
+  }
+  case CoveredFunctionsAction: {
+    CovData.get()->printCoveredFunctions(outs());
+    return 0;
+  }
+  }
+}




More information about the llvm-commits mailing list