#include "sanitizer_platform.h"
#if SANITIZER_FUCHSIA
#include <zircon/process.h>
#include <zircon/sanitizer.h>
#include <zircon/syscalls.h>
#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
#include "sanitizer_interface_internal.h"
#include "sanitizer_internal_defs.h"
# include "sanitizer_symbolizer_markup_constants.h"
using namespace __sanitizer;
namespace __sancov {
namespace {
constexpr u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL;
static_assert(SANITIZER_WORDSIZE == 64, "Fuchsia is always LP64");
constexpr const char kSancovSinkName[] = "sancov";
class TracePcGuardController final {
public:
constexpr TracePcGuardController() {}
void InitTracePcGuard(u32 *start, u32 *end) {
if (end > start && *start == 0 && common_flags()->coverage) {
u32 idx = Setup(end - start);
for (u32 *p = start; p < end; ++p) {
*p = idx++;
}
}
}
void TracePcGuard(u32 *guard, uptr pc) {
atomic_uint32_t *guard_ptr = reinterpret_cast<atomic_uint32_t *>(guard);
u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed);
if (idx > 0)
array_[idx] = pc;
}
void Dump() {
Lock locked(&setup_lock_);
if (array_) {
CHECK_NE(vmo_, ZX_HANDLE_INVALID);
__sanitizer_publish_data(kSancovSinkName, vmo_);
vmo_ = ZX_HANDLE_INVALID;
Printf("SanitizerCoverage: " FORMAT_DUMPFILE " with up to %u PCs\n",
kSancovSinkName, vmo_name_, next_index_ - 1);
}
}
private:
static constexpr size_t MappingSize = sizeof(uptr) << 32;
Mutex setup_lock_;
uptr *array_ = nullptr;
u32 next_index_ = 0;
zx_handle_t vmo_ = {};
char vmo_name_[ZX_MAX_NAME_LEN] = {};
size_t DataSize() const { return next_index_ * sizeof(uintptr_t); }
u32 Setup(u32 num_guards) {
Lock locked(&setup_lock_);
DCHECK(common_flags()->coverage);
if (next_index_ == 0) {
CHECK_EQ(vmo_, ZX_HANDLE_INVALID);
CHECK_EQ(array_, nullptr);
next_index_ = 1 + num_guards;
zx_status_t status = _zx_vmo_create(DataSize(), ZX_VMO_RESIZABLE, &vmo_);
CHECK_EQ(status, ZX_OK);
internal_snprintf(vmo_name_, sizeof(vmo_name_), "%s.%zu", kSancovSinkName,
internal_getpid());
_zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_,
internal_strlen(vmo_name_));
uint64_t size = DataSize();
status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size,
sizeof(size));
CHECK_EQ(status, ZX_OK);
uintptr_t mapping;
status =
_zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
0, vmo_, 0, MappingSize, &mapping);
CHECK_EQ(status, ZX_OK);
array_ = reinterpret_cast<uptr *>(mapping);
array_[0] = Magic64;
return 1;
} else {
CHECK_NE(vmo_, ZX_HANDLE_INVALID);
CHECK_NE(array_, nullptr);
uint32_t first_index = next_index_;
next_index_ += num_guards;
zx_status_t status = _zx_vmo_set_size(vmo_, DataSize());
CHECK_EQ(status, ZX_OK);
uint64_t size = DataSize();
status = _zx_object_set_property(vmo_, ZX_PROP_VMO_CONTENT_SIZE, &size,
sizeof(size));
CHECK_EQ(status, ZX_OK);
return first_index;
}
}
};
static TracePcGuardController pc_guard_controller;
}
}
namespace __sanitizer {
void InitializeCoverage(bool enabled, const char *dir) {
CHECK_EQ(enabled, common_flags()->coverage);
CHECK_EQ(dir, common_flags()->coverage_dir);
static bool coverage_enabled = false;
if (!coverage_enabled) {
coverage_enabled = enabled;
Atexit(__sanitizer_cov_dump);
AddDieCallback(__sanitizer_cov_dump);
}
}
}
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(const uptr *pcs,
uptr len) {
UNIMPLEMENTED();
}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) {
if (!*guard)
return;
__sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1);
}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init,
u32 *start, u32 *end) {
if (start == end || *start)
return;
__sancov::pc_guard_controller.InitTracePcGuard(start, end);
}
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() {
__sancov::pc_guard_controller.Dump();
}
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() {
__sanitizer_dump_trace_pc_guard_coverage();
}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
}
#endif