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 3c5e4c2e517d..5c1ec1f84eab 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 2d366098eab5..9ebbb74b7b72 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 000000000000..0295aa789ab4 --- /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 */ | ||
