1 /**
2  * @file backtrace.c
3  *
4  * @remark Copyright 2002 OProfile authors
5  * @remark Read the file COPYING
6  *
7  * @author John Levon
8  * @author David Smith
9  * Modified for Xen by Amitabha Roy
10  *
11  */
12 
13 #include <xen/types.h>
14 #include <asm/page.h>
15 #include <xen/xenoprof.h>
16 #include <xen/guest_access.h>
17 
18 struct __packed frame_head {
19     struct frame_head * ebp;
20     unsigned long ret;
21 };
22 typedef struct frame_head frame_head_t;
23 
24 struct __packed frame_head_32bit {
25     uint32_t ebp;
26     uint32_t ret;
27 };
28 typedef struct frame_head_32bit frame_head32_t;
29 
30 static struct frame_head *
dump_hypervisor_backtrace(struct vcpu * vcpu,const struct frame_head * head,int mode)31 dump_hypervisor_backtrace(struct vcpu *vcpu, const struct frame_head *head,
32                           int mode)
33 {
34     if (!xenoprof_add_trace(vcpu, head->ret, mode))
35         return 0;
36 
37     /* frame pointers should strictly progress back up the stack
38      * (towards higher addresses) */
39     if (head >= head->ebp)
40         return NULL;
41 
42     return head->ebp;
43 }
44 
is_32bit_vcpu(struct vcpu * vcpu)45 static inline int is_32bit_vcpu(struct vcpu *vcpu)
46 {
47     if (is_hvm_vcpu(vcpu))
48         return !hvm_long_mode_active(vcpu);
49     else
50         return is_pv_32bit_vcpu(vcpu);
51 }
52 
53 static struct frame_head *
dump_guest_backtrace(struct vcpu * vcpu,const struct frame_head * head,int mode)54 dump_guest_backtrace(struct vcpu *vcpu, const struct frame_head *head,
55                      int mode)
56 {
57     /* Also check accessibility of one struct frame_head beyond. */
58     frame_head_t bufhead[2];
59 
60     if ( is_32bit_vcpu(vcpu) )
61     {
62         frame_head32_t bufhead32[2];
63 
64         if ( raw_copy_from_guest(bufhead32, head, sizeof(bufhead32)) )
65             return 0;
66         bufhead[0].ebp = (struct frame_head *)(unsigned long)bufhead32[0].ebp;
67         bufhead[0].ret = bufhead32[0].ret;
68     }
69     else if ( raw_copy_from_guest(bufhead, head, sizeof(bufhead)) )
70         return 0;
71 
72     if ( !xenoprof_add_trace(vcpu, bufhead[0].ret, mode) )
73         return 0;
74 
75     /* frame pointers should strictly progress back up the stack
76      * (towards higher addresses) */
77     if ( head >= bufhead[0].ebp )
78         return NULL;
79 
80     return bufhead[0].ebp;
81 }
82 
83 /*
84  * |             | /\ Higher addresses
85  * |             |
86  * --------------- stack base (address of current_thread_info)
87  * | thread info |
88  * .             .
89  * |    stack    |
90  * --------------- saved regs->ebp value if valid (frame_head address)
91  * .             .
92  * --------------- saved regs->rsp value if x86_64
93  * |             |
94  * --------------- struct pt_regs * stored on stack if 32-bit
95  * |             |
96  * .             .
97  * |             |
98  * --------------- %esp
99  * |             |
100  * |             | \/ Lower addresses
101  *
102  * Thus, regs (or regs->rsp for x86_64) <-> stack base restricts the
103  * valid(ish) ebp values. Note: (1) for x86_64, NMI and several other
104  * exceptions use special stacks, maintained by the interrupt stack table
105  * (IST). These stacks are set up in trap_init() in
106  * arch/x86_64/kernel/traps.c. Thus, for x86_64, regs now does not point
107  * to the kernel stack; instead, it points to some location on the NMI
108  * stack. On the other hand, regs->rsp is the stack pointer saved when the
109  * NMI occurred. (2) For 32-bit, regs->esp is not valid because the
110  * processor does not save %esp on the kernel stack when interrupts occur
111  * in the kernel mode.
112  */
113 #if defined(CONFIG_FRAME_POINTER)
valid_hypervisor_stack(const struct frame_head * head,const struct cpu_user_regs * regs)114 static int valid_hypervisor_stack(const struct frame_head *head,
115 				  const struct cpu_user_regs *regs)
116 {
117     unsigned long headaddr = (unsigned long)head;
118     unsigned long stack = (unsigned long)regs->rsp;
119     unsigned long stack_base = (stack & ~(STACK_SIZE - 1)) + STACK_SIZE;
120 
121     return headaddr > stack && headaddr < stack_base;
122 }
123 #else
124 /* without fp, it's just junk */
valid_hypervisor_stack(const struct frame_head * head,const struct cpu_user_regs * regs)125 static int valid_hypervisor_stack(const struct frame_head *head,
126 				  const struct cpu_user_regs *regs)
127 {
128     return 0;
129 }
130 #endif
131 
xenoprof_backtrace(struct vcpu * vcpu,const struct cpu_user_regs * regs,unsigned long depth,int mode)132 void xenoprof_backtrace(struct vcpu *vcpu, const struct cpu_user_regs *regs,
133 			unsigned long depth, int mode)
134 {
135     const struct frame_head *head = (void *)regs->rbp;
136 
137     if (mode > 1) {
138         while (depth-- && valid_hypervisor_stack(head, regs))
139             head = dump_hypervisor_backtrace(vcpu, head, mode);
140         return;
141     }
142 
143     while (depth-- && head)
144         head = dump_guest_backtrace(vcpu, head, mode);
145 }
146