Commit | Line | Data |
---|---|---|
2a12c463 RG |
1 | /* Provide basic stack dumping functions |
2 | * | |
3 | * Copyright 2004-2009 Analog Devices Inc. | |
4 | * | |
5 | * Licensed under the GPL-2 or later | |
6 | */ | |
7 | ||
8 | #include <linux/kernel.h> | |
9 | #include <linux/thread_info.h> | |
10 | #include <linux/mm.h> | |
11 | #include <linux/uaccess.h> | |
12 | #include <linux/module.h> | |
13 | #include <asm/trace.h> | |
14 | ||
15 | /* | |
16 | * Checks to see if the address pointed to is either a | |
17 | * 16-bit CALL instruction, or a 32-bit CALL instruction | |
18 | */ | |
19 | static bool is_bfin_call(unsigned short *addr) | |
20 | { | |
9a95e2f1 | 21 | unsigned int opcode; |
2a12c463 | 22 | |
9a95e2f1 | 23 | if (!get_instruction(&opcode, addr)) |
2a12c463 RG |
24 | return false; |
25 | ||
26 | if ((opcode >= 0x0060 && opcode <= 0x0067) || | |
9a95e2f1 RG |
27 | (opcode >= 0x0070 && opcode <= 0x0077) || |
28 | (opcode >= 0xE3000000 && opcode <= 0xE3FFFFFF)) | |
2a12c463 RG |
29 | return true; |
30 | ||
31 | return false; | |
32 | ||
33 | } | |
34 | ||
35 | void show_stack(struct task_struct *task, unsigned long *stack) | |
36 | { | |
37 | #ifdef CONFIG_PRINTK | |
38 | unsigned int *addr, *endstack, *fp = 0, *frame; | |
39 | unsigned short *ins_addr; | |
40 | char buf[150]; | |
41 | unsigned int i, j, ret_addr, frame_no = 0; | |
42 | ||
43 | /* | |
44 | * If we have been passed a specific stack, use that one otherwise | |
45 | * if we have been passed a task structure, use that, otherwise | |
46 | * use the stack of where the variable "stack" exists | |
47 | */ | |
48 | ||
49 | if (stack == NULL) { | |
50 | if (task) { | |
51 | /* We know this is a kernel stack, so this is the start/end */ | |
52 | stack = (unsigned long *)task->thread.ksp; | |
53 | endstack = (unsigned int *)(((unsigned int)(stack) & ~(THREAD_SIZE - 1)) + THREAD_SIZE); | |
54 | } else { | |
55 | /* print out the existing stack info */ | |
56 | stack = (unsigned long *)&stack; | |
57 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | |
58 | } | |
59 | } else | |
60 | endstack = (unsigned int *)PAGE_ALIGN((unsigned int)stack); | |
61 | ||
62 | printk(KERN_NOTICE "Stack info:\n"); | |
63 | decode_address(buf, (unsigned int)stack); | |
64 | printk(KERN_NOTICE " SP: [0x%p] %s\n", stack, buf); | |
65 | ||
66 | if (!access_ok(VERIFY_READ, stack, (unsigned int)endstack - (unsigned int)stack)) { | |
67 | printk(KERN_NOTICE "Invalid stack pointer\n"); | |
68 | return; | |
69 | } | |
70 | ||
71 | /* First thing is to look for a frame pointer */ | |
72 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF); addr < endstack; addr++) { | |
73 | if (*addr & 0x1) | |
74 | continue; | |
75 | ins_addr = (unsigned short *)*addr; | |
76 | ins_addr--; | |
77 | if (is_bfin_call(ins_addr)) | |
78 | fp = addr - 1; | |
79 | ||
80 | if (fp) { | |
81 | /* Let's check to see if it is a frame pointer */ | |
82 | while (fp >= (addr - 1) && fp < endstack | |
83 | && fp && ((unsigned int) fp & 0x3) == 0) | |
84 | fp = (unsigned int *)*fp; | |
85 | if (fp == 0 || fp == endstack) { | |
86 | fp = addr - 1; | |
87 | break; | |
88 | } | |
89 | fp = 0; | |
90 | } | |
91 | } | |
92 | if (fp) { | |
93 | frame = fp; | |
94 | printk(KERN_NOTICE " FP: (0x%p)\n", fp); | |
95 | } else | |
96 | frame = 0; | |
97 | ||
98 | /* | |
99 | * Now that we think we know where things are, we | |
100 | * walk the stack again, this time printing things out | |
101 | * incase there is no frame pointer, we still look for | |
102 | * valid return addresses | |
103 | */ | |
104 | ||
105 | /* First time print out data, next time, print out symbols */ | |
106 | for (j = 0; j <= 1; j++) { | |
107 | if (j) | |
108 | printk(KERN_NOTICE "Return addresses in stack:\n"); | |
109 | else | |
110 | printk(KERN_NOTICE " Memory from 0x%08lx to %p", ((long unsigned int)stack & ~0xF), endstack); | |
111 | ||
112 | fp = frame; | |
113 | frame_no = 0; | |
114 | ||
115 | for (addr = (unsigned int *)((unsigned int)stack & ~0xF), i = 0; | |
116 | addr < endstack; addr++, i++) { | |
117 | ||
118 | ret_addr = 0; | |
119 | if (!j && i % 8 == 0) | |
120 | printk(KERN_NOTICE "%p:", addr); | |
121 | ||
122 | /* if it is an odd address, or zero, just skip it */ | |
123 | if (*addr & 0x1 || !*addr) | |
124 | goto print; | |
125 | ||
126 | ins_addr = (unsigned short *)*addr; | |
127 | ||
128 | /* Go back one instruction, and see if it is a CALL */ | |
129 | ins_addr--; | |
130 | ret_addr = is_bfin_call(ins_addr); | |
131 | print: | |
132 | if (!j && stack == (unsigned long *)addr) | |
133 | printk("[%08x]", *addr); | |
134 | else if (ret_addr) | |
135 | if (j) { | |
136 | decode_address(buf, (unsigned int)*addr); | |
137 | if (frame == addr) { | |
138 | printk(KERN_NOTICE " frame %2i : %s\n", frame_no, buf); | |
139 | continue; | |
140 | } | |
141 | printk(KERN_NOTICE " address : %s\n", buf); | |
142 | } else | |
143 | printk("<%08x>", *addr); | |
144 | else if (fp == addr) { | |
145 | if (j) | |
146 | frame = addr+1; | |
147 | else | |
148 | printk("(%08x)", *addr); | |
149 | ||
150 | fp = (unsigned int *)*addr; | |
151 | frame_no++; | |
152 | ||
153 | } else if (!j) | |
154 | printk(" %08x ", *addr); | |
155 | } | |
156 | if (!j) | |
157 | printk("\n"); | |
158 | } | |
159 | #endif | |
160 | } | |
161 | EXPORT_SYMBOL(show_stack); | |
162 | ||
163 | void dump_stack(void) | |
164 | { | |
165 | unsigned long stack; | |
166 | #ifdef CONFIG_DEBUG_BFIN_HWTRACE_ON | |
167 | int tflags; | |
168 | #endif | |
169 | trace_buffer_save(tflags); | |
170 | dump_bfin_trace_buffer(); | |
196779b9 | 171 | dump_stack_print_info(KERN_DEFAULT); |
2a12c463 RG |
172 | show_stack(current, &stack); |
173 | trace_buffer_restore(tflags); | |
174 | } | |
175 | EXPORT_SYMBOL(dump_stack); |