diff -Nraup linux-2.6.33/arch/x86/include/asm/ptrace.h linux-2.6.33_perfkvm/arch/x86/include/asm/ptrace.h
--- linux-2.6.33/arch/x86/include/asm/ptrace.h	2010-02-25 02:52:17.000000000 +0800
+++ linux-2.6.33_perfkvm/arch/x86/include/asm/ptrace.h	2010-03-03 14:57:03.792070616 +0800
@@ -167,6 +167,15 @@ static inline int user_mode(struct pt_re
 #endif
 }
 
+static inline int user_mode_cs(u16 cs)
+{
+#ifdef CONFIG_X86_32
+	return (cs & SEGMENT_RPL_MASK) == USER_RPL;
+#else
+	return !!(cs & 3);
+#endif
+}
+
 static inline int user_mode_vm(struct pt_regs *regs)
 {
 #ifdef CONFIG_X86_32
diff -Nraup linux-2.6.33/arch/x86/kvm/vmx.c linux-2.6.33_perfkvm/arch/x86/kvm/vmx.c
--- linux-2.6.33/arch/x86/kvm/vmx.c	2010-02-25 02:52:17.000000000 +0800
+++ linux-2.6.33_perfkvm/arch/x86/kvm/vmx.c	2010-03-03 15:06:01.660057862 +0800
@@ -26,6 +26,7 @@
 #include <linux/sched.h>
 #include <linux/moduleparam.h>
 #include <linux/ftrace_event.h>
+#include <linux/perf_event.h>
 #include "kvm_cache_regs.h"
 #include "x86.h"
 
@@ -3553,8 +3554,14 @@ static void vmx_complete_interrupts(stru
 
 	/* We need to handle NMIs before interrupts are enabled */
 	if ((exit_intr_info & INTR_INFO_INTR_TYPE_MASK) == INTR_TYPE_NMI_INTR &&
-	    (exit_intr_info & INTR_INFO_VALID_MASK))
+	    (exit_intr_info & INTR_INFO_VALID_MASK)) {
+		u64 rip = vmcs_readl(GUEST_RIP);
+		int user_mode;
+		user_mode = user_mode_cs(vmcs_read16(GUEST_CS_SELECTOR));
+		perf_save_virt_ip(user_mode, rip);
 		asm("int $2");
+		perf_reset_virt_ip();
+	}
 
 	idtv_info_valid = idt_vectoring_info & VECTORING_INFO_VALID_MASK;
 
diff -Nraup linux-2.6.33/include/linux/perf_event.h linux-2.6.33_perfkvm/include/linux/perf_event.h
--- linux-2.6.33/include/linux/perf_event.h	2010-02-25 02:52:17.000000000 +0800
+++ linux-2.6.33_perfkvm/include/linux/perf_event.h	2010-03-03 15:22:05.325064001 +0800
@@ -287,11 +287,13 @@ struct perf_event_mmap_page {
 	__u64	data_tail;		/* user-space written tail */
 };
 
-#define PERF_RECORD_MISC_CPUMODE_MASK		(3 << 0)
-#define PERF_RECORD_MISC_CPUMODE_UNKNOWN		(0 << 0)
+#define PERF_RECORD_MISC_CPUMODE_MASK		(7 << 0)
+#define PERF_RECORD_MISC_CPUMODE_UNKNOWN	(0 << 0)
 #define PERF_RECORD_MISC_KERNEL			(1 << 0)
 #define PERF_RECORD_MISC_USER			(2 << 0)
 #define PERF_RECORD_MISC_HYPERVISOR		(3 << 0)
+#define PERF_RECORD_MISC_GUEST_KERNEL		(4 << 0)
+#define PERF_RECORD_MISC_GUEST_USER		(5 << 0)
 
 struct perf_event_header {
 	__u32	type;
@@ -841,6 +843,37 @@ static inline void perf_event_mmap(struc
 		__perf_event_mmap(vma);
 }
 
+struct perf_virt_ip_info {
+	int	user_mode;
+	u64	ip;
+};
+
+DECLARE_PER_CPU(struct perf_virt_ip_info, perf_virt_ip);
+extern void perf_save_virt_ip(int user_mode, u64 ip);
+extern void perf_reset_virt_ip(void);
+
+static inline u64 perf_instruction_pointer(struct pt_regs *regs)
+{
+	u64 ip;
+	ip = percpu_read(perf_virt_ip.ip);
+	if (!ip)
+		ip = instruction_pointer(regs);
+	else
+		perf_reset_virt_ip();
+	return ip;
+}
+
+static inline unsigned int perf_misc_flags(struct pt_regs *regs)
+{
+	if (percpu_read(perf_virt_ip.ip)) {
+		return percpu_read(perf_virt_ip.user_mode) ?
+			PERF_RECORD_MISC_GUEST_USER :
+			PERF_RECORD_MISC_GUEST_KERNEL;
+	} else
+		return user_mode(regs) ? PERF_RECORD_MISC_USER :
+				 PERF_RECORD_MISC_KERNEL;
+}
+
 extern void perf_event_comm(struct task_struct *tsk);
 extern void perf_event_fork(struct task_struct *tsk);
 
@@ -855,12 +888,6 @@ extern void perf_tp_event(int event_id, 
 				 void *record, int entry_size);
 extern void perf_bp_event(struct perf_event *event, void *data);
 
-#ifndef perf_misc_flags
-#define perf_misc_flags(regs)	(user_mode(regs) ? PERF_RECORD_MISC_USER : \
-				 PERF_RECORD_MISC_KERNEL)
-#define perf_instruction_pointer(regs)	instruction_pointer(regs)
-#endif
-
 extern int perf_output_begin(struct perf_output_handle *handle,
 			     struct perf_event *event, unsigned int size,
 			     int nmi, int sample);
@@ -895,6 +922,10 @@ perf_sw_event(u32 event_id, u64 nr, int 
 static inline void
 perf_bp_event(struct perf_event *event, void *data)		{ }
 
+static inline void perf_save_virt_ip(int user_mode, u64 ip)	{ }
+static inline void perf_reset_virt_ip(void)	{ }
+#define perf_instruction_pointer(event, regs)	instruction_pointer(regs)
+
 static inline void perf_event_mmap(struct vm_area_struct *vma)		{ }
 static inline void perf_event_comm(struct task_struct *tsk)		{ }
 static inline void perf_event_fork(struct task_struct *tsk)		{ }
diff -Nraup linux-2.6.33/kernel/perf_event.c linux-2.6.33_perfkvm/kernel/perf_event.c
--- linux-2.6.33/kernel/perf_event.c	2010-02-25 02:52:17.000000000 +0800
+++ linux-2.6.33_perfkvm/kernel/perf_event.c	2010-03-03 15:16:25.521592849 +0800
@@ -3077,6 +3077,26 @@ void perf_output_sample(struct perf_outp
 	}
 }
 
+DEFINE_PER_CPU(struct perf_virt_ip_info, perf_virt_ip) = {0,0};
+EXPORT_PER_CPU_SYMBOL(perf_virt_ip);
+
+void perf_save_virt_ip(int user_mode, u64 ip)
+{
+	if (!atomic_read(&nr_events))
+		return;
+	percpu_write(perf_virt_ip.user_mode, ip);
+	percpu_write(perf_virt_ip.ip, ip);
+}
+EXPORT_SYMBOL_GPL(perf_save_virt_ip);
+
+void perf_reset_virt_ip(void)
+{
+	if (!percpu_read(perf_virt_ip.ip))
+		return;
+	percpu_write(perf_virt_ip.ip, 0);
+}
+EXPORT_SYMBOL_GPL(perf_reset_virt_ip);
+
 void perf_prepare_sample(struct perf_event_header *header,
 			 struct perf_sample_data *data,
 			 struct perf_event *event,
