diff options
| author | Kostya Serebryany <kcc@google.com> | 2015-03-05 22:19:25 +0000 |
|---|---|---|
| committer | Kostya Serebryany <kcc@google.com> | 2015-03-05 22:19:25 +0000 |
| commit | 769ddaa2d493a805e6d48040585e41666c2123be (patch) | |
| tree | 82321c2f6e3e2ddca46df7cea547b3f6c4b233f5 | |
| parent | 2cd9d0b78310081f5a5175932ec00d8642fb0dfc (diff) | |
| download | bcm5719-llvm-769ddaa2d493a805e6d48040585e41666c2123be.tar.gz bcm5719-llvm-769ddaa2d493a805e6d48040585e41666c2123be.zip | |
[sanitizer] Reconstruct the function that dumps block/edge coverage, hopefully making it more robust. Also increase the allowed coverage size on 32-bit.
llvm-svn: 231413
4 files changed, 83 insertions, 80 deletions
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc index 39c3df4d50b..7b7225f187c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep.cc @@ -79,6 +79,8 @@ class CoverageData { void DumpTrace(); void DumpAsBitSet(); void DumpCounters(); + void DumpOffsets(); + void DumpAll(); ALWAYS_INLINE void TraceBasicBlock(s32 *id); @@ -98,7 +100,7 @@ class CoverageData { private: // Maximal size pc array may ever grow. // We MmapNoReserve this space to ensure that the array is contiguous. - static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 24, 1 << 27); + static const uptr kPcArrayMaxSize = FIRST_32_SECOND_64(1 << 26, 1 << 27); // The amount file mapping for the pc array is grown by. static const uptr kPcArrayMmapSize = 64 * 1024; @@ -520,23 +522,23 @@ static void CovWritePacked(int pid, const char *module, const void *blob, // If packed = true and name == 0: <pid>.<sancov>.<packed>. // If packed = true and name != 0: <name>.<sancov>.<packed> (name is // user-supplied). -static int CovOpenFile(bool packed, const char *name, - const char *extension = "sancov") { - InternalScopedString path(kMaxPathLength); +static int CovOpenFile(InternalScopedString *path, bool packed, + const char *name, const char *extension = "sancov") { + path->clear(); if (!packed) { CHECK(name); - path.append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(), + path->append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(), extension); } else { if (!name) - path.append("%s/%zd.%s.packed", coverage_dir, internal_getpid(), + path->append("%s/%zd.%s.packed", coverage_dir, internal_getpid(), extension); else - path.append("%s/%s.%s.packed", coverage_dir, name, extension); + path->append("%s/%s.%s.packed", coverage_dir, name, extension); } - uptr fd = OpenFile(path.data(), true); + uptr fd = OpenFile(path->data(), true); if (internal_iserror(fd)) { - Report(" SanitizerCoverage: failed to open %s for writing\n", path.data()); + Report(" SanitizerCoverage: failed to open %s for writing\n", path->data()); return -1; } return fd; @@ -557,12 +559,13 @@ void CoverageData::DumpTrace() { &module_address); out.append("%s 0x%zx\n", module_name, module_address); } - int fd = CovOpenFile(false, "trace-points"); + InternalScopedString path(kMaxPathLength); + int fd = CovOpenFile(&path, false, "trace-points"); if (fd < 0) return; internal_write(fd, out.data(), out.length()); internal_close(fd); - fd = CovOpenFile(false, "trace-compunits"); + fd = CovOpenFile(&path, false, "trace-compunits"); if (fd < 0) return; out.clear(); for (uptr i = 0; i < comp_unit_name_vec.size(); i++) @@ -570,7 +573,7 @@ void CoverageData::DumpTrace() { internal_write(fd, out.data(), out.length()); internal_close(fd); - fd = CovOpenFile(false, "trace-events"); + fd = CovOpenFile(&path, false, "trace-events"); if (fd < 0) return; uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]); u8 *event_bytes = reinterpret_cast<u8*>(tr_event_array); @@ -621,7 +624,8 @@ void CoverageData::DumpCallerCalleePairs() { callee_module_address); } } - int fd = CovOpenFile(false, "caller-callee"); + InternalScopedString path(kMaxPathLength); + int fd = CovOpenFile(&path, false, "caller-callee"); if (fd < 0) return; internal_write(fd, out.data(), out.length()); internal_close(fd); @@ -647,6 +651,7 @@ void CoverageData::DumpCounters() { if (!n) return; InternalScopedBuffer<u8> bitset(n); coverage_data.Update8bitCounterBitsetAndClearCounters(bitset.data()); + InternalScopedString path(kMaxPathLength); for (uptr m = 0; m < module_name_vec.size(); m++) { auto r = module_name_vec[m]; @@ -654,7 +659,8 @@ void CoverageData::DumpCounters() { CHECK_LE(r.beg, r.end); CHECK_LE(r.end, size()); const char *base_name = StripModuleName(r.name); - int fd = CovOpenFile(/* packed */ false, base_name, "counters-sancov"); + int fd = + CovOpenFile(&path, /* packed */ false, base_name, "counters-sancov"); if (fd < 0) return; internal_write(fd, bitset.data() + r.beg, r.end - r.beg); internal_close(fd); @@ -667,6 +673,7 @@ void CoverageData::DumpAsBitSet() { if (!common_flags()->coverage_bitset) return; if (!size()) return; InternalScopedBuffer<char> out(size()); + InternalScopedString path(kMaxPathLength); for (uptr m = 0; m < module_name_vec.size(); m++) { uptr n_set_bits = 0; auto r = module_name_vec[m]; @@ -680,7 +687,7 @@ void CoverageData::DumpAsBitSet() { n_set_bits++; } const char *base_name = StripModuleName(r.name); - int fd = CovOpenFile(/* packed */ false, base_name, "bitset-sancov"); + int fd = CovOpenFile(&path, /* packed */ false, base_name, "bitset-sancov"); if (fd < 0) return; internal_write(fd, out.data() + r.beg, r.end - r.beg); internal_close(fd); @@ -690,67 +697,58 @@ void CoverageData::DumpAsBitSet() { } } -// Dump the coverage on disk. -static void CovDump() { - if (!coverage_enabled || common_flags()->coverage_direct) return; -#if !SANITIZER_WINDOWS - if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) - return; - coverage_data.DumpAsBitSet(); - coverage_data.DumpCounters(); - coverage_data.DumpTrace(); +void CoverageData::DumpOffsets() { + auto sym = Symbolizer::GetOrInit(); if (!common_flags()->coverage_pcs) return; - uptr size = coverage_data.size(); - InternalMmapVector<u32> offsets(size); - uptr *vb = coverage_data.data(); - uptr *ve = vb + size; - SortArray(vb, size); - MemoryMappingLayout proc_maps(/*cache_enabled*/true); - uptr mb, me, off, prot; - InternalScopedString module(kMaxPathLength); + CHECK_NE(sym, nullptr); + InternalMmapVector<u32> offsets(0); InternalScopedString path(kMaxPathLength); - for (int i = 0; - proc_maps.Next(&mb, &me, &off, module.data(), module.size(), &prot); - i++) { - if ((prot & MemoryMappingLayout::kProtectionExecute) == 0) - continue; - while (vb < ve && *vb < mb) vb++; - if (vb >= ve) break; - if (*vb < me) { - offsets.clear(); - const uptr *old_vb = vb; - CHECK_LE(off, *vb); - for (; vb < ve && *vb < me; vb++) { - uptr diff = *vb - (i ? mb : 0) + off; - CHECK_LE(diff, 0xffffffffU); - offsets.push_back(static_cast<u32>(diff)); - } - const char *module_name = StripModuleName(module.data()); - if (cov_sandboxed) { - if (cov_fd >= 0) { - CovWritePacked(internal_getpid(), module_name, offsets.data(), - offsets.size() * sizeof(u32)); - VReport(1, " CovDump: %zd PCs written to packed file\n", vb - old_vb); - } - } else { - // One file per module per process. - path.clear(); - path.append("%s/%s.%zd.sancov", coverage_dir, module_name, - internal_getpid()); - int fd = CovOpenFile(false /* packed */, module_name); - if (fd > 0) { - internal_write(fd, offsets.data(), offsets.size() * sizeof(u32)); - internal_close(fd); - VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), - vb - old_vb); - } + for (uptr m = 0; m < module_name_vec.size(); m++) { + offsets.clear(); + auto r = module_name_vec[m]; + CHECK(r.name); + CHECK_LE(r.beg, r.end); + CHECK_LE(r.end, size()); + const char *module_name = "<unknown>"; + for (uptr i = r.beg; i < r.end; i++) { + uptr pc = data()[i]; + if (!pc) continue; // Not visited. + uptr offset = 0; + sym->GetModuleNameAndOffsetForPC(pc, &module_name, &offset); + if (!offset || offset > 0xffffffffU) continue; + offsets.push_back(static_cast<u32>(offset)); + } + module_name = StripModuleName(r.name); + if (cov_sandboxed) { + if (cov_fd >= 0) { + CovWritePacked(internal_getpid(), module_name, offsets.data(), + offsets.size() * sizeof(u32)); + VReport(1, " CovDump: %zd PCs written to packed file\n", + offsets.size()); } + } else { + // One file per module per process. + int fd = CovOpenFile(&path, false /* packed */, module_name); + if (fd < 0) continue; + internal_write(fd, offsets.data(), offsets.size() * sizeof(u32)); + internal_close(fd); + VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), + offsets.size()); } } if (cov_fd >= 0) internal_close(cov_fd); - coverage_data.DumpCallerCalleePairs(); -#endif // !SANITIZER_WINDOWS +} + +void CoverageData::DumpAll() { + if (!coverage_enabled || common_flags()->coverage_direct) return; + if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed)) + return; + DumpAsBitSet(); + DumpCounters(); + DumpTrace(); + DumpOffsets(); + DumpCallerCalleePairs(); } void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { @@ -760,15 +758,18 @@ void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { if (!cov_sandboxed) return; cov_fd = args->coverage_fd; cov_max_block_size = args->coverage_max_block_size; - if (cov_fd < 0) + if (cov_fd < 0) { + InternalScopedString path(kMaxPathLength); // Pre-open the file now. The sandbox won't allow us to do it later. - cov_fd = CovOpenFile(true /* packed */, 0); + cov_fd = CovOpenFile(&path, true /* packed */, 0); + } } int MaybeOpenCovFile(const char *name) { CHECK(name); if (!coverage_enabled) return -1; - return CovOpenFile(true /* packed */, name); + InternalScopedString path(kMaxPathLength); + return CovOpenFile(&path, true /* packed */, name); } void CovBeforeFork() { @@ -824,7 +825,9 @@ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() { coverage_dir = common_flags()->coverage_dir; coverage_data.Init(); } -SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { CovDump(); } +SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() { + coverage_data.DumpAll(); +} SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_module_init(s32 *guards, uptr npcs, u8 *counters, const char *comp_unit_name) { diff --git a/compiler-rt/test/asan/TestCases/Linux/coverage-module-unloaded.cc b/compiler-rt/test/asan/TestCases/Linux/coverage-module-unloaded.cc index f8d9c57f81b..573fc466481 100644 --- a/compiler-rt/test/asan/TestCases/Linux/coverage-module-unloaded.cc +++ b/compiler-rt/test/asan/TestCases/Linux/coverage-module-unloaded.cc @@ -50,7 +50,7 @@ int main(int argc, char **argv) { // CHECK: PID: [[PID:[0-9]+]] // CHECK: [[PID]].sancov: 1 PCs written -// CHECK: .so.[[PID]] -// If we get coverage for both DSOs, it means the module wasn't unloaded and -// this test is useless. -// CHECK-NOT: .so.[[PID]] +// CHECK: test_1.so.[[PID]] +// CHECK: test_2.so.[[PID]] +// Even though we've unloaded one of the libs we still dump the coverage file +// for that lib (although the data will be inaccurate, it at all useful) diff --git a/compiler-rt/test/asan/TestCases/Linux/coverage-sandboxing.cc b/compiler-rt/test/asan/TestCases/Linux/coverage-sandboxing.cc index 1a72c6bb9a6..15bada8865b 100644 --- a/compiler-rt/test/asan/TestCases/Linux/coverage-sandboxing.cc +++ b/compiler-rt/test/asan/TestCases/Linux/coverage-sandboxing.cc @@ -78,8 +78,8 @@ int main(int argc, char **argv) { #endif // CHECK-vanilla: PID: [[PID:[0-9]+]] -// CHECK-vanilla: [[PID]].sancov: 1 PCs written // CHECK-vanilla: .so.[[PID]].sancov: 258 PCs written +// CHECK-vanilla: [[PID]].sancov: 1 PCs written // CHECK-sandbox: PID: [[PID:[0-9]+]] // CHECK-sandbox: 258 PCs written to packed file diff --git a/compiler-rt/test/asan/TestCases/Linux/coverage.cc b/compiler-rt/test/asan/TestCases/Linux/coverage.cc index 06fe1a295ea..ebd13395dbf 100644 --- a/compiler-rt/test/asan/TestCases/Linux/coverage.cc +++ b/compiler-rt/test/asan/TestCases/Linux/coverage.cc @@ -57,12 +57,12 @@ int main(int argc, char **argv) { // CHECK-foo-NOT: .so.[[PID]] // // CHECK-bar: PID: [[PID:[0-9]+]] -// CHECK-bar: [[PID]].sancov: 1 PCs written // CHECK-bar: .so.[[PID]].sancov: 1 PCs written +// CHECK-bar: [[PID]].sancov: 1 PCs written // // CHECK-foo-bar: PID: [[PID:[0-9]+]] -// CHECK-foo-bar: [[PID]].sancov: 2 PCs written // CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written +// CHECK-foo-bar: [[PID]].sancov: 2 PCs written // // CHECK-report: AddressSanitizer: global-buffer-overflow // CHECK-report: PCs written |

