From 2d56abacd1437338fb39226366edd3ecbce9058c Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Wed, 18 Mar 2015 22:03:39 +0000 Subject: [PATCH] [sanitizer] change the sanitizer coverage format once again, this time adding a magic to the beginning of the file llvm-svn: 232679 --- .../sanitizer_common/sanitizer_coverage_libcdep.cc | 28 +++++-- compiler-rt/lib/sanitizer_common/scripts/sancov.py | 87 +++++++++++++--------- compiler-rt/test/asan/lit.cfg | 2 +- 3 files changed, 76 insertions(+), 41 deletions(-) diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 6ef8bf4..428e1fc 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/compiler-rt/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(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/compiler-rt/lib/sanitizer_common/scripts/sancov.py b/compiler-rt/lib/sanitizer_common/scripts/sancov.py index 4435216..a09dabb 100755 --- a/compiler-rt/lib/sanitizer_common/scripts/sancov.py +++ b/compiler-rt/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() diff --git a/compiler-rt/test/asan/lit.cfg b/compiler-rt/test/asan/lit.cfg index 5b70b3d..a6f443c 100644 --- a/compiler-rt/test/asan/lit.cfg +++ b/compiler-rt/test/asan/lit.cfg @@ -121,7 +121,7 @@ sancov = os.path.join(sanitizer_common_source_dir, "scripts", "sancov.py") if not os.path.exists(sancov): lit_config.fatal("Can't find script on path %r" % sancov) python_exec = get_required_attr(config, "python_executable") -config.substitutions.append( ("%sancov", python_exec + " " + sancov + " " + config.bits + " ") ) +config.substitutions.append( ("%sancov", python_exec + " " + sancov + " ") ) # Determine kernel bitness if config.host_arch.find('64') != -1 and config.android != "1": -- 2.7.4