aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-06-07 14:30:21 +0100
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-06-07 14:30:21 +0100
commit94c85019981270a21e6e3aeba694f3b7b444b566 (patch)
treec42a47aae990fa457bbd10e8372a4cb9744d094e
parent30f01d9011561268556d47273a8599ebd9b3173a (diff)
downloadxen-94c85019981270a21e6e3aeba694f3b7b444b566.tar.gz
xen-94c85019981270a21e6e3aeba694f3b7b444b566.tar.bz2
xen-94c85019981270a21e6e3aeba694f3b7b444b566.zip
Add backtrace support to xenoprof.
Signed-off-by: Amitabha Roy <amitabha.roy@gmail.com> Reviewed-by: Jose Renato G Santos <joserenato.santos@hp.com>
-rw-r--r--xen/Rules.mk32
-rw-r--r--xen/arch/ia64/xen/oprofile/perfmon.c7
-rw-r--r--xen/arch/x86/oprofile/Makefile1
-rw-r--r--xen/arch/x86/oprofile/backtrace.c132
-rw-r--r--xen/arch/x86/oprofile/op_model_athlon.c6
-rw-r--r--xen/arch/x86/oprofile/op_model_p4.c8
-rw-r--r--xen/arch/x86/oprofile/op_model_ppro.c6
-rw-r--r--xen/arch/x86/traps.c2
-rw-r--r--xen/common/xenoprof.c135
-rw-r--r--xen/include/asm-ia64/xenoprof.h12
-rw-r--r--xen/include/asm-x86/xenoprof.h11
-rw-r--r--xen/include/public/xenoprof.h8
-rw-r--r--xen/include/xen/xenoprof.h2
13 files changed, 300 insertions, 62 deletions
diff --git a/xen/Rules.mk b/xen/Rules.mk
index ac42711a11..55ae9746e0 100644
--- a/xen/Rules.mk
+++ b/xen/Rules.mk
@@ -3,10 +3,11 @@
# If you change any of these configuration options then you must
# 'make clean' before rebuilding.
#
-verbose ?= n
-perfc ?= n
-perfc_arrays?= n
-crash_debug ?= n
+verbose ?= n
+perfc ?= n
+perfc_arrays ?= n
+crash_debug ?= n
+frame_pointer ?= n
XEN_ROOT=$(BASEDIR)/..
include $(XEN_ROOT)/Config.mk
@@ -14,11 +15,15 @@ include $(XEN_ROOT)/Config.mk
# Hardcoded configuration implications and dependencies.
# Do this is a neater way if it becomes unwieldy.
ifeq ($(debug),y)
-verbose := y
+verbose := y
+frame_pointer := y
endif
ifeq ($(perfc_arrays),y)
perfc := y
endif
+ifeq ($(frame_pointer),y)
+CFLAGS := $(shell echo $(CFLAGS) | sed -e 's/-f[^ ]*omit-frame-pointer//g')
+endif
# Set ARCH/SUBARCH appropriately.
override COMPILE_SUBARCH := $(XEN_COMPILE_ARCH)
@@ -50,18 +55,19 @@ ALL_OBJS-y += $(BASEDIR)/drivers/built_in.o
ALL_OBJS-$(ACM_SECURITY) += $(BASEDIR)/acm/built_in.o
ALL_OBJS-y += $(BASEDIR)/arch/$(TARGET_ARCH)/built_in.o
-CFLAGS-y += -g -D__XEN__
-CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY
-CFLAGS-$(verbose) += -DVERBOSE
-CFLAGS-$(crash_debug) += -DCRASH_DEBUG
-CFLAGS-$(perfc) += -DPERF_COUNTERS
-CFLAGS-$(perfc_arrays) += -DPERF_ARRAYS
+CFLAGS-y += -g -D__XEN__
+CFLAGS-$(ACM_SECURITY) += -DACM_SECURITY
+CFLAGS-$(verbose) += -DVERBOSE
+CFLAGS-$(crash_debug) += -DCRASH_DEBUG
+CFLAGS-$(perfc) += -DPERF_COUNTERS
+CFLAGS-$(perfc_arrays) += -DPERF_ARRAYS
+CFLAGS-$(frame_pointer) += -fno-omit-frame-pointer -DCONFIG_FRAME_POINTER
ifneq ($(max_phys_cpus),)
-CFLAGS-y += -DMAX_PHYS_CPUS=$(max_phys_cpus)
+CFLAGS-y += -DMAX_PHYS_CPUS=$(max_phys_cpus)
endif
-AFLAGS-y += -D__ASSEMBLY__
+AFLAGS-y += -D__ASSEMBLY__
ALL_OBJS := $(ALL_OBJS-y)
diff --git a/xen/arch/ia64/xen/oprofile/perfmon.c b/xen/arch/ia64/xen/oprofile/perfmon.c
index 0488e1298b..4fce815fb0 100644
--- a/xen/arch/ia64/xen/oprofile/perfmon.c
+++ b/xen/arch/ia64/xen/oprofile/perfmon.c
@@ -37,7 +37,7 @@
#include <asm/ptrace.h>
// XXX move them to an appropriate header file
-extern void xenoprof_log_event(struct vcpu *vcpu,
+extern void xenoprof_log_event(struct vcpu *vcpu, struct pt_regs * regs,
unsigned long eip, int mode, int event);
extern int is_active(struct domain *d);
@@ -55,7 +55,10 @@ xenoprof_handler(struct task_struct *task, void *buf, pfm_ovfl_arg_t *arg,
if (!allow_virq || !allow_ints)
return 0;
- xenoprof_log_event(current, ip, xenoprofile_get_mode(task, regs), event);
+ // Note that log event actually expect cpu_user_regs, cast back
+ // appropriately when doing the backtrace implementation in ia64
+ xenoprof_log_event(current, regs, ip, xenoprofile_get_mode(task, regs),
+ event);
// send VIRQ_XENOPROF
if (is_active(current->domain) && !ring_0(regs))
diff --git a/xen/arch/x86/oprofile/Makefile b/xen/arch/x86/oprofile/Makefile
index 1956c02df5..956e3d1b5d 100644
--- a/xen/arch/x86/oprofile/Makefile
+++ b/xen/arch/x86/oprofile/Makefile
@@ -3,3 +3,4 @@ obj-y += nmi_int.o
obj-y += op_model_p4.o
obj-y += op_model_ppro.o
obj-y += op_model_athlon.o
+obj-y += backtrace.o
diff --git a/xen/arch/x86/oprofile/backtrace.c b/xen/arch/x86/oprofile/backtrace.c
new file mode 100644
index 0000000000..ad0b6eb0aa
--- /dev/null
+++ b/xen/arch/x86/oprofile/backtrace.c
@@ -0,0 +1,132 @@
+/**
+ * @file backtrace.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ * @author David Smith
+ * Modified for Xen by Amitabha Roy
+ *
+ */
+
+#include<xen/types.h>
+#include<asm/page.h>
+#include<xen/xenoprof.h>
+#include<asm/guest_access.h>
+
+struct frame_head {
+ struct frame_head * ebp;
+ unsigned long ret;
+} __attribute__((packed));
+
+static struct frame_head *
+dump_hypervisor_backtrace(struct domain *d, struct vcpu *vcpu,
+ struct frame_head * head, int mode)
+{
+ if (!xenoprof_add_trace(d, vcpu, head->ret, mode))
+ return 0;
+
+ /* frame pointers should strictly progress back up the stack
+ * (towards higher addresses) */
+ if (head >= head->ebp)
+ return NULL;
+
+ return head->ebp;
+}
+
+static struct frame_head *
+dump_guest_backtrace(struct domain *d, struct vcpu *vcpu,
+ struct frame_head * head, int mode)
+{
+ struct frame_head bufhead[2];
+ XEN_GUEST_HANDLE(char) guest_head = guest_handle_from_ptr(head, char);
+
+ /* Also check accessibility of one struct frame_head beyond */
+ if (!guest_handle_okay(guest_head, sizeof(bufhead)))
+ return 0;
+ if (__copy_from_guest_offset((char *)bufhead, guest_head, 0,
+ sizeof(bufhead)))
+ return 0;
+
+ if (!xenoprof_add_trace(d, vcpu, bufhead[0].ret, mode))
+ return 0;
+
+ /* frame pointers should strictly progress back up the stack
+ * (towards higher addresses) */
+ if (head >= bufhead[0].ebp)
+ return NULL;
+
+ return bufhead[0].ebp;
+}
+
+/*
+ * | | /\ Higher addresses
+ * | |
+ * --------------- stack base (address of current_thread_info)
+ * | thread info |
+ * . .
+ * | stack |
+ * --------------- saved regs->ebp value if valid (frame_head address)
+ * . .
+ * --------------- saved regs->rsp value if x86_64
+ * | |
+ * --------------- struct pt_regs * stored on stack if 32-bit
+ * | |
+ * . .
+ * | |
+ * --------------- %esp
+ * | |
+ * | | \/ Lower addresses
+ *
+ * Thus, regs (or regs->rsp for x86_64) <-> stack base restricts the
+ * valid(ish) ebp values. Note: (1) for x86_64, NMI and several other
+ * exceptions use special stacks, maintained by the interrupt stack table
+ * (IST). These stacks are set up in trap_init() in
+ * arch/x86_64/kernel/traps.c. Thus, for x86_64, regs now does not point
+ * to the kernel stack; instead, it points to some location on the NMI
+ * stack. On the other hand, regs->rsp is the stack pointer saved when the
+ * NMI occurred. (2) For 32-bit, regs->esp is not valid because the
+ * processor does not save %esp on the kernel stack when interrupts occur
+ * in the kernel mode.
+ */
+#if defined(CONFIG_FRAME_POINTER)
+static int valid_hypervisor_stack(struct frame_head * head,
+ struct cpu_user_regs * regs)
+{
+ unsigned long headaddr = (unsigned long)head;
+#ifdef CONFIG_X86_64
+ unsigned long stack = (unsigned long)regs->rsp;
+#else
+ unsigned long stack = (unsigned long)regs;
+#endif
+ unsigned long stack_base = (stack & ~(STACK_SIZE - 1)) + STACK_SIZE;
+
+ return headaddr > stack && headaddr < stack_base;
+}
+#else
+/* without fp, it's just junk */
+static int valid_hypervisor_stack(struct frame_head * head,
+ struct cpu_user_regs * regs)
+{
+ return 0;
+}
+#endif
+
+void xenoprof_backtrace(struct domain *d, struct vcpu *vcpu,
+ struct cpu_user_regs * const regs,
+ unsigned long depth, int mode)
+{
+ struct frame_head *head;
+
+ head = (struct frame_head *)regs->ebp;
+
+ if (mode > 1) {
+ while (depth-- && valid_hypervisor_stack(head, regs))
+ head = dump_hypervisor_backtrace(d, vcpu, head, mode);
+ return;
+ }
+
+ while (depth-- && head)
+ head = dump_guest_backtrace(d, vcpu, head, mode);
+}
diff --git a/xen/arch/x86/oprofile/op_model_athlon.c b/xen/arch/x86/oprofile/op_model_athlon.c
index ec99be48b0..adcc9209f7 100644
--- a/xen/arch/x86/oprofile/op_model_athlon.c
+++ b/xen/arch/x86/oprofile/op_model_athlon.c
@@ -43,8 +43,8 @@
static unsigned long reset_value[NUM_COUNTERS];
-extern void xenoprof_log_event(struct vcpu *v, unsigned long eip,
- int mode, int event);
+extern void xenoprof_log_event(struct vcpu *v, struct cpu_user_regs * regs,
+ unsigned long eip, int mode, int event);
extern int xenoprofile_get_mode(struct vcpu *v,
struct cpu_user_regs * const regs);
@@ -130,7 +130,7 @@ static int athlon_check_ctrs(unsigned int const cpu,
for (i = 0 ; i < NUM_COUNTERS; ++i) {
CTR_READ(low, high, msrs, i);
if (CTR_OVERFLOWED(low)) {
- xenoprof_log_event(current, eip, mode, i);
+ xenoprof_log_event(current, regs, eip, mode, i);
CTR_WRITE(reset_value[i], msrs, i);
ovf = 1;
}
diff --git a/xen/arch/x86/oprofile/op_model_p4.c b/xen/arch/x86/oprofile/op_model_p4.c
index c285ea1d41..8fcb7ce0bc 100644
--- a/xen/arch/x86/oprofile/op_model_p4.c
+++ b/xen/arch/x86/oprofile/op_model_p4.c
@@ -620,8 +620,8 @@ static void p4_setup_ctrs(struct op_msrs const * const msrs)
}
}
-extern void xenoprof_log_event(struct vcpu *v, unsigned long eip,
- int mode, int event);
+extern void xenoprof_log_event(struct vcpu *v, struct cpu_user_regs * regs,
+ unsigned long eip, int mode, int event);
extern int xenoprofile_get_mode(struct vcpu *v,
struct cpu_user_regs * const regs);
@@ -664,8 +664,8 @@ static int p4_check_ctrs(unsigned int const cpu,
CCCR_READ(low, high, real);
CTR_READ(ctr, high, real);
if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
- xenoprof_log_event(current, eip, mode, i);
- CTR_WRITE(reset_value[i], real);
+ xenoprof_log_event(current, regs, eip, mode, i);
+ CTR_WRITE(reset_value[i], real);
CCCR_CLEAR_OVF(low);
CCCR_WRITE(low, high, real);
CTR_WRITE(reset_value[i], real);
diff --git a/xen/arch/x86/oprofile/op_model_ppro.c b/xen/arch/x86/oprofile/op_model_ppro.c
index 139f4571bf..6c4344ee21 100644
--- a/xen/arch/x86/oprofile/op_model_ppro.c
+++ b/xen/arch/x86/oprofile/op_model_ppro.c
@@ -88,8 +88,8 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs)
}
}
-extern void xenoprof_log_event(struct vcpu *v, unsigned long eip,
- int mode, int event);
+extern void xenoprof_log_event(struct vcpu *v, struct cpu_user_regs * regs,
+ unsigned long eip, int mode, int event);
extern int xenoprofile_get_mode(struct vcpu *v,
struct cpu_user_regs * const regs);
@@ -106,7 +106,7 @@ static int ppro_check_ctrs(unsigned int const cpu,
for (i = 0 ; i < NUM_COUNTERS; ++i) {
CTR_READ(low, high, msrs, i);
if (CTR_OVERFLOWED(low)) {
- xenoprof_log_event(current, eip, mode, i);
+ xenoprof_log_event(current, regs, eip, mode, i);
CTR_WRITE(reset_value[i], msrs, i);
ovf = 1;
}
diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c
index fb454043eb..ec9738e9e3 100644
--- a/xen/arch/x86/traps.c
+++ b/xen/arch/x86/traps.c
@@ -167,7 +167,7 @@ static void show_guest_stack(struct cpu_user_regs *regs)
printk("\n");
}
-#ifdef NDEBUG
+#if !defined(CONFIG_FRAME_POINTER)
static void show_trace(struct cpu_user_regs *regs)
{
diff --git a/xen/common/xenoprof.c b/xen/common/xenoprof.c
index 7e2a04bb5c..13dbdd8a04 100644
--- a/xen/common/xenoprof.c
+++ b/xen/common/xenoprof.c
@@ -31,6 +31,7 @@ unsigned int pdomains;
unsigned int activated;
struct domain *xenoprof_primary_profiler;
int xenoprof_state = XENOPROF_IDLE;
+static unsigned long backtrace_depth;
u64 total_samples;
u64 invalid_buffer_samples;
@@ -205,7 +206,8 @@ static int alloc_xenoprof_struct(
i = 0;
for_each_vcpu ( d, v )
{
- xenoprof_buf_t *buf = (xenoprof_buf_t *)&d->xenoprof->rawbuf[i * bufsize];
+ xenoprof_buf_t *buf = (xenoprof_buf_t *)
+ &d->xenoprof->rawbuf[i * bufsize];
d->xenoprof->vcpu[v->vcpu_id].event_size = max_samples;
d->xenoprof->vcpu[v->vcpu_id].buffer = buf;
@@ -414,21 +416,82 @@ static int add_passive_list(XEN_GUEST_HANDLE(void) arg)
return ret;
}
-void xenoprof_log_event(
- struct vcpu *vcpu, unsigned long eip, int mode, int event)
+
+/* Get space in the buffer */
+static int xenoprof_buf_space(struct domain *d, xenoprof_buf_t * buf, int size)
+{
+ int head, tail;
+
+ head = xenoprof_buf(d, buf, event_head);
+ tail = xenoprof_buf(d, buf, event_tail);
+
+ return ((tail > head) ? 0 : size) + tail - head - 1;
+}
+
+/* Check for space and add a sample. Return 1 if successful, 0 otherwise. */
+static int xenoprof_add_sample(struct domain *d, xenoprof_buf_t *buf,
+ unsigned long eip, int mode, int event)
+{
+ int head, tail, size;
+
+ head = xenoprof_buf(d, buf, event_head);
+ tail = xenoprof_buf(d, buf, event_tail);
+ size = xenoprof_buf(d, buf, event_size);
+
+ /* make sure indexes in shared buffer are sane */
+ if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) )
+ {
+ corrupted_buffer_samples++;
+ return 0;
+ }
+
+ if ( xenoprof_buf_space(d, buf, size) > 0 )
+ {
+ xenoprof_buf(d, buf, event_log[head].eip) = eip;
+ xenoprof_buf(d, buf, event_log[head].mode) = mode;
+ xenoprof_buf(d, buf, event_log[head].event) = event;
+ head++;
+ if ( head >= size )
+ head = 0;
+
+ xenoprof_buf(d, buf, event_head) = head;
+ }
+ else
+ {
+ xenoprof_buf(d, buf, lost_samples)++;
+ lost_samples++;
+ return 0;
+ }
+
+ return 1;
+}
+
+int xenoprof_add_trace(struct domain *d, struct vcpu *vcpu,
+ unsigned long eip, int mode)
+{
+ xenoprof_buf_t *buf = d->xenoprof->vcpu[vcpu->vcpu_id].buffer;
+
+ /* Do not accidentally write an escape code due to a broken frame. */
+ if ( eip == XENOPROF_ESCAPE_CODE )
+ {
+ invalid_buffer_samples++;
+ return 0;
+ }
+
+ return xenoprof_add_sample(d, buf, eip, mode, 0);
+}
+
+void xenoprof_log_event(struct vcpu *vcpu,
+ struct cpu_user_regs * regs, unsigned long eip,
+ int mode, int event)
{
struct domain *d = vcpu->domain;
struct xenoprof_vcpu *v;
xenoprof_buf_t *buf;
- int head;
- int tail;
- int size;
-
total_samples++;
- /* ignore samples of un-monitored domains */
- /* Count samples in idle separate from other unmonitored domains */
+ /* Ignore samples of un-monitored domains. */
if ( !is_profiled(d) )
{
others_samples++;
@@ -436,41 +499,29 @@ void xenoprof_log_event(
}
v = &d->xenoprof->vcpu[vcpu->vcpu_id];
-
- /* Sanity check. Should never happen */
if ( v->buffer == NULL )
{
invalid_buffer_samples++;
return;
}
-
+
buf = v->buffer;
- head = xenoprof_buf(d, buf, event_head);
- tail = xenoprof_buf(d, buf, event_tail);
- size = v->event_size;
-
- /* make sure indexes in shared buffer are sane */
- if ( (head < 0) || (head >= size) || (tail < 0) || (tail >= size) )
+ /* Provide backtrace if requested. */
+ if ( backtrace_depth > 0 )
{
- corrupted_buffer_samples++;
- return;
+ if ( (xenoprof_buf_space(d, buf, v->event_size) < 2) ||
+ !xenoprof_add_sample(d, buf, XENOPROF_ESCAPE_CODE, mode,
+ XENOPROF_TRACE_BEGIN) )
+ {
+ xenoprof_buf(d, buf, lost_samples)++;
+ lost_samples++;
+ return;
+ }
}
- if ( (head == tail - 1) || (head == size - 1 && tail == 0) )
+ if ( xenoprof_add_sample(d, buf, eip, mode, event) )
{
- xenoprof_buf(d, buf, lost_samples)++;
- lost_samples++;
- }
- else
- {
- xenoprof_buf(d, buf, event_log[head].eip) = eip;
- xenoprof_buf(d, buf, event_log[head].mode) = mode;
- xenoprof_buf(d, buf, event_log[head].event) = event;
- head++;
- if ( head >= size )
- head = 0;
- xenoprof_buf(d, buf, event_head) = head;
if ( is_active(vcpu->domain) )
active_samples++;
else
@@ -481,9 +532,15 @@ void xenoprof_log_event(
xenoprof_buf(d, buf, kernel_samples)++;
else
xenoprof_buf(d, buf, xen_samples)++;
+
}
+
+ if ( backtrace_depth > 0 )
+ xenoprof_backtrace(d, vcpu, regs, backtrace_depth, mode);
}
+
+
static int xenoprof_op_init(XEN_GUEST_HANDLE(void) arg)
{
struct xenoprof_init xenoprof_init;
@@ -685,7 +742,8 @@ int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg)
break;
case XENOPROF_stop:
- if ( xenoprof_state != XENOPROF_PROFILING ) {
+ if ( xenoprof_state != XENOPROF_PROFILING )
+ {
ret = -EPERM;
break;
}
@@ -729,9 +787,18 @@ int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg)
activated = 0;
adomains=0;
xenoprof_primary_profiler = NULL;
+ backtrace_depth=0;
ret = 0;
}
break;
+
+ case XENOPROF_set_backtrace:
+ ret = 0;
+ if ( !xenoprof_backtrace_supported() )
+ ret = -EINVAL;
+ else if ( copy_from_guest(&backtrace_depth, arg, 1) )
+ ret = -EFAULT;
+ break;
default:
ret = -ENOSYS;
diff --git a/xen/include/asm-ia64/xenoprof.h b/xen/include/asm-ia64/xenoprof.h
index b8b1e602d9..159716cf05 100644
--- a/xen/include/asm-ia64/xenoprof.h
+++ b/xen/include/asm-ia64/xenoprof.h
@@ -37,7 +37,17 @@ void xenoprof_arch_release_counters(void);
struct vcpu;
struct cpu_user_regs;
int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs);
-
+static inline int xenoprof_backtrace_supported(void)
+{
+ return 0;
+}
+static inline void xenoprof_backtrace(
+ struct domain *d, struct vcpu *vcpu,
+ struct pt_regs *const regs, unsigned long depth, int mode)
+{
+ /* To be implemented */
+ return;
+}
#define xenoprof_shared_gmfn(d, gmaddr, maddr) \
assign_domain_page((d), (gmaddr), (maddr));
diff --git a/xen/include/asm-x86/xenoprof.h b/xen/include/asm-x86/xenoprof.h
index 8554f7c383..2ce369dd81 100644
--- a/xen/include/asm-x86/xenoprof.h
+++ b/xen/include/asm-x86/xenoprof.h
@@ -46,7 +46,18 @@ int xenoprof_arch_counter(XEN_GUEST_HANDLE(void) arg);
struct vcpu;
struct cpu_user_regs;
+
int xenoprofile_get_mode(struct vcpu *v, struct cpu_user_regs * const regs);
+
+static inline int xenoprof_backtrace_supported(void)
+{
+ return 1;
+}
+
+void xenoprof_backtrace(
+ struct domain *d, struct vcpu *vcpu,
+ struct cpu_user_regs *const regs, unsigned long depth, int mode);
+
#define xenoprof_shared_gmfn(d, gmaddr, maddr) \
do { \
(void)(maddr); \
diff --git a/xen/include/public/xenoprof.h b/xen/include/public/xenoprof.h
index d16d8ca3f6..183078d8db 100644
--- a/xen/include/public/xenoprof.h
+++ b/xen/include/public/xenoprof.h
@@ -49,7 +49,8 @@
#define XENOPROF_release_counters 12
#define XENOPROF_shutdown 13
#define XENOPROF_get_buffer 14
-#define XENOPROF_last_op 14
+#define XENOPROF_set_backtrace 15
+#define XENOPROF_last_op 15
#define MAX_OPROF_EVENTS 32
#define MAX_OPROF_DOMAINS 25
@@ -62,6 +63,11 @@ struct event_log {
uint8_t event;
};
+/* PC value that indicates a special code */
+#define XENOPROF_ESCAPE_CODE ~0UL
+/* Transient events for the xenoprof->oprofile cpu buf */
+#define XENOPROF_TRACE_BEGIN 1
+
/* Xenoprof buffer shared between Xen and domain - 1 per VCPU */
struct xenoprof_buf {
uint32_t event_head;
diff --git a/xen/include/xen/xenoprof.h b/xen/include/xen/xenoprof.h
index 8983f0c987..83e9ec094e 100644
--- a/xen/include/xen/xenoprof.h
+++ b/xen/include/xen/xenoprof.h
@@ -66,6 +66,8 @@ struct domain;
void free_xenoprof_pages(struct domain *d);
int do_xenoprof_op(int op, XEN_GUEST_HANDLE(void) arg);
+int xenoprof_add_trace(struct domain *d, struct vcpu *v,
+ unsigned long eip, int mode);
extern struct domain *xenoprof_primary_profiler;