summaryrefslogtreecommitdiffstats
path: root/llvm/tools
diff options
context:
space:
mode:
authorMike Aizatsky <aizatsky@chromium.org>2016-01-14 22:34:11 +0000
committerMike Aizatsky <aizatsky@chromium.org>2016-01-14 22:34:11 +0000
commitd0281d875cbc16325c59a160d83bb92a8e8d93f1 (patch)
treef5d6e64e96e4cd7e7eba9052093d87f7adb624ea /llvm/tools
parent60f82a269f975c7cd45b1dfd2721b28db75e905e (diff)
downloadbcm5719-llvm-d0281d875cbc16325c59a160d83bb92a8e8d93f1.tar.gz
bcm5719-llvm-d0281d875cbc16325c59a160d83bb92a8e8d93f1.zip
[sancov] html report
Differential Revision: http://reviews.llvm.org/D16161 llvm-svn: 257824
Diffstat (limited to 'llvm/tools')
-rw-r--r--llvm/tools/sancov/sancov.cc150
1 files changed, 144 insertions, 6 deletions
diff --git a/llvm/tools/sancov/sancov.cc b/llvm/tools/sancov/sancov.cc
index a07cdbe097a..7daabe5eb3e 100644
--- a/llvm/tools/sancov/sancov.cc
+++ b/llvm/tools/sancov/sancov.cc
@@ -55,7 +55,8 @@ namespace {
enum ActionType {
PrintAction,
CoveredFunctionsAction,
- NotCoveredFunctionsAction
+ NotCoveredFunctionsAction,
+ HtmlReportAction
};
cl::opt<ActionType> Action(
@@ -65,6 +66,8 @@ cl::opt<ActionType> Action(
"Print all covered funcions."),
clEnumValN(NotCoveredFunctionsAction, "not-covered-functions",
"Print all not covered funcions."),
+ clEnumValN(HtmlReportAction, "html-report",
+ "Print HTML coverage report."),
clEnumValEnd));
static cl::list<std::string> ClInputFiles(cl::Positional, cl::OneOrMore,
@@ -167,19 +170,24 @@ std::string stripPathPrefix(std::string Path) {
return Path.substr(Pos + ClStripPathPrefix.size());
}
+static std::unique_ptr<symbolize::LLVMSymbolizer> createSymbolizer() {
+ symbolize::LLVMSymbolizer::Options SymbolizerOptions;
+ SymbolizerOptions.Demangle = ClDemangle;
+ SymbolizerOptions.UseSymbolTable = true;
+ return std::unique_ptr<symbolize::LLVMSymbolizer>(
+ new symbolize::LLVMSymbolizer(SymbolizerOptions));
+}
+
// Compute [FileLoc -> FunctionName] map for given addresses.
static std::map<FileLoc, std::string>
computeFunctionsMap(const std::set<uint64_t> &Addrs) {
std::map<FileLoc, std::string> Fns;
- symbolize::LLVMSymbolizer::Options SymbolizerOptions;
- SymbolizerOptions.Demangle = ClDemangle;
- SymbolizerOptions.UseSymbolTable = true;
- symbolize::LLVMSymbolizer Symbolizer(SymbolizerOptions);
+ auto Symbolizer(createSymbolizer());
// Fill in Fns map.
for (auto Addr : Addrs) {
- auto InliningInfo = Symbolizer.symbolizeInlinedCode(ClBinaryName, Addr);
+ auto InliningInfo = Symbolizer->symbolizeInlinedCode(ClBinaryName, Addr);
FailIfError(InliningInfo);
for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) {
auto FrameInfo = InliningInfo->getFrame(I);
@@ -398,6 +406,56 @@ static void printFunctionLocs(const std::set<FunctionLoc> &FnLocs,
}
}
+static std::string escapeHtml(const std::string &S) {
+ std::string Result;
+ Result.reserve(S.size());
+ for (char Ch : S) {
+ switch (Ch) {
+ case '&':
+ Result.append("&amp;");
+ break;
+ case '\'':
+ Result.append("&apos;");
+ break;
+ case '"':
+ Result.append("&quot;");
+ break;
+ case '<':
+ Result.append("&lt;");
+ break;
+ case '>':
+ Result.append("&gt;");
+ break;
+ default:
+ Result.push_back(Ch);
+ break;
+ }
+ }
+ return Result;
+}
+
+// Computes a map file_name->{line_number}
+static std::map<std::string, std::set<int>>
+getFileLines(const std::set<uint64_t> &Addrs) {
+ std::map<std::string, std::set<int>> FileLines;
+
+ auto Symbolizer(createSymbolizer());
+
+ // Fill in FileLines 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);
+ FileLines[FileName.str()].insert(FrameInfo.Line);
+ }
+ }
+
+ return FileLines;
+}
+
class CoverageData {
public:
// Read single file coverage data.
@@ -471,6 +529,82 @@ class CoverageData {
}
}
+ void printReport(raw_ostream &OS) {
+ // file_name -> set of covered lines;
+ std::map<std::string, std::set<int>> CoveredFileLines =
+ getFileLines(*Addrs);
+ std::map<std::string, std::set<int>> CoveragePoints =
+ getFileLines(getCoveragePoints(ClBinaryName));
+
+ std::string Title = stripPathPrefix(ClBinaryName) + " Coverage Report";
+
+ OS << "<html>\n";
+ OS << "<head>\n";
+
+ // Stylesheet
+ OS << "<style>\n";
+ OS << ".covered { background: #7F7; }\n";
+ OS << ".notcovered { background: #F77; }\n";
+ OS << "</style>\n";
+ OS << "<title>" << Title << "</title>\n";
+ OS << "</head>\n";
+ OS << "<body>\n";
+
+ // Title
+ OS << "<h1>" << Title << "</h1>\n";
+ OS << "<p>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 << "</p>\n";
+
+ // TOC
+ OS << "<ul>\n";
+ for (auto It : CoveredFileLines) {
+ auto FileName = It.first;
+ OS << "<li><a href=\"#" << escapeHtml(FileName) << "\">"
+ << stripPathPrefix(FileName) << "</a></li>\n";
+ }
+ OS << "</ul>\n";
+
+ // Source
+ for (auto It : CoveredFileLines) {
+ auto FileName = It.first;
+ auto Lines = It.second;
+ auto CovLines = CoveragePoints[FileName];
+
+ OS << "<a name=\"" << escapeHtml(FileName) << "\"> </a>\n";
+ OS << "<h2>" << stripPathPrefix(FileName) << "</h2>\n";
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(FileName);
+ if (!BufOrErr) {
+ OS << "Error reading file: " << FileName << " : "
+ << BufOrErr.getError().message() << "("
+ << BufOrErr.getError().value() << ")\n";
+ continue;
+ }
+
+ OS << "<pre>\n";
+ for (line_iterator I = line_iterator(*BufOrErr.get(), false);
+ !I.is_at_eof(); ++I) {
+ OS << "<span ";
+ if (Lines.find(I.line_number()) != Lines.end())
+ OS << "class=covered";
+ else if (CovLines.find(I.line_number()) != CovLines.end())
+ OS << "class=notcovered";
+ OS << ">";
+ OS << escapeHtml(*I) << "</span>\n";
+ }
+ OS << "</pre>\n";
+ }
+
+ OS << "</body>\n";
+ OS << "</html>\n";
+ }
+
// Print list of covered functions.
// Line format: <file_name>:<line> <function_name>
void printCoveredFunctions(raw_ostream &OS) {
@@ -527,6 +661,10 @@ int main(int argc, char **argv) {
CovData.get()->printNotCoveredFunctions(outs());
return 0;
}
+ case HtmlReportAction: {
+ CovData.get()->printReport(outs());
+ return 0;
+ }
}
llvm_unreachable("unsupported action");
OpenPOWER on IntegriCloud