aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/oprofile
diff options
context:
space:
mode:
authorGeorge Dunlap <george.dunlap@eu.citrix.com>2012-01-23 09:36:29 +0000
committerGeorge Dunlap <george.dunlap@eu.citrix.com>2012-01-23 09:36:29 +0000
commita2bef2635bb7e4295692ad4c87e199be84d11e56 (patch)
tree19351f2e771bb442ba991a538874a9cb1ec72f64 /xen/arch/x86/oprofile
parentfb55c1dd70c077075644a3d6a8d362e221659c23 (diff)
downloadxen-a2bef2635bb7e4295692ad4c87e199be84d11e56.tar.gz
xen-a2bef2635bb7e4295692ad4c87e199be84d11e56.tar.bz2
xen-a2bef2635bb7e4295692ad4c87e199be84d11e56.zip
xenoprof: Handle 32-bit guest stacks properly in a 64-bit hypervisor
The dump_guest_backtrace() function attempted to walk the stack based on the assumption that the guest and hypervisor pointer sizes were the same; thus any 32-bit guest running under 64-bit hypervisor would have unreliable results. In 64-bit mode, read the 32-bit stack frame properly. Signed-off-by: Marcus Granado <marcus.granado@eu.citrix.com> Signed-off-by: George Dunlap <george.dunlap@eu.citrix.com> Committed-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/oprofile')
-rw-r--r--xen/arch/x86/oprofile/backtrace.c48
1 files changed, 41 insertions, 7 deletions
diff --git a/xen/arch/x86/oprofile/backtrace.c b/xen/arch/x86/oprofile/backtrace.c
index 5d5f9df8cb..6df0f181ef 100644
--- a/xen/arch/x86/oprofile/backtrace.c
+++ b/xen/arch/x86/oprofile/backtrace.c
@@ -20,6 +20,13 @@ struct frame_head {
unsigned long ret;
} __attribute__((packed));
+#ifdef CONFIG_X86_64
+struct frame_head_32bit {
+ uint32_t ebp;
+ unsigned long ret;
+} __attribute__((packed));
+#endif
+
static struct frame_head *
dump_hypervisor_backtrace(struct domain *d, struct vcpu *vcpu,
struct frame_head * head, int mode)
@@ -35,19 +42,46 @@ dump_hypervisor_backtrace(struct domain *d, struct vcpu *vcpu,
return head->ebp;
}
+#ifdef CONFIG_X86_64
+static inline int is_32bit_vcpu(struct vcpu *vcpu)
+{
+ if (is_hvm_vcpu(vcpu))
+ return !hvm_long_mode_enabled(vcpu);
+ else
+ return is_pv_32bit_vcpu(vcpu);
+}
+#endif
+
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;
+
+#ifdef CONFIG_X86_64
+ if ( is_32bit_vcpu(vcpu) )
+ {
+ struct frame_head_32bit bufhead32[2];
+ /* Also check accessibility of one struct frame_head beyond */
+ if (!guest_handle_okay(guest_head, sizeof(bufhead32)))
+ return 0;
+ if (__copy_from_guest_offset((char *)bufhead32, guest_head, 0,
+ sizeof(bufhead32)))
+ return 0;
+ bufhead[0].ebp=(struct frame_head *)(unsigned long)bufhead32[0].ebp;
+ bufhead[0].ret=bufhead32[0].ret;
+ }
+ else
+#endif
+ {
+ /* 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;