Merge tag 'fbdev-fixes-3.13' of git://git.kernel.org/pub/scm/linux/kernel/git/tomba...
[linux-drm-fsl-dcu.git] / arch / parisc / kernel / unwind.c
1 /*
2  * Kernel unwinding support
3  *
4  * (c) 2002-2004 Randolph Chung <tausq@debian.org>
5  *
6  * Derived partially from the IA64 implementation. The PA-RISC
7  * Runtime Architecture Document is also a useful reference to
8  * understand what is happening here
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/init.h>
13 #include <linux/sched.h>
14 #include <linux/slab.h>
15 #include <linux/kallsyms.h>
16 #include <linux/sort.h>
17
18 #include <asm/uaccess.h>
19 #include <asm/assembly.h>
20 #include <asm/asm-offsets.h>
21 #include <asm/ptrace.h>
22
23 #include <asm/unwind.h>
24
25 /* #define DEBUG 1 */
26 #ifdef DEBUG
27 #define dbg(x...) printk(x)
28 #else
29 #define dbg(x...)
30 #endif
31
32 #define KERNEL_START (KERNEL_BINARY_TEXT_START)
33
34 extern struct unwind_table_entry __start___unwind[];
35 extern struct unwind_table_entry __stop___unwind[];
36
37 static spinlock_t unwind_lock;
38 /*
39  * the kernel unwind block is not dynamically allocated so that
40  * we can call unwind_init as early in the bootup process as 
41  * possible (before the slab allocator is initialized)
42  */
43 static struct unwind_table kernel_unwind_table __read_mostly;
44 static LIST_HEAD(unwind_tables);
45
46 static inline const struct unwind_table_entry *
47 find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
48 {
49         const struct unwind_table_entry *e = NULL;
50         unsigned long lo, hi, mid;
51
52         lo = 0; 
53         hi = table->length - 1; 
54         
55         while (lo <= hi) {
56                 mid = (hi - lo) / 2 + lo;
57                 e = &table->table[mid];
58                 if (addr < e->region_start)
59                         hi = mid - 1;
60                 else if (addr > e->region_end)
61                         lo = mid + 1;
62                 else
63                         return e;
64         }
65
66         return NULL;
67 }
68
69 static const struct unwind_table_entry *
70 find_unwind_entry(unsigned long addr)
71 {
72         struct unwind_table *table;
73         const struct unwind_table_entry *e = NULL;
74
75         if (addr >= kernel_unwind_table.start && 
76             addr <= kernel_unwind_table.end)
77                 e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
78         else 
79                 list_for_each_entry(table, &unwind_tables, list) {
80                         if (addr >= table->start && 
81                             addr <= table->end)
82                                 e = find_unwind_entry_in_table(table, addr);
83                         if (e) {
84                                 /* Move-to-front to exploit common traces */
85                                 list_move(&table->list, &unwind_tables);
86                                 break;
87                         }
88                 }
89
90         return e;
91 }
92
93 static void
94 unwind_table_init(struct unwind_table *table, const char *name,
95                   unsigned long base_addr, unsigned long gp,
96                   void *table_start, void *table_end)
97 {
98         struct unwind_table_entry *start = table_start;
99         struct unwind_table_entry *end = 
100                 (struct unwind_table_entry *)table_end - 1;
101
102         table->name = name;
103         table->base_addr = base_addr;
104         table->gp = gp;
105         table->start = base_addr + start->region_start;
106         table->end = base_addr + end->region_end;
107         table->table = (struct unwind_table_entry *)table_start;
108         table->length = end - start + 1;
109         INIT_LIST_HEAD(&table->list);
110
111         for (; start <= end; start++) {
112                 if (start < end && 
113                     start->region_end > (start+1)->region_start) {
114                         printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
115                 }
116
117                 start->region_start += base_addr;
118                 start->region_end += base_addr;
119         }
120 }
121
122 static int cmp_unwind_table_entry(const void *a, const void *b)
123 {
124         return ((const struct unwind_table_entry *)a)->region_start
125              - ((const struct unwind_table_entry *)b)->region_start;
126 }
127
128 static void
129 unwind_table_sort(struct unwind_table_entry *start,
130                   struct unwind_table_entry *finish)
131 {
132         sort(start, finish - start, sizeof(struct unwind_table_entry),
133              cmp_unwind_table_entry, NULL);
134 }
135
136 struct unwind_table *
137 unwind_table_add(const char *name, unsigned long base_addr, 
138                  unsigned long gp,
139                  void *start, void *end)
140 {
141         struct unwind_table *table;
142         unsigned long flags;
143         struct unwind_table_entry *s = (struct unwind_table_entry *)start;
144         struct unwind_table_entry *e = (struct unwind_table_entry *)end;
145
146         unwind_table_sort(s, e);
147
148         table = kmalloc(sizeof(struct unwind_table), GFP_USER);
149         if (table == NULL)
150                 return NULL;
151         unwind_table_init(table, name, base_addr, gp, start, end);
152         spin_lock_irqsave(&unwind_lock, flags);
153         list_add_tail(&table->list, &unwind_tables);
154         spin_unlock_irqrestore(&unwind_lock, flags);
155
156         return table;
157 }
158
159 void unwind_table_remove(struct unwind_table *table)
160 {
161         unsigned long flags;
162
163         spin_lock_irqsave(&unwind_lock, flags);
164         list_del(&table->list);
165         spin_unlock_irqrestore(&unwind_lock, flags);
166
167         kfree(table);
168 }
169
170 /* Called from setup_arch to import the kernel unwind info */
171 int __init unwind_init(void)
172 {
173         long start, stop;
174         register unsigned long gp __asm__ ("r27");
175
176         start = (long)&__start___unwind[0];
177         stop = (long)&__stop___unwind[0];
178
179         spin_lock_init(&unwind_lock);
180
181         printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n", 
182             start, stop,
183             (stop - start) / sizeof(struct unwind_table_entry));
184
185         unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
186                           gp, 
187                           &__start___unwind[0], &__stop___unwind[0]);
188 #if 0
189         {
190                 int i;
191                 for (i = 0; i < 10; i++)
192                 {
193                         printk("region 0x%x-0x%x\n", 
194                                 __start___unwind[i].region_start, 
195                                 __start___unwind[i].region_end);
196                 }
197         }
198 #endif
199         return 0;
200 }
201
202 #ifdef CONFIG_64BIT
203 #define get_func_addr(fptr) fptr[2]
204 #else
205 #define get_func_addr(fptr) fptr[0]
206 #endif
207
208 static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
209 {
210         extern void handle_interruption(int, struct pt_regs *);
211         static unsigned long *hi = (unsigned long *)&handle_interruption;
212
213         if (pc == get_func_addr(hi)) {
214                 struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
215                 dbg("Unwinding through handle_interruption()\n");
216                 info->prev_sp = regs->gr[30];
217                 info->prev_ip = regs->iaoq[0];
218
219                 return 1;
220         }
221
222         return 0;
223 }
224
225 static void unwind_frame_regs(struct unwind_frame_info *info)
226 {
227         const struct unwind_table_entry *e;
228         unsigned long npc;
229         unsigned int insn;
230         long frame_size = 0;
231         int looking_for_rp, rpoffset = 0;
232
233         e = find_unwind_entry(info->ip);
234         if (e == NULL) {
235                 unsigned long sp;
236
237                 dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
238
239 #ifdef CONFIG_KALLSYMS
240                 /* Handle some frequent special cases.... */
241                 {
242                         char symname[KSYM_NAME_LEN];
243                         char *modname;
244
245                         kallsyms_lookup(info->ip, NULL, NULL, &modname,
246                                 symname);
247
248                         dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
249
250                         if (strcmp(symname, "_switch_to_ret") == 0) {
251                                 info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
252                                 info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
253                                 dbg("_switch_to_ret @ %lx - setting "
254                                     "prev_sp=%lx prev_ip=%lx\n", 
255                                     info->ip, info->prev_sp, 
256                                     info->prev_ip);
257                                 return;
258                         } else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
259                                    strcmp(symname, "syscall_exit") == 0) {
260                                 info->prev_ip = info->prev_sp = 0;
261                                 return;
262                         }
263                 }
264 #endif
265
266                 /* Since we are doing the unwinding blind, we don't know if
267                    we are adjusting the stack correctly or extracting the rp
268                    correctly. The rp is checked to see if it belongs to the
269                    kernel text section, if not we assume we don't have a 
270                    correct stack frame and we continue to unwind the stack.
271                    This is not quite correct, and will fail for loadable
272                    modules. */
273                 sp = info->sp & ~63;
274                 do {
275                         unsigned long tmp;
276
277                         info->prev_sp = sp - 64;
278                         info->prev_ip = 0;
279                         if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET))) 
280                                 break;
281                         info->prev_ip = tmp;
282                         sp = info->prev_sp;
283                 } while (!kernel_text_address(info->prev_ip));
284
285                 info->rp = 0;
286
287                 dbg("analyzing func @ %lx with no unwind info, setting "
288                     "prev_sp=%lx prev_ip=%lx\n", info->ip, 
289                     info->prev_sp, info->prev_ip);
290         } else {
291                 dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
292                     "Save_RP = %d, Millicode = %d size = %u\n", 
293                     e->region_start, e->region_end, e->Save_SP, e->Save_RP, 
294                     e->Millicode, e->Total_frame_size);
295
296                 looking_for_rp = e->Save_RP;
297
298                 for (npc = e->region_start; 
299                      (frame_size < (e->Total_frame_size << 3) || 
300                       looking_for_rp) && 
301                      npc < info->ip; 
302                      npc += 4) {
303
304                         insn = *(unsigned int *)npc;
305
306                         if ((insn & 0xffffc000) == 0x37de0000 ||
307                             (insn & 0xffe00000) == 0x6fc00000) {
308                                 /* ldo X(sp), sp, or stwm X,D(sp) */
309                                 frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
310                                         ((insn & 0x3fff) >> 1);
311                                 dbg("analyzing func @ %lx, insn=%08x @ "
312                                     "%lx, frame_size = %ld\n", info->ip,
313                                     insn, npc, frame_size);
314                         } else if ((insn & 0xffe00008) == 0x73c00008) {
315                                 /* std,ma X,D(sp) */
316                                 frame_size += (insn & 0x1 ? -1 << 13 : 0) | 
317                                         (((insn >> 4) & 0x3ff) << 3);
318                                 dbg("analyzing func @ %lx, insn=%08x @ "
319                                     "%lx, frame_size = %ld\n", info->ip,
320                                     insn, npc, frame_size);
321                         } else if (insn == 0x6bc23fd9) { 
322                                 /* stw rp,-20(sp) */
323                                 rpoffset = 20;
324                                 looking_for_rp = 0;
325                                 dbg("analyzing func @ %lx, insn=stw rp,"
326                                     "-20(sp) @ %lx\n", info->ip, npc);
327                         } else if (insn == 0x0fc212c1) {
328                                 /* std rp,-16(sr0,sp) */
329                                 rpoffset = 16;
330                                 looking_for_rp = 0;
331                                 dbg("analyzing func @ %lx, insn=std rp,"
332                                     "-16(sp) @ %lx\n", info->ip, npc);
333                         }
334                 }
335
336                 if (!unwind_special(info, e->region_start, frame_size)) {
337                         info->prev_sp = info->sp - frame_size;
338                         if (e->Millicode)
339                                 info->rp = info->r31;
340                         else if (rpoffset)
341                                 info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
342                         info->prev_ip = info->rp;
343                         info->rp = 0;
344                 }
345
346                 dbg("analyzing func @ %lx, setting prev_sp=%lx "
347                     "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp, 
348                     info->prev_ip, npc);
349         }
350 }
351
352 void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t, 
353                        struct pt_regs *regs)
354 {
355         memset(info, 0, sizeof(struct unwind_frame_info));
356         info->t = t;
357         info->sp = regs->gr[30];
358         info->ip = regs->iaoq[0];
359         info->rp = regs->gr[2];
360         info->r31 = regs->gr[31];
361
362         dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n", 
363             t ? (int)t->pid : -1, info->sp, info->ip);
364 }
365
366 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
367 {
368         struct pt_regs *r = &t->thread.regs;
369         struct pt_regs *r2;
370
371         r2 = kmalloc(sizeof(struct pt_regs), GFP_ATOMIC);
372         if (!r2)
373                 return;
374         *r2 = *r;
375         r2->gr[30] = r->ksp;
376         r2->iaoq[0] = r->kpc;
377         unwind_frame_init(info, t, r2);
378         kfree(r2);
379 }
380
381 void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
382 {
383         unwind_frame_init(info, current, regs);
384 }
385
386 int unwind_once(struct unwind_frame_info *next_frame)
387 {
388         unwind_frame_regs(next_frame);
389
390         if (next_frame->prev_sp == 0 ||
391             next_frame->prev_ip == 0)
392                 return -1;
393
394         next_frame->sp = next_frame->prev_sp;
395         next_frame->ip = next_frame->prev_ip;
396         next_frame->prev_sp = 0;
397         next_frame->prev_ip = 0;
398
399         dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n", 
400             next_frame->t ? (int)next_frame->t->pid : -1, 
401             next_frame->sp, next_frame->ip);
402
403         return 0;
404 }
405
406 int unwind_to_user(struct unwind_frame_info *info)
407 {
408         int ret;
409         
410         do {
411                 ret = unwind_once(info);
412         } while (!ret && !(info->ip & 3));
413
414         return ret;
415 }
416
417 unsigned long return_address(unsigned int level)
418 {
419         struct unwind_frame_info info;
420         struct pt_regs r;
421         unsigned long sp;
422
423         /* initialize unwind info */
424         asm volatile ("copy %%r30, %0" : "=r"(sp));
425         memset(&r, 0, sizeof(struct pt_regs));
426         r.iaoq[0] = (unsigned long) current_text_addr();
427         r.gr[2] = (unsigned long) __builtin_return_address(0);
428         r.gr[30] = sp;
429         unwind_frame_init(&info, current, &r);
430
431         /* unwind stack */
432         ++level;
433         do {
434                 if (unwind_once(&info) < 0 || info.ip == 0)
435                         return 0;
436                 if (!kernel_text_address(info.ip))
437                         return 0;
438         } while (info.ip && level--);
439
440         return info.ip;
441 }