xref: /linux/arch/loongarch/include/asm/unwind.h (revision dc74a9e8a8c57966a563ab078ba91c8b2c0d0a72)
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;
25*dc74a9e8SJinyang He 	bool first, error, reset;
26a51ac524SQing Zhang 	int graph_idx;
2749aef111SQing Zhang 	unsigned long sp, pc, ra;
2849232773SQing Zhang };
2949232773SQing Zhang 
30c5ac25e0SJinyang He bool default_next_frame(struct unwind_state *state);
31c5ac25e0SJinyang 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 }
55c5ac25e0SJinyang He 
56c5ac25e0SJinyang He static __always_inline void __unwind_start(struct unwind_state *state,
57c5ac25e0SJinyang He 					struct task_struct *task, struct pt_regs *regs)
58c5ac25e0SJinyang He {
59c5ac25e0SJinyang He 	memset(state, 0, sizeof(*state));
60c5ac25e0SJinyang He 	if (regs) {
61c5ac25e0SJinyang He 		state->sp = regs->regs[3];
62c5ac25e0SJinyang He 		state->pc = regs->csr_era;
63c5ac25e0SJinyang He 		state->ra = regs->regs[1];
64c5ac25e0SJinyang He 	} else if (task && task != current) {
65c5ac25e0SJinyang He 		state->sp = thread_saved_fp(task);
66c5ac25e0SJinyang He 		state->pc = thread_saved_ra(task);
67c5ac25e0SJinyang He 		state->ra = 0;
68c5ac25e0SJinyang He 	} else {
69c5ac25e0SJinyang He 		state->sp = (unsigned long)__builtin_frame_address(0);
70c5ac25e0SJinyang He 		state->pc = (unsigned long)__builtin_return_address(0);
71c5ac25e0SJinyang He 		state->ra = 0;
72c5ac25e0SJinyang He 	}
73c5ac25e0SJinyang He 	state->task = task;
74c5ac25e0SJinyang He 	get_stack_info(state->sp, state->task, &state->stack_info);
75c5ac25e0SJinyang He 	state->pc = unwind_graph_addr(state, state->pc, state->sp);
76c5ac25e0SJinyang He }
77c5ac25e0SJinyang He 
78c5ac25e0SJinyang He static __always_inline unsigned long __unwind_get_return_address(struct unwind_state *state)
79c5ac25e0SJinyang He {
80c5ac25e0SJinyang He 	return unwind_done(state) ? 0 : state->pc;
81c5ac25e0SJinyang He }
8249232773SQing Zhang #endif /* _ASM_UNWIND_H */
83