4 * @remark Copyright 2002 OProfile authors
5 * @remark Read the file COPYING
11 #include <linux/oprofile.h>
12 #include <linux/sched.h>
14 #include <asm/ptrace.h>
17 struct frame_head
* ebp
;
19 } __attribute__((packed
));
21 static struct frame_head
*
22 dump_backtrace(struct frame_head
* head
)
24 oprofile_add_trace(head
->ret
);
26 /* frame pointers should strictly progress back up the stack
27 * (towards higher addresses) */
28 if (head
>= head
->ebp
)
34 /* check that the page(s) containing the frame head are present */
35 static int pages_present(struct frame_head
* head
)
37 struct mm_struct
* mm
= current
->mm
;
39 /* FIXME: only necessary once per page */
40 if (!check_user_page_readable(mm
, (unsigned long)head
))
43 return check_user_page_readable(mm
, (unsigned long)(head
+ 1));
47 * | | /\ Higher addresses
49 * --------------- stack base (address of current_thread_info)
53 * --------------- saved regs->ebp value if valid (frame_head address)
55 * --------------- struct pt_regs stored on stack (struct pt_regs *)
59 * --------------- %esp
61 * | | \/ Lower addresses
63 * Thus, &pt_regs <-> stack base restricts the valid(ish) ebp values
65 #ifdef CONFIG_FRAME_POINTER
66 static int valid_kernel_stack(struct frame_head
* head
, struct pt_regs
* regs
)
68 unsigned long headaddr
= (unsigned long)head
;
69 unsigned long stack
= (unsigned long)regs
;
70 unsigned long stack_base
= (stack
& ~(THREAD_SIZE
- 1)) + THREAD_SIZE
;
72 return headaddr
> stack
&& headaddr
< stack_base
;
75 /* without fp, it's just junk */
76 static int valid_kernel_stack(struct frame_head
* head
, struct pt_regs
* regs
)
84 x86_backtrace(struct pt_regs
* const regs
, unsigned int depth
)
86 struct frame_head
*head
;
89 head
= (struct frame_head
*)regs
->rbp
;
91 head
= (struct frame_head
*)regs
->ebp
;
94 if (!user_mode(regs
)) {
95 while (depth
-- && valid_kernel_stack(head
, regs
))
96 head
= dump_backtrace(head
);
101 if (!spin_trylock(¤t
->mm
->page_table_lock
))
105 while (depth
-- && head
&& pages_present(head
))
106 head
= dump_backtrace(head
);
109 spin_unlock(¤t
->mm
->page_table_lock
);