summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2015-03-18 22:03:39 +0000
committerKostya Serebryany <kcc@google.com>2015-03-18 22:03:39 +0000
commit103a7f0784d8040537c016bb1e9d9101319cc736 (patch)
treebe150f95bd37615e8339bd3b09771a203b51d2fa /lib
parente9db3b421db09ac3541070a92d4c17134b1447d3 (diff)
[sanitizer] change the sanitizer coverage format once again, this time adding a magic to the beginning of the file
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@232679 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r--lib/sanitizer_common/sanitizer_coverage_libcdep.cc28
-rwxr-xr-xlib/sanitizer_common/scripts/sancov.py87
2 files changed, 75 insertions, 40 deletions
diff --git a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
index 6ef8bf487..428e1fcb1 100644
--- a/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ b/lib/sanitizer_common/sanitizer_coverage_libcdep.cc
@@ -24,8 +24,12 @@
// and atomically set Guard to -Guard.
// - __sanitizer_cov_dump: dump the coverage data to disk.
// For every module of the current process that has coverage data
-// this will create a file module_name.PID.sancov. The file format is simple:
-// it's just a sorted sequence of 4-byte offsets in the module.
+// this will create a file module_name.PID.sancov.
+//
+// The file format is simple: the first 8 bytes is the magic,
+// one of 0xC0BFFFFFFFFFFF64 and 0xC0BFFFFFFFFFFF32. The last byte of the
+// magic defines the size of the following offsets.
+// The rest of the data is the offsets in the module.
//
// Eventually, this coverage implementation should be obsoleted by a more
// powerful general purpose Clang/LLVM coverage instrumentation.
@@ -43,6 +47,9 @@
#include "sanitizer_symbolizer.h"
#include "sanitizer_flags.h"
+static const u64 kMagic64 = 0xC0BFFFFFFFFFFF64ULL;
+static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL;
+
static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
static atomic_uintptr_t coverage_counter;
@@ -731,6 +738,9 @@ void CoverageData::DumpOffsets() {
InternalScopedString path(kMaxPathLength);
for (uptr m = 0; m < module_name_vec.size(); m++) {
offsets.clear();
+ uptr num_words_for_magic = SANITIZER_WORDSIZE == 64 ? 1 : 2;
+ for (uptr i = 0; i < num_words_for_magic; i++)
+ offsets.push_back(0);
auto r = module_name_vec[m];
CHECK(r.name);
CHECK_LE(r.beg, r.end);
@@ -745,17 +755,24 @@ void CoverageData::DumpOffsets() {
offsets.push_back(BundlePcAndCounter(offset, counter));
}
+ CHECK_GE(offsets.size(), num_words_for_magic);
SortArray(offsets.data(), offsets.size());
for (uptr i = 0; i < offsets.size(); i++)
offsets[i] = UnbundlePc(offsets[i]);
+ uptr num_offsets = offsets.size() - num_words_for_magic;
+ u64 *magic_p = reinterpret_cast<u64*>(offsets.data());
+ CHECK_EQ(*magic_p, 0ULL);
+ // FIXME: we may want to write 32-bit offsets even in 64-mode
+ // if all the offsets are small enough.
+ *magic_p = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32;
+
module_name = StripModuleName(r.name);
if (cov_sandboxed) {
if (cov_fd >= 0) {
CovWritePacked(internal_getpid(), module_name, offsets.data(),
offsets.size() * sizeof(offsets[0]));
- VReport(1, " CovDump: %zd PCs written to packed file\n",
- offsets.size());
+ VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets);
}
} else {
// One file per module per process.
@@ -763,8 +780,7 @@ void CoverageData::DumpOffsets() {
if (fd < 0) continue;
internal_write(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
internal_close(fd);
- VReport(1, " CovDump: %s: %zd PCs written\n", path.data(),
- offsets.size());
+ VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets);
}
}
if (cov_fd >= 0)
diff --git a/lib/sanitizer_common/scripts/sancov.py b/lib/sanitizer_common/scripts/sancov.py
index 443521633..a09dabbe1 100755
--- a/lib/sanitizer_common/scripts/sancov.py
+++ b/lib/sanitizer_common/scripts/sancov.py
@@ -9,7 +9,7 @@ import sys
import bisect
import os.path
-prog_name = "";
+prog_name = ""
def Usage():
print >> sys.stderr, "Usage: \n" + \
@@ -19,41 +19,65 @@ def Usage():
" " + prog_name + " [32|64] rawunpack file1 [file2 ...]\n"
exit(1)
+def CheckBits(bits):
+ if bits != 32 and bits != 64:
+ raise Exception("Wrond bitness: %d" % bits)
+
def TypeCodeForBits(bits):
- if bits == 64:
- return 'L'
- else:
- return 'I'
+ CheckBits(bits)
+ return 'L' if bits == 64 else 'I'
+
+kMagic64 = 0xC0BFFFFFFFFFFF64
+kMagic32 = 0xC0BFFFFFFFFFFF32
-def ReadOneFile(path, bits):
+def MagicForBits(bits):
+ CheckBits(bits)
+ return kMagic64 if bits == 64 else kMagic32
+
+def ReadOneFile(path):
with open(path, mode="rb") as f:
f.seek(0, 2)
size = f.tell()
f.seek(0, 0)
+ if size <= 8:
+ raise Exception('File %s is short (> 8 bytes)' % path)
+ magic_word = struct.unpack('L', f.read(8))[0];
+ if magic_word == kMagic64:
+ bits = 64
+ elif magic_word == kMagic32:
+ bits = 32
+ else:
+ raise Exception('Bad magic word in %s' % path)
+ size -= 8
s = array.array(TypeCodeForBits(bits), f.read(size))
- print >>sys.stderr, "%s: read %d PCs from %s" % (prog_name, size * 8 / bits, path)
+ print >>sys.stderr, "%s: read %d %d-bit PCs from %s" % (prog_name, size * 8 / bits, bits, path)
return s
-def Merge(files, bits):
+def Merge(files):
s = set()
for f in files:
- s = s.union(set(ReadOneFile(f, bits)))
+ s = s.union(set(ReadOneFile(f)))
print >> sys.stderr, "%s: %d files merged; %d PCs total" % \
(prog_name, len(files), len(s))
return sorted(s)
-def PrintFiles(files, bits):
+def PrintFiles(files):
if len(files) > 1:
- s = Merge(files, bits)
+ s = Merge(files)
else: # If there is just on file, print the PCs in order.
- s = ReadOneFile(files[0], bits)
+ s = ReadOneFile(files[0])
for i in s:
print "0x%x" % i
-def MergeAndPrint(files, bits):
+def MergeAndPrint(files):
if sys.stdout.isatty():
Usage()
- s = Merge(files, bits)
+ s = Merge(files)
+ bits = 32
+ magic = kMagic32
+ if max(s) > 0xFFFFFFFF:
+ bits = 64
+ magic = kMagic64
a = array.array(TypeCodeForBits(bits), s)
a.tofile(sys.stdout)
@@ -86,11 +110,12 @@ def Unpack(files):
for f in files:
UnpackOneFile(f)
-def UnpackOneRawFile(path, map_path, bits):
+def UnpackOneRawFile(path, map_path):
mem_map = []
with open(map_path, mode="rt") as f_map:
print >> sys.stderr, "%s: reading map %s" % (prog_name, map_path)
- if bits != int(f_map.readline()):
+ bits = int(f_map.readline())
+ if bits != 32 and bits != 64:
raise Exception('Wrong bits size in the map')
for line in f_map:
parts = line.rstrip().split()
@@ -128,34 +153,28 @@ def UnpackOneRawFile(path, map_path, bits):
arr = array.array(TypeCodeForBits(bits))
arr.fromlist(sorted(pc_list))
with open(dst_path, 'ab') as f2:
+ array.array('L', [MagicForBits(bits)]).tofile(f2)
arr.tofile(f2)
-def RawUnpack(files, bits):
+def RawUnpack(files):
for f in files:
if not f.endswith('.sancov.raw'):
raise Exception('Unexpected raw file name %s' % f)
f_map = f[:-3] + 'map'
- UnpackOneRawFile(f, f_map, bits)
+ UnpackOneRawFile(f, f_map)
if __name__ == '__main__':
prog_name = sys.argv[0]
- if len(sys.argv) <= 3:
- Usage();
-
- if sys.argv[1] == "32":
- bits = 32
- elif sys.argv[1] == "64":
- bits = 64
- else:
+ if len(sys.argv) <= 2:
Usage();
- if sys.argv[2] == "print":
- PrintFiles(sys.argv[3:], bits)
- elif sys.argv[2] == "merge":
- MergeAndPrint(sys.argv[3:], bits)
- elif sys.argv[2] == "unpack":
- Unpack(sys.argv[3:])
- elif sys.argv[2] == "rawunpack":
- RawUnpack(sys.argv[3:], bits)
+ if sys.argv[1] == "print":
+ PrintFiles(sys.argv[2:])
+ elif sys.argv[1] == "merge":
+ MergeAndPrint(sys.argv[2:])
+ elif sys.argv[1] == "unpack":
+ Unpack(sys.argv[2:])
+ elif sys.argv[1] == "rawunpack":
+ RawUnpack(sys.argv[2:])
else:
Usage()