1 /* SPDX-License-Identifier: GPL-2.0 */
3 * Most of this ideas comes from x86.
5 * Copyright (C) 2022 Loongson Technology Corporation Limited
10 #include <linux/sched.h>
11 #include <linux/ftrace.h>
13 #include <asm/ptrace.h>
14 #include <asm/stacktrace.h>
23 char type
; /* UNWINDER_XXX */
24 struct stack_info stack_info
;
25 struct task_struct
*task
;
26 bool first
, error
, reset
;
28 unsigned long sp
, fp
, pc
, ra
;
31 bool default_next_frame(struct unwind_state
*state
);
33 void unwind_start(struct unwind_state
*state
,
34 struct task_struct
*task
, struct pt_regs
*regs
);
35 bool unwind_next_frame(struct unwind_state
*state
);
36 unsigned long unwind_get_return_address(struct unwind_state
*state
);
38 static inline bool unwind_done(struct unwind_state
*state
)
40 return state
->stack_info
.type
== STACK_TYPE_UNKNOWN
;
43 static inline bool unwind_error(struct unwind_state
*state
)
48 #define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_regs, regs[1]))
50 static inline unsigned long unwind_graph_addr(struct unwind_state
*state
,
51 unsigned long pc
, unsigned long cfa
)
53 return ftrace_graph_ret_addr(state
->task
, &state
->graph_idx
,
54 pc
, (unsigned long *)(cfa
- GRAPH_FAKE_OFFSET
));
57 static __always_inline
void __unwind_start(struct unwind_state
*state
,
58 struct task_struct
*task
, struct pt_regs
*regs
)
60 memset(state
, 0, sizeof(*state
));
62 state
->sp
= regs
->regs
[3];
63 state
->pc
= regs
->csr_era
;
64 state
->ra
= regs
->regs
[1];
65 state
->fp
= regs
->regs
[22];
66 } else if (task
&& task
!= current
) {
67 state
->sp
= thread_saved_fp(task
);
68 state
->pc
= thread_saved_ra(task
);
72 state
->sp
= (unsigned long)__builtin_frame_address(0);
73 state
->pc
= (unsigned long)__builtin_return_address(0);
78 get_stack_info(state
->sp
, state
->task
, &state
->stack_info
);
79 state
->pc
= unwind_graph_addr(state
, state
->pc
, state
->sp
);
82 static __always_inline
unsigned long __unwind_get_return_address(struct unwind_state
*state
)
84 if (unwind_done(state
))
87 return __kernel_text_address(state
->pc
) ? state
->pc
: 0;
90 #ifdef CONFIG_UNWINDER_ORC
91 void unwind_init(void);
92 void unwind_module_init(struct module
*mod
, void *orc_ip
, size_t orc_ip_size
, void *orc
, size_t orc_size
);
94 static inline void unwind_init(void) {}
95 static inline void unwind_module_init(struct module
*mod
, void *orc_ip
, size_t orc_ip_size
, void *orc
, size_t orc_size
) {}
98 #endif /* _ASM_UNWIND_H */