[compiler-rt] r252683 - Sancov in C++.

Alexey Samsonov via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 10 20:17:23 PST 2015


Sorry for joining that late. I'm pretty sure compiler-rt is the wrong place
for this tool, and we should move it under llvm/tools/ instead (together
with llvm-symbolizer, llvm-cxxdump etc.):

* we don't include any LLVM headers in compiler-rt libraries (there will be
some discussion to allow that for profile library, but there are different
reasons).
actually, we even support standalone build of compiler-rt repository, and
there is no guarantee that LLVM source code (or CMake rules definitions)
will be available.
* sancov is a parser/transformer of specific binary format, not a compiler
runtime (or resource file that should accompany it).
* sancov uses LLVM libs, so we want as much LLVM developers as possible to
be able to build/test it. Currently it will never be compiled if
compiler-rt is missing, or sanitizers are not supported on host.
* LLVM test-suite is more suitable for writing lit tests for sancov: it
should be tested on a host architecture like every other tool.

True, we'll need to update sancov every time we change the sancov output
format, but that's fine: I believe that would happen less frequently than
notoriously unstable LLVM API will be updated, requiring a mirroring commit
to sancov implementation.


On Tue, Nov 10, 2015 at 5:26 PM, Mike Aizatsky via llvm-commits <
llvm-commits at lists.llvm.org> wrote:

> Author: aizatsky
> Date: Tue Nov 10 19:26:57 2015
> New Revision: 252683
>
> URL: http://llvm.org/viewvc/llvm-project?rev=252683&view=rev
> Log:
> Sancov in C++.
>
> Summary:
> First batch of sancov.py rewrite in C++.
> Supports "-print" and "-covered_functions" commands.
>
> Differential Revision: http://reviews.llvm.org/D14356
>
> Added:
>     compiler-rt/trunk/lib/sanitizer_common/sancov.cc
> Modified:
>     compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
>
> Modified: compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt
> URL:
> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt?rev=252683&r1=252682&r2=252683&view=diff
>
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt (original)
> +++ compiler-rt/trunk/lib/sanitizer_common/CMakeLists.txt Tue Nov 10
> 19:26:57 2015
> @@ -156,3 +156,6 @@ add_compiler_rt_object_libraries(RTSanit
>  if(COMPILER_RT_INCLUDE_TESTS)
>    add_subdirectory(tests)
>  endif()
> +
> +add_llvm_tool(sancov sancov.cc)
> +target_link_libraries(sancov LLVMSupport LLVMSymbolize LLVMObject
> LLVMDebugInfoDWARF LLVMDebugInfoPDB)
>
> Added: compiler-rt/trunk/lib/sanitizer_common/sancov.cc
> URL:
> http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/sanitizer_common/sancov.cc?rev=252683&view=auto
>
> ==============================================================================
> --- compiler-rt/trunk/lib/sanitizer_common/sancov.cc (added)
> +++ compiler-rt/trunk/lib/sanitizer_common/sancov.cc Tue Nov 10 19:26:57
> 2015
> @@ -0,0 +1,283 @@
> +//===-- 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 <cxxabi.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);
> +}
> +
> +static std::string demangle(std::string Name) {
> +  if (Name.substr(0, 2) != "_Z")
> +    return Name;
> +
> +  int status = 0;
> +  char *DemangledName =
> +      abi::__cxa_demangle(Name.c_str(), nullptr, nullptr, &status);
> +  if (status != 0)
> +    return Name;
> +  std::string Result = DemangledName;
> +  free(DemangledName);
> +  return Result;
> +}
> +
> +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);
> +    }
> +
> +    std::unique_ptr<std::vector<uint64_t>> Addrs(new
> 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());
> +
> +    std::unique_ptr<std::vector<uint64_t>> AddrsVector(
> +        new 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) { // NOLINT(runtime/references)
> +    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) { //
> NOLINT(runtime/references)
> +    if (Addrs->empty())
> +      return;
> +    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);
> +        uint32_t Line = FrameInfo.Line;
> +        std::string FunctionName = FrameInfo.FunctionName;
> +        if (ClDemangle)
> +          FunctionName = demangle(FrameInfo.FunctionName);
> +
> +        FileLoc Loc = { FileName.str(), Line };
> +        Fns[Loc] = 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.find(FunctionName) !=
> ProcessedFunctions.end())
> +          continue;
> +        ProcessedFunctions.insert(FunctionName);
> +
> +        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;
> +  }
> +  }
> +}
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
>



-- 
Alexey Samsonov
vonosmas at gmail.com
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20151110/dc642d21/attachment-0001.html>


More information about the llvm-commits mailing list