diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 8c26cb4141..75e03337f9 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1572,6 +1572,8 @@ int xc_domctl(xc_interface *xch, struct xen_domctl *domctl);
 int xc_sysctl(xc_interface *xch, struct xen_sysctl *sysctl);
 
 int xc_version(xc_interface *xch, int cmd, void *arg);
+int xc_edge_trace(xc_interface *xch, domid_t dom_id, int mode,
+    unsigned int size, uint64_t *buf);
 
 int xc_flask_op(xc_interface *xch, xen_flask_op_t *op);
 
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index f395594a8f..97663f219b 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -530,6 +530,28 @@ int xc_version(xc_interface *xch, int cmd, void *arg)
     return rc;
 }
 
+int xc_edge_trace(xc_interface *xch,
+    domid_t dom_id, int mode, unsigned int size, uint64_t* arg)
+{
+    int rc;
+
+    DECLARE_HYPERCALL_BOUNCE(arg, size * sizeof(uint64_t),
+        XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+
+    if ( xc_hypercall_bounce_pre(xch, arg) )
+    {
+        PERROR("Could not bounce buffer for edge_trace hypercall");
+        return -ENOMEM;
+    }
+
+    rc = do_edge_trace(xch, dom_id, mode, size, HYPERCALL_BUFFER(arg));
+
+    xc_hypercall_bounce_post(xch, arg);
+
+    return rc;
+}
+
+
 unsigned long xc_make_page_below_4G(
     xc_interface *xch, uint32_t domid, unsigned long mfn)
 {
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 1c27b0fded..60b0d8ebe3 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -229,6 +229,14 @@ static inline int do_xen_version(xc_interface *xch, int cmd, xc_hypercall_buffer
                     cmd, HYPERCALL_BUFFER_AS_ARG(dest));
 }
 
+static inline int do_edge_trace(xc_interface *xch, domid_t dom_id, int mode,
+                                unsigned int size, xc_hypercall_buffer_t *buf)
+{
+    DECLARE_HYPERCALL_BUFFER_ARGUMENT(buf);
+    return xencall4(xch->xcall, __HYPERVISOR_edge_trace, dom_id, mode,
+        size, HYPERCALL_BUFFER_AS_ARG(buf));
+}
+
 static inline int do_physdev_op(xc_interface *xch, int cmd, void *op, size_t len)
 {
     int ret = -1;
diff --git a/xen/Kconfig b/xen/Kconfig
index 65d491d776..5ed2c9c390 100644
--- a/xen/Kconfig
+++ b/xen/Kconfig
@@ -38,4 +38,8 @@ config LTO
 
 	  If unsure, say N.
 
+config TRACE_PC
+    bool "Enable tracing e.g. for fuzzing"
+    default false
+
 source "Kconfig.debug"
diff --git a/xen/Rules.mk b/xen/Rules.mk
index 77bcd44922..dde14e3228 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -170,6 +170,10 @@ clean:: $(addprefix _clean_, $(subdir-all))
 _clean_%/: FORCE
 	$(MAKE) -f $(BASEDIR)/Rules.mk -C $* clean
 
+ifeq ($(CONFIG_TRACE_PC),y)
+$(objs-need-tracing): CFLAGS += -fsanitize-coverage=trace-pc
+endif
+
 %.o: %.c Makefile
 	$(CC) $(CFLAGS) -c $< -o $@
 
diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c
index c07999b518..a4d36517f9 100644
--- a/xen/arch/arm/traps.c
+++ b/xen/arch/arm/traps.c
@@ -1419,6 +1419,7 @@ static arm_hypercall_t arm_hypercall_table[] = {
     HYPERCALL(platform_op, 1),
     HYPERCALL_ARM(vcpu_op, 3),
     HYPERCALL(vm_assist, 2),
+    HYPERCALL(edge_trace, 4),
 };
 
 #ifndef NDEBUG
diff --git a/xen/arch/x86/hvm/hypercall.c b/xen/arch/x86/hvm/hypercall.c
index e7238ce293..fed8363d8a 100644
--- a/xen/arch/x86/hvm/hypercall.c
+++ b/xen/arch/x86/hvm/hypercall.c
@@ -132,6 +132,7 @@ static const hypercall_table_t hvm_hypercall_table[] = {
     COMPAT_CALL(mmuext_op),
     HYPERCALL(xenpmu_op),
     COMPAT_CALL(dm_op),
+    HYPERCALL(edge_trace),
     HYPERCALL(arch_1)
 };
 
diff --git a/xen/arch/x86/hypercall.c b/xen/arch/x86/hypercall.c
index e30181817a..caa9376d29 100644
--- a/xen/arch/x86/hypercall.c
+++ b/xen/arch/x86/hypercall.c
@@ -67,6 +67,7 @@ const hypercall_args_t hypercall_args_table[NR_hypercalls] =
     ARGS(tmem_op, 1),
     ARGS(xenpmu_op, 2),
     ARGS(dm_op, 3),
+    ARGS(edge_trace, 4),
     ARGS(mca, 1),
     ARGS(arch_1, 1),
 };
diff --git a/xen/arch/x86/pv/hypercall.c b/xen/arch/x86/pv/hypercall.c
index 7c5e5a629d..24f931a895 100644
--- a/xen/arch/x86/pv/hypercall.c
+++ b/xen/arch/x86/pv/hypercall.c
@@ -79,6 +79,7 @@ static const hypercall_table_t pv_hypercall_table[] = {
 #endif
     HYPERCALL(xenpmu_op),
     COMPAT_CALL(dm_op),
+    HYPERCALL(edge_trace),
     HYPERCALL(mca),
     HYPERCALL(arch_1),
 };
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 26c5a64337..274baf084b 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -6,6 +6,8 @@ obj-y += cpupool.o
 obj-$(CONFIG_HAS_DEVICE_TREE) += device_tree.o
 obj-y += domctl.o
 obj-y += domain.o
+obj-$(CONFIG_TRACE_PC) += edge_trace.o
+obj-$(CONFIG_TRACE_PC) += edge_tracer.o
 obj-y += event_2l.o
 obj-y += event_channel.o
 obj-y += event_fifo.o
@@ -80,3 +82,14 @@ subdir-$(CONFIG_GCOV) += gcov
 
 subdir-y += libelf
 subdir-$(CONFIG_HAS_DEVICE_TREE) += libfdt
+
+objs-need-tracing := bsearch.o \
+    decompress.o device_tree.o domain.o domctl.o earlycpio.o grant_table.o \
+    guestcopy.o gunzip.o inflate.o kernel.o kexec.o keyhandler.o kimage.o \
+    lib.o livepatch.o lzo.o mem_access.o memory.o multicall.o notifier.o \
+    page_alloc.o pdx.o perfc.o radix_tree.o rangeset.o \
+    rbtree.o shutdown.o smp.o sort.o stop_machine.o string.o \
+    symbols.o symbols-dummy.o sysctl.o time.o tmem.o \
+    tmem_control.o tmem_xen.o trace.o unlz4.o unlzo.o unxz.o version.o \
+    virtual_region.o vmap.o vm_event.o warning.o xenoprof.o \
+    xmalloc_tlsf.o
diff --git a/xen/common/edge_trace.c b/xen/common/edge_trace.c
new file mode 100644
index 0000000000..7b325f4d17
--- /dev/null
+++ b/xen/common/edge_trace.c
@@ -0,0 +1,77 @@
+/******************************************************************************
+ * edge_trace.c
+ *
+ * Copyright (c) 2017 Felix Schmoll
+ */
+
+#include <xen/edge_trace.h>
+#include <xen/xmalloc.h>
+#include <xen/guest_access.h>
+#include <xen/sched.h>
+
+long do_edge_trace(domid_t dom, int mode, unsigned int size,
+    XEN_GUEST_HANDLE_PARAM(uint64_t) buf)
+{
+    int ret = 0;
+    struct domain *d;
+
+    if( dom == DOMID_SELF )
+        d = current->domain;
+    else
+        d = get_domain_by_id(dom);
+
+    if( !d )
+        return -EINVAL; /* invalid domain */
+
+    switch ( mode )
+    {
+        case TRACE_START:
+        {
+            if( d->tracing_buffer )
+            {
+                ret = -EBUSY; /* domain already being traced */
+                break;
+            }
+
+            d->tracing_buffer_pos = 0;
+            d->tracing_buffer_size = size;
+            d->tracing_buffer = xmalloc_array(uint64_t, size);
+
+            if( !d->tracing_buffer )
+                ret = -ENOMEM;
+            break;
+        }
+
+        case TRACE_STOP:
+        {
+            uint64_t* temp = d->tracing_buffer;
+            d->tracing_buffer = NULL;
+
+            if( copy_to_guest(buf, temp, d->tracing_buffer_pos) )
+                ret = -EFAULT;
+
+            xfree(temp);
+
+            ret = d->tracing_buffer_pos;
+            break;
+        }
+
+        default:
+            ret = -ENOSYS;
+    }
+
+    if( dom != DOMID_SELF )
+        put_domain(d);
+
+    return ret;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/common/edge_tracer.c b/xen/common/edge_tracer.c
new file mode 100644
index 0000000000..eb7ab96d8f
--- /dev/null
+++ b/xen/common/edge_tracer.c
@@ -0,0 +1,25 @@
+/******************************************************************************
+ * edge_tracer.c
+ *
+ * Copyright (c) 2017 Felix Schmoll
+ */
+
+#include <xen/edge_trace.h>
+#include <xen/kernel.h>
+
+void __sanitizer_cov_trace_pc(void)
+{
+        struct domain *d;
+
+        if( system_state < SYS_STATE_active )
+            return;
+
+        d = current->domain;
+
+        if(d->tracing_buffer &&
+           d->tracing_buffer_pos < d->tracing_buffer_size)
+        {
+            d->tracing_buffer[d->tracing_buffer_pos++] =
+                (uint64_t) __builtin_return_address(0);
+        }
+}
diff --git a/xen/include/public/xen.h b/xen/include/public/xen.h
index 2ac6b1e24d..0b113847c9 100644
--- a/xen/include/public/xen.h
+++ b/xen/include/public/xen.h
@@ -121,6 +121,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_ulong_t);
 #define __HYPERVISOR_xc_reserved_op       39 /* reserved for XenClient */
 #define __HYPERVISOR_xenpmu_op            40
 #define __HYPERVISOR_dm_op                41
+#define __HYPERVISOR_edge_trace           42
 
 /* Architecture-specific hypercall definitions. */
 #define __HYPERVISOR_arch_0               48
diff --git a/xen/include/xen/edge_trace.h b/xen/include/xen/edge_trace.h
new file mode 100644
index 0000000000..aa34c3ef96
--- /dev/null
+++ b/xen/include/xen/edge_trace.h
@@ -0,0 +1,19 @@
+/******************************************************************************
+ * edge_trace.h
+ *
+ * Information structure that lives at the bottom of the per-cpu Xen stack.
+ */
+
+#ifndef __TRACE_H__
+#define __TRACE_H__
+
+#include <xen/types.h>
+#include <xen/sched.h>
+#include <asm/current.h>
+
+#define TRACE_START 0
+#define TRACE_STOP 1
+
+void __sanitizer_cov_trace_pc(void);
+
+#endif
diff --git a/xen/include/xen/hypercall.h b/xen/include/xen/hypercall.h
index cc99aea57d..48afc82bc0 100644
--- a/xen/include/xen/hypercall.h
+++ b/xen/include/xen/hypercall.h
@@ -83,6 +83,13 @@ do_xen_version(
     XEN_GUEST_HANDLE_PARAM(void) arg);
 
 extern long
+do_edge_trace(
+    domid_t dom_id,
+    int mode,
+    unsigned int size,
+    XEN_GUEST_HANDLE_PARAM(uint64_t) buf);
+
+extern long
 do_console_io(
     int cmd,
     int count,
diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h
index 1127ca99bd..eb0e9722d7 100644
--- a/xen/include/xen/sched.h
+++ b/xen/include/xen/sched.h
@@ -483,6 +483,12 @@ struct domain
         unsigned int guest_request_enabled       : 1;
         unsigned int guest_request_sync          : 1;
     } monitor;
+
+#ifdef CONFIG_TRACE_PC
+    uint64_t* tracing_buffer;
+    unsigned int tracing_buffer_pos;
+    unsigned int tracing_buffer_size;
+#endif
 };
 
 /* Protect updates/reads (resp.) of domain_list and domain_hash. */
