forked from OSchip/llvm-project
[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:
parent
e48237df95
commit
cba49d4b04
|
@ -445,6 +445,9 @@ class InternalMmapVectorNoCtor {
|
|||
const T *data() const {
|
||||
return data_;
|
||||
}
|
||||
T *data() {
|
||||
return data_;
|
||||
}
|
||||
uptr capacity() const {
|
||||
return capacity_;
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.")
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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]]
|
Loading…
Reference in New Issue