xref: /linux/arch/loongarch/include/asm/unwind.h (revision c5ac25e0d78a6f63446b8fef4d8630ccd7a2663d)
149232773SQing Zhang /* SPDX-License-Identifier: GPL-2.0 */
249232773SQing Zhang /*
349232773SQing Zhang  * Most of this ideas comes from x86.
449232773SQing Zhang  *
549232773SQing Zhang  * Copyright (C) 2022 Loongson Technology Corporation Limited
649232773SQing Zhang  */
749232773SQing Zhang #ifndef _ASM_UNWIND_H
849232773SQing Zhang #define _ASM_UNWIND_H
949232773SQing Zhang 
1049232773SQing Zhang #include <linux/sched.h>
115bb8d344SJinyang He #include <linux/ftrace.h>
1249232773SQing Zhang 
135bb8d344SJinyang He #include <asm/ptrace.h>
1449232773SQing Zhang #include <asm/stacktrace.h>
1549232773SQing Zhang 
1649aef111SQing Zhang enum unwinder_type {
1749aef111SQing Zhang 	UNWINDER_GUESS,
1849aef111SQing Zhang 	UNWINDER_PROLOGUE,
1949aef111SQing Zhang };
2049aef111SQing Zhang 
2149232773SQing Zhang struct unwind_state {
2249aef111SQing Zhang 	char type; /* UNWINDER_XXX */
2349232773SQing Zhang 	struct stack_info stack_info;
2449232773SQing Zhang 	struct task_struct *task;
254733f09dSQing Zhang 	bool first, error, is_ftrace;
26a51ac524SQing Zhang 	int graph_idx;
2749aef111SQing Zhang 	unsigned long sp, pc, ra;
2849232773SQing Zhang };
2949232773SQing Zhang 
30*c5ac25e0SJinyang He bool default_next_frame(struct unwind_state *state);
31*c5ac25e0SJinyang He 
3249232773SQing Zhang void unwind_start(struct unwind_state *state,
3349232773SQing Zhang 		  struct task_struct *task, struct pt_regs *regs);
3449232773SQing Zhang bool unwind_next_frame(struct unwind_state *state);
3549232773SQing Zhang unsigned long unwind_get_return_address(struct unwind_state *state);
3649232773SQing Zhang 
3749232773SQing Zhang static inline bool unwind_done(struct unwind_state *state)
3849232773SQing Zhang {
3949232773SQing Zhang 	return state->stack_info.type == STACK_TYPE_UNKNOWN;
4049232773SQing Zhang }
4149232773SQing Zhang 
4249232773SQing Zhang static inline bool unwind_error(struct unwind_state *state)
4349232773SQing Zhang {
4449232773SQing Zhang 	return state->error;
4549232773SQing Zhang }
4649232773SQing Zhang 
475bb8d344SJinyang He #define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
485bb8d344SJinyang He 
495bb8d344SJinyang He static inline unsigned long unwind_graph_addr(struct unwind_state *state,
505bb8d344SJinyang He 					unsigned long pc, unsigned long cfa)
515bb8d344SJinyang He {
525bb8d344SJinyang He 	return ftrace_graph_ret_addr(state->task, &state->graph_idx,
535bb8d344SJinyang He 				     pc, (unsigned long *)(cfa - GRAPH_FAKE_OFFSET));
545bb8d344SJinyang He }
55*c5ac25e0SJinyang He 
56*c5ac25e0SJinyang He static __always_inline void __unwind_start(struct unwind_state *state,
57*c5ac25e0SJinyang He 					struct task_struct *task, struct pt_regs *regs)
58*c5ac25e0SJinyang He {
59*c5ac25e0SJinyang He 	memset(state, 0, sizeof(*state));
60*c5ac25e0SJinyang He 	if (regs) {
61*c5ac25e0SJinyang He 		state->sp = regs->regs[3];
62*c5ac25e0SJinyang He 		state->pc = regs->csr_era;
63*c5ac25e0SJinyang He 		state->ra = regs->regs[1];
64*c5ac25e0SJinyang He 	} else if (task && task != current) {
65*c5ac25e0SJinyang He 		state->sp = thread_saved_fp(task);
66*c5ac25e0SJinyang He 		state->pc = thread_saved_ra(task);
67*c5ac25e0SJinyang He 		state->ra = 0;
68*c5ac25e0SJinyang He 	} else {
69*c5ac25e0SJinyang He 		state->sp = (unsigned long)__builtin_frame_address(0);
70*c5ac25e0SJinyang He 		state->pc = (unsigned long)__builtin_return_address(0);
71*c5ac25e0SJinyang He 		state->ra = 0;
72*c5ac25e0SJinyang He 	}
73*c5ac25e0SJinyang He 	state->task = task;
74*c5ac25e0SJinyang He 	get_stack_info(state->sp, state->task, &state->stack_info);
75*c5ac25e0SJinyang He 	state->pc = unwind_graph_addr(state, state->pc, state->sp);
76*c5ac25e0SJinyang He }
77*c5ac25e0SJinyang He 
78*c5ac25e0SJinyang He static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
79*c5ac25e0SJinyang He {
80*c5ac25e0SJinyang He 	return unwind_done(state) ? 0 : state->pc;
81*c5ac25e0SJinyang He }
8249232773SQing Zhang #endif /* _ASM_UNWIND_H */
83