[sanitizer] add run-time a flag coverage_order_pcs. When true, the PCs are dumped in the order of their appearance

llvm-svn: 232573
This commit is contained in:
Kostya Serebryany 2015-03-18 00:23:44 +00:00
parent e48237df95
commit cba49d4b04
5 changed files with 106 additions and 10 deletions

View File

@ -445,6 +445,9 @@ class InternalMmapVectorNoCtor {
const T *data() const {
return data_;
}
T *data() {
return data_;
}
uptr capacity() const {
return capacity_;
}

View File

@ -352,6 +352,32 @@ void CoverageData::InitializeGuards(s32 *guards, uptr n,
UpdateModuleNameVec(caller_pc, range_beg, range_end);
}
static const uptr kBundleCounterBits = 16;
// When coverage_order_pcs==true and SANITIZER_WORDSIZE==64
// we insert the global counter into the first 16 bits of the PC.
uptr BundlePcAndCounter(uptr pc, uptr counter) {
if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
return pc;
static const uptr kMaxCounter = (1 << kBundleCounterBits) - 1;
if (counter > kMaxCounter)
counter = kMaxCounter;
CHECK_EQ(0, pc >> (SANITIZER_WORDSIZE - kBundleCounterBits));
return pc | (counter << (SANITIZER_WORDSIZE - kBundleCounterBits));
}
uptr UnbundlePc(uptr bundle) {
if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
return bundle;
return (bundle << kBundleCounterBits) >> kBundleCounterBits;
}
uptr UnbundleCounter(uptr bundle) {
if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
return 0;
return bundle >> (SANITIZER_WORDSIZE - kBundleCounterBits);
}
// If guard is negative, atomically set it to -guard and store the PC in
// pc_array.
void CoverageData::Add(uptr pc, u32 *guard) {
@ -367,8 +393,8 @@ void CoverageData::Add(uptr pc, u32 *guard) {
return; // May happen after fork when pc_array_index becomes 0.
CHECK_LT(idx * sizeof(uptr),
atomic_load(&pc_array_size, memory_order_acquire));
pc_array[idx] = pc;
atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
pc_array[idx] = BundlePcAndCounter(pc, counter);
}
// Registers a pair caller=>callee.
@ -555,7 +581,7 @@ void CoverageData::DumpTrace() {
for (uptr i = 0, n = size(); i < n; i++) {
const char *module_name = "<unknown>";
uptr module_address = 0;
sym->GetModuleNameAndOffsetForPC(pc_array[i], &module_name,
sym->GetModuleNameAndOffsetForPC(UnbundlePc(pc_array[i]), &module_name,
&module_address);
out.append("%s 0x%zx\n", module_name, module_address);
}
@ -681,7 +707,7 @@ void CoverageData::DumpAsBitSet() {
CHECK_LE(r.beg, r.end);
CHECK_LE(r.end, size());
for (uptr i = r.beg; i < r.end; i++) {
uptr pc = data()[i];
uptr pc = UnbundlePc(pc_array[i]);
out[i] = pc ? '1' : '0';
if (pc)
n_set_bits++;
@ -711,12 +737,18 @@ void CoverageData::DumpOffsets() {
CHECK_LE(r.end, size());
const char *module_name = "<unknown>";
for (uptr i = r.beg; i < r.end; i++) {
uptr pc = data()[i];
uptr pc = UnbundlePc(pc_array[i]);
uptr counter = UnbundleCounter(pc_array[i]);
if (!pc) continue; // Not visited.
uptr offset = 0;
sym->GetModuleNameAndOffsetForPC(pc, &module_name, &offset);
offsets.push_back(offset);
offsets.push_back(BundlePcAndCounter(offset, counter));
}
SortArray(offsets.data(), offsets.size());
for (uptr i = 0; i < offsets.size(); i++)
offsets[i] = UnbundlePc(offsets[i]);
module_name = StripModuleName(r.name);
if (cov_sandboxed) {
if (cov_fd >= 0) {

View File

@ -111,10 +111,12 @@ COMMON_FLAG(
bool, coverage, false,
"If set, coverage information will be dumped at program shutdown (if the "
"coverage instrumentation was enabled at compile time).")
// On by default, but works only if coverage == true.
COMMON_FLAG(bool, coverage_pcs, true,
"If set (and if 'coverage' is set too), the coverage information "
"will be dumped as a set of PC offsets for every module.")
COMMON_FLAG(bool, coverage_order_pcs, false,
"If true, the PCs will be dumped in the order they've"
" appeared during the execution.")
COMMON_FLAG(bool, coverage_bitset, false,
"If set (and if 'coverage' is set too), the coverage information "
"will also be dumped as a bitset to a separate file.")

View File

@ -30,20 +30,23 @@ def ReadOneFile(path, bits):
f.seek(0, 2)
size = f.tell()
f.seek(0, 0)
s = set(array.array(TypeCodeForBits(bits), f.read(size)))
s = array.array(TypeCodeForBits(bits), f.read(size))
print >>sys.stderr, "%s: read %d PCs from %s" % (prog_name, size * 8 / bits, path)
return s
def Merge(files, bits):
s = set()
for f in files:
s = s.union(ReadOneFile(f, bits))
s = s.union(set(ReadOneFile(f, bits)))
print >> sys.stderr, "%s: %d files merged; %d PCs total" % \
(prog_name, len(files), len(s))
return sorted(s)
def PrintFiles(files, bits):
s = Merge(files, bits)
if len(files) > 1:
s = Merge(files, bits)
else: # If there is just on file, print the PCs in order.
s = ReadOneFile(files[0], bits)
for i in s:
print "0x%x" % i

View File

@ -0,0 +1,56 @@
// Test coverage_order_pcs=1 flag which orders the PCs by their appearance.
// RUN: DIR=%T/coverage-order-pcs
// RUN: rm -rf $DIR
// RUN: mkdir $DIR
// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t
// RUN: ASAN_OPTIONS=coverage_dir=$DIR:coverage=1:coverage_order_pcs=0 %t
// RUN: mv $DIR/*sancov $DIR/A
// RUN: ASAN_OPTIONS=coverage_dir=$DIR:coverage=1:coverage_order_pcs=0 %t 1
// RUN: mv $DIR/*sancov $DIR/B
// RUN: ASAN_OPTIONS=coverage_dir=$DIR:coverage=1:coverage_order_pcs=1 %t
// RUN: mv $DIR/*sancov $DIR/C
// RUN: ASAN_OPTIONS=coverage_dir=$DIR:coverage=1:coverage_order_pcs=1 %t 1
// RUN: mv $DIR/*sancov $DIR/D
//
// RUN: (%sancov print $DIR/A; %sancov print $DIR/B; %sancov print $DIR/C; %sancov print $DIR/D) | FileCheck %s
//
// RUN: rm -rf $DIR
// Ordering works only in 64-bit mode for now.
// REQUIRES: asan-64-bits
#include <stdio.h>
void foo() { fprintf(stderr, "FOO\n"); }
void bar() { fprintf(stderr, "BAR\n"); }
int main(int argc, char **argv) {
if (argc == 2) {
foo();
bar();
} else {
bar();
foo();
}
}
// Run A: no ordering
// CHECK: [[FOO:0x[0-9a-f]*]]
// CHECK-NEXT: [[BAR:0x[0-9a-f]*]]
// CHECK-NEXT: [[MAIN:0x[0-9a-f]*]]
//
// Run B: still no ordering
// CHECK-NEXT: [[FOO]]
// CHECK-NEXT: [[BAR]]
// CHECK-NEXT: [[MAIN]]
//
// Run C: MAIN, BAR, FOO
// CHECK-NEXT: [[MAIN]]
// CHECK-NEXT: [[BAR]]
// CHECK-NEXT: [[FOO]]
//
// Run D: MAIN, FOO, BAR
// CHECK-NEXT: [[MAIN]]
// CHECK-NEXT: [[FOO]]
// CHECK-NEXT: [[BAR]]