[PATCH] i386/x86-64: Work around gcc bug with noreturn functions in unwinder
[linux-2.6.git] / 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         unsigned call_frame:1;
22 };
23
24 #define UNW_PC(frame)        (frame)->regs.rip
25 #define UNW_SP(frame)        (frame)->regs.rsp
26 #ifdef CONFIG_FRAME_POINTER
27 #define UNW_FP(frame)        (frame)->regs.rbp
28 #define FRAME_RETADDR_OFFSET 8
29 #define FRAME_LINK_OFFSET    0
30 #define STACK_BOTTOM(tsk)    (((tsk)->thread.rsp0 - 1) & ~(THREAD_SIZE - 1))
31 #define STACK_TOP(tsk)       ((tsk)->thread.rsp0)
32 #endif
33 /* Might need to account for the special exception and interrupt handling
34    stacks here, since normally
35         EXCEPTION_STACK_ORDER < THREAD_ORDER < IRQSTACK_ORDER,
36    but the construct is needed only for getting across the stack switch to
37    the interrupt stack - thus considering the IRQ stack itself is unnecessary,
38    and the overhead of comparing against all exception handling stacks seems
39    not desirable. */
40 #define STACK_LIMIT(ptr)     (((ptr) - 1) & ~(THREAD_SIZE - 1))
41
42 #define UNW_REGISTER_INFO \
43         PTREGS_INFO(rax), \
44         PTREGS_INFO(rdx), \
45         PTREGS_INFO(rcx), \
46         PTREGS_INFO(rbx), \
47         PTREGS_INFO(rsi), \
48         PTREGS_INFO(rdi), \
49         PTREGS_INFO(rbp), \
50         PTREGS_INFO(rsp), \
51         PTREGS_INFO(r8), \
52         PTREGS_INFO(r9), \
53         PTREGS_INFO(r10), \
54         PTREGS_INFO(r11), \
55         PTREGS_INFO(r12), \
56         PTREGS_INFO(r13), \
57         PTREGS_INFO(r14), \
58         PTREGS_INFO(r15), \
59         PTREGS_INFO(rip)
60
61 #define UNW_DEFAULT_RA(raItem, dataAlign) \
62         ((raItem).where == Memory && \
63          !((raItem).value * (dataAlign) + 8))
64
65 static inline void arch_unw_init_frame_info(struct unwind_frame_info *info,
66                                             /*const*/ struct pt_regs *regs)
67 {
68         info->regs = *regs;
69 }
70
71 static inline void arch_unw_init_blocked(struct unwind_frame_info *info)
72 {
73         extern const char thread_return[];
74
75         memset(&info->regs, 0, sizeof(info->regs));
76         info->regs.rip = (unsigned long)thread_return;
77         info->regs.cs = __KERNEL_CS;
78         __get_user(info->regs.rbp, (unsigned long *)info->task->thread.rsp);
79         info->regs.rsp = info->task->thread.rsp;
80         info->regs.ss = __KERNEL_DS;
81 }
82
83 extern int arch_unwind_init_running(struct unwind_frame_info *,
84                                     int (*callback)(struct unwind_frame_info *,
85                                                     void *arg),
86                                     void *arg);
87
88 static inline int arch_unw_user_mode(const struct unwind_frame_info *info)
89 {
90 #if 0 /* This can only work when selector register saves/restores
91          are properly annotated (and tracked in UNW_REGISTER_INFO). */
92         return user_mode(&info->regs);
93 #else
94         return (long)info->regs.rip >= 0
95                || (info->regs.rip >= VSYSCALL_START && info->regs.rip < VSYSCALL_END)
96                || (long)info->regs.rsp >= 0;
97 #endif
98 }
99
100 #else
101
102 #define UNW_PC(frame) ((void)(frame), 0)
103 #define UNW_SP(frame) ((void)(frame), 0)
104
105 static inline int arch_unw_user_mode(const void *info)
106 {
107         return 0;
108 }
109
110 #endif
111
112 #endif /* _ASM_X86_64_UNWIND_H */