<div dir="ltr">Bot is broken <a href="http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux/builds/25474/steps/run%20asan-dynamic%20tests/logs/stdio">http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux/builds/25474/steps/run%20asan-dynamic%20tests/logs/stdio</a></div><br><div class="gmail_quote"><div dir="ltr">On Wed, Sep 28, 2016 at 2:48 PM Mike Aizatsky via llvm-commits <<a href="mailto:llvm-commits@lists.llvm.org">llvm-commits@lists.llvm.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Author: aizatsky<br class="gmail_msg">
Date: Wed Sep 28 16:39:28 2016<br class="gmail_msg">
New Revision: 282639<br class="gmail_msg">
<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=282639&view=rev" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project?rev=282639&view=rev</a><br class="gmail_msg">
Log:<br class="gmail_msg">
[sancov] introducing symbolized coverage files (.symcov)<br class="gmail_msg">
<br class="gmail_msg">
Summary:<br class="gmail_msg">
Answering any meaningful questions about .sancov files requires<br class="gmail_msg">
accessing symbol information from the corresponding binary.<br class="gmail_msg">
<br class="gmail_msg">
This change introduces a separate intermediate data structure and<br class="gmail_msg">
format: symbolized coverage. It contains all symbol information that<br class="gmail_msg">
is required to answer common queries:<br class="gmail_msg">
- merging<br class="gmail_msg">
- coverd/uncovered files and functions<br class="gmail_msg">
- line status.<br class="gmail_msg">
<br class="gmail_msg">
Also removing the html report functionality from sancov: generated<br class="gmail_msg">
HTML files are too huge, and a different approach is required.<br class="gmail_msg">
Maintaining this half-working approach in the C++ is painful.<br class="gmail_msg">
<br class="gmail_msg">
Differential Revision: <a href="https://reviews.llvm.org/D24947" rel="noreferrer" class="gmail_msg" target="_blank">https://reviews.llvm.org/D24947</a><br class="gmail_msg">
<br class="gmail_msg">
Added:<br class="gmail_msg">
    llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.0.symcov<br class="gmail_msg">
    llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.1.symcov<br class="gmail_msg">
    llvm/trunk/test/tools/sancov/merge.test<br class="gmail_msg">
    llvm/trunk/test/tools/sancov/symbolize.test<br class="gmail_msg">
Removed:<br class="gmail_msg">
    llvm/trunk/test/tools/sancov/html-report.test<br class="gmail_msg">
Modified:<br class="gmail_msg">
    llvm/trunk/include/llvm/DebugInfo/DIContext.h<br class="gmail_msg">
    llvm/trunk/tools/sancov/sancov.cc<br class="gmail_msg">
<br class="gmail_msg">
Modified: llvm/trunk/include/llvm/DebugInfo/DIContext.h<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DIContext.h?rev=282639&r1=282638&r2=282639&view=diff" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/DIContext.h?rev=282639&r1=282638&r2=282639&view=diff</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/include/llvm/DebugInfo/DIContext.h (original)<br class="gmail_msg">
+++ llvm/trunk/include/llvm/DebugInfo/DIContext.h Wed Sep 28 16:39:28 2016<br class="gmail_msg">
@@ -42,6 +42,10 @@ struct DILineInfo {<br class="gmail_msg">
   bool operator!=(const DILineInfo &RHS) const {<br class="gmail_msg">
     return !(*this == RHS);<br class="gmail_msg">
   }<br class="gmail_msg">
+  bool operator<(const DILineInfo &RHS) const {<br class="gmail_msg">
+    return std::tie(FileName, FunctionName, Line, Column) <<br class="gmail_msg">
+           std::tie(RHS.FileName, RHS.FunctionName, RHS.Line, RHS.Column);<br class="gmail_msg">
+  }<br class="gmail_msg">
 };<br class="gmail_msg">
<br class="gmail_msg">
 typedef SmallVector<std::pair<uint64_t, DILineInfo>, 16> DILineInfoTable;<br class="gmail_msg">
<br class="gmail_msg">
Added: llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.0.symcov<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.0.symcov?rev=282639&view=auto" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.0.symcov?rev=282639&view=auto</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.0.symcov (added)<br class="gmail_msg">
+++ llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.0.symcov Wed Sep 28 16:39:28 2016<br class="gmail_msg">
@@ -0,0 +1,25 @@<br class="gmail_msg">
+{<br class="gmail_msg">
+  "covered-points" : ["4e132b", "4e1472", "4e1520", "4e1553", "4e1586"],<br class="gmail_msg">
+  "binary-hash" : "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",<br class="gmail_msg">
+  "point-symbol-info" : {<br class="gmail_msg">
+    "test/tools/sancov/Inputs/foo.cpp" : {<br class="gmail_msg">
+      "foo()" : {<br class="gmail_msg">
+        "4e178c" : "5:0"<br class="gmail_msg">
+      }<br class="gmail_msg">
+    },<br class="gmail_msg">
+    "test/tools/sancov/Inputs/test.cpp" : {<br class="gmail_msg">
+      "bar(std::string)" : {<br class="gmail_msg">
+        "4e132b" : "12:0"<br class="gmail_msg">
+      },<br class="gmail_msg">
+      "main" : {<br class="gmail_msg">
+        "4e1472" : "14:0",<br class="gmail_msg">
+        "4e14c2" : "16:9",<br class="gmail_msg">
+        "4e1520" : "17:5",<br class="gmail_msg">
+        "4e1553" : "17:5",<br class="gmail_msg">
+        "4e1586" : "17:5",<br class="gmail_msg">
+        "4e1635" : "19:1",<br class="gmail_msg">
+        "4e1690" : "17:5"<br class="gmail_msg">
+      }<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
Added: llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.1.symcov<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.1.symcov?rev=282639&view=auto" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.1.symcov?rev=282639&view=auto</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.1.symcov (added)<br class="gmail_msg">
+++ llvm/trunk/test/tools/sancov/Inputs/test-linux_x86_64.1.symcov Wed Sep 28 16:39:28 2016<br class="gmail_msg">
@@ -0,0 +1,25 @@<br class="gmail_msg">
+{<br class="gmail_msg">
+  "covered-points" : ["4e132b", "4e1472", "4e14c2", "4e1520", "4e1553", "4e1586", "4e178c"],<br class="gmail_msg">
+  "binary-hash" : "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",<br class="gmail_msg">
+  "point-symbol-info" : {<br class="gmail_msg">
+    "test/tools/sancov/Inputs/foo.cpp" : {<br class="gmail_msg">
+      "foo()" : {<br class="gmail_msg">
+        "4e178c" : "5:0"<br class="gmail_msg">
+      }<br class="gmail_msg">
+    },<br class="gmail_msg">
+    "test/tools/sancov/Inputs/test.cpp" : {<br class="gmail_msg">
+      "bar(std::string)" : {<br class="gmail_msg">
+        "4e132b" : "12:0"<br class="gmail_msg">
+      },<br class="gmail_msg">
+      "main" : {<br class="gmail_msg">
+        "4e1472" : "14:0",<br class="gmail_msg">
+        "4e14c2" : "16:9",<br class="gmail_msg">
+        "4e1520" : "17:5",<br class="gmail_msg">
+        "4e1553" : "17:5",<br class="gmail_msg">
+        "4e1586" : "17:5",<br class="gmail_msg">
+        "4e1635" : "19:1",<br class="gmail_msg">
+        "4e1690" : "17:5"<br class="gmail_msg">
+      }<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
Removed: llvm/trunk/test/tools/sancov/html-report.test<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/html-report.test?rev=282638&view=auto" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/html-report.test?rev=282638&view=auto</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/test/tools/sancov/html-report.test (original)<br class="gmail_msg">
+++ llvm/trunk/test/tools/sancov/html-report.test (removed)<br class="gmail_msg">
@@ -1,6 +0,0 @@<br class="gmail_msg">
-REQUIRES: x86_64-linux<br class="gmail_msg">
-RUN: sancov -html-report %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s<br class="gmail_msg">
-<br class="gmail_msg">
-// It's very difficult to test html report. Do basic smoke check.<br class="gmail_msg">
-CHECK: {{.*/Inputs/test.cpp}}<br class="gmail_msg">
-<br class="gmail_msg">
<br class="gmail_msg">
Added: llvm/trunk/test/tools/sancov/merge.test<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/merge.test?rev=282639&view=auto" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/merge.test?rev=282639&view=auto</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/test/tools/sancov/merge.test (added)<br class="gmail_msg">
+++ llvm/trunk/test/tools/sancov/merge.test Wed Sep 28 16:39:28 2016<br class="gmail_msg">
@@ -0,0 +1,64 @@<br class="gmail_msg">
+REQUIRES: x86_64-linux<br class="gmail_msg">
+RUN: sancov -merge %p/Inputs/test-linux_x86_64.0.symcov| FileCheck --check-prefix=MERGE1 %s<br class="gmail_msg">
+RUN: sancov -merge %p/Inputs/test-linux_x86_64.0.symcov %p/Inputs/test-linux_x86_64.1.symcov| FileCheck --check-prefix=MERGE2 %s<br class="gmail_msg">
+<br class="gmail_msg">
+MERGE1: {<br class="gmail_msg">
+MERGE1-NEXT:   "covered-points" : ["4e132b", "4e1472", "4e1520", "4e1553", "4e1586"],<br class="gmail_msg">
+MERGE1-NEXT:   "binary-hash" : "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",<br class="gmail_msg">
+MERGE1-NEXT:   "point-symbol-info" : {<br class="gmail_msg">
+MERGE1-NEXT:     "test/tools/sancov/Inputs/foo.cpp" : {<br class="gmail_msg">
+MERGE1-NEXT:       "foo()" : {<br class="gmail_msg">
+MERGE1-NEXT:         "4e178c" : "5:0"<br class="gmail_msg">
+MERGE1-NEXT:       }<br class="gmail_msg">
+MERGE1-NEXT:     },<br class="gmail_msg">
+MERGE1-NEXT:     "test/tools/sancov/Inputs/test.cpp" : {<br class="gmail_msg">
+MERGE1-NEXT:       "bar(std::string)" : {<br class="gmail_msg">
+MERGE1-NEXT:         "4e132b" : "12:0"<br class="gmail_msg">
+MERGE1-NEXT:       },<br class="gmail_msg">
+MERGE1-NEXT:       "main" : {<br class="gmail_msg">
+MERGE1-NEXT:         "4e1472" : "14:0",<br class="gmail_msg">
+MERGE1-NEXT:         "4e14c2" : "16:9",<br class="gmail_msg">
+MERGE1-NEXT:         "4e1520" : "17:5",<br class="gmail_msg">
+MERGE1-NEXT:         "4e1553" : "17:5",<br class="gmail_msg">
+MERGE1-NEXT:         "4e1586" : "17:5",<br class="gmail_msg">
+MERGE1-NEXT:         "4e1635" : "19:1",<br class="gmail_msg">
+MERGE1-NEXT:         "4e1690" : "17:5"<br class="gmail_msg">
+MERGE1-NEXT:       }<br class="gmail_msg">
+MERGE1-NEXT:     }<br class="gmail_msg">
+MERGE1-NEXT:   }<br class="gmail_msg">
+MERGE1-NEXT: }<br class="gmail_msg">
+<br class="gmail_msg">
+MERGE2: {<br class="gmail_msg">
+MERGE2-NEXT:   "covered-points" : ["BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e132b", "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1472", "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e14c2", "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1520", "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1553", "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1586", "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e178c"],<br class="gmail_msg">
+MERGE2-NEXT:   "point-symbol-info" : {<br class="gmail_msg">
+MERGE2-NEXT:     "test/tools/sancov/Inputs/foo.cpp" : {<br class="gmail_msg">
+MERGE2-NEXT:      "foo()" : {<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e178c" : "5:0",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e178c" : "5:0"<br class="gmail_msg">
+MERGE2-NEXT:       }<br class="gmail_msg">
+MERGE2-NEXT:     },<br class="gmail_msg">
+MERGE2-NEXT:     "test/tools/sancov/Inputs/test.cpp" : {<br class="gmail_msg">
+MERGE2-NEXT:       "bar(std::string)" : {<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e132b" : "12:0",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e132b" : "12:0"<br class="gmail_msg">
+MERGE2-NEXT:       },<br class="gmail_msg">
+MERGE2-NEXT:       "main" : {<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1472" : "14:0",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e14c2" : "16:9",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1520" : "17:5",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1553" : "17:5",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1586" : "17:5",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1635" : "19:1",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1690" : "17:5",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1472" : "14:0",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e14c2" : "16:9",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1520" : "17:5",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1553" : "17:5",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1586" : "17:5",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1635" : "19:1",<br class="gmail_msg">
+MERGE2-NEXT:         "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5:4e1690" : "17:5"<br class="gmail_msg">
+MERGE2-NEXT:       }<br class="gmail_msg">
+MERGE2-NEXT:     }<br class="gmail_msg">
+MERGE2-NEXT:   }<br class="gmail_msg">
+MERGE2-NEXT: }<br class="gmail_msg">
+<br class="gmail_msg">
<br class="gmail_msg">
Added: llvm/trunk/test/tools/sancov/symbolize.test<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/symbolize.test?rev=282639&view=auto" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/sancov/symbolize.test?rev=282639&view=auto</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/test/tools/sancov/symbolize.test (added)<br class="gmail_msg">
+++ llvm/trunk/test/tools/sancov/symbolize.test Wed Sep 28 16:39:28 2016<br class="gmail_msg">
@@ -0,0 +1,29 @@<br class="gmail_msg">
+REQUIRES: x86_64-linux<br class="gmail_msg">
+RUN: sancov -symbolize -strip_path_prefix="llvm/" %p/Inputs/test-linux_x86_64 %p/Inputs/test-linux_x86_64.0.sancov | FileCheck %s<br class="gmail_msg">
+<br class="gmail_msg">
+CHECK: {<br class="gmail_msg">
+CHECK-NEXT:  "covered-points" : ["4e132b", "4e1472", "4e1520", "4e1553", "4e1586"],<br class="gmail_msg">
+CHECK-NEXT:  "binary-hash" : "BB3CDD5045AED83906F6ADCC1C4DAF7E2596A6B5",<br class="gmail_msg">
+CHECK-NEXT:  "point-symbol-info" : {<br class="gmail_msg">
+CHECK-NEXT:    "test/tools/sancov/Inputs/foo.cpp" : {<br class="gmail_msg">
+CHECK-NEXT:      "foo()" : {<br class="gmail_msg">
+CHECK-NEXT:        "4e178c" : "5:0"<br class="gmail_msg">
+CHECK-NEXT:     }<br class="gmail_msg">
+CHECK-NEXT:   },<br class="gmail_msg">
+CHECK-NEXT:   "test/tools/sancov/Inputs/test.cpp" : {<br class="gmail_msg">
+CHECK-NEXT:     "bar(std::string)" : {<br class="gmail_msg">
+CHECK-NEXT:       "4e132b" : "12:0"<br class="gmail_msg">
+CHECK-NEXT:      },<br class="gmail_msg">
+CHECK-NEXT:      "main" : {<br class="gmail_msg">
+CHECK-NEXT:        "4e1472" : "14:0",<br class="gmail_msg">
+CHECK-NEXT:        "4e14c2" : "16:9",<br class="gmail_msg">
+CHECK-NEXT:        "4e1520" : "17:5",<br class="gmail_msg">
+CHECK-NEXT:        "4e1553" : "17:5",<br class="gmail_msg">
+CHECK-NEXT:        "4e1586" : "17:5",<br class="gmail_msg">
+CHECK-NEXT:        "4e1635" : "19:1",<br class="gmail_msg">
+CHECK-NEXT:        "4e1690" : "17:5"<br class="gmail_msg">
+CHECK-NEXT:      }<br class="gmail_msg">
+CHECK-NEXT:    }<br class="gmail_msg">
+CHECK-NEXT:  }<br class="gmail_msg">
+CHECK-NEXT:}<br class="gmail_msg">
+<br class="gmail_msg">
<br class="gmail_msg">
Modified: llvm/trunk/tools/sancov/sancov.cc<br class="gmail_msg">
URL: <a href="http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/sancov/sancov.cc?rev=282639&r1=282638&r2=282639&view=diff" rel="noreferrer" class="gmail_msg" target="_blank">http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/sancov/sancov.cc?rev=282639&r1=282638&r2=282639&view=diff</a><br class="gmail_msg">
==============================================================================<br class="gmail_msg">
--- llvm/trunk/tools/sancov/sancov.cc (original)<br class="gmail_msg">
+++ llvm/trunk/tools/sancov/sancov.cc Wed Sep 28 16:39:28 2016<br class="gmail_msg">
@@ -11,6 +11,7 @@<br class="gmail_msg">
 // coverage.<br class="gmail_msg">
 //===----------------------------------------------------------------------===//<br class="gmail_msg">
 #include "llvm/ADT/STLExtras.h"<br class="gmail_msg">
+#include "llvm/ADT/StringExtras.h"<br class="gmail_msg">
 #include "llvm/ADT/Twine.h"<br class="gmail_msg">
 #include "llvm/DebugInfo/Symbolize/Symbolize.h"<br class="gmail_msg">
 #include "llvm/MC/MCAsmInfo.h"<br class="gmail_msg">
@@ -41,11 +42,14 @@<br class="gmail_msg">
 #include "llvm/Support/Path.h"<br class="gmail_msg">
 #include "llvm/Support/PrettyStackTrace.h"<br class="gmail_msg">
 #include "llvm/Support/Regex.h"<br class="gmail_msg">
+#include "llvm/Support/SHA1.h"<br class="gmail_msg">
 #include "llvm/Support/Signals.h"<br class="gmail_msg">
+#include "llvm/Support/SourceMgr.h"<br class="gmail_msg">
 #include "llvm/Support/SpecialCaseList.h"<br class="gmail_msg">
 #include "llvm/Support/TargetRegistry.h"<br class="gmail_msg">
 #include "llvm/Support/TargetSelect.h"<br class="gmail_msg">
 #include "llvm/Support/ToolOutputFile.h"<br class="gmail_msg">
+#include "llvm/Support/YAMLParser.h"<br class="gmail_msg">
 #include "llvm/Support/raw_ostream.h"<br class="gmail_msg">
<br class="gmail_msg">
 #include <algorithm><br class="gmail_msg">
@@ -62,28 +66,33 @@ namespace {<br class="gmail_msg">
 // --------- COMMAND LINE FLAGS ---------<br class="gmail_msg">
<br class="gmail_msg">
 enum ActionType {<br class="gmail_msg">
-  PrintAction,<br class="gmail_msg">
-  PrintCovPointsAction,<br class="gmail_msg">
   CoveredFunctionsAction,<br class="gmail_msg">
-  NotCoveredFunctionsAction,<br class="gmail_msg">
   HtmlReportAction,<br class="gmail_msg">
-  StatsAction<br class="gmail_msg">
+  MergeAction,<br class="gmail_msg">
+  NotCoveredFunctionsAction,<br class="gmail_msg">
+  PrintAction,<br class="gmail_msg">
+  PrintCovPointsAction,<br class="gmail_msg">
+  StatsAction,<br class="gmail_msg">
+  SymbolizeAction<br class="gmail_msg">
 };<br class="gmail_msg">
<br class="gmail_msg">
 cl::opt<ActionType> Action(<br class="gmail_msg">
     cl::desc("Action (required)"), cl::Required,<br class="gmail_msg">
-    cl::values(clEnumValN(PrintAction, "print", "Print coverage addresses"),<br class="gmail_msg">
-               clEnumValN(PrintCovPointsAction, "print-coverage-pcs",<br class="gmail_msg">
-                          "Print coverage instrumentation points addresses."),<br class="gmail_msg">
-               clEnumValN(CoveredFunctionsAction, "covered-functions",<br class="gmail_msg">
-                          "Print all covered funcions."),<br class="gmail_msg">
-               clEnumValN(NotCoveredFunctionsAction, "not-covered-functions",<br class="gmail_msg">
-                          "Print all not covered funcions."),<br class="gmail_msg">
-               clEnumValN(HtmlReportAction, "html-report",<br class="gmail_msg">
-                          "Print HTML coverage report."),<br class="gmail_msg">
-               clEnumValN(StatsAction, "print-coverage-stats",<br class="gmail_msg">
-                          "Print coverage statistics."),<br class="gmail_msg">
-               clEnumValEnd));<br class="gmail_msg">
+    cl::values(<br class="gmail_msg">
+        clEnumValN(PrintAction, "print", "Print coverage addresses"),<br class="gmail_msg">
+        clEnumValN(PrintCovPointsAction, "print-coverage-pcs",<br class="gmail_msg">
+                   "Print coverage instrumentation points addresses."),<br class="gmail_msg">
+        clEnumValN(CoveredFunctionsAction, "covered-functions",<br class="gmail_msg">
+                   "Print all covered funcions."),<br class="gmail_msg">
+        clEnumValN(NotCoveredFunctionsAction, "not-covered-functions",<br class="gmail_msg">
+                   "Print all not covered funcions."),<br class="gmail_msg">
+        clEnumValN(StatsAction, "print-coverage-stats",<br class="gmail_msg">
+                   "Print coverage statistics."),<br class="gmail_msg">
+        clEnumValN(HtmlReportAction, "html-report",<br class="gmail_msg">
+                   "REMOVED. Use -symbolize & symcov-report-server.py."),<br class="gmail_msg">
+        clEnumValN(SymbolizeAction, "symbolize",<br class="gmail_msg">
+                   "Produces a symbolized JSON report from binary report."),<br class="gmail_msg">
+        clEnumValN(MergeAction, "merge", "Merges reports."), clEnumValEnd));<br class="gmail_msg">
<br class="gmail_msg">
 static cl::list<std::string><br class="gmail_msg">
     ClInputFiles(cl::Positional, cl::OneOrMore,<br class="gmail_msg">
@@ -119,66 +128,99 @@ static const uint32_t BinCoverageMagic =<br class="gmail_msg">
 static const uint32_t Bitness32 = 0xFFFFFF32;<br class="gmail_msg">
 static const uint32_t Bitness64 = 0xFFFFFF64;<br class="gmail_msg">
<br class="gmail_msg">
+static Regex SancovFileRegex("(.*)\\.[0-9]+\\.sancov");<br class="gmail_msg">
+static Regex SymcovFileRegex(".*\\.symcov");<br class="gmail_msg">
+<br class="gmail_msg">
+// --------- MAIN DATASTRUCTURES ----------<br class="gmail_msg">
+<br class="gmail_msg">
+// Contents of .sancov file: list of coverage point addresses that were<br class="gmail_msg">
+// executed.<br class="gmail_msg">
+struct RawCoverage {<br class="gmail_msg">
+  explicit RawCoverage(std::unique_ptr<std::set<uint64_t>> Addrs)<br class="gmail_msg">
+      : Addrs(std::move(Addrs)) {}<br class="gmail_msg">
+<br class="gmail_msg">
+  // Read binary .sancov file.<br class="gmail_msg">
+  static ErrorOr<std::unique_ptr<RawCoverage>><br class="gmail_msg">
+  read(const std::string &FileName);<br class="gmail_msg">
+<br class="gmail_msg">
+  std::unique_ptr<std::set<uint64_t>> Addrs;<br class="gmail_msg">
+};<br class="gmail_msg">
+<br class="gmail_msg">
+// Coverage point has an opaque Id and corresponds to multiple source locations.<br class="gmail_msg">
+struct CoveragePoint {<br class="gmail_msg">
+  explicit CoveragePoint(const std::string &Id) : Id(Id) {}<br class="gmail_msg">
+<br class="gmail_msg">
+  std::string Id;<br class="gmail_msg">
+  SmallVector<DILineInfo, 1> Locs;<br class="gmail_msg">
+};<br class="gmail_msg">
+<br class="gmail_msg">
+// Symcov file content: set of covered Ids plus information about all available<br class="gmail_msg">
+// coverage points.<br class="gmail_msg">
+struct SymbolizedCoverage {<br class="gmail_msg">
+  // Read json .symcov file.<br class="gmail_msg">
+  static std::unique_ptr<SymbolizedCoverage> read(const std::string &InputFile);<br class="gmail_msg">
+<br class="gmail_msg">
+  std::set<std::string> CoveredIds;<br class="gmail_msg">
+  std::string BinaryHash;<br class="gmail_msg">
+  std::vector<CoveragePoint> Points;<br class="gmail_msg">
+};<br class="gmail_msg">
+<br class="gmail_msg">
+struct CoverageStats {<br class="gmail_msg">
+  size_t AllPoints;<br class="gmail_msg">
+  size_t CovPoints;<br class="gmail_msg">
+  size_t AllFns;<br class="gmail_msg">
+  size_t CovFns;<br class="gmail_msg">
+};<br class="gmail_msg">
+<br class="gmail_msg">
 // --------- ERROR HANDLING ---------<br class="gmail_msg">
<br class="gmail_msg">
-static void Fail(const llvm::Twine &E) {<br class="gmail_msg">
+static void fail(const llvm::Twine &E) {<br class="gmail_msg">
   errs() << "Error: " << E << "\n";<br class="gmail_msg">
   exit(1);<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-static void FailIfError(std::error_code Error) {<br class="gmail_msg">
+static void failIf(bool B, const llvm::Twine &E) {<br class="gmail_msg">
+  if (B)<br class="gmail_msg">
+    fail(E);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+static void failIfError(std::error_code Error) {<br class="gmail_msg">
   if (!Error)<br class="gmail_msg">
     return;<br class="gmail_msg">
   errs() << "Error: " << Error.message() << "(" << Error.value() << ")\n";<br class="gmail_msg">
   exit(1);<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-template <typename T> static void FailIfError(const ErrorOr<T> &E) {<br class="gmail_msg">
-  FailIfError(E.getError());<br class="gmail_msg">
+template <typename T> static void failIfError(const ErrorOr<T> &E) {<br class="gmail_msg">
+  failIfError(E.getError());<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-static void FailIfError(Error Err) {<br class="gmail_msg">
+static void failIfError(Error Err) {<br class="gmail_msg">
   if (Err) {<br class="gmail_msg">
     logAllUnhandledErrors(std::move(Err), errs(), "Error: ");<br class="gmail_msg">
     exit(1);<br class="gmail_msg">
   }<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-template <typename T> static void FailIfError(Expected<T> &E) {<br class="gmail_msg">
-  FailIfError(E.takeError());<br class="gmail_msg">
+template <typename T> static void failIfError(Expected<T> &E) {<br class="gmail_msg">
+  failIfError(E.takeError());<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-static void FailIfNotEmpty(const llvm::Twine &E) {<br class="gmail_msg">
+static void failIfNotEmpty(const llvm::Twine &E) {<br class="gmail_msg">
   if (E.str().empty())<br class="gmail_msg">
     return;<br class="gmail_msg">
-  Fail(E);<br class="gmail_msg">
+  fail(E);<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
 template <typename T><br class="gmail_msg">
-static void FailIfEmpty(const std::unique_ptr<T> &Ptr,<br class="gmail_msg">
+static void failIfEmpty(const std::unique_ptr<T> &Ptr,<br class="gmail_msg">
                         const std::string &Message) {<br class="gmail_msg">
   if (Ptr.get())<br class="gmail_msg">
     return;<br class="gmail_msg">
-  Fail(Message);<br class="gmail_msg">
-}<br class="gmail_msg">
-<br class="gmail_msg">
-// ---------<br class="gmail_msg">
-<br class="gmail_msg">
-// Produces std::map<K, std::vector<E>> grouping input<br class="gmail_msg">
-// elements by FuncTy result.<br class="gmail_msg">
-template <class RangeTy, class FuncTy><br class="gmail_msg">
-static inline auto group_by(const RangeTy &R, FuncTy F)<br class="gmail_msg">
-    -> std::map<typename std::decay<decltype(F(*R.begin()))>::type,<br class="gmail_msg">
-                std::vector<typename std::decay<decltype(*R.begin())>::type>> {<br class="gmail_msg">
-  std::map<typename std::decay<decltype(F(*R.begin()))>::type,<br class="gmail_msg">
-           std::vector<typename std::decay<decltype(*R.begin())>::type>><br class="gmail_msg">
-      Result;<br class="gmail_msg">
-  for (const auto &E : R) {<br class="gmail_msg">
-    Result[F(E)].push_back(E);<br class="gmail_msg">
-  }<br class="gmail_msg">
-  return Result;<br class="gmail_msg">
+  fail(Message);<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
+// ----------- Coverage I/O ----------<br class="gmail_msg">
 template <typename T><br class="gmail_msg">
 static void readInts(const char *Start, const char *End,<br class="gmail_msg">
                      std::set<uint64_t> *Ints) {<br class="gmail_msg">
@@ -187,34 +229,321 @@ static void readInts(const char *Start,<br class="gmail_msg">
   std::copy(S, E, std::inserter(*Ints, Ints->end()));<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-struct FileLoc {<br class="gmail_msg">
-  bool operator<(const FileLoc &RHS) const {<br class="gmail_msg">
-    return std::tie(FileName, Line) < std::tie(RHS.FileName, RHS.Line);<br class="gmail_msg">
+ErrorOr<std::unique_ptr<RawCoverage>><br class="gmail_msg">
+RawCoverage::read(const std::string &FileName) {<br class="gmail_msg">
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =<br class="gmail_msg">
+      MemoryBuffer::getFile(FileName);<br class="gmail_msg">
+  if (!BufOrErr)<br class="gmail_msg">
+    return BufOrErr.getError();<br class="gmail_msg">
+  std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());<br class="gmail_msg">
+  if (Buf->getBufferSize() < 8) {<br class="gmail_msg">
+    errs() << "File too small (<8): " << Buf->getBufferSize() << '\n';<br class="gmail_msg">
+    return make_error_code(errc::illegal_byte_sequence);<br class="gmail_msg">
   }<br class="gmail_msg">
+  const FileHeader *Header =<br class="gmail_msg">
+      reinterpret_cast<const FileHeader *>(Buf->getBufferStart());<br class="gmail_msg">
<br class="gmail_msg">
-  std::string FileName;<br class="gmail_msg">
-  uint32_t Line;<br class="gmail_msg">
-};<br class="gmail_msg">
+  if (Header->Magic != BinCoverageMagic) {<br class="gmail_msg">
+    errs() << "Wrong magic: " << Header->Magic << '\n';<br class="gmail_msg">
+    return make_error_code(errc::illegal_byte_sequence);<br class="gmail_msg">
+  }<br class="gmail_msg">
<br class="gmail_msg">
-struct FileFn {<br class="gmail_msg">
-  bool operator<(const FileFn &RHS) const {<br class="gmail_msg">
-    return std::tie(FileName, FunctionName) <<br class="gmail_msg">
-           std::tie(RHS.FileName, RHS.FunctionName);<br class="gmail_msg">
+  auto Addrs = llvm::make_unique<std::set<uint64_t>>();<br class="gmail_msg">
+<br class="gmail_msg">
+  switch (Header->Bitness) {<br class="gmail_msg">
+  case Bitness64:<br class="gmail_msg">
+    readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),<br class="gmail_msg">
+                       Addrs.get());<br class="gmail_msg">
+    break;<br class="gmail_msg">
+  case Bitness32:<br class="gmail_msg">
+    readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),<br class="gmail_msg">
+                       Addrs.get());<br class="gmail_msg">
+    break;<br class="gmail_msg">
+  default:<br class="gmail_msg">
+    errs() << "Unsupported bitness: " << Header->Bitness << '\n';<br class="gmail_msg">
+    return make_error_code(errc::illegal_byte_sequence);<br class="gmail_msg">
   }<br class="gmail_msg">
<br class="gmail_msg">
-  std::string FileName;<br class="gmail_msg">
-  std::string FunctionName;<br class="gmail_msg">
-};<br class="gmail_msg">
+  return std::unique_ptr<RawCoverage>(new RawCoverage(std::move(Addrs)));<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
-struct FnLoc {<br class="gmail_msg">
-  bool operator<(const FnLoc &RHS) const {<br class="gmail_msg">
-    return std::tie(Loc, FunctionName) < std::tie(RHS.Loc, RHS.FunctionName);<br class="gmail_msg">
+// Print coverage addresses.<br class="gmail_msg">
+raw_ostream &operator<<(raw_ostream &OS, const RawCoverage &CoverageData) {<br class="gmail_msg">
+  for (auto Addr : *CoverageData.Addrs) {<br class="gmail_msg">
+    OS << "0x";<br class="gmail_msg">
+    OS.write_hex(Addr);<br class="gmail_msg">
+    OS << "\n";<br class="gmail_msg">
   }<br class="gmail_msg">
+  return OS;<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
-  FileLoc Loc;<br class="gmail_msg">
-  std::string FunctionName;<br class="gmail_msg">
+static raw_ostream &operator<<(raw_ostream &OS, const CoverageStats &Stats) {<br class="gmail_msg">
+  OS << "all-edges: " << Stats.AllPoints << "\n";<br class="gmail_msg">
+  OS << "cov-edges: " << Stats.CovPoints << "\n";<br class="gmail_msg">
+  OS << "all-functions: " << Stats.AllFns << "\n";<br class="gmail_msg">
+  OS << "cov-functions: " << Stats.CovFns << "\n";<br class="gmail_msg">
+  return OS;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Helper for writing out JSON. Handles indents and commas using<br class="gmail_msg">
+// scope variables for objects and arrays.<br class="gmail_msg">
+class JSONWriter {<br class="gmail_msg">
+public:<br class="gmail_msg">
+  JSONWriter(raw_ostream &Out) : OS(Out) {}<br class="gmail_msg">
+  JSONWriter(const JSONWriter &) = delete;<br class="gmail_msg">
+  ~JSONWriter() { OS << "\n"; }<br class="gmail_msg">
+<br class="gmail_msg">
+  void operator<<(StringRef S) { printJSONStringLiteral(S, OS); }<br class="gmail_msg">
+<br class="gmail_msg">
+  // Helper RAII class to output JSON objects.<br class="gmail_msg">
+  class Object {<br class="gmail_msg">
+  public:<br class="gmail_msg">
+    Object(JSONWriter *W, raw_ostream &OS) : W(W), OS(OS) {<br class="gmail_msg">
+      OS << "{";<br class="gmail_msg">
+      W->Indent++;<br class="gmail_msg">
+    }<br class="gmail_msg">
+    Object(const Object &) = delete;<br class="gmail_msg">
+    ~Object() {<br class="gmail_msg">
+      W->Indent--;<br class="gmail_msg">
+      OS << "\n";<br class="gmail_msg">
+      W->indent();<br class="gmail_msg">
+      OS << "}";<br class="gmail_msg">
+    }<br class="gmail_msg">
+<br class="gmail_msg">
+    void key(StringRef Key) {<br class="gmail_msg">
+      Index++;<br class="gmail_msg">
+      if (Index > 0)<br class="gmail_msg">
+        OS << ",";<br class="gmail_msg">
+      OS << "\n";<br class="gmail_msg">
+      W->indent();<br class="gmail_msg">
+      printJSONStringLiteral(Key, OS);<br class="gmail_msg">
+      OS << " : ";<br class="gmail_msg">
+    }<br class="gmail_msg">
+<br class="gmail_msg">
+  private:<br class="gmail_msg">
+    JSONWriter *W;<br class="gmail_msg">
+    raw_ostream &OS;<br class="gmail_msg">
+    int Index = -1;<br class="gmail_msg">
+  };<br class="gmail_msg">
+<br class="gmail_msg">
+  std::unique_ptr<Object> object() { return make_unique<Object>(this, OS); }<br class="gmail_msg">
+<br class="gmail_msg">
+  // Helper RAII class to output JSON arrays.<br class="gmail_msg">
+  class Array {<br class="gmail_msg">
+  public:<br class="gmail_msg">
+    Array(raw_ostream &OS) : OS(OS) { OS << "["; }<br class="gmail_msg">
+    Array(const Array &) = delete;<br class="gmail_msg">
+    ~Array() { OS << "]"; }<br class="gmail_msg">
+    void next() {<br class="gmail_msg">
+      Index++;<br class="gmail_msg">
+      if (Index > 0)<br class="gmail_msg">
+        OS << ", ";<br class="gmail_msg">
+    }<br class="gmail_msg">
+<br class="gmail_msg">
+  private:<br class="gmail_msg">
+    raw_ostream &OS;<br class="gmail_msg">
+    int Index = -1;<br class="gmail_msg">
+  };<br class="gmail_msg">
+<br class="gmail_msg">
+  std::unique_ptr<Array> array() { return make_unique<Array>(OS); }<br class="gmail_msg">
+<br class="gmail_msg">
+private:<br class="gmail_msg">
+  void indent() { OS.indent(Indent * 2); }<br class="gmail_msg">
+<br class="gmail_msg">
+  static void printJSONStringLiteral(StringRef S, raw_ostream &OS) {<br class="gmail_msg">
+    if (S.find('"') == std::string::npos) {<br class="gmail_msg">
+      OS << "\"" << S << "\"";<br class="gmail_msg">
+      return;<br class="gmail_msg">
+    }<br class="gmail_msg">
+    OS << "\"";<br class="gmail_msg">
+    for (char Ch : S.bytes()) {<br class="gmail_msg">
+      if (Ch == '"')<br class="gmail_msg">
+        OS << "\\";<br class="gmail_msg">
+      OS << Ch;<br class="gmail_msg">
+    }<br class="gmail_msg">
+    OS << "\"";<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  raw_ostream &OS;<br class="gmail_msg">
+  int Indent = 0;<br class="gmail_msg">
 };<br class="gmail_msg">
<br class="gmail_msg">
+// Output symbolized information for coverage points in JSON.<br class="gmail_msg">
+// Format:<br class="gmail_msg">
+// {<br class="gmail_msg">
+//   '<file_name>' : {<br class="gmail_msg">
+//     '<function_name>' : {<br class="gmail_msg">
+//       '<point_id'> : '<line_number>:'<column_number'.<br class="gmail_msg">
+//          ....<br class="gmail_msg">
+//       }<br class="gmail_msg">
+//    }<br class="gmail_msg">
+// }<br class="gmail_msg">
+static void operator<<(JSONWriter &W,<br class="gmail_msg">
+                       const std::vector<CoveragePoint> &Points) {<br class="gmail_msg">
+  // Group points by file.<br class="gmail_msg">
+  auto ByFile(W.object());<br class="gmail_msg">
+  std::map<std::string, std::vector<const CoveragePoint *>> PointsByFile;<br class="gmail_msg">
+  for (const auto &Point : Points) {<br class="gmail_msg">
+    for (const DILineInfo &Loc : Point.Locs) {<br class="gmail_msg">
+      PointsByFile[Loc.FileName].push_back(&Point);<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  for (const auto &P : PointsByFile) {<br class="gmail_msg">
+    std::string FileName = P.first;<br class="gmail_msg">
+    ByFile->key(FileName);<br class="gmail_msg">
+<br class="gmail_msg">
+    // Group points by function.<br class="gmail_msg">
+    auto ByFn(W.object());<br class="gmail_msg">
+    std::map<std::string, std::vector<const CoveragePoint *>> PointsByFn;<br class="gmail_msg">
+    for (auto PointPtr : P.second) {<br class="gmail_msg">
+      for (const DILineInfo &Loc : PointPtr->Locs) {<br class="gmail_msg">
+        PointsByFn[Loc.FunctionName].push_back(PointPtr);<br class="gmail_msg">
+      }<br class="gmail_msg">
+    }<br class="gmail_msg">
+<br class="gmail_msg">
+    for (const auto &P : PointsByFn) {<br class="gmail_msg">
+      std::string FunctionName = P.first;<br class="gmail_msg">
+      ByFn->key(FunctionName);<br class="gmail_msg">
+<br class="gmail_msg">
+      // Output <point_id> : "<line>:<col>".<br class="gmail_msg">
+      auto ById(W.object());<br class="gmail_msg">
+      for (const CoveragePoint *Point : P.second) {<br class="gmail_msg">
+        for (const auto &Loc : Point->Locs) {<br class="gmail_msg">
+          if (Loc.FileName != FileName || Loc.FunctionName != FunctionName)<br class="gmail_msg">
+            continue;<br class="gmail_msg">
+<br class="gmail_msg">
+          ById->key(Point->Id);<br class="gmail_msg">
+          W << (utostr(Loc.Line) + ":" + utostr(Loc.Column));<br class="gmail_msg">
+        }<br class="gmail_msg">
+      }<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+static void operator<<(JSONWriter &W, const SymbolizedCoverage &C) {<br class="gmail_msg">
+  auto O(W.object());<br class="gmail_msg">
+<br class="gmail_msg">
+  {<br class="gmail_msg">
+    O->key("covered-points");<br class="gmail_msg">
+    auto PointsArray(W.array());<br class="gmail_msg">
+<br class="gmail_msg">
+    for (const auto &P : C.CoveredIds) {<br class="gmail_msg">
+      PointsArray->next();<br class="gmail_msg">
+      W << P;<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  {<br class="gmail_msg">
+    if (!C.BinaryHash.empty()) {<br class="gmail_msg">
+      O->key("binary-hash");<br class="gmail_msg">
+      W << C.BinaryHash;<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  {<br class="gmail_msg">
+    O->key("point-symbol-info");<br class="gmail_msg">
+    W << C.Points;<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+static std::string parseScalarString(yaml::Node *N) {<br class="gmail_msg">
+  SmallString<64> StringStorage;<br class="gmail_msg">
+  yaml::ScalarNode *S = dyn_cast<yaml::ScalarNode>(N);<br class="gmail_msg">
+  failIf(!S, "expected string");<br class="gmail_msg">
+  return S->getValue(StringStorage);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+std::unique_ptr<SymbolizedCoverage><br class="gmail_msg">
+SymbolizedCoverage::read(const std::string &InputFile) {<br class="gmail_msg">
+  auto Coverage(make_unique<SymbolizedCoverage>());<br class="gmail_msg">
+<br class="gmail_msg">
+  std::map<std::string, CoveragePoint> Points;<br class="gmail_msg">
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =<br class="gmail_msg">
+      MemoryBuffer::getFile(InputFile);<br class="gmail_msg">
+  failIfError(BufOrErr);<br class="gmail_msg">
+<br class="gmail_msg">
+  SourceMgr SM;<br class="gmail_msg">
+  yaml::Stream S(**BufOrErr, SM);<br class="gmail_msg">
+<br class="gmail_msg">
+  yaml::document_iterator DI = S.begin();<br class="gmail_msg">
+  failIf(DI == S.end(), "empty document: " + InputFile);<br class="gmail_msg">
+  yaml::Node *Root = DI->getRoot();<br class="gmail_msg">
+  failIf(!Root, "expecting root node: " + InputFile);<br class="gmail_msg">
+  yaml::MappingNode *Top = dyn_cast<yaml::MappingNode>(Root);<br class="gmail_msg">
+  failIf(!Top, "expecting mapping node: " + InputFile);<br class="gmail_msg">
+<br class="gmail_msg">
+  for (auto &KVNode : *Top) {<br class="gmail_msg">
+    auto Key = parseScalarString(KVNode.getKey());<br class="gmail_msg">
+<br class="gmail_msg">
+    if (Key == "covered-points") {<br class="gmail_msg">
+      yaml::SequenceNode *Points =<br class="gmail_msg">
+          dyn_cast<yaml::SequenceNode>(KVNode.getValue());<br class="gmail_msg">
+      failIf(!Points, "expected array: " + InputFile);<br class="gmail_msg">
+<br class="gmail_msg">
+      for (auto I = Points->begin(), E = Points->end(); I != E; ++I) {<br class="gmail_msg">
+        Coverage->CoveredIds.insert(parseScalarString(&*I));<br class="gmail_msg">
+      }<br class="gmail_msg">
+    } else if (Key == "binary-hash") {<br class="gmail_msg">
+      Coverage->BinaryHash = parseScalarString(KVNode.getValue());<br class="gmail_msg">
+    } else if (Key == "point-symbol-info") {<br class="gmail_msg">
+      yaml::MappingNode *PointSymbolInfo =<br class="gmail_msg">
+          dyn_cast<yaml::MappingNode>(KVNode.getValue());<br class="gmail_msg">
+      failIf(!PointSymbolInfo, "expected mapping node: " + InputFile);<br class="gmail_msg">
+<br class="gmail_msg">
+      for (auto &FileKVNode : *PointSymbolInfo) {<br class="gmail_msg">
+        auto Filename = parseScalarString(FileKVNode.getKey());<br class="gmail_msg">
+<br class="gmail_msg">
+        yaml::MappingNode *FileInfo =<br class="gmail_msg">
+            dyn_cast<yaml::MappingNode>(FileKVNode.getValue());<br class="gmail_msg">
+        failIf(!FileInfo, "expected mapping node: " + InputFile);<br class="gmail_msg">
+<br class="gmail_msg">
+        for (auto &FunctionKVNode : *FileInfo) {<br class="gmail_msg">
+          auto FunctionName = parseScalarString(FunctionKVNode.getKey());<br class="gmail_msg">
+<br class="gmail_msg">
+          yaml::MappingNode *FunctionInfo =<br class="gmail_msg">
+              dyn_cast<yaml::MappingNode>(FunctionKVNode.getValue());<br class="gmail_msg">
+          failIf(!FunctionInfo, "expected mapping node: " + InputFile);<br class="gmail_msg">
+<br class="gmail_msg">
+          for (auto &PointKVNode : *FunctionInfo) {<br class="gmail_msg">
+            auto PointId = parseScalarString(PointKVNode.getKey());<br class="gmail_msg">
+            auto Loc = parseScalarString(PointKVNode.getValue());<br class="gmail_msg">
+<br class="gmail_msg">
+            size_t ColonPos = Loc.find(':');<br class="gmail_msg">
+            failIf(ColonPos == std::string::npos, "expected ':': " + InputFile);<br class="gmail_msg">
+<br class="gmail_msg">
+            auto LineStr = Loc.substr(0, ColonPos);<br class="gmail_msg">
+            auto ColStr = Loc.substr(ColonPos + 1, Loc.size());<br class="gmail_msg">
+<br class="gmail_msg">
+            if (Points.find(PointId) == Points.end())<br class="gmail_msg">
+              Points.insert(std::make_pair(PointId, CoveragePoint(PointId)));<br class="gmail_msg">
+<br class="gmail_msg">
+            DILineInfo LineInfo;<br class="gmail_msg">
+            LineInfo.FileName = Filename;<br class="gmail_msg">
+            LineInfo.FunctionName = FunctionName;<br class="gmail_msg">
+            char *End;<br class="gmail_msg">
+            LineInfo.Line = std::strtoul(LineStr.c_str(), &End, 10);<br class="gmail_msg">
+            LineInfo.Column = std::strtoul(ColStr.c_str(), &End, 10);<br class="gmail_msg">
+<br class="gmail_msg">
+            CoveragePoint *CoveragePoint = &Points.find(PointId)->second;<br class="gmail_msg">
+            CoveragePoint->Locs.push_back(LineInfo);<br class="gmail_msg">
+          }<br class="gmail_msg">
+        }<br class="gmail_msg">
+      }<br class="gmail_msg">
+    } else {<br class="gmail_msg">
+      errs() << "Ignoring unknown key: " << Key << "\n";<br class="gmail_msg">
+    }<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  for (auto &KV : Points) {<br class="gmail_msg">
+    Coverage->Points.push_back(KV.second);<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  return Coverage;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// ---------- MAIN FUNCTIONALITY ----------<br class="gmail_msg">
+<br class="gmail_msg">
 std::string stripPathPrefix(std::string Path) {<br class="gmail_msg">
   if (ClStripPathPrefix.empty())<br class="gmail_msg">
     return Path;<br class="gmail_msg">
@@ -232,21 +561,11 @@ static std::unique_ptr<symbolize::LLVMSy<br class="gmail_msg">
       new symbolize::LLVMSymbolizer(SymbolizerOptions));<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-// A DILineInfo with address.<br class="gmail_msg">
-struct AddrInfo : public DILineInfo {<br class="gmail_msg">
-  uint64_t Addr;<br class="gmail_msg">
-<br class="gmail_msg">
-  AddrInfo(const DILineInfo &DI, uint64_t Addr) : DILineInfo(DI), Addr(Addr) {<br class="gmail_msg">
-    FileName = normalizeFilename(FileName);<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-private:<br class="gmail_msg">
-  static std::string normalizeFilename(const std::string &FileName) {<br class="gmail_msg">
-    SmallString<256> S(FileName);<br class="gmail_msg">
-    sys::path::remove_dots(S, /* remove_dot_dot */ true);<br class="gmail_msg">
-    return S.str().str();<br class="gmail_msg">
-  }<br class="gmail_msg">
-};<br class="gmail_msg">
+static std::string normalizeFilename(const std::string &FileName) {<br class="gmail_msg">
+  SmallString<256> S(FileName);<br class="gmail_msg">
+  sys::path::remove_dots(S, /* remove_dot_dot */ true);<br class="gmail_msg">
+  return stripPathPrefix(S.str().str());<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
 class Blacklists {<br class="gmail_msg">
 public:<br class="gmail_msg">
@@ -254,16 +573,14 @@ public:<br class="gmail_msg">
       : DefaultBlacklist(createDefaultBlacklist()),<br class="gmail_msg">
         UserBlacklist(createUserBlacklist()) {}<br class="gmail_msg">
<br class="gmail_msg">
-  // AddrInfo contains normalized filename. It is important to check it rather<br class="gmail_msg">
-  // than DILineInfo.<br class="gmail_msg">
-  bool isBlacklisted(const AddrInfo &AI) {<br class="gmail_msg">
-    if (DefaultBlacklist && DefaultBlacklist->inSection("fun", AI.FunctionName))<br class="gmail_msg">
+  bool isBlacklisted(const DILineInfo &I) {<br class="gmail_msg">
+    if (DefaultBlacklist && DefaultBlacklist->inSection("fun", I.FunctionName))<br class="gmail_msg">
       return true;<br class="gmail_msg">
-    if (DefaultBlacklist && DefaultBlacklist->inSection("src", AI.FileName))<br class="gmail_msg">
+    if (DefaultBlacklist && DefaultBlacklist->inSection("src", I.FileName))<br class="gmail_msg">
       return true;<br class="gmail_msg">
-    if (UserBlacklist && UserBlacklist->inSection("fun", AI.FunctionName))<br class="gmail_msg">
+    if (UserBlacklist && UserBlacklist->inSection("fun", I.FunctionName))<br class="gmail_msg">
       return true;<br class="gmail_msg">
-    if (UserBlacklist && UserBlacklist->inSection("src", AI.FileName))<br class="gmail_msg">
+    if (UserBlacklist && UserBlacklist->inSection("src", I.FileName))<br class="gmail_msg">
       return true;<br class="gmail_msg">
     return false;<br class="gmail_msg">
   }<br class="gmail_msg">
@@ -276,7 +593,7 @@ private:<br class="gmail_msg">
         MemoryBuffer::getMemBuffer(DefaultBlacklistStr);<br class="gmail_msg">
     std::string Error;<br class="gmail_msg">
     auto Blacklist = SpecialCaseList::create(MB.get(), Error);<br class="gmail_msg">
-    FailIfNotEmpty(Error);<br class="gmail_msg">
+    failIfNotEmpty(Error);<br class="gmail_msg">
     return Blacklist;<br class="gmail_msg">
   }<br class="gmail_msg">
<br class="gmail_msg">
@@ -290,32 +607,43 @@ private:<br class="gmail_msg">
   std::unique_ptr<SpecialCaseList> UserBlacklist;<br class="gmail_msg">
 };<br class="gmail_msg">
<br class="gmail_msg">
-// Collect all debug info for given addresses.<br class="gmail_msg">
-static std::vector<AddrInfo> getAddrInfo(const std::string &ObjectFile,<br class="gmail_msg">
-                                         const std::set<uint64_t> &Addrs,<br class="gmail_msg">
-                                         bool InlinedCode) {<br class="gmail_msg">
-  std::vector<AddrInfo> Result;<br class="gmail_msg">
+static std::vector<CoveragePoint><br class="gmail_msg">
+getCoveragePoints(const std::string &ObjectFile,<br class="gmail_msg">
+                  const std::set<uint64_t> &Addrs, bool InlinedCode) {<br class="gmail_msg">
+  std::vector<CoveragePoint> Result;<br class="gmail_msg">
   auto Symbolizer(createSymbolizer());<br class="gmail_msg">
   Blacklists B;<br class="gmail_msg">
<br class="gmail_msg">
   for (auto Addr : Addrs) {<br class="gmail_msg">
+    std::set<DILineInfo> Infos; // deduplicate debug info.<br class="gmail_msg">
+<br class="gmail_msg">
     auto LineInfo = Symbolizer->symbolizeCode(ObjectFile, Addr);<br class="gmail_msg">
-    FailIfError(LineInfo);<br class="gmail_msg">
-    auto LineAddrInfo = AddrInfo(*LineInfo, Addr);<br class="gmail_msg">
-    if (B.isBlacklisted(LineAddrInfo))<br class="gmail_msg">
+    failIfError(LineInfo);<br class="gmail_msg">
+    LineInfo->FileName = normalizeFilename(LineInfo->FileName);<br class="gmail_msg">
+    if (B.isBlacklisted(*LineInfo))<br class="gmail_msg">
       continue;<br class="gmail_msg">
-    Result.push_back(LineAddrInfo);<br class="gmail_msg">
+<br class="gmail_msg">
+    auto Id = utohexstr(Addr, true);<br class="gmail_msg">
+    auto Point = CoveragePoint(Id);<br class="gmail_msg">
+    Infos.insert(*LineInfo);<br class="gmail_msg">
+    Point.Locs.push_back(*LineInfo);<br class="gmail_msg">
+<br class="gmail_msg">
     if (InlinedCode) {<br class="gmail_msg">
       auto InliningInfo = Symbolizer->symbolizeInlinedCode(ObjectFile, Addr);<br class="gmail_msg">
-      FailIfError(InliningInfo);<br class="gmail_msg">
+      failIfError(InliningInfo);<br class="gmail_msg">
       for (uint32_t I = 0; I < InliningInfo->getNumberOfFrames(); ++I) {<br class="gmail_msg">
         auto FrameInfo = InliningInfo->getFrame(I);<br class="gmail_msg">
-        auto FrameAddrInfo = AddrInfo(FrameInfo, Addr);<br class="gmail_msg">
-        if (B.isBlacklisted(FrameAddrInfo))<br class="gmail_msg">
+        FrameInfo.FileName = normalizeFilename(FrameInfo.FileName);<br class="gmail_msg">
+        if (B.isBlacklisted(FrameInfo))<br class="gmail_msg">
           continue;<br class="gmail_msg">
-        Result.push_back(FrameAddrInfo);<br class="gmail_msg">
+        if (Infos.find(FrameInfo) == Infos.end()) {<br class="gmail_msg">
+          Infos.insert(FrameInfo);<br class="gmail_msg">
+          Point.Locs.push_back(FrameInfo);<br class="gmail_msg">
+        }<br class="gmail_msg">
       }<br class="gmail_msg">
     }<br class="gmail_msg">
+<br class="gmail_msg">
+    Result.push_back(Point);<br class="gmail_msg">
   }<br class="gmail_msg">
<br class="gmail_msg">
   return Result;<br class="gmail_msg">
@@ -353,7 +681,7 @@ static void findMachOIndirectCovFunction<br class="gmail_msg">
             if (IndirectSymbol < Symtab.nsyms) {<br class="gmail_msg">
               object::SymbolRef Symbol = *(O.getSymbolByIndex(IndirectSymbol));<br class="gmail_msg">
               Expected<StringRef> Name = Symbol.getName();<br class="gmail_msg">
-              FailIfError(Name);<br class="gmail_msg">
+              failIfError(Name);<br class="gmail_msg">
               if (isCoveragePointSymbol(Name.get())) {<br class="gmail_msg">
                 Result->insert(Addr);<br class="gmail_msg">
               }<br class="gmail_msg">
@@ -376,11 +704,11 @@ findSanitizerCovFunctions(const object::<br class="gmail_msg">
<br class="gmail_msg">
   for (const object::SymbolRef &Symbol : O.symbols()) {<br class="gmail_msg">
     Expected<uint64_t> AddressOrErr = Symbol.getAddress();<br class="gmail_msg">
-    FailIfError(AddressOrErr);<br class="gmail_msg">
+    failIfError(AddressOrErr);<br class="gmail_msg">
     uint64_t Address = AddressOrErr.get();<br class="gmail_msg">
<br class="gmail_msg">
     Expected<StringRef> NameOrErr = Symbol.getName();<br class="gmail_msg">
-    FailIfError(NameOrErr);<br class="gmail_msg">
+    failIfError(NameOrErr);<br class="gmail_msg">
     StringRef Name = NameOrErr.get();<br class="gmail_msg">
<br class="gmail_msg">
     if (!(Symbol.getFlags() & object::BasicSymbolRef::SF_Undefined) &&<br class="gmail_msg">
@@ -394,11 +722,11 @@ findSanitizerCovFunctions(const object::<br class="gmail_msg">
          CO->export_directories()) {<br class="gmail_msg">
       uint32_t RVA;<br class="gmail_msg">
       std::error_code EC = Export.getExportRVA(RVA);<br class="gmail_msg">
-      FailIfError(EC);<br class="gmail_msg">
+      failIfError(EC);<br class="gmail_msg">
<br class="gmail_msg">
       StringRef Name;<br class="gmail_msg">
       EC = Export.getSymbolName(Name);<br class="gmail_msg">
-      FailIfError(EC);<br class="gmail_msg">
+      failIfError(EC);<br class="gmail_msg">
<br class="gmail_msg">
       if (isCoveragePointSymbol(Name))<br class="gmail_msg">
         Result.insert(CO->getImageBase() + RVA);<br class="gmail_msg">
@@ -423,36 +751,36 @@ static void getObjectCoveragePoints(cons<br class="gmail_msg">
<br class="gmail_msg">
   std::string Error;<br class="gmail_msg">
   const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error);<br class="gmail_msg">
-  FailIfNotEmpty(Error);<br class="gmail_msg">
+  failIfNotEmpty(Error);<br class="gmail_msg">
<br class="gmail_msg">
   std::unique_ptr<const MCSubtargetInfo> STI(<br class="gmail_msg">
       TheTarget->createMCSubtargetInfo(TripleName, "", ""));<br class="gmail_msg">
-  FailIfEmpty(STI, "no subtarget info for target " + TripleName);<br class="gmail_msg">
+  failIfEmpty(STI, "no subtarget info for target " + TripleName);<br class="gmail_msg">
<br class="gmail_msg">
   std::unique_ptr<const MCRegisterInfo> MRI(<br class="gmail_msg">
       TheTarget->createMCRegInfo(TripleName));<br class="gmail_msg">
-  FailIfEmpty(MRI, "no register info for target " + TripleName);<br class="gmail_msg">
+  failIfEmpty(MRI, "no register info for target " + TripleName);<br class="gmail_msg">
<br class="gmail_msg">
   std::unique_ptr<const MCAsmInfo> AsmInfo(<br class="gmail_msg">
       TheTarget->createMCAsmInfo(*MRI, TripleName));<br class="gmail_msg">
-  FailIfEmpty(AsmInfo, "no asm info for target " + TripleName);<br class="gmail_msg">
+  failIfEmpty(AsmInfo, "no asm info for target " + TripleName);<br class="gmail_msg">
<br class="gmail_msg">
   std::unique_ptr<const MCObjectFileInfo> MOFI(new MCObjectFileInfo);<br class="gmail_msg">
   MCContext Ctx(AsmInfo.get(), MRI.get(), MOFI.get());<br class="gmail_msg">
   std::unique_ptr<MCDisassembler> DisAsm(<br class="gmail_msg">
       TheTarget->createMCDisassembler(*STI, Ctx));<br class="gmail_msg">
-  FailIfEmpty(DisAsm, "no disassembler info for target " + TripleName);<br class="gmail_msg">
+  failIfEmpty(DisAsm, "no disassembler info for target " + TripleName);<br class="gmail_msg">
<br class="gmail_msg">
   std::unique_ptr<const MCInstrInfo> MII(TheTarget->createMCInstrInfo());<br class="gmail_msg">
-  FailIfEmpty(MII, "no instruction info for target " + TripleName);<br class="gmail_msg">
+  failIfEmpty(MII, "no instruction info for target " + TripleName);<br class="gmail_msg">
<br class="gmail_msg">
   std::unique_ptr<const MCInstrAnalysis> MIA(<br class="gmail_msg">
       TheTarget->createMCInstrAnalysis(MII.get()));<br class="gmail_msg">
-  FailIfEmpty(MIA, "no instruction analysis info for target " + TripleName);<br class="gmail_msg">
+  failIfEmpty(MIA, "no instruction analysis info for target " + TripleName);<br class="gmail_msg">
<br class="gmail_msg">
   auto SanCovAddrs = findSanitizerCovFunctions(O);<br class="gmail_msg">
   if (SanCovAddrs.empty())<br class="gmail_msg">
-    Fail("__sanitizer_cov* functions not found");<br class="gmail_msg">
+    fail("__sanitizer_cov* functions not found");<br class="gmail_msg">
<br class="gmail_msg">
   for (object::SectionRef Section : O.sections()) {<br class="gmail_msg">
     if (Section.isVirtual() || !Section.isText()) // llvm-objdump does the same.<br class="gmail_msg">
@@ -463,7 +791,7 @@ static void getObjectCoveragePoints(cons<br class="gmail_msg">
       continue;<br class="gmail_msg">
<br class="gmail_msg">
     StringRef BytesStr;<br class="gmail_msg">
-    FailIfError(Section.getContents(BytesStr));<br class="gmail_msg">
+    failIfError(Section.getContents(BytesStr));<br class="gmail_msg">
     ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(BytesStr.data()),<br class="gmail_msg">
                             BytesStr.size());<br class="gmail_msg">
<br class="gmail_msg">
@@ -494,13 +822,13 @@ visitObjectFiles(const object::Archive &<br class="gmail_msg">
   Error Err;<br class="gmail_msg">
   for (auto &C : A.children(Err)) {<br class="gmail_msg">
     Expected<std::unique_ptr<object::Binary>> ChildOrErr = C.getAsBinary();<br class="gmail_msg">
-    FailIfError(ChildOrErr);<br class="gmail_msg">
+    failIfError(ChildOrErr);<br class="gmail_msg">
     if (auto *O = dyn_cast<object::ObjectFile>(&*ChildOrErr.get()))<br class="gmail_msg">
       Fn(*O);<br class="gmail_msg">
     else<br class="gmail_msg">
-      FailIfError(object::object_error::invalid_file_type);<br class="gmail_msg">
+      failIfError(object::object_error::invalid_file_type);<br class="gmail_msg">
   }<br class="gmail_msg">
-  FailIfError(std::move(Err));<br class="gmail_msg">
+  failIfError(std::move(Err));<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
 static void<br class="gmail_msg">
@@ -509,7 +837,7 @@ visitObjectFiles(const std::string &File<br class="gmail_msg">
   Expected<object::OwningBinary<object::Binary>> BinaryOrErr =<br class="gmail_msg">
       object::createBinary(FileName);<br class="gmail_msg">
   if (!BinaryOrErr)<br class="gmail_msg">
-    FailIfError(BinaryOrErr);<br class="gmail_msg">
+    failIfError(BinaryOrErr);<br class="gmail_msg">
<br class="gmail_msg">
   object::Binary &Binary = *BinaryOrErr.get().getBinary();<br class="gmail_msg">
   if (object::Archive *A = dyn_cast<object::Archive>(&Binary))<br class="gmail_msg">
@@ -517,10 +845,11 @@ visitObjectFiles(const std::string &File<br class="gmail_msg">
   else if (object::ObjectFile *O = dyn_cast<object::ObjectFile>(&Binary))<br class="gmail_msg">
     Fn(*O);<br class="gmail_msg">
   else<br class="gmail_msg">
-    FailIfError(object::object_error::invalid_file_type);<br class="gmail_msg">
+    failIfError(object::object_error::invalid_file_type);<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-std::set<uint64_t> findSanitizerCovFunctions(const std::string &FileName) {<br class="gmail_msg">
+static std::set<uint64_t><br class="gmail_msg">
+findSanitizerCovFunctions(const std::string &FileName) {<br class="gmail_msg">
   std::set<uint64_t> Result;<br class="gmail_msg">
   visitObjectFiles(FileName, [&](const object::ObjectFile &O) {<br class="gmail_msg">
     auto Addrs = findSanitizerCovFunctions(O);<br class="gmail_msg">
@@ -532,7 +861,7 @@ std::set<uint64_t> findSanitizerCovFunct<br class="gmail_msg">
 // Locate addresses of all coverage points in a file. Coverage point<br class="gmail_msg">
 // is defined as the 'address of instruction following __sanitizer_cov<br class="gmail_msg">
 // call - 1'.<br class="gmail_msg">
-std::set<uint64_t> getCoveragePoints(const std::string &FileName) {<br class="gmail_msg">
+static std::set<uint64_t> findCoveragePointAddrs(const std::string &FileName) {<br class="gmail_msg">
   std::set<uint64_t> Result;<br class="gmail_msg">
   visitObjectFiles(FileName, [&](const object::ObjectFile &O) {<br class="gmail_msg">
     getObjectCoveragePoints(O, &Result);<br class="gmail_msg">
@@ -541,66 +870,18 @@ std::set<uint64_t> getCoveragePoints(con<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
 static void printCovPoints(const std::string &ObjFile, raw_ostream &OS) {<br class="gmail_msg">
-  for (uint64_t Addr : getCoveragePoints(ObjFile)) {<br class="gmail_msg">
+  for (uint64_t Addr : findCoveragePointAddrs(ObjFile)) {<br class="gmail_msg">
     OS << "0x";<br class="gmail_msg">
     OS.write_hex(Addr);<br class="gmail_msg">
     OS << "\n";<br class="gmail_msg">
   }<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-static std::string escapeHtml(const std::string &S) {<br class="gmail_msg">
-  std::string Result;<br class="gmail_msg">
-  Result.reserve(S.size());<br class="gmail_msg">
-  for (char Ch : S) {<br class="gmail_msg">
-    switch (Ch) {<br class="gmail_msg">
-    case '&':<br class="gmail_msg">
-      Result.append("&amp;");<br class="gmail_msg">
-      break;<br class="gmail_msg">
-    case '\'':<br class="gmail_msg">
-      Result.append("&apos;");<br class="gmail_msg">
-      break;<br class="gmail_msg">
-    case '"':<br class="gmail_msg">
-      Result.append("&quot;");<br class="gmail_msg">
-      break;<br class="gmail_msg">
-    case '<':<br class="gmail_msg">
-      Result.append("&lt;");<br class="gmail_msg">
-      break;<br class="gmail_msg">
-    case '>':<br class="gmail_msg">
-      Result.append("&gt;");<br class="gmail_msg">
-      break;<br class="gmail_msg">
-    default:<br class="gmail_msg">
-      Result.push_back(Ch);<br class="gmail_msg">
-      break;<br class="gmail_msg">
-    }<br class="gmail_msg">
-  }<br class="gmail_msg">
-  return Result;<br class="gmail_msg">
-}<br class="gmail_msg">
-<br class="gmail_msg">
-// Adds leading zeroes wrapped in 'lz' style.<br class="gmail_msg">
-// Leading zeroes help locate 000% coverage.<br class="gmail_msg">
-static std::string formatHtmlPct(size_t Pct) {<br class="gmail_msg">
-  Pct = std::max(std::size_t{0}, std::min(std::size_t{100}, Pct));<br class="gmail_msg">
-<br class="gmail_msg">
-  std::string Num = std::to_string(Pct);<br class="gmail_msg">
-  std::string Zeroes(3 - Num.size(), '0');<br class="gmail_msg">
-  if (!Zeroes.empty())<br class="gmail_msg">
-    Zeroes = "<span class='lz'>" + Zeroes + "</span>";<br class="gmail_msg">
-<br class="gmail_msg">
-  return Zeroes + Num;<br class="gmail_msg">
-}<br class="gmail_msg">
-<br class="gmail_msg">
-static std::string anchorName(const std::string &Anchor) {<br class="gmail_msg">
-  llvm::MD5 Hasher;<br class="gmail_msg">
-  llvm::MD5::MD5Result Hash;<br class="gmail_msg">
-  Hasher.update(Anchor);<br class="gmail_msg">
-  Hasher.final(Hash);<br class="gmail_msg">
-<br class="gmail_msg">
-  SmallString<32> HexString;<br class="gmail_msg">
-  llvm::MD5::stringifyResult(Hash, HexString);<br class="gmail_msg">
-  return HexString.str().str();<br class="gmail_msg">
-}<br class="gmail_msg">
-<br class="gmail_msg">
 static ErrorOr<bool> isCoverageFile(const std::string &FileName) {<br class="gmail_msg">
+  auto ShortFileName = llvm::sys::path::filename(FileName);<br class="gmail_msg">
+  if (!SancovFileRegex.match(ShortFileName))<br class="gmail_msg">
+    return false;<br class="gmail_msg">
+<br class="gmail_msg">
   ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =<br class="gmail_msg">
       MemoryBuffer::getFile(FileName);<br class="gmail_msg">
   if (!BufOrErr) {<br class="gmail_msg">
@@ -618,490 +899,187 @@ static ErrorOr<bool> isCoverageFile(cons<br class="gmail_msg">
   return Header->Magic == BinCoverageMagic;<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-struct CoverageStats {<br class="gmail_msg">
-  CoverageStats() : AllPoints(0), CovPoints(0), AllFns(0), CovFns(0) {}<br class="gmail_msg">
-<br class="gmail_msg">
-  size_t AllPoints;<br class="gmail_msg">
-  size_t CovPoints;<br class="gmail_msg">
-  size_t AllFns;<br class="gmail_msg">
-  size_t CovFns;<br class="gmail_msg">
-};<br class="gmail_msg">
-<br class="gmail_msg">
-static raw_ostream &operator<<(raw_ostream &OS, const CoverageStats &Stats) {<br class="gmail_msg">
-  OS << "all-edges: " << Stats.AllPoints << "\n";<br class="gmail_msg">
-  OS << "cov-edges: " << Stats.CovPoints << "\n";<br class="gmail_msg">
-  OS << "all-functions: " << Stats.AllFns << "\n";<br class="gmail_msg">
-  OS << "cov-functions: " << Stats.CovFns << "\n";<br class="gmail_msg">
-  return OS;<br class="gmail_msg">
+static bool isSymbolizedCoverageFile(const std::string &FileName) {<br class="gmail_msg">
+  auto ShortFileName = llvm::sys::path::filename(FileName);<br class="gmail_msg">
+  return SymcovFileRegex.match(ShortFileName);<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-class CoverageData {<br class="gmail_msg">
-public:<br class="gmail_msg">
-  // Read single file coverage data.<br class="gmail_msg">
-  static ErrorOr<std::unique_ptr<CoverageData>><br class="gmail_msg">
-  read(const std::string &FileName) {<br class="gmail_msg">
-    ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =<br class="gmail_msg">
-        MemoryBuffer::getFile(FileName);<br class="gmail_msg">
-    if (!BufOrErr)<br class="gmail_msg">
-      return BufOrErr.getError();<br class="gmail_msg">
-    std::unique_ptr<MemoryBuffer> Buf = std::move(BufOrErr.get());<br class="gmail_msg">
-    if (Buf->getBufferSize() < 8) {<br class="gmail_msg">
-      errs() << "File too small (<8): " << Buf->getBufferSize() << '\n';<br class="gmail_msg">
-      return make_error_code(errc::illegal_byte_sequence);<br class="gmail_msg">
-    }<br class="gmail_msg">
-    const FileHeader *Header =<br class="gmail_msg">
-        reinterpret_cast<const FileHeader *>(Buf->getBufferStart());<br class="gmail_msg">
-<br class="gmail_msg">
-    if (Header->Magic != BinCoverageMagic) {<br class="gmail_msg">
-      errs() << "Wrong magic: " << Header->Magic << '\n';<br class="gmail_msg">
-      return make_error_code(errc::illegal_byte_sequence);<br class="gmail_msg">
-    }<br class="gmail_msg">
-<br class="gmail_msg">
-    auto Addrs = llvm::make_unique<std::set<uint64_t>>();<br class="gmail_msg">
-<br class="gmail_msg">
-    switch (Header->Bitness) {<br class="gmail_msg">
-    case Bitness64:<br class="gmail_msg">
-      readInts<uint64_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),<br class="gmail_msg">
-                         Addrs.get());<br class="gmail_msg">
-      break;<br class="gmail_msg">
-    case Bitness32:<br class="gmail_msg">
-      readInts<uint32_t>(Buf->getBufferStart() + 8, Buf->getBufferEnd(),<br class="gmail_msg">
-                         Addrs.get());<br class="gmail_msg">
-      break;<br class="gmail_msg">
-    default:<br class="gmail_msg">
-      errs() << "Unsupported bitness: " << Header->Bitness << '\n';<br class="gmail_msg">
-      return make_error_code(errc::illegal_byte_sequence);<br class="gmail_msg">
-    }<br class="gmail_msg">
-<br class="gmail_msg">
-    return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  // Merge multiple coverage data together.<br class="gmail_msg">
-  static std::unique_ptr<CoverageData><br class="gmail_msg">
-  merge(const std::vector<std::unique_ptr<CoverageData>> &Covs) {<br class="gmail_msg">
-    auto Addrs = llvm::make_unique<std::set<uint64_t>>();<br class="gmail_msg">
-<br class="gmail_msg">
-    for (const auto &Cov : Covs)<br class="gmail_msg">
-      Addrs->insert(Cov->Addrs->begin(), Cov->Addrs->end());<br class="gmail_msg">
-<br class="gmail_msg">
-    return std::unique_ptr<CoverageData>(new CoverageData(std::move(Addrs)));<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  // Read list of files and merges their coverage info.<br class="gmail_msg">
-  static ErrorOr<std::unique_ptr<CoverageData>><br class="gmail_msg">
-  readAndMerge(const std::vector<std::string> &FileNames) {<br class="gmail_msg">
-    std::vector<std::unique_ptr<CoverageData>> Covs;<br class="gmail_msg">
-    for (const auto &FileName : FileNames) {<br class="gmail_msg">
-      auto Cov = read(FileName);<br class="gmail_msg">
-      if (!Cov)<br class="gmail_msg">
-        return Cov.getError();<br class="gmail_msg">
-      Covs.push_back(std::move(Cov.get()));<br class="gmail_msg">
-    }<br class="gmail_msg">
-    return merge(Covs);<br class="gmail_msg">
-  }<br class="gmail_msg">
+static std::unique_ptr<SymbolizedCoverage><br class="gmail_msg">
+symbolize(const RawCoverage &Data, const std::string ObjectFile) {<br class="gmail_msg">
+  auto Coverage = make_unique<SymbolizedCoverage>();<br class="gmail_msg">
<br class="gmail_msg">
-  // Print coverage addresses.<br class="gmail_msg">
-  void printAddrs(raw_ostream &OS) {<br class="gmail_msg">
-    for (auto Addr : *Addrs) {<br class="gmail_msg">
-      OS << "0x";<br class="gmail_msg">
-      OS.write_hex(Addr);<br class="gmail_msg">
-      OS << "\n";<br class="gmail_msg">
-    }<br class="gmail_msg">
+  ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =<br class="gmail_msg">
+      MemoryBuffer::getFile(ObjectFile);<br class="gmail_msg">
+  failIfError(BufOrErr);<br class="gmail_msg">
+  SHA1 Hasher;<br class="gmail_msg">
+  Hasher.update((*BufOrErr)->getBuffer());<br class="gmail_msg">
+  Coverage->BinaryHash = toHex(Hasher.final());<br class="gmail_msg">
+<br class="gmail_msg">
+  for (uint64_t Addr : *Data.Addrs) {<br class="gmail_msg">
+    Coverage->CoveredIds.insert(utohexstr(Addr, true));<br class="gmail_msg">
+  }<br class="gmail_msg">
+<br class="gmail_msg">
+  std::set<uint64_t> AllAddrs = findCoveragePointAddrs(ObjectFile);<br class="gmail_msg">
+  if (!std::includes(AllAddrs.begin(), AllAddrs.end(), Data.Addrs->begin(),<br class="gmail_msg">
+                     Data.Addrs->end())) {<br class="gmail_msg">
+    fail("Coverage points in binary and .sancov file do not match.");<br class="gmail_msg">
   }<br class="gmail_msg">
+  Coverage->Points = getCoveragePoints(ObjectFile, AllAddrs, true);<br class="gmail_msg">
+  return Coverage;<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
-protected:<br class="gmail_msg">
-  explicit CoverageData(std::unique_ptr<std::set<uint64_t>> Addrs)<br class="gmail_msg">
-      : Addrs(std::move(Addrs)) {}<br class="gmail_msg">
-<br class="gmail_msg">
-  friend class CoverageDataWithObjectFile;<br class="gmail_msg">
+struct FileFn {<br class="gmail_msg">
+  bool operator<(const FileFn &RHS) const {<br class="gmail_msg">
+    return std::tie(FileName, FunctionName) <<br class="gmail_msg">
+           std::tie(RHS.FileName, RHS.FunctionName);<br class="gmail_msg">
+  }<br class="gmail_msg">
<br class="gmail_msg">
-  std::unique_ptr<std::set<uint64_t>> Addrs;<br class="gmail_msg">
+  std::string FileName;<br class="gmail_msg">
+  std::string FunctionName;<br class="gmail_msg">
 };<br class="gmail_msg">
<br class="gmail_msg">
-// Coverage data translated into source code line-level information.<br class="gmail_msg">
-// Fetches debug info in constructor and calculates various information per<br class="gmail_msg">
-// request.<br class="gmail_msg">
-class SourceCoverageData {<br class="gmail_msg">
-public:<br class="gmail_msg">
-  enum LineStatus {<br class="gmail_msg">
-    // coverage information for the line is not available.<br class="gmail_msg">
-    // default value in maps.<br class="gmail_msg">
-    UNKNOWN = 0,<br class="gmail_msg">
-    // the line is fully covered.<br class="gmail_msg">
-    COVERED = 1,<br class="gmail_msg">
-    // the line is fully uncovered.<br class="gmail_msg">
-    NOT_COVERED = 2,<br class="gmail_msg">
-    // some points in the line a covered, some are not.<br class="gmail_msg">
-    MIXED = 3<br class="gmail_msg">
-  };<br class="gmail_msg">
-<br class="gmail_msg">
-  SourceCoverageData(std::string ObjectFile, const std::set<uint64_t> &Addrs)<br class="gmail_msg">
-      : AllCovPoints(getCoveragePoints(ObjectFile)) {<br class="gmail_msg">
-    if (!std::includes(AllCovPoints.begin(), AllCovPoints.end(), Addrs.begin(),<br class="gmail_msg">
-                       Addrs.end())) {<br class="gmail_msg">
-      Fail("Coverage points in binary and .sancov file do not match.");<br class="gmail_msg">
-    }<br class="gmail_msg">
-<br class="gmail_msg">
-    AllAddrInfo = getAddrInfo(ObjectFile, AllCovPoints, true);<br class="gmail_msg">
-    CovAddrInfo = getAddrInfo(ObjectFile, Addrs, true);<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  // Compute number of coverage points hit/total in a file.<br class="gmail_msg">
-  // file_name -> <coverage, all_coverage><br class="gmail_msg">
-  std::map<std::string, std::pair<size_t, size_t>> computeFileCoverage() {<br class="gmail_msg">
-    std::map<std::string, std::pair<size_t, size_t>> FileCoverage;<br class="gmail_msg">
-    auto AllCovPointsByFile =<br class="gmail_msg">
-        group_by(AllAddrInfo, [](const AddrInfo &AI) { return AI.FileName; });<br class="gmail_msg">
-    auto CovPointsByFile =<br class="gmail_msg">
-        group_by(CovAddrInfo, [](const AddrInfo &AI) { return AI.FileName; });<br class="gmail_msg">
-<br class="gmail_msg">
-    for (const auto &P : AllCovPointsByFile) {<br class="gmail_msg">
-      const std::string &FileName = P.first;<br class="gmail_msg">
-<br class="gmail_msg">
-      FileCoverage[FileName] =<br class="gmail_msg">
-          std::make_pair(CovPointsByFile[FileName].size(),<br class="gmail_msg">
-                         AllCovPointsByFile[FileName].size());<br class="gmail_msg">
-    }<br class="gmail_msg">
-    return FileCoverage;<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  // line_number -> line_status.<br class="gmail_msg">
-  typedef std::map<int, LineStatus> LineStatusMap;<br class="gmail_msg">
-  // file_name -> LineStatusMap<br class="gmail_msg">
-  typedef std::map<std::string, LineStatusMap> FileLineStatusMap;<br class="gmail_msg">
-<br class="gmail_msg">
-  // fills in the {file_name -> {line_no -> status}} map.<br class="gmail_msg">
-  FileLineStatusMap computeLineStatusMap() {<br class="gmail_msg">
-    FileLineStatusMap StatusMap;<br class="gmail_msg">
-<br class="gmail_msg">
-    auto AllLocs = group_by(AllAddrInfo, [](const AddrInfo &AI) {<br class="gmail_msg">
-      return FileLoc{AI.FileName, AI.Line};<br class="gmail_msg">
-    });<br class="gmail_msg">
-    auto CovLocs = group_by(CovAddrInfo, [](const AddrInfo &AI) {<br class="gmail_msg">
-      return FileLoc{AI.FileName, AI.Line};<br class="gmail_msg">
-    });<br class="gmail_msg">
-<br class="gmail_msg">
-    for (const auto &P : AllLocs) {<br class="gmail_msg">
-      const FileLoc &Loc = P.first;<br class="gmail_msg">
-      auto I = CovLocs.find(Loc);<br class="gmail_msg">
-<br class="gmail_msg">
-      if (I == CovLocs.end()) {<br class="gmail_msg">
-        StatusMap[Loc.FileName][Loc.Line] = NOT_COVERED;<br class="gmail_msg">
-      } else {<br class="gmail_msg">
-        StatusMap[Loc.FileName][Loc.Line] =<br class="gmail_msg">
-            (I->second.size() == P.second.size()) ? COVERED : MIXED;<br class="gmail_msg">
-      }<br class="gmail_msg">
+static std::set<FileFn><br class="gmail_msg">
+computeFunctions(const std::vector<CoveragePoint> &Points) {<br class="gmail_msg">
+  std::set<FileFn> Fns;<br class="gmail_msg">
+  for (const auto &Point : Points) {<br class="gmail_msg">
+    for (const auto &Loc : Point.Locs) {<br class="gmail_msg">
+      Fns.insert(FileFn{Loc.FileName, Loc.FunctionName});<br class="gmail_msg">
     }<br class="gmail_msg">
-    return StatusMap;<br class="gmail_msg">
   }<br class="gmail_msg">
+  return Fns;<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
-  std::set<FileFn> computeAllFunctions() const {<br class="gmail_msg">
-    std::set<FileFn> Fns;<br class="gmail_msg">
-    for (const auto &AI : AllAddrInfo) {<br class="gmail_msg">
-      Fns.insert(FileFn{AI.FileName, AI.FunctionName});<br class="gmail_msg">
-    }<br class="gmail_msg">
-    return Fns;<br class="gmail_msg">
-  }<br class="gmail_msg">
+static std::set<FileFn><br class="gmail_msg">
+computeNotCoveredFunctions(const SymbolizedCoverage &Coverage) {<br class="gmail_msg">
+  auto Fns = computeFunctions(Coverage.Points);<br class="gmail_msg">
<br class="gmail_msg">
-  std::set<FileFn> computeCoveredFunctions() const {<br class="gmail_msg">
-    std::set<FileFn> Fns;<br class="gmail_msg">
-    auto CovFns = group_by(CovAddrInfo, [](const AddrInfo &AI) {<br class="gmail_msg">
-      return FileFn{AI.FileName, AI.FunctionName};<br class="gmail_msg">
-    });<br class="gmail_msg">
+  for (const auto &Point : Coverage.Points) {<br class="gmail_msg">
+    if (Coverage.CoveredIds.find(Point.Id) == Coverage.CoveredIds.end())<br class="gmail_msg">
+      continue;<br class="gmail_msg">
<br class="gmail_msg">
-    for (const auto &P : CovFns) {<br class="gmail_msg">
-      Fns.insert(P.first);<br class="gmail_msg">
+    for (const auto &Loc : Point.Locs) {<br class="gmail_msg">
+      Fns.erase(FileFn{Loc.FileName, Loc.FunctionName});<br class="gmail_msg">
     }<br class="gmail_msg">
-    return Fns;<br class="gmail_msg">
   }<br class="gmail_msg">
<br class="gmail_msg">
-  std::set<FileFn> computeNotCoveredFunctions() const {<br class="gmail_msg">
-    std::set<FileFn> Fns;<br class="gmail_msg">
-<br class="gmail_msg">
-    auto AllFns = group_by(AllAddrInfo, [](const AddrInfo &AI) {<br class="gmail_msg">
-      return FileFn{AI.FileName, AI.FunctionName};<br class="gmail_msg">
-    });<br class="gmail_msg">
-    auto CovFns = group_by(CovAddrInfo, [](const AddrInfo &AI) {<br class="gmail_msg">
-      return FileFn{AI.FileName, AI.FunctionName};<br class="gmail_msg">
-    });<br class="gmail_msg">
-<br class="gmail_msg">
-    for (const auto &P : AllFns) {<br class="gmail_msg">
-      if (CovFns.find(P.first) == CovFns.end()) {<br class="gmail_msg">
-        Fns.insert(P.first);<br class="gmail_msg">
-      }<br class="gmail_msg">
-    }<br class="gmail_msg">
-    return Fns;<br class="gmail_msg">
-  }<br class="gmail_msg">
+  return Fns;<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
-  // Compute % coverage for each function.<br class="gmail_msg">
-  std::map<FileFn, int> computeFunctionsCoverage() const {<br class="gmail_msg">
-    std::map<FileFn, int> FnCoverage;<br class="gmail_msg">
-    auto AllFns = group_by(AllAddrInfo, [](const AddrInfo &AI) {<br class="gmail_msg">
-      return FileFn{AI.FileName, AI.FunctionName};<br class="gmail_msg">
-    });<br class="gmail_msg">
+static std::set<FileFn><br class="gmail_msg">
+computeCoveredFunctions(const SymbolizedCoverage &Coverage) {<br class="gmail_msg">
+  auto AllFns = computeFunctions(Coverage.Points);<br class="gmail_msg">
+  std::set<FileFn> Result;<br class="gmail_msg">
<br class="gmail_msg">
-    auto CovFns = group_by(CovAddrInfo, [](const AddrInfo &AI) {<br class="gmail_msg">
-      return FileFn{AI.FileName, AI.FunctionName};<br class="gmail_msg">
-    });<br class="gmail_msg">
+  for (const auto &Point : Coverage.Points) {<br class="gmail_msg">
+    if (Coverage.CoveredIds.find(Point.Id) == Coverage.CoveredIds.end())<br class="gmail_msg">
+      continue;<br class="gmail_msg">
<br class="gmail_msg">
-    for (const auto &P : AllFns) {<br class="gmail_msg">
-      FileFn F = P.first;<br class="gmail_msg">
-      FnCoverage[F] = CovFns[F].size() * 100 / P.second.size();<br class="gmail_msg">
+    for (const auto &Loc : Point.Locs) {<br class="gmail_msg">
+      Result.insert(FileFn{Loc.FileName, Loc.FunctionName});<br class="gmail_msg">
     }<br class="gmail_msg">
-<br class="gmail_msg">
-    return FnCoverage;<br class="gmail_msg">
   }<br class="gmail_msg">
<br class="gmail_msg">
-  typedef std::map<FileLoc, std::set<std::string>> FunctionLocs;<br class="gmail_msg">
-  // finds first line number in a file for each function.<br class="gmail_msg">
-  FunctionLocs resolveFunctions(const std::set<FileFn> &Fns) const {<br class="gmail_msg">
-    std::vector<AddrInfo> FnAddrs;<br class="gmail_msg">
-    for (const auto &AI : AllAddrInfo) {<br class="gmail_msg">
-      if (Fns.find(FileFn{AI.FileName, AI.FunctionName}) != Fns.end())<br class="gmail_msg">
-        FnAddrs.push_back(AI);<br class="gmail_msg">
-    }<br class="gmail_msg">
-<br class="gmail_msg">
-    auto GroupedAddrs = group_by(FnAddrs, [](const AddrInfo &AI) {<br class="gmail_msg">
-      return FnLoc{FileLoc{AI.FileName, AI.Line}, AI.FunctionName};<br class="gmail_msg">
-    });<br class="gmail_msg">
-<br class="gmail_msg">
-    FunctionLocs Result;<br class="gmail_msg">
-    std::string LastFileName;<br class="gmail_msg">
-    std::set<std::string> ProcessedFunctions;<br class="gmail_msg">
-<br class="gmail_msg">
-    for (const auto &P : GroupedAddrs) {<br class="gmail_msg">
-      const FnLoc &Loc = P.first;<br class="gmail_msg">
-      std::string FileName = Loc.Loc.FileName;<br class="gmail_msg">
-      std::string FunctionName = Loc.FunctionName;<br class="gmail_msg">
-<br class="gmail_msg">
-      if (LastFileName != FileName)<br class="gmail_msg">
-        ProcessedFunctions.clear();<br class="gmail_msg">
-      LastFileName = FileName;<br class="gmail_msg">
+  return Result;<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
-      if (!ProcessedFunctions.insert(FunctionName).second)<br class="gmail_msg">
+typedef std::map<FileFn, std::pair<uint32_t, uint32_t>> FunctionLocs;<br class="gmail_msg">
+// finds first location in a file for each function.<br class="gmail_msg">
+static FunctionLocs resolveFunctions(const SymbolizedCoverage &Coverage,<br class="gmail_msg">
+                                     const std::set<FileFn> &Fns) {<br class="gmail_msg">
+  FunctionLocs Result;<br class="gmail_msg">
+  for (const auto &Point : Coverage.Points) {<br class="gmail_msg">
+    for (const auto &Loc : Point.Locs) {<br class="gmail_msg">
+      FileFn Fn = FileFn{Loc.FileName, Loc.FunctionName};<br class="gmail_msg">
+      if (Fns.find(Fn) == Fns.end())<br class="gmail_msg">
         continue;<br class="gmail_msg">
<br class="gmail_msg">
-      auto FLoc = FileLoc{FileName, Loc.Loc.Line};<br class="gmail_msg">
-      Result[FLoc].insert(FunctionName);<br class="gmail_msg">
-    }<br class="gmail_msg">
-    return Result;<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  std::set<std::string> files() const {<br class="gmail_msg">
-    std::set<std::string> Files;<br class="gmail_msg">
-    for (const auto &AI : AllAddrInfo) {<br class="gmail_msg">
-      Files.insert(AI.FileName);<br class="gmail_msg">
+      auto P = std::make_pair(Loc.Line, Loc.Column);<br class="gmail_msg">
+      auto I = Result.find(Fn);<br class="gmail_msg">
+      if (I == Result.end() || I->second > P) {<br class="gmail_msg">
+        Result[Fn] = P;<br class="gmail_msg">
+      }<br class="gmail_msg">
     }<br class="gmail_msg">
-    return Files;<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  void collectStats(CoverageStats *Stats) const {<br class="gmail_msg">
-    Stats->AllPoints += AllCovPoints.size();<br class="gmail_msg">
-    Stats->AllFns += computeAllFunctions().size();<br class="gmail_msg">
-    Stats->CovFns += computeCoveredFunctions().size();<br class="gmail_msg">
   }<br class="gmail_msg">
+  return Result;<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
-private:<br class="gmail_msg">
-  const std::set<uint64_t> AllCovPoints;<br class="gmail_msg">
-<br class="gmail_msg">
-  std::vector<AddrInfo> AllAddrInfo;<br class="gmail_msg">
-  std::vector<AddrInfo> CovAddrInfo;<br class="gmail_msg">
-};<br class="gmail_msg">
-<br class="gmail_msg">
-static void printFunctionLocs(const SourceCoverageData::FunctionLocs &FnLocs,<br class="gmail_msg">
-                              raw_ostream &OS) {<br class="gmail_msg">
-  for (const auto &Fns : FnLocs) {<br class="gmail_msg">
-    for (const auto &Fn : Fns.second) {<br class="gmail_msg">
-      OS << stripPathPrefix(Fns.first.FileName) << ":" << Fns.first.Line << " "<br class="gmail_msg">
-         << Fn << "\n";<br class="gmail_msg">
-    }<br class="gmail_msg">
+static void printFunctionLocs(const FunctionLocs &FnLocs, raw_ostream &OS) {<br class="gmail_msg">
+  for (const auto &P : FnLocs) {<br class="gmail_msg">
+    OS << stripPathPrefix(P.first.FileName) << ":" << P.second.first << " "<br class="gmail_msg">
+       << P.first.FunctionName << "\n";<br class="gmail_msg">
+  }<br class="gmail_msg">
+}<br class="gmail_msg">
+CoverageStats computeStats(const SymbolizedCoverage &Coverage) {<br class="gmail_msg">
+  CoverageStats Stats = {Coverage.Points.size(), Coverage.CoveredIds.size(),<br class="gmail_msg">
+                         computeFunctions(Coverage.Points).size(),<br class="gmail_msg">
+                         computeCoveredFunctions(Coverage).size()};<br class="gmail_msg">
+  return Stats;<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Print list of covered functions.<br class="gmail_msg">
+// Line format: <file_name>:<line> <function_name><br class="gmail_msg">
+static void printCoveredFunctions(const SymbolizedCoverage &CovData,<br class="gmail_msg">
+                                  raw_ostream &OS) {<br class="gmail_msg">
+  auto CoveredFns = computeCoveredFunctions(CovData);<br class="gmail_msg">
+  printFunctionLocs(resolveFunctions(CovData, CoveredFns), OS);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Print list of not covered functions.<br class="gmail_msg">
+// Line format: <file_name>:<line> <function_name><br class="gmail_msg">
+static void printNotCoveredFunctions(const SymbolizedCoverage &CovData,<br class="gmail_msg">
+                                     raw_ostream &OS) {<br class="gmail_msg">
+  auto NotCoveredFns = computeNotCoveredFunctions(CovData);<br class="gmail_msg">
+  printFunctionLocs(resolveFunctions(CovData, NotCoveredFns), OS);<br class="gmail_msg">
+}<br class="gmail_msg">
+<br class="gmail_msg">
+// Read list of files and merges their coverage info.<br class="gmail_msg">
+static void readAndPrintRawCoverage(const std::vector<std::string> &FileNames,<br class="gmail_msg">
+                                    raw_ostream &OS) {<br class="gmail_msg">
+  std::vector<std::unique_ptr<RawCoverage>> Covs;<br class="gmail_msg">
+  for (const auto &FileName : FileNames) {<br class="gmail_msg">
+    auto Cov = RawCoverage::read(FileName);<br class="gmail_msg">
+    if (!Cov)<br class="gmail_msg">
+      continue;<br class="gmail_msg">
+    OS << *Cov.get();<br class="gmail_msg">
   }<br class="gmail_msg">
 }<br class="gmail_msg">
<br class="gmail_msg">
-// Holder for coverage data + filename of corresponding object file.<br class="gmail_msg">
-class CoverageDataWithObjectFile : public CoverageData {<br class="gmail_msg">
-public:<br class="gmail_msg">
-  static ErrorOr<std::unique_ptr<CoverageDataWithObjectFile>><br class="gmail_msg">
-  readAndMerge(const std::string &ObjectFile,<br class="gmail_msg">
-               const std::vector<std::string> &FileNames) {<br class="gmail_msg">
-    auto MergedDataOrError = CoverageData::readAndMerge(FileNames);<br class="gmail_msg">
-    if (!MergedDataOrError)<br class="gmail_msg">
-      return MergedDataOrError.getError();<br class="gmail_msg">
-    return std::unique_ptr<CoverageDataWithObjectFile>(<br class="gmail_msg">
-        new CoverageDataWithObjectFile(ObjectFile,<br class="gmail_msg">
-                                       std::move(MergedDataOrError.get())));<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  std::string object_file() const { return ObjectFile; }<br class="gmail_msg">
-<br class="gmail_msg">
-  // Print list of covered functions.<br class="gmail_msg">
-  // Line format: <file_name>:<line> <function_name><br class="gmail_msg">
-  void printCoveredFunctions(raw_ostream &OS) const {<br class="gmail_msg">
-    SourceCoverageData SCovData(ObjectFile, *Addrs);<br class="gmail_msg">
-    auto CoveredFns = SCovData.computeCoveredFunctions();<br class="gmail_msg">
-    printFunctionLocs(SCovData.resolveFunctions(CoveredFns), OS);<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  // Print list of not covered functions.<br class="gmail_msg">
-  // Line format: <file_name>:<line> <function_name><br class="gmail_msg">
-  void printNotCoveredFunctions(raw_ostream &OS) const {<br class="gmail_msg">
-    SourceCoverageData SCovData(ObjectFile, *Addrs);<br class="gmail_msg">
-    auto NotCoveredFns = SCovData.computeNotCoveredFunctions();<br class="gmail_msg">
-    printFunctionLocs(SCovData.resolveFunctions(NotCoveredFns), OS);<br class="gmail_msg">
-  }<br class="gmail_msg">
-<br class="gmail_msg">
-  void printReport(raw_ostream &OS) const {<br class="gmail_msg">
-    SourceCoverageData SCovData(ObjectFile, *Addrs);<br class="gmail_msg">
-    auto LineStatusMap = SCovData.computeLineStatusMap();<br class="gmail_msg">
-<br class="gmail_msg">
-    std::set<FileFn> AllFns = SCovData.computeAllFunctions();<br class="gmail_msg">
-    // file_loc -> set[function_name]<br class="gmail_msg">
-    auto AllFnsByLoc = SCovData.resolveFunctions(AllFns);<br class="gmail_msg">
-    auto FileCoverage = SCovData.computeFileCoverage();<br class="gmail_msg">
-<br class="gmail_msg">
-    auto FnCoverage = SCovData.computeFunctionsCoverage();<br class="gmail_msg">
-    auto FnCoverageByFile =<br class="gmail_msg">
-        group_by(FnCoverage, [](const std::pair<FileFn, int> &FileFn) {<br class="gmail_msg">
-          return FileFn.first.FileName;<br class="gmail_msg">
-        });<br class="gmail_msg">
-<br class="gmail_msg">
-    // TOC<br class="gmail_msg">
-<br class="gmail_msg">
-    size_t NotCoveredFilesCount = 0;<br class="gmail_msg">
-    std::set<std::string> Files = SCovData.files();<br class="gmail_msg">
-<br class="gmail_msg">
-    // Covered Files.<br class="gmail_msg">
-    OS << "<details open><summary>Touched Files</summary>\n";<br class="gmail_msg">
-    OS << "<table>\n";<br class="gmail_msg">
-    OS << "<tr><th>File</th><th>Coverage %</th>";<br class="gmail_msg">
-    OS << "<th>Hit (Total) Fns</th></tr>\n";<br class="gmail_msg">
-    for (const auto &FileName : Files) {<br class="gmail_msg">
-      std::pair<size_t, size_t> FC = FileCoverage[FileName];<br class="gmail_msg">
-      if (FC.first == 0) {<br class="gmail_msg">
-        NotCoveredFilesCount++;<br class="gmail_msg">
-        continue;<br class="gmail_msg">
-      }<br class="gmail_msg">
-      size_t CovPct = FC.second == 0 ? 100 : 100 * FC.first / FC.second;<br class="gmail_msg">
+static std::unique_ptr<SymbolizedCoverage><br class="gmail_msg">
+merge(const std::vector<std::unique_ptr<SymbolizedCoverage>> &Coverages) {<br class="gmail_msg">
+  auto Result = make_unique<SymbolizedCoverage>();<br class="gmail_msg">
<br class="gmail_msg">
-      OS << "<tr><td><a href=\"#" << anchorName(FileName) << "\">"<br class="gmail_msg">
-         << stripPathPrefix(FileName) << "</a></td>"<br class="gmail_msg">
-         << "<td>" << formatHtmlPct(CovPct) << "%</td>"<br class="gmail_msg">
-         << "<td>" << FC.first << " (" << FC.second << ")"<br class="gmail_msg">
-         << "</tr>\n";<br class="gmail_msg">
-    }<br class="gmail_msg">
-    OS << "</table>\n";<br class="gmail_msg">
-    OS << "</details>\n";<br class="gmail_msg">
-<br class="gmail_msg">
-    // Not covered files.<br class="gmail_msg">
-    if (NotCoveredFilesCount) {<br class="gmail_msg">
-      OS << "<details><summary>Not Touched Files</summary>\n";<br class="gmail_msg">
-      OS << "<table>\n";<br class="gmail_msg">
-      for (const auto &FileName : Files) {<br class="gmail_msg">
-        std::pair<size_t, size_t> FC = FileCoverage[FileName];<br class="gmail_msg">
-        if (FC.first == 0)<br class="gmail_msg">
-          OS << "<tr><td>" << stripPathPrefix(FileName) << "</td>\n";<br class="gmail_msg">
-      }<br class="gmail_msg">
-      OS << "</table>\n";<br class="gmail_msg">
-      OS << "</details>\n";<br class="gmail_msg">
-    } else {<br class="gmail_msg">
-      OS << "<p>Congratulations! All source files are touched.</p>\n";<br class="gmail_msg">
+  for (size_t I = 0; I < Coverages.size(); ++I) {<br class="gmail_msg">
+    const SymbolizedCoverage &Coverage = *Coverages[I];<br class="gmail_msg">
+    std::string Prefix;<br class="gmail_msg">
+    if (Coverages.size() > 1) {<br class="gmail_msg">
+      // prefix is not needed when there's only one file.<br class="gmail_msg">
+      Prefix =<br class="gmail_msg">
+          (Coverage.BinaryHash.size() ? Coverage.BinaryHash : utostr(I)) + ":";<br class="gmail_msg">
     }<br class="gmail_msg">
<br class="gmail_msg">
-    // Source<br class="gmail_msg">
-    for (const auto &FileName : Files) {<br class="gmail_msg">
-      std::pair<size_t, size_t> FC = FileCoverage[FileName];<br class="gmail_msg">
-      if (FC.first == 0)<br class="gmail_msg">
-        continue;<br class="gmail_msg">
-      OS << "<a name=\"" << anchorName(FileName) << "\"></a>\n";<br class="gmail_msg">
-      OS << "<h2>" << stripPathPrefix(FileName) << "</h2>\n";<br class="gmail_msg">
-      OS << "<details open><summary>Function Coverage</summary>";<br class="gmail_msg">
-      OS << "<div class='fnlist'>\n";<br class="gmail_msg">
-<br class="gmail_msg">
-      auto &FileFnCoverage = FnCoverageByFile[FileName];<br class="gmail_msg">
-<br class="gmail_msg">
-      for (const auto &P : FileFnCoverage) {<br class="gmail_msg">
-        std::string FunctionName = P.first.FunctionName;<br class="gmail_msg">
-<br class="gmail_msg">
-        OS << "<div class='fn' style='order: " << P.second << "'>";<br class="gmail_msg">
-        OS << "<span class='pct'>" << formatHtmlPct(P.second)<br class="gmail_msg">
-           << "%</span>&nbsp;";<br class="gmail_msg">
-        OS << "<span class='name'><a href=\"#"<br class="gmail_msg">
-           << anchorName(FileName + "::" + FunctionName) << "\">";<br class="gmail_msg">
-        OS << escapeHtml(FunctionName) << "</a></span>";<br class="gmail_msg">
-        OS << "</div>\n";<br class="gmail_msg">
-      }<br class="gmail_msg">
-      OS << "</div></details>\n";<br class="gmail_msg">
-<br class="gmail_msg">
-      ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =<br class="gmail_msg">
-          MemoryBuffer::getFile(FileName);<br class="gmail_msg">
-      if (!BufOrErr) {<br class="gmail_msg">
-        OS << "Error reading file: " << FileName << " : "<br class="gmail_msg">
-           << BufOrErr.getError().message() << "("<br class="gmail_msg">
-           << BufOrErr.getError().value() << ")\n";<br class="gmail_msg">
-        continue;<br class="gmail_msg">
-      }<br class="gmail_msg">
-<br class="gmail_msg">
-      OS << "<pre>\n";<br class="gmail_msg">
-      const auto &LineStatuses = LineStatusMap[FileName];<br class="gmail_msg">
-      for (line_iterator I = line_iterator(*BufOrErr.get(), false);<br class="gmail_msg">
-           !I.is_at_eof(); ++I) {<br class="gmail_msg">
-        uint32_t Line = I.line_number();<br class="gmail_msg">
-        { // generate anchors (if any);<br class="gmail_msg">
-          FileLoc Loc = FileLoc{FileName, Line};<br class="gmail_msg">
-          auto It = AllFnsByLoc.find(Loc);<br class="gmail_msg">
-          if (It != AllFnsByLoc.end()) {<br class="gmail_msg">
-            for (const std::string &Fn : It->second) {<br class="gmail_msg">
-              OS << "<a name=\"" << anchorName(FileName + "::" + Fn)<br class="gmail_msg">
-                 << "\"></a>";<br class="gmail_msg">
-            };<br class="gmail_msg">
-          }<br class="gmail_msg">
-        }<br class="gmail_msg">
+    for (const auto &Id : Coverage.CoveredIds) {<br class="gmail_msg">
+      Result->CoveredIds.insert(Prefix + Id);<br class="gmail_msg">
+    }<br class="gmail_msg">
<br class="gmail_msg">
-        OS << "<span ";<br class="gmail_msg">
-        auto LIT = LineStatuses.find(I.line_number());<br class="gmail_msg">
-        auto Status = (LIT != LineStatuses.end()) ? LIT->second<br class="gmail_msg">
-                                                  : SourceCoverageData::UNKNOWN;<br class="gmail_msg">
-        switch (Status) {<br class="gmail_msg">
-        case SourceCoverageData::UNKNOWN:<br class="gmail_msg">
-          OS << "class=unknown";<br class="gmail_msg">
-          break;<br class="gmail_msg">
-        case SourceCoverageData::COVERED:<br class="gmail_msg">
-          OS << "class=covered";<br class="gmail_msg">
-          break;<br class="gmail_msg">
-        case SourceCoverageData::NOT_COVERED:<br class="gmail_msg">
-          OS << "class=notcovered";<br class="gmail_msg">
-          break;<br class="gmail_msg">
-        case SourceCoverageData::MIXED:<br class="gmail_msg">
-          OS << "class=mixed";<br class="gmail_msg">
-          break;<br class="gmail_msg">
-        }<br class="gmail_msg">
-        OS << ">";<br class="gmail_msg">
-        OS << escapeHtml(*I) << "</span>\n";<br class="gmail_msg">
-      }<br class="gmail_msg">
-      OS << "</pre>\n";<br class="gmail_msg">
+    for (const auto &CovPoint : Coverage.Points) {<br class="gmail_msg">
+      CoveragePoint NewPoint(CovPoint);<br class="gmail_msg">
+      NewPoint.Id = Prefix + CovPoint.Id;<br class="gmail_msg">
+      Result->Points.push_back(NewPoint);<br class="gmail_msg">
     }<br class="gmail_msg">
   }<br class="gmail_msg">
<br class="gmail_msg">
-  void collectStats(CoverageStats *Stats) const {<br class="gmail_msg">
-    Stats->CovPoints += Addrs->size();<br class="gmail_msg">
-<br class="gmail_msg">
-    SourceCoverageData SCovData(ObjectFile, *Addrs);<br class="gmail_msg">
-    SCovData.collectStats(Stats);<br class="gmail_msg">
+  if (Coverages.size() == 1) {<br class="gmail_msg">
+    Result->BinaryHash = Coverages[0]->BinaryHash;<br class="gmail_msg">
   }<br class="gmail_msg">
<br class="gmail_msg">
-private:<br class="gmail_msg">
-  CoverageDataWithObjectFile(std::string ObjectFile,<br class="gmail_msg">
-                             std::unique_ptr<CoverageData> Coverage)<br class="gmail_msg">
-      : CoverageData(std::move(Coverage->Addrs)),<br class="gmail_msg">
-        ObjectFile(std::move(ObjectFile)) {}<br class="gmail_msg">
-  const std::string ObjectFile;<br class="gmail_msg">
-};<br class="gmail_msg">
+  return Result;<br class="gmail_msg">
+}<br class="gmail_msg">
<br class="gmail_msg">
-// Multiple coverage files data organized by object file.<br class="gmail_msg">
-class CoverageDataSet {<br class="gmail_msg">
-public:<br class="gmail_msg">
-  static ErrorOr<std::unique_ptr<CoverageDataSet>><br class="gmail_msg">
-  readCmdArguments(std::vector<std::string> FileNames) {<br class="gmail_msg">
+static std::unique_ptr<SymbolizedCoverage><br class="gmail_msg">
+readSymbolizeAndMergeCmdArguments(std::vector<std::string> FileNames) {<br class="gmail_msg">
+  std::vector<std::unique_ptr<SymbolizedCoverage>> Coverages;<br class="gmail_msg">
+<br class="gmail_msg">
+  {<br class="gmail_msg">
     // Short name => file name.<br class="gmail_msg">
     std::map<std::string, std::string> ObjFiles;<br class="gmail_msg">
     std::string FirstObjFile;<br class="gmail_msg">
@@ -1109,6 +1087,10 @@ public:<br class="gmail_msg">
<br class="gmail_msg">
     // Partition input values into coverage/object files.<br class="gmail_msg">
     for (const auto &FileName : FileNames) {<br class="gmail_msg">
+      if (isSymbolizedCoverageFile(FileName)) {<br class="gmail_msg">
+        Coverages.push_back(SymbolizedCoverage::read(FileName));<br class="gmail_msg">
+      }<br class="gmail_msg">
+<br class="gmail_msg">
       auto ErrorOrIsCoverage = isCoverageFile(FileName);<br class="gmail_msg">
       if (!ErrorOrIsCoverage)<br class="gmail_msg">
         continue;<br class="gmail_msg">
@@ -1117,7 +1099,7 @@ public:<br class="gmail_msg">
       } else {<br class="gmail_msg">
         auto ShortFileName = llvm::sys::path::filename(FileName);<br class="gmail_msg">
         if (ObjFiles.find(ShortFileName) != ObjFiles.end()) {<br class="gmail_msg">
-          Fail("Duplicate binary file with a short name: " + ShortFileName);<br class="gmail_msg">
+          fail("Duplicate binary file with a short name: " + ShortFileName);<br class="gmail_msg">
         }<br class="gmail_msg">
<br class="gmail_msg">
         ObjFiles[ShortFileName] = FileName;<br class="gmail_msg"></blockquote></div>