Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/vitb/linux...
[linux-2.6] / include / asm-x86_64 / unwind.h
1 #ifndef _ASM_X86_64_UNWIND_H
2 #define _ASM_X86_64_UNWIND_H
3
4 /*
5  * Copyright (C) 2002-2006 Novell, Inc.
6  *      Jan Beulich <jbeulich@novell.com>
7  * This code is released under version 2 of the GNU GPL.
8  */
9
10 #ifdef CONFIG_STACK_UNWIND
11
12 #include <linux/sched.h>
13 #include <asm/ptrace.h>
14 #include <asm/uaccess.h>
15 #include <asm/vsyscall.h>
16
17 struct unwind_frame_info
18 {
19         struct pt_regs regs;
20         struct task_struct *task;
21 };
22
23 #define UNW_PC(frame)        (frame)->regs.rip
24 #define UNW_SP(frame)        (frame)->regs.rsp
25 #ifdef CONFIG_FRAME_POINTER
26 #define UNW_FP(frame)        (frame)->regs.rbp
27 #define FRAME_RETADDR_OFFSET 8
28 #define FRAME_LINK_OFFSET    0
29 #define STACK_BOTTOM(tsk)    (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1))
30 #define STACK_TOP(tsk)       ((tsk)->thread.rsp0)
31 #endif
32 /* Might need to account for the special exception and interrupt handling
33    stacks here, since normally
34         EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER,
35    but the construct is needed only for getting across the stack switch to
36    the interrupt stack - thus considering the IRQ stack itself is unnecessary,
37    and the overhead of comparing against all exception handling stacks seems
38    not desirable. */
39 #define STACK_LIMIT(ptr)     (((ptr) - 1) & ~(THREAD_SIZE - 1))
40
41 #define UNW_REGISTER_INFO \
42         PTREGS_INFO(rax), \
43         PTREGS_INFO(rdx), \
44         PTREGS_INFO(rcx), \
45         PTREGS_INFO(rbx), \
46         PTREGS_INFO(rsi), \
47         PTREGS_INFO(rdi), \
48         PTREGS_INFO(rbp), \
49         PTREGS_INFO(rsp), \
50         PTREGS_INFO(r8), \
51         PTREGS_INFO(r9), \
52         PTREGS_INFO(r10), \
53         PTREGS_INFO(r11), \
54         PTREGS_INFO(r12), \
55         PTREGS_INFO(r13), \
56         PTREGS_INFO(r14), \
57         PTREGS_INFO(r15), \
58         PTREGS_INFO(rip)
59
60 static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
61                                             /*const*/ struct pt_regs *regs)
62 {
63         info->regs = *regs;
64 }
65
66 static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
67 {
68         extern const char thread_return[];
69
70         memset(&info->regs, 0, sizeof(info->regs));
71         info->regs.rip = (unsigned long)thread_return;
72         info->regs.cs = __KERNEL_CS;
73         __get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp);
74         info->regs.rsp = info->task->thread.rsp;
75         info->regs.ss = __KERNEL_DS;
76 }
77
78 extern int arch_unwind_init_running(struct unwind_frame_info *,
79                                     int (*callback)(struct unwind_frame_info *,
80                                                     void *arg),
81                                     void *arg);
82
83 static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
84 {
85 #if 0 /* This can only work when selector register saves/restores
86          are properly annotated (and tracked in UNW_REGISTER_INFO). */
87         return user_mode(&info->regs);
88 #else
89         return (long)info->regs.rip >= 0
90                || (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END)
91                || (long)info->regs.rsp >= 0;
92 #endif
93 }
94
95 #else
96
97 #define UNW_PC(frame) ((void)(frame), 0)
98 #define UNW_SP(frame) ((void)(frame), 0)
99
100 static inline int arch_unw_user_mode(const void *info)
101 {
102         return 0;
103 }
104
105 #endif
106
107 #endif /* _ASM_X86_64_UNWIND_H */