diff options
author | Jan Beulich <jbeulich@novell.com> | 2006-06-26 07:57:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-26 13:48:17 -0400 |
commit | 4552d5dc08b79868829b4be8951b29b07284753f (patch) | |
tree | 7b25695b4c0e1917fc80e8dd4bc494de36320ccc /include | |
parent | 2b28592b07223d7fc0691ce3fe57d495dc9cbe3a (diff) |
[PATCH] x86_64: reliable stack trace support
These are the generic bits needed to enable reliable stack traces based
on Dwarf2-like (.eh_frame) unwind information. Subsequent patches will
enable x86-64 and i386 to make use of this.
Thanks to Andi Kleen and Ingo Molnar, who pointed out several possibilities
for improvement.
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'include')
-rw-r--r-- | include/linux/kernel.h | 7 | ||||
-rw-r--r-- | include/linux/module.h | 3 | ||||
-rw-r--r-- | include/linux/unwind.h | 119 |
3 files changed, 129 insertions, 0 deletions
diff --git a/include/linux/kernel.h b/include/linux/kernel.h index 3c5e4c2e517..5c1ec1f84ea 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h | |||
@@ -32,6 +32,7 @@ extern const char linux_banner[]; | |||
32 | 32 | ||
33 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) | 33 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
34 | #define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) | 34 | #define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) |
35 | #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) | ||
35 | 36 | ||
36 | #define KERN_EMERG "<0>" /* system is unusable */ | 37 | #define KERN_EMERG "<0>" /* system is unusable */ |
37 | #define KERN_ALERT "<1>" /* action must be taken immediately */ | 38 | #define KERN_ALERT "<1>" /* action must be taken immediately */ |
@@ -336,6 +337,12 @@ struct sysinfo { | |||
336 | /* Force a compilation error if condition is true */ | 337 | /* Force a compilation error if condition is true */ |
337 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) | 338 | #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) |
338 | 339 | ||
340 | /* Force a compilation error if condition is true, but also produce a | ||
341 | result (of value 0 and type size_t), so the expression can be used | ||
342 | e.g. in a structure initializer (or where-ever else comma expressions | ||
343 | aren't permitted). */ | ||
344 | #define BUILD_BUG_ON_ZERO(e) (sizeof(char[1 - 2 * !!(e)]) - 1) | ||
345 | |||
339 | /* Trap pasters of __FUNCTION__ at compile-time */ | 346 | /* Trap pasters of __FUNCTION__ at compile-time */ |
340 | #define __FUNCTION__ (__func__) | 347 | #define __FUNCTION__ (__func__) |
341 | 348 | ||
diff --git a/include/linux/module.h b/include/linux/module.h index 2d366098eab..9ebbb74b7b7 100644 --- a/include/linux/module.h +++ b/include/linux/module.h | |||
@@ -285,6 +285,9 @@ struct module | |||
285 | /* The size of the executable code in each section. */ | 285 | /* The size of the executable code in each section. */ |
286 | unsigned long init_text_size, core_text_size; | 286 | unsigned long init_text_size, core_text_size; |
287 | 287 | ||
288 | /* The handle returned from unwind_add_table. */ | ||
289 | void *unwind_info; | ||
290 | |||
288 | /* Arch-specific module values */ | 291 | /* Arch-specific module values */ |
289 | struct mod_arch_specific arch; | 292 | struct mod_arch_specific arch; |
290 | 293 | ||
diff --git a/include/linux/unwind.h b/include/linux/unwind.h new file mode 100644 index 00000000000..0295aa789ab --- /dev/null +++ b/include/linux/unwind.h | |||
@@ -0,0 +1,119 @@ | |||
1 | #ifndef _LINUX_UNWIND_H | ||
2 | #define _LINUX_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 | * A simple API for unwinding kernel stacks. This is used for | ||
10 | * debugging and error reporting purposes. The kernel doesn't need | ||
11 | * full-blown stack unwinding with all the bells and whistles, so there | ||
12 | * is not much point in implementing the full Dwarf2 unwind API. | ||
13 | */ | ||
14 | |||
15 | #include <linux/config.h> | ||
16 | |||
17 | struct module; | ||
18 | |||
19 | #ifdef CONFIG_STACK_UNWIND | ||
20 | |||
21 | #include <asm/unwind.h> | ||
22 | |||
23 | #ifndef ARCH_UNWIND_SECTION_NAME | ||
24 | #define ARCH_UNWIND_SECTION_NAME ".eh_frame" | ||
25 | #endif | ||
26 | |||
27 | /* | ||
28 | * Initialize unwind support. | ||
29 | */ | ||
30 | extern void unwind_init(void); | ||
31 | |||
32 | extern void *unwind_add_table(struct module *, | ||
33 | const void *table_start, | ||
34 | unsigned long table_size); | ||
35 | |||
36 | extern void unwind_remove_table(void *handle, int init_only); | ||
37 | |||
38 | extern int unwind_init_frame_info(struct unwind_frame_info *, | ||
39 | struct task_struct *, | ||
40 | /*const*/ struct pt_regs *); | ||
41 | |||
42 | /* | ||
43 | * Prepare to unwind a blocked task. | ||
44 | */ | ||
45 | extern int unwind_init_blocked(struct unwind_frame_info *, | ||
46 | struct task_struct *); | ||
47 | |||
48 | /* | ||
49 | * Prepare to unwind the currently running thread. | ||
50 | */ | ||
51 | extern int unwind_init_running(struct unwind_frame_info *, | ||
52 | asmlinkage void (*callback)(struct unwind_frame_info *, | ||
53 | void *arg), | ||
54 | void *arg); | ||
55 | |||
56 | /* | ||
57 | * Unwind to previous to frame. Returns 0 if successful, negative | ||
58 | * number in case of an error. | ||
59 | */ | ||
60 | extern int unwind(struct unwind_frame_info *); | ||
61 | |||
62 | /* | ||
63 | * Unwind until the return pointer is in user-land (or until an error | ||
64 | * occurs). Returns 0 if successful, negative number in case of | ||
65 | * error. | ||
66 | */ | ||
67 | extern int unwind_to_user(struct unwind_frame_info *); | ||
68 | |||
69 | #else | ||
70 | |||
71 | struct unwind_frame_info {}; | ||
72 | |||
73 | static inline void unwind_init(void) {} | ||
74 | |||
75 | static inline void *unwind_add_table(struct module *mod, | ||
76 | const void *table_start, | ||
77 | unsigned long table_size) | ||
78 | { | ||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | static inline void unwind_remove_table(void *handle, int init_only) | ||
83 | { | ||
84 | } | ||
85 | |||
86 | static inline int unwind_init_frame_info(struct unwind_frame_info *info, | ||
87 | struct task_struct *tsk, | ||
88 | const struct pt_regs *regs) | ||
89 | { | ||
90 | return -ENOSYS; | ||
91 | } | ||
92 | |||
93 | static inline int unwind_init_blocked(struct unwind_frame_info *info, | ||
94 | struct task_struct *tsk) | ||
95 | { | ||
96 | return -ENOSYS; | ||
97 | } | ||
98 | |||
99 | static inline int unwind_init_running(struct unwind_frame_info *info, | ||
100 | asmlinkage void (*cb)(struct unwind_frame_info *, | ||
101 | void *arg), | ||
102 | void *arg) | ||
103 | { | ||
104 | return -ENOSYS; | ||
105 | } | ||
106 | |||
107 | static inline int unwind(struct unwind_frame_info *info) | ||
108 | { | ||
109 | return -ENOSYS; | ||
110 | } | ||
111 | |||
112 | static inline int unwind_to_user(struct unwind_frame_info *info) | ||
113 | { | ||
114 | return -ENOSYS; | ||
115 | } | ||
116 | |||
117 | #endif | ||
118 | |||
119 | #endif /* _LINUX_UNWIND_H */ | ||