Index: llvm/trunk/test/tools/sancov/blacklist.test =================================================================== --- llvm/trunk/test/tools/sancov/blacklist.test +++ llvm/trunk/test/tools/sancov/blacklist.test @@ -1,5 +1,5 @@ REQUIRES: x86_64-linux -RUN: sancov -obj %p/Inputs/test-linux_x86_64 -covered-functions -blacklist %p/Inputs/blacklist.txt %p/Inputs/test-linux_x86_64.sancov | FileCheck %s +RUN: sancov -covered-functions -blacklist %p/Inputs/blacklist.txt %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s CHECK-NOT: Inputs{{[/\\]}}test.cpp:12 bar(std::string) CHECK: Inputs{{[/\\]}}test.cpp:14 main Index: llvm/trunk/test/tools/sancov/covered_functions.test =================================================================== --- llvm/trunk/test/tools/sancov/covered_functions.test +++ llvm/trunk/test/tools/sancov/covered_functions.test @@ -1,7 +1,7 @@ REQUIRES: x86_64-linux -RUN: sancov -obj %p/Inputs/test-linux_x86_64 -covered-functions %p/Inputs/test-linux_x86_64.sancov | FileCheck %s -RUN: sancov -obj %p/Inputs/test-linux_x86_64 -covered-functions -strip_path_prefix=Inputs/ %p/Inputs/test-linux_x86_64.sancov | FileCheck --check-prefix=STRIP_PATH %s -RUN: sancov -obj %p/Inputs/test-linux_x86_64 -demangle=0 -covered-functions %p/Inputs/test-linux_x86_64.sancov | FileCheck --check-prefix=NO_DEMANGLE %s +RUN: sancov -covered-functions %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s +RUN: sancov -covered-functions -strip_path_prefix=Inputs/ %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck --check-prefix=STRIP_PATH %s +RUN: sancov -demangle=0 -covered-functions %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck --check-prefix=NO_DEMANGLE %s CHECK: Inputs{{[/\\]}}test.cpp:12 bar(std::string) CHECK: Inputs{{[/\\]}}test.cpp:14 main Index: llvm/trunk/test/tools/sancov/html-report.test =================================================================== --- llvm/trunk/test/tools/sancov/html-report.test +++ llvm/trunk/test/tools/sancov/html-report.test @@ -1,5 +1,5 @@ REQUIRES: x86_64-linux -RUN: sancov -obj %p/Inputs/test-linux_x86_64 -html-report %p/Inputs/test-linux_x86_64.sancov | FileCheck %s +RUN: sancov -html-report %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s // It's very difficult to test html report. Do basic smoke check. CHECK: {{}} Index: llvm/trunk/test/tools/sancov/not_covered_functions.test =================================================================== --- llvm/trunk/test/tools/sancov/not_covered_functions.test +++ llvm/trunk/test/tools/sancov/not_covered_functions.test @@ -1,6 +1,6 @@ REQUIRES: x86_64-linux -RUN: sancov -obj %p/Inputs/test-linux_x86_64 -not-covered-functions %p/Inputs/test-linux_x86_64.sancov | FileCheck %s -RUN: sancov -obj %p/Inputs/test-linux_x86_64 -not-covered-functions %p/Inputs/test-linux_x86_64-1.sancov | FileCheck --check-prefix=CHECK1 --allow-empty %s +RUN: sancov -not-covered-functions %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s +RUN: sancov -not-covered-functions %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.1.sancov | FileCheck --check-prefix=CHECK1 --allow-empty %s CHECK: Inputs{{[/\\]}}foo.cpp:5 foo() CHECK-NOT: {{.*__sanitizer.*}} Index: llvm/trunk/test/tools/sancov/print.test =================================================================== --- llvm/trunk/test/tools/sancov/print.test +++ llvm/trunk/test/tools/sancov/print.test @@ -1,5 +1,5 @@ REQUIRES: x86_64-linux -RUN: sancov -obj %p/Inputs/test-linux_x86_64 -print %p/Inputs/test-linux_x86_64.sancov | FileCheck %s +RUN: sancov -print %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s CHECK: 0x4dbe2b CHECK: 0x4dbf72 Index: llvm/trunk/tools/sancov/sancov.cc =================================================================== --- llvm/trunk/tools/sancov/sancov.cc +++ llvm/trunk/tools/sancov/sancov.cc @@ -11,6 +11,7 @@ // coverage. //===----------------------------------------------------------------------===// #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Twine.h" #include "llvm/DebugInfo/Symbolize/Symbolize.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" @@ -34,6 +35,7 @@ #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Regex.h" #include "llvm/Support/Signals.h" #include "llvm/Support/SpecialCaseList.h" #include "llvm/Support/TargetRegistry.h" @@ -44,6 +46,7 @@ #include #include #include +#include #include using namespace llvm; @@ -70,12 +73,9 @@ "Print HTML coverage report."), clEnumValEnd)); -static cl::list ClInputFiles(cl::Positional, cl::OneOrMore, - cl::desc("")); - -static cl::opt - ClBinaryName("obj", cl::Required, - cl::desc("Path to object file to be symbolized")); +static cl::list + ClInputFiles(cl::Positional, cl::OneOrMore, + cl::desc("(|<.sancov file>)...")); static cl::opt ClDemangle("demangle", cl::init(true), @@ -108,6 +108,11 @@ // --------- +static void Fail(const llvm::Twine &E) { + errs() << "Error: " << E << "\n"; + exit(1); +} + static void FailIfError(std::error_code Error) { if (!Error) return; @@ -119,11 +124,10 @@ FailIfError(E.getError()); } -static void FailIfNotEmpty(const std::string &E) { - if (E.empty()) +static void FailIfNotEmpty(const llvm::Twine &E) { + if (E.str().empty()) return; - errs() << "Error: " << E << "\n"; - exit(1); + Fail(E); } template @@ -131,8 +135,7 @@ const std::string &Message) { if (Ptr.get()) return; - errs() << "Error: " << Message << "\n"; - exit(1); + Fail(Message); } template @@ -180,14 +183,14 @@ // Compute [FileLoc -> FunctionName] map for given addresses. static std::map -computeFunctionsMap(const std::set &Addrs) { +computeFunctionsMap(std::string ObjectFile, const std::set &Addrs) { std::map Fns; auto Symbolizer(createSymbolizer()); // Fill in Fns map. for (auto Addr : Addrs) { - auto InliningInfo = Symbolizer->symbolizeInlinedCode(ClBinaryName, Addr); + auto InliningInfo = Symbolizer->symbolizeInlinedCode(ObjectFile, Addr); FailIfError(InliningInfo); for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) { auto FrameInfo = InliningInfo->getFrame(I); @@ -203,8 +206,9 @@ // Compute functions for given addresses. It keeps only the first // occurence of a function within a file. -std::set computeFunctionLocs(const std::set &Addrs) { - std::map Fns = computeFunctionsMap(Addrs); +std::set computeFunctionLocs(std::string ObjectFile, + const std::set &Addrs) { + std::map Fns = computeFunctionsMap(ObjectFile, Addrs); std::set Result; std::string LastFileName; @@ -248,7 +252,7 @@ } if (Result.empty()) - FailIfNotEmpty("__sanitizer_cov* functions not found"); + Fail("__sanitizer_cov* functions not found"); return Result; } @@ -436,14 +440,14 @@ // Computes a map file_name->{line_number} static std::map> -getFileLines(const std::set &Addrs) { +getFileLines(std::string ObjectFile, const std::set &Addrs) { std::map> FileLines; auto Symbolizer(createSymbolizer()); // Fill in FileLines map. for (auto Addr : Addrs) { - auto InliningInfo = Symbolizer->symbolizeInlinedCode(ClBinaryName, Addr); + auto InliningInfo = Symbolizer->symbolizeInlinedCode(ObjectFile, Addr); FailIfError(InliningInfo); for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) { auto FrameInfo = InliningInfo->getFrame(I); @@ -456,44 +460,58 @@ return FileLines; } +static ErrorOr isCoverageFile(std::string FileName) { + ErrorOr> BufOrErr = + MemoryBuffer::getFile(FileName); + if (!BufOrErr) + return BufOrErr.getError(); + std::unique_ptr Buf = std::move(BufOrErr.get()); + if (Buf->getBufferSize() < 8) { + return false; + } + const FileHeader *Header = + reinterpret_cast(Buf->getBufferStart()); + return Header->Magic == BinCoverageMagic; +} + class CoverageData { public: // Read single file coverage data. - static ErrorOr> read(std::string FileName) { - ErrorOr> BufOrErr = - MemoryBuffer::getFile(FileName); - if (!BufOrErr) - return BufOrErr.getError(); - std::unique_ptr 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(Buf->getBufferStart()); - - if (Header->Magic != BinCoverageMagic) { - errs() << "Wrong magic: " << Header->Magic; - return make_error_code(errc::illegal_byte_sequence); - } - - auto Addrs = llvm::make_unique>(); - - switch (Header->Bitness) { - case Bitness64: - readInts(Buf->getBufferStart() + 8, Buf->getBufferEnd(), - Addrs.get()); - break; - case Bitness32: - readInts(Buf->getBufferStart() + 8, Buf->getBufferEnd(), - Addrs.get()); - break; - default: - errs() << "Unsupported bitness: " << Header->Bitness; - return make_error_code(errc::illegal_byte_sequence); - } + static ErrorOr> read(std::string FileName) { + ErrorOr> BufOrErr = + MemoryBuffer::getFile(FileName); + if (!BufOrErr) + return BufOrErr.getError(); + std::unique_ptr 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(Buf->getBufferStart()); + + if (Header->Magic != BinCoverageMagic) { + errs() << "Wrong magic: " << Header->Magic; + return make_error_code(errc::illegal_byte_sequence); + } + + auto Addrs = llvm::make_unique>(); + + switch (Header->Bitness) { + case Bitness64: + readInts(Buf->getBufferStart() + 8, Buf->getBufferEnd(), + Addrs.get()); + break; + case Bitness32: + readInts(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(new CoverageData(std::move(Addrs))); + return std::unique_ptr(new CoverageData(std::move(Addrs))); } // Merge multiple coverage data together. @@ -529,37 +547,12 @@ } } - void printReport(raw_ostream &OS) { + void printReport(std::string ObjectFile, raw_ostream &OS) { // file_name -> set of covered lines; std::map> CoveredFileLines = - getFileLines(*Addrs); + getFileLines(ObjectFile, *Addrs); std::map> CoveragePoints = - getFileLines(getCoveragePoints(ClBinaryName)); - - std::string Title = stripPathPrefix(ClBinaryName) + " Coverage Report"; - - OS << "\n"; - OS << "\n"; - - // Stylesheet - OS << "\n"; - OS << "" << Title << "\n"; - OS << "\n"; - OS << "\n"; - - // Title - OS << "

" << Title << "

\n"; - OS << "

Coverage files: "; - for (auto InputFile : ClInputFiles) { - llvm::sys::fs::file_status Status; - llvm::sys::fs::status(InputFile, Status); - OS << stripPathPrefix(InputFile) << " (" - << Status.getLastModificationTime().str() << ")"; - } - OS << "

\n"; + getFileLines(ObjectFile, getCoveragePoints(ObjectFile)); // TOC OS << "