Skip to content

Commit 93a4fa6

Browse files
zhangqingmychenhuacai
authored andcommitted
LoongArch: Add STACKTRACE support
1. Use common arch_stack_walk() infrastructure to avoid duplicated code and avoid taking care of the stack storage and filtering. 2. Add sched_ra (means sched return address) and sched_cfa (means sched call frame address) to thread_info, and store them in switch_to(). 3. Add __get_wchan() implementation. Now we can print the process stack and wait channel by cat /proc/*/stack and /proc/*/wchan. Signed-off-by: Qing Zhang <zhangqing@loongson.cn> Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
1 parent 49aef11 commit 93a4fa6

8 files changed

Lines changed: 93 additions & 6 deletions

File tree

arch/loongarch/Kconfig

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ config LOONGARCH
4242
select ARCH_MIGHT_HAVE_PC_PARPORT
4343
select ARCH_MIGHT_HAVE_PC_SERIO
4444
select ARCH_SPARSEMEM_ENABLE
45+
select ARCH_STACKWALK
4546
select ARCH_SUPPORTS_ACPI
4647
select ARCH_SUPPORTS_ATOMIC_RMW
4748
select ARCH_SUPPORTS_HUGETLBFS
@@ -151,6 +152,10 @@ config LOCKDEP_SUPPORT
151152
bool
152153
default y
153154

155+
config STACKTRACE_SUPPORT
156+
bool
157+
default y
158+
154159
# MACH_LOONGSON32 and MACH_LOONGSON64 are delibrately carried over from the
155160
# MIPS Loongson code, to preserve Loongson-specific code paths in drivers that
156161
# are shared between architectures, and specifically expecting the symbols.

arch/loongarch/include/asm/processor.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,10 @@ struct thread_struct {
101101
unsigned long reg23, reg24, reg25, reg26; /* s0-s3 */
102102
unsigned long reg27, reg28, reg29, reg30, reg31; /* s4-s8 */
103103

104+
/* __schedule() return address / call frame address */
105+
unsigned long sched_ra;
106+
unsigned long sched_cfa;
107+
104108
/* CSR registers */
105109
unsigned long csr_prmd;
106110
unsigned long csr_crmd;
@@ -129,6 +133,9 @@ struct thread_struct {
129133
struct loongarch_fpu fpu FPU_ALIGN;
130134
};
131135

136+
#define thread_saved_ra(tsk) (tsk->thread.sched_ra)
137+
#define thread_saved_fp(tsk) (tsk->thread.sched_cfa)
138+
132139
#define INIT_THREAD { \
133140
/* \
134141
* Main processor registers \
@@ -145,6 +152,8 @@ struct thread_struct {
145152
.reg29 = 0, \
146153
.reg30 = 0, \
147154
.reg31 = 0, \
155+
.sched_ra = 0, \
156+
.sched_cfa = 0, \
148157
.csr_crmd = 0, \
149158
.csr_prmd = 0, \
150159
.csr_euen = 0, \

arch/loongarch/include/asm/switch_to.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,27 @@ struct task_struct;
1515
* @prev: The task previously executed.
1616
* @next: The task to begin executing.
1717
* @next_ti: task_thread_info(next).
18+
* @sched_ra: __schedule return address.
19+
* @sched_cfa: __schedule call frame address.
1820
*
1921
* This function is used whilst scheduling to save the context of prev & load
2022
* the context of next. Returns prev.
2123
*/
2224
extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev,
23-
struct task_struct *next, struct thread_info *next_ti);
25+
struct task_struct *next, struct thread_info *next_ti,
26+
void *sched_ra, void *sched_cfa);
2427

2528
/*
2629
* For newly created kernel threads switch_to() will return to
2730
* ret_from_kernel_thread, newly created user threads to ret_from_fork.
2831
* That is, everything following __switch_to() will be skipped for new threads.
2932
* So everything that matters to new threads should be placed before __switch_to().
3033
*/
31-
#define switch_to(prev, next, last) \
32-
do { \
33-
lose_fpu_inatomic(1, prev); \
34-
(last) = __switch_to(prev, next, task_thread_info(next)); \
34+
#define switch_to(prev, next, last) \
35+
do { \
36+
lose_fpu_inatomic(1, prev); \
37+
(last) = __switch_to(prev, next, task_thread_info(next), \
38+
__builtin_return_address(0), __builtin_frame_address(0)); \
3539
} while (0)
3640

3741
#endif /* _ASM_SWITCH_TO_H */

arch/loongarch/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ obj-$(CONFIG_EFI) += efi.o
1515
obj-$(CONFIG_CPU_HAS_FPU) += fpu.o
1616

1717
obj-$(CONFIG_MODULES) += module.o module-sections.o
18+
obj-$(CONFIG_STACKTRACE) += stacktrace.o
1819

1920
obj-$(CONFIG_PROC_FS) += proc.o
2021

arch/loongarch/kernel/asm-offsets.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ void output_thread_defines(void)
103103
OFFSET(THREAD_REG29, task_struct, thread.reg29);
104104
OFFSET(THREAD_REG30, task_struct, thread.reg30);
105105
OFFSET(THREAD_REG31, task_struct, thread.reg31);
106+
OFFSET(THREAD_SCHED_RA, task_struct, thread.sched_ra);
107+
OFFSET(THREAD_SCHED_CFA, task_struct, thread.sched_cfa);
106108
OFFSET(THREAD_CSRCRMD, task_struct,
107109
thread.csr_crmd);
108110
OFFSET(THREAD_CSRPRMD, task_struct,

arch/loongarch/kernel/process.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
135135
childregs = (struct pt_regs *) childksp - 1;
136136
/* Put the stack after the struct pt_regs. */
137137
childksp = (unsigned long) childregs;
138+
p->thread.sched_cfa = 0;
138139
p->thread.csr_euen = 0;
139140
p->thread.csr_crmd = csr_read32(LOONGARCH_CSR_CRMD);
140141
p->thread.csr_prmd = csr_read32(LOONGARCH_CSR_PRMD);
@@ -145,6 +146,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
145146
p->thread.reg23 = (unsigned long)args->fn;
146147
p->thread.reg24 = (unsigned long)args->fn_arg;
147148
p->thread.reg01 = (unsigned long)ret_from_kernel_thread;
149+
p->thread.sched_ra = (unsigned long)ret_from_kernel_thread;
148150
memset(childregs, 0, sizeof(struct pt_regs));
149151
childregs->csr_euen = p->thread.csr_euen;
150152
childregs->csr_crmd = p->thread.csr_crmd;
@@ -161,6 +163,7 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
161163

162164
p->thread.reg03 = (unsigned long) childregs;
163165
p->thread.reg01 = (unsigned long) ret_from_fork;
166+
p->thread.sched_ra = (unsigned long) ret_from_fork;
164167

165168
/*
166169
* New tasks lose permission to use the fpu. This accelerates context
@@ -181,7 +184,31 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
181184

182185
unsigned long __get_wchan(struct task_struct *task)
183186
{
184-
return 0;
187+
unsigned long pc;
188+
struct unwind_state state;
189+
190+
if (!try_get_task_stack(task))
191+
return 0;
192+
193+
unwind_start(&state, task, NULL);
194+
state.sp = thread_saved_fp(task);
195+
get_stack_info(state.sp, state.task, &state.stack_info);
196+
state.pc = thread_saved_ra(task);
197+
#ifdef CONFIG_UNWINDER_PROLOGUE
198+
state.type = UNWINDER_PROLOGUE;
199+
#endif
200+
for (; !unwind_done(&state); unwind_next_frame(&state)) {
201+
pc = unwind_get_return_address(&state);
202+
if (!pc)
203+
break;
204+
if (in_sched_functions(pc))
205+
continue;
206+
break;
207+
}
208+
209+
put_task_stack(task);
210+
211+
return pc;
185212
}
186213

187214
bool in_irq_stack(unsigned long stack, struct stack_info *info)

arch/loongarch/kernel/stacktrace.c

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Stack trace management functions
4+
*
5+
* Copyright (C) 2022 Loongson Technology Corporation Limited
6+
*/
7+
#include <linux/sched.h>
8+
#include <linux/stacktrace.h>
9+
10+
#include <asm/stacktrace.h>
11+
#include <asm/unwind.h>
12+
13+
void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
14+
struct task_struct *task, struct pt_regs *regs)
15+
{
16+
unsigned long addr;
17+
struct pt_regs dummyregs;
18+
struct unwind_state state;
19+
20+
regs = &dummyregs;
21+
22+
if (task == current) {
23+
regs->regs[3] = (unsigned long)__builtin_frame_address(0);
24+
regs->csr_era = (unsigned long)__builtin_return_address(0);
25+
} else {
26+
regs->regs[3] = thread_saved_fp(task);
27+
regs->csr_era = thread_saved_ra(task);
28+
}
29+
30+
regs->regs[1] = 0;
31+
for (unwind_start(&state, task, regs);
32+
!unwind_done(&state); unwind_next_frame(&state)) {
33+
addr = unwind_get_return_address(&state);
34+
if (!addr || !consume_entry(cookie, addr))
35+
break;
36+
}
37+
}

arch/loongarch/kernel/switch.S

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ SYM_FUNC_START(__switch_to)
2121

2222
cpu_save_nonscratch a0
2323
stptr.d ra, a0, THREAD_REG01
24+
stptr.d a3, a0, THREAD_SCHED_RA
25+
stptr.d a4, a0, THREAD_SCHED_CFA
2426
move tp, a2
2527
cpu_restore_nonscratch a1
2628

0 commit comments

Comments
 (0)