1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2022 Loongson Technology Corporation Limited
5 #include <linux/kallsyms.h>
8 #include <asm/ptrace.h>
9 #include <asm/unwind.h>
11 unsigned long unwind_get_return_address(struct unwind_state *state)
14 if (unwind_done(state))
18 else if (state->first)
21 return *(unsigned long *)(state->sp);
24 EXPORT_SYMBOL_GPL(unwind_get_return_address);
26 static bool unwind_by_guess(struct unwind_state *state)
28 struct stack_info *info = &state->stack_info;
31 for (state->sp += sizeof(unsigned long);
32 state->sp < info->end;
33 state->sp += sizeof(unsigned long)) {
34 addr = *(unsigned long *)(state->sp);
35 if (__kernel_text_address(addr))
42 static bool unwind_by_prologue(struct unwind_state *state)
44 struct stack_info *info = &state->stack_info;
45 union loongarch_instruction *ip, *ip_end;
46 unsigned long frame_size = 0, frame_ra = -1;
47 unsigned long size, offset, pc = state->pc;
49 if (state->sp >= info->end || state->sp < info->begin)
52 if (!kallsyms_lookup_size_offset(pc, &size, &offset))
55 ip = (union loongarch_instruction *)(pc - offset);
56 ip_end = (union loongarch_instruction *)pc;
59 if (is_stack_alloc_ins(ip)) {
60 frame_size = (1 << 12) - ip->reg2i12_format.immediate;
75 if (is_ra_save_ins(ip)) {
76 frame_ra = ip->reg2i12_format.immediate;
79 if (is_branch_ins(ip))
86 state->sp = state->sp + frame_size;
95 state->pc = *(unsigned long *)(state->sp + frame_ra);
96 state->sp = state->sp + frame_size;
97 return !!__kernel_text_address(state->pc);
100 state->first = false;
101 if (state->pc == state->ra)
104 state->pc = state->ra;
106 return !!__kernel_text_address(state->ra);
109 void unwind_start(struct unwind_state *state, struct task_struct *task,
110 struct pt_regs *regs)
112 memset(state, 0, sizeof(*state));
114 if (regs && __kernel_text_address(regs->csr_era)) {
115 state->pc = regs->csr_era;
116 state->sp = regs->regs[3];
117 state->ra = regs->regs[1];
118 state->type = UNWINDER_PROLOGUE;
124 get_stack_info(state->sp, state->task, &state->stack_info);
126 if (!unwind_done(state) && !__kernel_text_address(state->pc))
127 unwind_next_frame(state);
129 EXPORT_SYMBOL_GPL(unwind_start);
131 bool unwind_next_frame(struct unwind_state *state)
133 struct stack_info *info = &state->stack_info;
134 struct pt_regs *regs;
137 if (unwind_done(state))
141 switch (state->type) {
143 state->first = false;
144 if (unwind_by_guess(state))
148 case UNWINDER_PROLOGUE:
149 if (unwind_by_prologue(state))
152 if (info->type == STACK_TYPE_IRQ &&
153 info->end == state->sp) {
154 regs = (struct pt_regs *)info->next_sp;
157 if (user_mode(regs) || !__kernel_text_address(pc))
161 state->sp = regs->regs[3];
162 state->ra = regs->regs[1];
164 get_stack_info(state->sp, state->task, info);
170 state->sp = info->next_sp;
172 } while (!get_stack_info(state->sp, state->task, info));
176 EXPORT_SYMBOL_GPL(unwind_next_frame);