1 // SPDX-License-Identifier: GPL-2.0
3 * Kernel unwinding support
5 * (c) 2002-2004 Randolph Chung <tausq@debian.org>
7 * Derived partially from the IA64 implementation. The PA-RISC
8 * Runtime Architecture Document is also a useful reference to
9 * understand what is happening here
12 #include <linux/kernel.h>
13 #include <linux/init.h>
14 #include <linux/sched.h>
15 #include <linux/slab.h>
16 #include <linux/kallsyms.h>
17 #include <linux/sort.h>
18 #include <linux/sched.h>
20 #include <linux/uaccess.h>
21 #include <asm/assembly.h>
22 #include <asm/asm-offsets.h>
23 #include <asm/ptrace.h>
25 #include <asm/unwind.h>
29 #define dbg(x...) printk(x)
34 #define KERNEL_START (KERNEL_BINARY_TEXT_START)
36 extern struct unwind_table_entry __start___unwind[];
37 extern struct unwind_table_entry __stop___unwind[];
39 static DEFINE_SPINLOCK(unwind_lock);
41 * the kernel unwind block is not dynamically allocated so that
42 * we can call unwind_init as early in the bootup process as
43 * possible (before the slab allocator is initialized)
45 static struct unwind_table kernel_unwind_table __read_mostly;
46 static LIST_HEAD(unwind_tables);
48 static inline const struct unwind_table_entry *
49 find_unwind_entry_in_table(const struct unwind_table *table, unsigned long addr)
51 const struct unwind_table_entry *e = NULL;
52 unsigned long lo, hi, mid;
55 hi = table->length - 1;
58 mid = (hi - lo) / 2 + lo;
59 e = &table->table[mid];
60 if (addr < e->region_start)
62 else if (addr > e->region_end)
71 static const struct unwind_table_entry *
72 find_unwind_entry(unsigned long addr)
74 struct unwind_table *table;
75 const struct unwind_table_entry *e = NULL;
77 if (addr >= kernel_unwind_table.start &&
78 addr <= kernel_unwind_table.end)
79 e = find_unwind_entry_in_table(&kernel_unwind_table, addr);
83 spin_lock_irqsave(&unwind_lock, flags);
84 list_for_each_entry(table, &unwind_tables, list) {
85 if (addr >= table->start &&
87 e = find_unwind_entry_in_table(table, addr);
89 /* Move-to-front to exploit common traces */
90 list_move(&table->list, &unwind_tables);
94 spin_unlock_irqrestore(&unwind_lock, flags);
101 unwind_table_init(struct unwind_table *table, const char *name,
102 unsigned long base_addr, unsigned long gp,
103 void *table_start, void *table_end)
105 struct unwind_table_entry *start = table_start;
106 struct unwind_table_entry *end =
107 (struct unwind_table_entry *)table_end - 1;
110 table->base_addr = base_addr;
112 table->start = base_addr + start->region_start;
113 table->end = base_addr + end->region_end;
114 table->table = (struct unwind_table_entry *)table_start;
115 table->length = end - start + 1;
116 INIT_LIST_HEAD(&table->list);
118 for (; start <= end; start++) {
120 start->region_end > (start+1)->region_start) {
121 printk("WARNING: Out of order unwind entry! %p and %p\n", start, start+1);
124 start->region_start += base_addr;
125 start->region_end += base_addr;
129 static int cmp_unwind_table_entry(const void *a, const void *b)
131 return ((const struct unwind_table_entry *)a)->region_start
132 - ((const struct unwind_table_entry *)b)->region_start;
136 unwind_table_sort(struct unwind_table_entry *start,
137 struct unwind_table_entry *finish)
139 sort(start, finish - start, sizeof(struct unwind_table_entry),
140 cmp_unwind_table_entry, NULL);
143 struct unwind_table *
144 unwind_table_add(const char *name, unsigned long base_addr,
146 void *start, void *end)
148 struct unwind_table *table;
150 struct unwind_table_entry *s = (struct unwind_table_entry *)start;
151 struct unwind_table_entry *e = (struct unwind_table_entry *)end;
153 unwind_table_sort(s, e);
155 table = kmalloc(sizeof(struct unwind_table), GFP_USER);
158 unwind_table_init(table, name, base_addr, gp, start, end);
159 spin_lock_irqsave(&unwind_lock, flags);
160 list_add_tail(&table->list, &unwind_tables);
161 spin_unlock_irqrestore(&unwind_lock, flags);
166 void unwind_table_remove(struct unwind_table *table)
170 spin_lock_irqsave(&unwind_lock, flags);
171 list_del(&table->list);
172 spin_unlock_irqrestore(&unwind_lock, flags);
177 /* Called from setup_arch to import the kernel unwind info */
178 int __init unwind_init(void)
181 register unsigned long gp __asm__ ("r27");
183 start = (long)&__start___unwind[0];
184 stop = (long)&__stop___unwind[0];
186 printk("unwind_init: start = 0x%lx, end = 0x%lx, entries = %lu\n",
188 (stop - start) / sizeof(struct unwind_table_entry));
190 unwind_table_init(&kernel_unwind_table, "kernel", KERNEL_START,
192 &__start___unwind[0], &__stop___unwind[0]);
196 for (i = 0; i < 10; i++)
198 printk("region 0x%x-0x%x\n",
199 __start___unwind[i].region_start,
200 __start___unwind[i].region_end);
208 #define get_func_addr(fptr) fptr[2]
210 #define get_func_addr(fptr) fptr[0]
213 static int unwind_special(struct unwind_frame_info *info, unsigned long pc, int frame_size)
215 extern void handle_interruption(int, struct pt_regs *);
216 static unsigned long *hi = (unsigned long *)&handle_interruption;
218 if (pc == get_func_addr(hi)) {
219 struct pt_regs *regs = (struct pt_regs *)(info->sp - frame_size - PT_SZ_ALGN);
220 dbg("Unwinding through handle_interruption()\n");
221 info->prev_sp = regs->gr[30];
222 info->prev_ip = regs->iaoq[0];
230 static void unwind_frame_regs(struct unwind_frame_info *info)
232 const struct unwind_table_entry *e;
236 int looking_for_rp, rpoffset = 0;
238 e = find_unwind_entry(info->ip);
242 dbg("Cannot find unwind entry for 0x%lx; forced unwinding\n", info->ip);
244 #ifdef CONFIG_KALLSYMS
245 /* Handle some frequent special cases.... */
247 char symname[KSYM_NAME_LEN];
250 kallsyms_lookup(info->ip, NULL, NULL, &modname,
253 dbg("info->ip = 0x%lx, name = %s\n", info->ip, symname);
255 if (strcmp(symname, "_switch_to_ret") == 0) {
256 info->prev_sp = info->sp - CALLEE_SAVE_FRAME_SIZE;
257 info->prev_ip = *(unsigned long *)(info->prev_sp - RP_OFFSET);
258 dbg("_switch_to_ret @ %lx - setting "
259 "prev_sp=%lx prev_ip=%lx\n",
260 info->ip, info->prev_sp,
263 } else if (strcmp(symname, "ret_from_kernel_thread") == 0 ||
264 strcmp(symname, "syscall_exit") == 0) {
265 info->prev_ip = info->prev_sp = 0;
271 /* Since we are doing the unwinding blind, we don't know if
272 we are adjusting the stack correctly or extracting the rp
273 correctly. The rp is checked to see if it belongs to the
274 kernel text section, if not we assume we don't have a
275 correct stack frame and we continue to unwind the stack.
276 This is not quite correct, and will fail for loadable
282 info->prev_sp = sp - 64;
285 /* The stack is at the end inside the thread_union
286 * struct. If we reach data, we have reached the
287 * beginning of the stack and should stop unwinding. */
288 if (info->prev_sp >= (unsigned long) task_thread_info(info->t) &&
289 info->prev_sp < ((unsigned long) task_thread_info(info->t)
295 if (get_user(tmp, (unsigned long *)(info->prev_sp - RP_OFFSET)))
299 } while (!kernel_text_address(info->prev_ip));
303 dbg("analyzing func @ %lx with no unwind info, setting "
304 "prev_sp=%lx prev_ip=%lx\n", info->ip,
305 info->prev_sp, info->prev_ip);
307 dbg("e->start = 0x%x, e->end = 0x%x, Save_SP = %d, "
308 "Save_RP = %d, Millicode = %d size = %u\n",
309 e->region_start, e->region_end, e->Save_SP, e->Save_RP,
310 e->Millicode, e->Total_frame_size);
312 looking_for_rp = e->Save_RP;
314 for (npc = e->region_start;
315 (frame_size < (e->Total_frame_size << 3) ||
320 insn = *(unsigned int *)npc;
322 if ((insn & 0xffffc001) == 0x37de0000 ||
323 (insn & 0xffe00001) == 0x6fc00000) {
324 /* ldo X(sp), sp, or stwm X,D(sp) */
325 frame_size += (insn & 0x3fff) >> 1;
326 dbg("analyzing func @ %lx, insn=%08x @ "
327 "%lx, frame_size = %ld\n", info->ip,
328 insn, npc, frame_size);
329 } else if ((insn & 0xffe00009) == 0x73c00008) {
331 frame_size += ((insn >> 4) & 0x3ff) << 3;
332 dbg("analyzing func @ %lx, insn=%08x @ "
333 "%lx, frame_size = %ld\n", info->ip,
334 insn, npc, frame_size);
335 } else if (insn == 0x6bc23fd9) {
339 dbg("analyzing func @ %lx, insn=stw rp,"
340 "-20(sp) @ %lx\n", info->ip, npc);
341 } else if (insn == 0x0fc212c1) {
342 /* std rp,-16(sr0,sp) */
345 dbg("analyzing func @ %lx, insn=std rp,"
346 "-16(sp) @ %lx\n", info->ip, npc);
350 if (frame_size > e->Total_frame_size << 3)
351 frame_size = e->Total_frame_size << 3;
353 if (!unwind_special(info, e->region_start, frame_size)) {
354 info->prev_sp = info->sp - frame_size;
356 info->rp = info->r31;
358 info->rp = *(unsigned long *)(info->prev_sp - rpoffset);
359 info->prev_ip = info->rp;
363 dbg("analyzing func @ %lx, setting prev_sp=%lx "
364 "prev_ip=%lx npc=%lx\n", info->ip, info->prev_sp,
369 void unwind_frame_init(struct unwind_frame_info *info, struct task_struct *t,
370 struct pt_regs *regs)
372 memset(info, 0, sizeof(struct unwind_frame_info));
374 info->sp = regs->gr[30];
375 info->ip = regs->iaoq[0];
376 info->rp = regs->gr[2];
377 info->r31 = regs->gr[31];
379 dbg("(%d) Start unwind from sp=%08lx ip=%08lx\n",
380 t ? (int)t->pid : -1, info->sp, info->ip);
383 void unwind_frame_init_from_blocked_task(struct unwind_frame_info *info, struct task_struct *t)
385 struct pt_regs *r = &t->thread.regs;
388 r2 = kmalloc(sizeof(struct pt_regs), GFP_ATOMIC);
393 r2->iaoq[0] = r->kpc;
394 unwind_frame_init(info, t, r2);
398 void unwind_frame_init_running(struct unwind_frame_info *info, struct pt_regs *regs)
400 unwind_frame_init(info, current, regs);
403 int unwind_once(struct unwind_frame_info *next_frame)
405 unwind_frame_regs(next_frame);
407 if (next_frame->prev_sp == 0 ||
408 next_frame->prev_ip == 0)
411 next_frame->sp = next_frame->prev_sp;
412 next_frame->ip = next_frame->prev_ip;
413 next_frame->prev_sp = 0;
414 next_frame->prev_ip = 0;
416 dbg("(%d) Continue unwind to sp=%08lx ip=%08lx\n",
417 next_frame->t ? (int)next_frame->t->pid : -1,
418 next_frame->sp, next_frame->ip);
423 int unwind_to_user(struct unwind_frame_info *info)
428 ret = unwind_once(info);
429 } while (!ret && !(info->ip & 3));
434 unsigned long return_address(unsigned int level)
436 struct unwind_frame_info info;
440 /* initialize unwind info */
441 asm volatile ("copy %%r30, %0" : "=r"(sp));
442 memset(&r, 0, sizeof(struct pt_regs));
443 r.iaoq[0] = (unsigned long) current_text_addr();
444 r.gr[2] = (unsigned long) __builtin_return_address(0);
446 unwind_frame_init(&info, current, &r);
451 if (unwind_once(&info) < 0 || info.ip == 0)
453 if (!kernel_text_address(info.ip))
455 } while (info.ip && level--);