Whamcloud - gitweb
b=10651
[fs/lustre-release.git] / lustre / kernel_patches / patches / llnl-frame-pointer-walk-fix-2.4.21-rhel.patch
1 Index: kernel/arch/i386/kernel/traps.c
2 ===================================================================
3 --- kernel.orig/arch/i386/kernel/traps.c        2006-05-26 16:12:28.000000000 -0700
4 +++ kernel/arch/i386/kernel/traps.c     2006-05-26 16:15:54.000000000 -0700
5 @@ -133,6 +133,30 @@
6  
7  #endif
8  
9 +void scan_stack (unsigned long *stack)
10 +{
11 +       int i;
12 +       unsigned long addr;
13 +       /* static to not take up stackspace */
14 +       static char buffer[NR_CPUS][512], *bufp;
15 +
16 +       bufp = buffer[smp_processor_id()];
17 +
18 +       /*
19 +        * If we have frame pointers then use them to get
20 +        * a 100% exact backtrace, up until the entry frame:
21 +        */
22 +       i = 1;
23 +       while (((long) stack & (THREAD_SIZE-1)) != 0) {
24 +               addr = *stack++;
25 +               if (kernel_text_address(addr)) {
26 +                       lookup_symbol(addr, bufp, 512);
27 +                       printk("[<%08lx>] %s (0x%p)\n", addr,bufp,stack-1);
28 +                       i++;
29 +               }
30 +       }
31 +}
32 +
33  #if CONFIG_FRAME_POINTER
34  void show_stack_frame_params (int param_count, unsigned long params[])
35  {
36 @@ -160,27 +184,23 @@
37                 printk("0x%x)\n", *p);
38  }
39  
40 -void frame_pointer_walk(unsigned long *stack)
41 +/* Display a stack trace for the currently executing task.  The 'dummy'
42 + * parameter serves a purpose although its value is unused.  We use the
43 + * address of 'dummy' as a reference point for finding the saved %ebp register
44 + * value on the stack.
45 + */
46 +void frame_pointer_walk (void *dummy)
47  {
48         int i;
49         unsigned long addr, task_addr, *frame_ptr, *next_frame_ptr, *eip_ptr,
50                       eip, stack_base;
51 -       /* static to not take up stackspace; if we race here too bad */
52 -       static char buffer[512];
53 +       /* static to not take up stackspace */
54 +       static char buffer[NR_CPUS][512], *bufp;
55  
56 -       addr = (unsigned long) stack;
57 +       bufp = buffer[smp_processor_id()];
58         task_addr = (unsigned long) current;
59         stack_base = task_addr + THREAD_SIZE - 1;
60 -
61 -       /* Simply return if we are doing a stack trace for any task other
62 -        * than the currently executing task.  To trace another task, we
63 -        * would need an %ebp register value for that task.
64 -        */
65 -       if (((addr < task_addr) || (addr > stack_base))) {
66 -               return;
67 -       }
68 -
69 -       frame_ptr = (unsigned long *) (&stack - 2);
70 +       frame_ptr = (unsigned long *) (&dummy - 2);
71  
72         for (; ; ) {
73                 next_frame_ptr = (unsigned long *) (*frame_ptr);
74 @@ -196,9 +216,9 @@
75                 eip = *eip_ptr;
76  
77                 if (kernel_text_address(eip)) {
78 -                       lookup_symbol(eip, buffer, 512);
79 +                       lookup_symbol(eip, bufp, 512);
80                         show_stack_frame_params(4, frame_ptr + 2);
81 -                       printk("[<%08lx>] %s (0x%x)\n", eip, buffer,
82 +                       printk("[<%08lx>] %s (0x%x)\n", eip, bufp,
83                                eip_ptr);
84                 }
85  
86 @@ -207,40 +227,49 @@
87  }
88  #endif
89  
90 +typedef void (*stack_trace_fn_t) (unsigned long *stack);
91 +
92 +#if CONFIG_FRAME_POINTER
93  void show_trace(unsigned long * stack)
94  {
95 -#if !CONFIG_FRAME_POINTER
96 -       int i;
97 -#endif
98 -       unsigned long addr, limit;
99 -       /* static to not take up stackspace; if we race here too bad */
100 -       static char buffer[512];
101 +       static const stack_trace_fn_t trace_fn_vector[] =
102 +               { scan_stack, frame_pointer_walk };
103 +       unsigned long addr, task_addr, stack_base;
104 +       int task_is_current;
105  
106         if (!stack)
107                 stack = (unsigned long*)&stack;
108  
109         printk("Call Trace:   ");
110 -       /*
111 -        * If we have frame pointers then use them to get
112 -        * a 100% exact backtrace, up until the entry frame:
113 -        */
114 -#if CONFIG_FRAME_POINTER
115 -       frame_pointer_walk(stack);
116 -#else
117 -       i = 1;
118 -       limit = ((unsigned long)stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE - 3;
119 -       while ((unsigned long)stack < limit) {
120 -               addr = *stack++;
121 -               if (kernel_text_address(addr)) {
122 -                       lookup_symbol(addr, buffer, 512);
123 -                       printk("[<%08lx>] %s (0x%x)\n", addr,buffer,stack-1);
124 -                       i++;
125 -               }
126 -       }
127 -#endif
128 +       addr = (unsigned long) stack;
129 +       task_addr = (unsigned long) current;
130 +       stack_base = task_addr + THREAD_SIZE - 1;
131 +       task_is_current = (addr >= task_addr) && (addr <= stack_base);
132 +       
133 +       /* We may use frame pointers to do a stack trace only if the current
134 +        * task is being traced.  Tracing some other task in this manner
135 +        * would require a saved %ebp register value.  Perhaps in the future
136 +        * I'll consider providing a means of obtaining this.
137 +        */
138 +       trace_fn_vector[task_is_current](stack);
139 +
140 +       printk("\n");
141 +}
142 +
143 +#else /* CONFIG_FRAME_POINTER */
144 +
145 +void show_trace(unsigned long * stack)
146 +{
147 +       if (!stack)
148 +               stack = (unsigned long*)&stack;
149 +
150 +       printk("Call Trace:\n");
151 +       scan_stack(stack);
152         printk("\n");
153  }
154  
155 +#endif /* CONFIG_FRAME_POINTER */
156 +
157  void show_trace_task(struct task_struct *tsk)
158  {
159         unsigned long esp = tsk->thread.esp;
160 Index: kernel/include/asm-i386/hw_irq.h
161 ===================================================================
162 --- kernel.orig/include/asm-i386/hw_irq.h       2006-05-26 16:11:33.000000000 -0700
163 +++ kernel/include/asm-i386/hw_irq.h    2006-05-26 16:13:51.000000000 -0700
164 @@ -153,6 +153,9 @@
165         /* there is a second layer of macro just to get the symbolic
166            name for the vector evaluated. This change is for RTLinux */
167  #define BUILD_SMP_INTERRUPT(x,v) XBUILD_SMP_INTERRUPT(x,v)
168 +
169 +#if CONFIG_X86_HIGH_ENTRY
170 +
171  #define XBUILD_SMP_INTERRUPT(x,v)\
172  asmlinkage void x(void); \
173  asmlinkage void call_##x(void); \
174 @@ -165,7 +168,26 @@
175         "movl $"SYMBOL_NAME_STR(smp_##x)", %ebp; call *%ebp\n\t" \
176         "jmp ret_from_intr; .previous\n");
177  
178 +#else
179 +
180 +#define XBUILD_SMP_INTERRUPT(x,v)\
181 +asmlinkage void x(void); \
182 +asmlinkage void call_##x(void); \
183 +__asm__( \
184 +".section .entry.text,\"ax\"\n"__ALIGN_STR"\n" \
185 +SYMBOL_NAME_STR(x) ":\n\t" \
186 +       "pushl $"#v"-256\n\t" \
187 +       SAVE_ALL_SWITCH \
188 +       SYMBOL_NAME_STR(call_##x)":\n\t" \
189 +       "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
190 +       "jmp ret_from_intr; .previous\n");
191 +
192 +#endif
193 +
194  #define BUILD_SMP_TIMER_INTERRUPT(x,v) XBUILD_SMP_TIMER_INTERRUPT(x,v)
195 +
196 +#if CONFIG_X86_HIGH_ENTRY
197 +
198  #define XBUILD_SMP_TIMER_INTERRUPT(x,v) \
199  asmlinkage void x(struct pt_regs * regs); \
200  asmlinkage void call_##x(void); \
201 @@ -181,6 +203,27 @@
202         "addl $4,%esp\n\t" \
203         "jmp ret_from_intr; .previous\n");
204  
205 +#else
206 +
207 +#define XBUILD_SMP_TIMER_INTERRUPT(x,v) \
208 +asmlinkage void x(struct pt_regs * regs); \
209 +asmlinkage void call_##x(void); \
210 +__asm__( \
211 +".section .entry.text,\"ax\"\n"__ALIGN_STR"\n" \
212 +SYMBOL_NAME_STR(x) ":\n\t" \
213 +       "pushl $"#v"-256\n\t" \
214 +       SAVE_ALL_SWITCH \
215 +       "movl %esp,%eax\n\t" \
216 +       "pushl %eax\n\t" \
217 +       SYMBOL_NAME_STR(call_##x)":\n\t" \
218 +       "call "SYMBOL_NAME_STR(smp_##x)"\n\t" \
219 +       "addl $4,%esp\n\t" \
220 +       "jmp ret_from_intr; .previous\n");
221 +
222 +#endif
223 +
224 +#if CONFIG_X86_HIGH_ENTRY
225 +
226  #define BUILD_COMMON_IRQ() \
227  asmlinkage void call_do_IRQ(void); \
228  __asm__( \
229 @@ -191,6 +234,20 @@
230         "movl $"SYMBOL_NAME_STR(do_IRQ)", %ebp; call *%ebp\n\t" \
231         "jmp ret_from_intr; .previous\n");
232  
233 +#else
234 +
235 +#define BUILD_COMMON_IRQ() \
236 +asmlinkage void call_do_IRQ(void); \
237 +__asm__( \
238 +       ".section .entry.text,\"ax\"\n" __ALIGN_STR"\n" \
239 +       "common_interrupt:\n\t" \
240 +       SAVE_ALL_SWITCH \
241 +       SYMBOL_NAME_STR(call_do_IRQ)":\n\t" \
242 +       "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
243 +       "jmp ret_from_intr; .previous\n");
244 +
245 +#endif
246 +
247  /* 
248   * subtle. orig_eax is used by the signal code to distinct between
249   * system calls and interrupted 'random user-space'. Thus we have