From nobody Thu Apr 25 20:45:24 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 05EF6C25B0C for ; Sat, 6 Aug 2022 08:10:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241500AbiHFIKW (ORCPT ); Sat, 6 Aug 2022 04:10:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57516 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229597AbiHFIKQ (ORCPT ); Sat, 6 Aug 2022 04:10:16 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 642D4E2B; Sat, 6 Aug 2022 01:10:13 -0700 (PDT) Received: from localhost.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxbyPdIe5ixooIAA--.1165S3; Sat, 06 Aug 2022 16:10:06 +0800 (CST) From: Qing Zhang To: Huacai Chen Cc: WANG Xuerui , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org, Jiaxun Yang , Arnd Bergmann , hejinyang@loongson.cn, tangyouling@loongson.cn, zhangqing@loongson.cn Subject: [PATCH v4 1/4] LoongArch: Add guess unwinder support Date: Sat, 6 Aug 2022 16:10:02 +0800 Message-Id: <20220806081005.332-2-zhangqing@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20220806081005.332-1-zhangqing@loongson.cn> References: <20220806081005.332-1-zhangqing@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxbyPdIe5ixooIAA--.1165S3 X-Coremail-Antispam: 1UD129KBjvJXoW3Gr43Xw43Jw1fJr1kAF1DKFg_yoWfCr48pF 98C3Z3GrW5G34Igr9xXr18Zrn8Gr4kCw12gF9xtFyFkF12qFyfXrnaya4DZFs8J3ykW3WI gF95Krs8Ka1UXaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPC14x267AKxVW5JVWrJwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_Jr4l82xGYIkIc2 x26xkF7I0E14v26r1I6r4UM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l84 ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AKxVWxJr0_GcWl e2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI 8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJVW8JwAC jcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2Y2ka0x kIwI1lc2xSY4AK67AK6r43MxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4U MI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67 AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1I6r4UMIIF0xvE2Ix0 cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z2 80aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI 43ZEXa7VUjZ2-5UUUUU== X-CM-SenderInfo: x2kd0wptlqwqxorr0wxvrqhubq/ Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Name "guess unwinder" comes from x86, It scans the stack and reports every kernel text address it finds. Three stages when we do unwind, 1) unwind_start(), the prapare of unwinding, fill unwind_state. 2) unwind_done(), judge whether the unwind process is finished or not. 3) unwind_next_frame(), unwind the next frame. Make the dump_stack process go through unwind process. Add get_stack_info() to get stack info. At present we have irq stack and task stack. Maybe add another type in future. The next_sp means the key info between this type stack and next type stack. Dividing unwinder helps to add new unwinders in the future. Signed-off-by: Qing Zhang --- arch/loongarch/Kconfig.debug | 9 ++++ arch/loongarch/include/asm/stacktrace.h | 17 +++++++ arch/loongarch/include/asm/unwind.h | 37 ++++++++++++++ arch/loongarch/kernel/Makefile | 2 + arch/loongarch/kernel/process.c | 61 ++++++++++++++++++++++ arch/loongarch/kernel/traps.c | 21 ++++---- arch/loongarch/kernel/unwind_guess.c | 67 +++++++++++++++++++++++++ 7 files changed, 203 insertions(+), 11 deletions(-) create mode 100644 arch/loongarch/include/asm/unwind.h create mode 100644 arch/loongarch/kernel/unwind_guess.c diff --git a/arch/loongarch/Kconfig.debug b/arch/loongarch/Kconfig.debug index e69de29bb2d1..68634d4fa27b 100644 --- a/arch/loongarch/Kconfig.debug +++ b/arch/loongarch/Kconfig.debug @@ -0,0 +1,9 @@ +config UNWINDER_GUESS + bool "Guess unwinder" + help + This option enables the "guess" unwinder for unwinding kernel stack + traces. It scans the stack and reports every kernel text address it + finds. Some of the addresses it reports may be incorrect. + + While this option often produces false positives, it can still be + useful in many cases. diff --git a/arch/loongarch/include/asm/stacktrace.h b/arch/loongarch/inclu= de/asm/stacktrace.h index 6b5c2a7aa706..49cb89213aeb 100644 --- a/arch/loongarch/include/asm/stacktrace.h +++ b/arch/loongarch/include/asm/stacktrace.h @@ -10,6 +10,23 @@ #include #include =20 +enum stack_type { + STACK_TYPE_UNKNOWN, + STACK_TYPE_TASK, + STACK_TYPE_IRQ, +}; + +struct stack_info { + enum stack_type type; + unsigned long begin, end, next_sp; +}; + +bool in_task_stack(unsigned long stack, struct task_struct *task, + struct stack_info *info); +bool in_irq_stack(unsigned long stack, struct stack_info *info); +int get_stack_info(unsigned long stack, struct task_struct *task, + struct stack_info *info); + #define STR_LONG_L __stringify(LONG_L) #define STR_LONG_S __stringify(LONG_S) #define STR_LONGSIZE __stringify(LONGSIZE) diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/a= sm/unwind.h new file mode 100644 index 000000000000..243330b39d0d --- /dev/null +++ b/arch/loongarch/include/asm/unwind.h @@ -0,0 +1,37 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Most of this ideas comes from x86. + * + * Copyright (C) 2022 Loongson Technology Corporation Limited + */ +#ifndef _ASM_UNWIND_H +#define _ASM_UNWIND_H + +#include + +#include + +struct unwind_state { + struct stack_info stack_info; + struct task_struct *task; + unsigned long sp, pc; + bool first; + bool error; +}; + +void unwind_start(struct unwind_state *state, struct task_struct *task, + struct pt_regs *regs); +bool unwind_next_frame(struct unwind_state *state); +unsigned long unwind_get_return_address(struct unwind_state *state); + +static inline bool unwind_done(struct unwind_state *state) +{ + return state->stack_info.type =3D=3D STACK_TYPE_UNKNOWN; +} + +static inline bool unwind_error(struct unwind_state *state) +{ + return state->error; +} + +#endif /* _ASM_UNWIND_H */ diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index 940de9173542..c5fa4adb23b6 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -22,4 +22,6 @@ obj-$(CONFIG_SMP) +=3D smp.o =20 obj-$(CONFIG_NUMA) +=3D numa.o =20 +obj-$(CONFIG_UNWINDER_GUESS) +=3D unwind_guess.o + CPPFLAGS_vmlinux.lds :=3D $(KBUILD_CFLAGS) diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/proces= s.c index bfa0dfe8b7d7..709b7a1664f8 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -44,6 +44,7 @@ #include #include #include +#include #include =20 /* @@ -183,6 +184,66 @@ unsigned long __get_wchan(struct task_struct *task) return 0; } =20 +bool in_task_stack(unsigned long stack, struct task_struct *task, + struct stack_info *info) +{ + unsigned long begin =3D (unsigned long)task_stack_page(task); + unsigned long end =3D begin + THREAD_SIZE - 32; + + if (stack < begin || stack >=3D end) + return false; + + info->type =3D STACK_TYPE_TASK; + info->begin =3D begin; + info->end =3D end; + info->next_sp =3D 0; + + return true; +} + +bool in_irq_stack(unsigned long stack, struct stack_info *info) +{ + unsigned long nextsp; + unsigned long begin =3D (unsigned long)this_cpu_read(irq_stack); + unsigned long end =3D begin + IRQ_STACK_START; + + if (stack < begin || stack >=3D end) + return false; + + nextsp =3D *(unsigned long *)end; + if (nextsp & (SZREG - 1)) + return false; + + info->type =3D STACK_TYPE_IRQ; + info->begin =3D begin; + info->end =3D end; + info->next_sp =3D nextsp; + + return true; +} + +int get_stack_info(unsigned long stack, struct task_struct *task, + struct stack_info *info) +{ + task =3D task ? : current; + + if (!stack || stack & (SZREG - 1)) + goto unknown; + + if (in_task_stack(stack, task, info)) + return 0; + + if (task !=3D current) + goto unknown; + + if (in_irq_stack(stack, info)) + return 0; + +unknown: + info->type =3D STACK_TYPE_UNKNOWN; + return -EINVAL; +} + unsigned long stack_top(void) { unsigned long top =3D TASK_SIZE & PAGE_MASK; diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c index 1bf58c65e2bf..f65fdf90d29e 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -43,6 +43,7 @@ #include #include #include +#include =20 #include "access-helper.h" =20 @@ -64,19 +65,17 @@ static void show_backtrace(struct task_struct *task, co= nst struct pt_regs *regs, const char *loglvl, bool user) { unsigned long addr; - unsigned long *sp =3D (unsigned long *)(regs->regs[3] & ~3); + struct unwind_state state; + struct pt_regs *pregs =3D (struct pt_regs *)regs; + + if (!task) + task =3D current; =20 printk("%sCall Trace:", loglvl); -#ifdef CONFIG_KALLSYMS - printk("%s\n", loglvl); -#endif - while (!kstack_end(sp)) { - if (__get_addr(&addr, sp++, user)) { - printk("%s (Bad stack address)", loglvl); - break; - } - if (__kernel_text_address(addr)) - print_ip_sym(loglvl, addr); + for (unwind_start(&state, task, pregs); + !unwind_done(&state); unwind_next_frame(&state)) { + addr =3D unwind_get_return_address(&state); + print_ip_sym(loglvl, addr); } printk("%s\n", loglvl); } diff --git a/arch/loongarch/kernel/unwind_guess.c b/arch/loongarch/kernel/u= nwind_guess.c new file mode 100644 index 000000000000..5afa6064d73e --- /dev/null +++ b/arch/loongarch/kernel/unwind_guess.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Loongson Technology Corporation Limited + */ +#include + +#include + +unsigned long unwind_get_return_address(struct unwind_state *state) +{ + if (unwind_done(state)) + return 0; + else if (state->first) + return state->pc; + + return *(unsigned long *)(state->sp); +} +EXPORT_SYMBOL_GPL(unwind_get_return_address); + +void unwind_start(struct unwind_state *state, struct task_struct *task, + struct pt_regs *regs) +{ + memset(state, 0, sizeof(*state)); + + if (regs) { + state->sp =3D regs->regs[3]; + state->pc =3D regs->csr_era; + } + + state->task =3D task; + state->first =3D true; + + get_stack_info(state->sp, state->task, &state->stack_info); + + if (!unwind_done(state) && !__kernel_text_address(state->pc)) + unwind_next_frame(state); +} +EXPORT_SYMBOL_GPL(unwind_start); + +bool unwind_next_frame(struct unwind_state *state) +{ + struct stack_info *info =3D &state->stack_info; + unsigned long addr; + + if (unwind_done(state)) + return false; + + if (state->first) + state->first =3D false; + + do { + for (state->sp +=3D sizeof(unsigned long); + state->sp < info->end; + state->sp +=3D sizeof(unsigned long)) { + addr =3D *(unsigned long *)(state->sp); + + if (__kernel_text_address(addr)) + return true; + } + + state->sp =3D info->next_sp; + + } while (!get_stack_info(state->sp, state->task, info)); + + return false; +} +EXPORT_SYMBOL_GPL(unwind_next_frame); --=20 2.20.1 From nobody Thu Apr 25 20:45:24 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A7948C25B06 for ; Sat, 6 Aug 2022 08:10:30 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241679AbiHFIK2 (ORCPT ); Sat, 6 Aug 2022 04:10:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57518 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233789AbiHFIKQ (ORCPT ); Sat, 6 Aug 2022 04:10:16 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 67B71E50; Sat, 6 Aug 2022 01:10:13 -0700 (PDT) Received: from localhost.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxbyPdIe5ixooIAA--.1165S4; Sat, 06 Aug 2022 16:10:07 +0800 (CST) From: Qing Zhang To: Huacai Chen Cc: WANG Xuerui , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org, Jiaxun Yang , Arnd Bergmann , hejinyang@loongson.cn, tangyouling@loongson.cn, zhangqing@loongson.cn Subject: [PATCH v4 2/4] LoongArch: Add prologue unwinder support Date: Sat, 6 Aug 2022 16:10:03 +0800 Message-Id: <20220806081005.332-3-zhangqing@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20220806081005.332-1-zhangqing@loongson.cn> References: <20220806081005.332-1-zhangqing@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxbyPdIe5ixooIAA--.1165S4 X-Coremail-Antispam: 1UD129KBjvJXoW3XF15Cw4kGFWDGrW8AF1UZFb_yoWDJF17pr ZxCr95Gr48Wrnagr9rXrs5urs5Grs29r12gFZxJr1rCF12qryxWrnYk34qvF4DJ3ykWr10 qFs5ArWagF4UJaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPC14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_Jryl82xGYIkIc2 x26xkF7I0E14v26r4j6ryUM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l84 ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AKxVWxJr0_GcWl e2I262IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI 8IcVAFwI0_JrI_JrylYx0Ex4A2jsIE14v26r1j6r4UMcvjeVCFs4IE7xkEbVWUJVW8JwAC jcxG0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lFIxGxcIEc7CjxVA2Y2ka0x kIwI1lc2xSY4AK67AK6r43MxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4U MI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67 AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v26r1I6r4UMIIF0xvE2Ix0 cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z2 80aVAFwI0_Jr0_Gr1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI 43ZEXa7VUUtEf5UUUUU== X-CM-SenderInfo: x2kd0wptlqwqxorr0wxvrqhubq/ Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" It unwind the stack frame based on prologue code analyze. CONFIG_KALLSYMS is needed, at least the address and length of each function. Three stages when we do unwind, 1) unwind_start(), the prapare of unwinding, fill unwind_state. 2) unwind_done(), judge whether the unwind process is finished or not. 3) unwind_next_frame(), unwind the next frame. Dividing unwinder helps to add new unwinders in the future, eg: unwinder_frame, unwinder_orc .etc Signed-off-by: Qing Zhang --- arch/loongarch/Kconfig.debug | 19 +++ arch/loongarch/include/asm/inst.h | 52 +++++++ arch/loongarch/include/asm/unwind.h | 12 +- arch/loongarch/kernel/Makefile | 1 + arch/loongarch/kernel/traps.c | 3 + arch/loongarch/kernel/unwind_prologue.c | 173 ++++++++++++++++++++++++ 6 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 arch/loongarch/kernel/unwind_prologue.c diff --git a/arch/loongarch/Kconfig.debug b/arch/loongarch/Kconfig.debug index 68634d4fa27b..57cdbe0cfd98 100644 --- a/arch/loongarch/Kconfig.debug +++ b/arch/loongarch/Kconfig.debug @@ -1,3 +1,11 @@ +choice + prompt "Choose kernel unwinder" + default UNWINDER_PROLOGUE if KALLSYMS + help + This determines which method will be used for unwinding kernel stack + traces for panics, oopses, bugs, warnings, perf, /proc//stack, + lockdep, and more. + config UNWINDER_GUESS bool "Guess unwinder" help @@ -7,3 +15,14 @@ config UNWINDER_GUESS =20 While this option often produces false positives, it can still be useful in many cases. + +config UNWINDER_PROLOGUE + bool "Prologue unwinder" + depends on KALLSYMS + help + This option enables the "prologue" unwinder for unwinding kernel stack + traces. It unwind the stack frame based on prologue code analyze. Sym= bol + information is needed, at least the address and length of each function. + Some of the addresses it reports may be incorrect. + +endchoice diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm= /inst.h index 575d1bb66ffb..b876907ca65a 100644 --- a/arch/loongarch/include/asm/inst.h +++ b/arch/loongarch/include/asm/inst.h @@ -23,12 +23,33 @@ enum reg1i20_op { lu32id_op =3D 0x0b, }; =20 +enum reg1i21_op { + beqz_op =3D 0x10, + bnez_op =3D 0x11, +}; + enum reg2i12_op { + addiw_op =3D 0x0a, + addid_op =3D 0x0b, lu52id_op =3D 0x0c, + ldb_op =3D 0xa0, + ldh_op =3D 0xa1, + ldw_op =3D 0xa2, + ldd_op =3D 0xa3, + stb_op =3D 0xa4, + sth_op =3D 0xa5, + stw_op =3D 0xa6, + std_op =3D 0xa7, }; =20 enum reg2i16_op { jirl_op =3D 0x13, + beq_op =3D 0x16, + bne_op =3D 0x17, + blt_op =3D 0x18, + bge_op =3D 0x19, + bltu_op =3D 0x1a, + bgeu_op =3D 0x1b, }; =20 struct reg0i26_format { @@ -110,6 +131,37 @@ enum loongarch_gpr { LOONGARCH_GPR_MAX }; =20 +#define is_imm12_negative(val) is_imm_negative(val, 12) + +static inline bool is_imm_negative(unsigned long val, unsigned int bit) +{ + return val & (1UL << (bit - 1)); +} + +static inline bool is_stack_alloc_ins(union loongarch_instruction *ip) +{ + /* addi.d $sp, $sp, -imm */ + return ip->reg2i12_format.opcode =3D=3D addid_op && + ip->reg2i12_format.rj =3D=3D LOONGARCH_GPR_SP && + ip->reg2i12_format.rd =3D=3D LOONGARCH_GPR_SP && + is_imm12_negative(ip->reg2i12_format.immediate); +} + +static inline bool is_ra_save_ins(union loongarch_instruction *ip) +{ + /* st.d $ra, $sp, offset */ + return ip->reg2i12_format.opcode =3D=3D std_op && + ip->reg2i12_format.rj =3D=3D LOONGARCH_GPR_SP && + ip->reg2i12_format.rd =3D=3D LOONGARCH_GPR_RA && + !is_imm12_negative(ip->reg2i12_format.immediate); +} + +static inline bool is_branch_insn(union loongarch_instruction insn) +{ + return insn.reg1i21_format.opcode >=3D beqz_op && + insn.reg1i21_format.opcode <=3D bgeu_op; +} + u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm); u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, in= t imm); u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsi= gned long pc, unsigned long dest); diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/a= sm/unwind.h index 243330b39d0d..e96ccebc8e2d 100644 --- a/arch/loongarch/include/asm/unwind.h +++ b/arch/loongarch/include/asm/unwind.h @@ -11,10 +11,20 @@ =20 #include =20 +enum unwinder_type { + UNWINDER_GUESS, + UNWINDER_PROLOGUE, +}; + struct unwind_state { + /* + * UNWINDER_PROLOGUE is the prologue analysis method + * UNWINDER_GUESS is the way to guess. + */ + char type; struct stack_info stack_info; struct task_struct *task; - unsigned long sp, pc; + unsigned long sp, pc, ra; bool first; bool error; }; diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index c5fa4adb23b6..918600e7b30f 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -23,5 +23,6 @@ obj-$(CONFIG_SMP) +=3D smp.o obj-$(CONFIG_NUMA) +=3D numa.o =20 obj-$(CONFIG_UNWINDER_GUESS) +=3D unwind_guess.o +obj-$(CONFIG_UNWINDER_PROLOGUE) +=3D unwind_prologue.o =20 CPPFLAGS_vmlinux.lds :=3D $(KBUILD_CFLAGS) diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c index f65fdf90d29e..aa1c95aaf595 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -71,6 +71,9 @@ static void show_backtrace(struct task_struct *task, cons= t struct pt_regs *regs, if (!task) task =3D current; =20 + if (user_mode(regs)) + state.type =3D UNWINDER_GUESS; + printk("%sCall Trace:", loglvl); for (unwind_start(&state, task, pregs); !unwind_done(&state); unwind_next_frame(&state)) { diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kerne= l/unwind_prologue.c new file mode 100644 index 000000000000..c253a2712981 --- /dev/null +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -0,0 +1,173 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Loongson Technology Corporation Limited + */ +#include + +#include +#include +#include + +unsigned long unwind_get_return_address(struct unwind_state *state) +{ + + if (unwind_done(state)) + return 0; + else if (state->type) + return state->pc; + else if (state->first) + return state->pc; + + return *(unsigned long *)(state->sp); + +} +EXPORT_SYMBOL_GPL(unwind_get_return_address); + +static bool unwind_by_prologue(struct unwind_state *state) +{ + struct stack_info *info =3D &state->stack_info; + union loongarch_instruction *ip, *ip_end; + unsigned long frame_size =3D 0, frame_ra =3D -1; + unsigned long size, offset, pc =3D state->pc; + + if (state->sp >=3D info->end || state->sp < info->begin) + return false; + + if (!kallsyms_lookup_size_offset(pc, &size, &offset)) + return false; + + ip =3D (union loongarch_instruction *)(pc - offset); + ip_end =3D (union loongarch_instruction *)pc; + + while (ip < ip_end) { + if (is_stack_alloc_ins(ip)) { + frame_size =3D (1 << 12) - ip->reg2i12_format.immediate; + ip++; + break; + } + ip++; + } + + if (!frame_size) { + if (state->first) + goto first; + + return false; + } + + while (ip < ip_end) { + if (is_ra_save_ins(ip)) { + frame_ra =3D ip->reg2i12_format.immediate; + break; + } + if (is_branch_insn(*ip)) + break; + ip++; + } + + if (frame_ra < 0) { + if (state->first) { + state->sp =3D state->sp + frame_size; + goto first; + } + return false; + } + + if (state->first) + state->first =3D false; + + state->pc =3D *(unsigned long *)(state->sp + frame_ra); + state->sp =3D state->sp + frame_size; + return !!__kernel_text_address(state->pc); + +first: + state->first =3D false; + if (state->pc =3D=3D state->ra) + return false; + + state->pc =3D state->ra; + + return !!__kernel_text_address(state->ra); +} + +static bool unwind_by_guess(struct unwind_state *state) +{ + struct stack_info *info =3D &state->stack_info; + unsigned long addr; + + for (state->sp +=3D sizeof(unsigned long); + state->sp < info->end; + state->sp +=3D sizeof(unsigned long)) { + addr =3D *(unsigned long *)(state->sp); + if (__kernel_text_address(addr)) + return true; + } + + return false; +} + +void unwind_start(struct unwind_state *state, struct task_struct *task, + struct pt_regs *regs) +{ + memset(state, 0, sizeof(*state)); + + if ((regs) && __kernel_text_address(regs->csr_era)) { + state->type =3D UNWINDER_PROLOGUE; + state->pc =3D regs->csr_era; + state->sp =3D regs->regs[3]; + state->ra =3D regs->regs[1]; + } + + state->task =3D task; + state->first =3D true; + + get_stack_info(state->sp, state->task, &state->stack_info); + + if (!unwind_done(state) && !__kernel_text_address(state->pc)) + unwind_next_frame(state); +} +EXPORT_SYMBOL_GPL(unwind_start); + +bool unwind_next_frame(struct unwind_state *state) +{ + struct stack_info *info =3D &state->stack_info; + struct pt_regs *regs; + unsigned long pc; + + if (unwind_done(state)) + return false; + + do { + if (state->type) { + if (unwind_by_prologue(state)) + return true; + + if (info->type =3D=3D STACK_TYPE_IRQ && + info->end =3D=3D state->sp) { + regs =3D (struct pt_regs *)info->next_sp; + pc =3D regs->csr_era; + if (user_mode(regs) || !__kernel_text_address(pc)) + return false; + + state->pc =3D pc; + state->sp =3D regs->regs[3]; + state->ra =3D regs->regs[1]; + state->first =3D true; + get_stack_info(state->sp, state->task, info); + + return true; + } + } else { + if (state->first) + state->first =3D false; + else if (unwind_by_guess(state)) + return true; + } + + state->sp =3D info->next_sp; + + } while (!get_stack_info(state->sp, state->task, info)); + + return false; +} +EXPORT_SYMBOL_GPL(unwind_next_frame); --=20 2.20.1 From nobody Thu Apr 25 20:45:24 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8FF1C25B06 for ; Sat, 6 Aug 2022 08:10:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241700AbiHFIKs (ORCPT ); Sat, 6 Aug 2022 04:10:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57626 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S239213AbiHFIKR (ORCPT ); Sat, 6 Aug 2022 04:10:17 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C5DDFF53; Sat, 6 Aug 2022 01:10:13 -0700 (PDT) Received: from localhost.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxbyPdIe5ixooIAA--.1165S5; Sat, 06 Aug 2022 16:10:08 +0800 (CST) From: Qing Zhang To: Huacai Chen Cc: WANG Xuerui , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org, Jiaxun Yang , Arnd Bergmann , hejinyang@loongson.cn, tangyouling@loongson.cn, zhangqing@loongson.cn Subject: [PATCH v4 3/4] LoongArch: Add stacktrace and get_wchan support Date: Sat, 6 Aug 2022 16:10:04 +0800 Message-Id: <20220806081005.332-4-zhangqing@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20220806081005.332-1-zhangqing@loongson.cn> References: <20220806081005.332-1-zhangqing@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxbyPdIe5ixooIAA--.1165S5 X-Coremail-Antispam: 1UD129KBjvJXoWxtF43tFy5Zr18WrWkGryrXrb_yoWfKr4kpF 9rCwsrJr4jgw1I9r9xt395ur98twn2gw42gF9xta4rAF12qFyrXry8JasrZF4Yv3y8Ga1S qrn5K39rKan8JaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUPK14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JrWl82xGYIkIc2 x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1UM2 8EF7xvwVC2z280aVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_Cr1j6rxd M2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjx v20xvE14v26r106r15McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_Gr1l F7xvr2IYc2Ij64vIr41lF7I21c0EjII2zVCS5cI20VAGYxC7M4IIrI8v6xkF7I0E8cxan2 IY04v7MxkIecxEwVAFwVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8 JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1V AFwI0_Jw0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY6xII jxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4 A2jsIE14v26r1j6r4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU 0xZFpf9x0JUBWlkUUUUU= X-CM-SenderInfo: x2kd0wptlqwqxorr0wxvrqhubq/ Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" 1. Use common arch_stack_walk infrastructure to avoid duplicated code and avoid taking care of the stack storage and filtering. 2. Add sra (means sched return address) and scfa (means sched call frame address) to thread_info and store it in switch_to(). 3. Add get wchan implement. Now we can print the process stack and wait channel by cat /proc/*/stack and /proc/*/wchan. Signed-off-by: Qing Zhang --- arch/loongarch/Kconfig | 5 ++++ arch/loongarch/include/asm/processor.h | 9 +++++++ arch/loongarch/include/asm/switch_to.h | 14 ++++++---- arch/loongarch/kernel/Makefile | 1 + arch/loongarch/kernel/asm-offsets.c | 2 ++ arch/loongarch/kernel/process.c | 30 ++++++++++++++++++++- arch/loongarch/kernel/stacktrace.c | 37 ++++++++++++++++++++++++++ arch/loongarch/kernel/switch.S | 2 ++ 8 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 arch/loongarch/kernel/stacktrace.c diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index fc2465892a60..8143774f99cb 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -39,6 +39,7 @@ config LOONGARCH select ARCH_INLINE_SPIN_UNLOCK_IRQRESTORE if !PREEMPTION select ARCH_MIGHT_HAVE_PC_PARPORT select ARCH_MIGHT_HAVE_PC_SERIO + select ARCH_STACKWALK select ARCH_SPARSEMEM_ENABLE select ARCH_SUPPORTS_ACPI select ARCH_SUPPORTS_ATOMIC_RMW @@ -141,6 +142,10 @@ config LOCKDEP_SUPPORT bool default y =20 +config STACKTRACE_SUPPORT + bool + default y + # MACH_LOONGSON32 and MACH_LOONGSON64 are delibrately carried over from the # MIPS Loongson code, to preserve Loongson-specific code paths in drivers = that # are shared between architectures, and specifically expecting the symbols. diff --git a/arch/loongarch/include/asm/processor.h b/arch/loongarch/includ= e/asm/processor.h index 57ec45aa078e..1c4b4308378d 100644 --- a/arch/loongarch/include/asm/processor.h +++ b/arch/loongarch/include/asm/processor.h @@ -101,6 +101,10 @@ struct thread_struct { unsigned long reg23, reg24, reg25, reg26; /* s0-s3 */ unsigned long reg27, reg28, reg29, reg30, reg31; /* s4-s8 */ =20 + /* __schedule() return address / call frame address */ + unsigned long sched_ra; + unsigned long sched_cfa; + /* CSR registers */ unsigned long csr_prmd; unsigned long csr_crmd; @@ -129,6 +133,9 @@ struct thread_struct { struct loongarch_fpu fpu FPU_ALIGN; }; =20 +#define thread_saved_ra(tsk) (tsk->thread.sched_ra) +#define thread_saved_fp(tsk) (tsk->thread.sched_cfa) + #define INIT_THREAD { \ /* \ * Main processor registers \ @@ -145,6 +152,8 @@ struct thread_struct { .reg29 =3D 0, \ .reg30 =3D 0, \ .reg31 =3D 0, \ + .sched_ra =3D 0, \ + .sched_cfa =3D 0, \ .csr_crmd =3D 0, \ .csr_prmd =3D 0, \ .csr_euen =3D 0, \ diff --git a/arch/loongarch/include/asm/switch_to.h b/arch/loongarch/includ= e/asm/switch_to.h index 2a8d04375574..43a5ab162d38 100644 --- a/arch/loongarch/include/asm/switch_to.h +++ b/arch/loongarch/include/asm/switch_to.h @@ -15,12 +15,15 @@ struct task_struct; * @prev: The task previously executed. * @next: The task to begin executing. * @next_ti: task_thread_info(next). + * @sched_ra: __schedule return address. + * @sched_cfa: __schedule call frame address. * * This function is used whilst scheduling to save the context of prev & l= oad * the context of next. Returns prev. */ extern asmlinkage struct task_struct *__switch_to(struct task_struct *prev, - struct task_struct *next, struct thread_info *next_ti); + struct task_struct *next, struct thread_info *next_ti, + void *sched_ra, void *sched_cfa); =20 /* * For newly created kernel threads switch_to() will return to @@ -28,10 +31,11 @@ extern asmlinkage struct task_struct *__switch_to(struc= t task_struct *prev, * That is, everything following __switch_to() will be skipped for new thr= eads. * So everything that matters to new threads should be placed before __swi= tch_to(). */ -#define switch_to(prev, next, last) \ -do { \ - lose_fpu_inatomic(1, prev); \ - (last) =3D __switch_to(prev, next, task_thread_info(next)); \ +#define switch_to(prev, next, last) \ +do { \ + lose_fpu_inatomic(1, prev); \ + (last) =3D __switch_to(prev, next, task_thread_info(next), \ + __builtin_return_address(0), __builtin_frame_address(0)); \ } while (0) =20 #endif /* _ASM_SWITCH_TO_H */ diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index 918600e7b30f..7449513eb08d 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_EFI) +=3D efi.o obj-$(CONFIG_CPU_HAS_FPU) +=3D fpu.o =20 obj-$(CONFIG_MODULES) +=3D module.o module-sections.o +obj-$(CONFIG_STACKTRACE) +=3D stacktrace.o =20 obj-$(CONFIG_PROC_FS) +=3D proc.o =20 diff --git a/arch/loongarch/kernel/asm-offsets.c b/arch/loongarch/kernel/as= m-offsets.c index 20cd9e16a95a..eb350f3ffae5 100644 --- a/arch/loongarch/kernel/asm-offsets.c +++ b/arch/loongarch/kernel/asm-offsets.c @@ -103,6 +103,8 @@ void output_thread_defines(void) OFFSET(THREAD_REG29, task_struct, thread.reg29); OFFSET(THREAD_REG30, task_struct, thread.reg30); OFFSET(THREAD_REG31, task_struct, thread.reg31); + OFFSET(THREAD_SCHED_RA, task_struct, thread.sched_ra); + OFFSET(THREAD_SCHED_CFA, task_struct, thread.sched_cfa); OFFSET(THREAD_CSRCRMD, task_struct, thread.csr_crmd); OFFSET(THREAD_CSRPRMD, task_struct, diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/proces= s.c index 709b7a1664f8..d9dba725ef02 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -135,6 +135,7 @@ int copy_thread(struct task_struct *p, const struct ker= nel_clone_args *args) childregs =3D (struct pt_regs *) childksp - 1; /* Put the stack after the struct pt_regs. */ childksp =3D (unsigned long) childregs; + p->thread.sched_cfa =3D 0; p->thread.csr_euen =3D 0; p->thread.csr_crmd =3D csr_read32(LOONGARCH_CSR_CRMD); p->thread.csr_prmd =3D csr_read32(LOONGARCH_CSR_PRMD); @@ -145,6 +146,7 @@ int copy_thread(struct task_struct *p, const struct ker= nel_clone_args *args) p->thread.reg23 =3D (unsigned long)args->fn; p->thread.reg24 =3D (unsigned long)args->fn_arg; p->thread.reg01 =3D (unsigned long)ret_from_kernel_thread; + p->thread.sched_ra =3D (unsigned long)ret_from_kernel_thread; memset(childregs, 0, sizeof(struct pt_regs)); childregs->csr_euen =3D p->thread.csr_euen; childregs->csr_crmd =3D p->thread.csr_crmd; @@ -161,6 +163,7 @@ int copy_thread(struct task_struct *p, const struct ker= nel_clone_args *args) =20 p->thread.reg03 =3D (unsigned long) childregs; p->thread.reg01 =3D (unsigned long) ret_from_fork; + p->thread.sched_ra =3D (unsigned long) ret_from_fork; =20 /* * New tasks lose permission to use the fpu. This accelerates context @@ -181,9 +184,34 @@ int copy_thread(struct task_struct *p, const struct ke= rnel_clone_args *args) =20 unsigned long __get_wchan(struct task_struct *task) { - return 0; + unsigned long pc; + struct unwind_state state; + + if (!try_get_task_stack(task)) + return 0; + + unwind_start(&state, task, NULL); + state.sp =3D thread_saved_fp(task); + get_stack_info(state.sp, state.task, &state.stack_info); + state.pc =3D thread_saved_ra(task); +#ifdef CONFIG_UNWINDER_PROLOGUE + state.type =3D UNWINDER_PROLOGUE; +#endif + for ( ; !unwind_done(&state); unwind_next_frame(&state)) { + pc =3D unwind_get_return_address(&state); + if (!pc) + break; + if (in_sched_functions(pc)) + continue; + break; + } + + put_task_stack(task); + + return pc; } =20 + bool in_task_stack(unsigned long stack, struct task_struct *task, struct stack_info *info) { diff --git a/arch/loongarch/kernel/stacktrace.c b/arch/loongarch/kernel/sta= cktrace.c new file mode 100644 index 000000000000..f4f4b8ad3917 --- /dev/null +++ b/arch/loongarch/kernel/stacktrace.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Stack trace management functions + * + * Copyright (C) 2022 Loongson Technology Corporation Limited + */ +#include +#include + +#include +#include + +void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie, + struct task_struct *task, struct pt_regs *regs) +{ + struct pt_regs dummyregs; + struct unwind_state state; + unsigned long addr; + + regs =3D &dummyregs; + + if (task =3D=3D current) { + regs->csr_era =3D (unsigned long)__builtin_return_address(0); + regs->regs[3] =3D (unsigned long)__builtin_frame_address(0); + } else { + regs->csr_era =3D thread_saved_ra(task); + regs->regs[3] =3D thread_saved_fp(task); + } + + regs->regs[1] =3D 0; + for (unwind_start(&state, task, regs); + !unwind_done(&state); unwind_next_frame(&state)) { + addr =3D unwind_get_return_address(&state); + if (!addr || !consume_entry(cookie, addr)) + break; + } +} diff --git a/arch/loongarch/kernel/switch.S b/arch/loongarch/kernel/switch.S index 37e84ac8ffc2..43ebbc3990f7 100644 --- a/arch/loongarch/kernel/switch.S +++ b/arch/loongarch/kernel/switch.S @@ -21,6 +21,8 @@ SYM_FUNC_START(__switch_to) =20 cpu_save_nonscratch a0 stptr.d ra, a0, THREAD_REG01 + stptr.d a3, a0, THREAD_SCHED_RA + stptr.d a4, a0, THREAD_SCHED_CFA move tp, a2 cpu_restore_nonscratch a1 =20 --=20 2.20.1 From nobody Thu Apr 25 20:45:24 2024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2466EC25B06 for ; Sat, 6 Aug 2022 08:10:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S241695AbiHFIKd (ORCPT ); Sat, 6 Aug 2022 04:10:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:57604 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S238561AbiHFIKR (ORCPT ); Sat, 6 Aug 2022 04:10:17 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id CB21325E3; Sat, 6 Aug 2022 01:10:14 -0700 (PDT) Received: from localhost.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxbyPdIe5ixooIAA--.1165S6; Sat, 06 Aug 2022 16:10:08 +0800 (CST) From: Qing Zhang To: Huacai Chen Cc: WANG Xuerui , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org, Jiaxun Yang , Arnd Bergmann , hejinyang@loongson.cn, tangyouling@loongson.cn, zhangqing@loongson.cn Subject: [PATCH v4 4/4] LoongArch: Add USER_STACKTRACE support Date: Sat, 6 Aug 2022 16:10:05 +0800 Message-Id: <20220806081005.332-5-zhangqing@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20220806081005.332-1-zhangqing@loongson.cn> References: <20220806081005.332-1-zhangqing@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxbyPdIe5ixooIAA--.1165S6 X-Coremail-Antispam: 1UD129KBjvJXoWxCryUZw1rCF1DtrW5KFWxWFg_yoW5ZF4fpF nFy3ZxtrWUWw4Skr9xZrykXr98Xw4kG3y2gFZxta45Zr17Xry8WFs7tFyvqFyUJ393Ja4S ga43Krn0qF4DZa7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUmY14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF0E3s1l82xGYI kIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2 z4x0Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr 1UM28EF7xvwVC2z280aVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_Cr1j 6rxdM2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6x IIjxv20xvE14v26r106r15McIj6I8E87Iv67AKxVWUJVW8JwAm72CE4IkC6x0Yz7v_Jr0_ Gr1lF7xvr2IYc2Ij64vIr41lF7I21c0EjII2zVCS5cI20VAGYxC7M4IIrI8v6xkF7I0E8c xan2IY04v7MxkIecxEwVAFwVW8ZwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWU JVW8JwC20s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67 kF1VAFwI0_Jw0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY 6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1UMIIF0xvE42xK8VAvwI8IcIk0rVWUJVWUCwCI42 IY6I8E87Iv67AKxVWUJVW8JwCI42IY6I8E87Iv6xkF7I0E14v26r4j6r4UJbIYCTnIWIev Ja73UjIFyTuYvjfUYyxRDUUUU X-CM-SenderInfo: x2kd0wptlqwqxorr0wxvrqhubq/ Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" To get the best output you can compile your userspace programs with frame pointers (at least glibc + the app you are tracing export "CC =3Dgcc -fno-omit-frame-pointer". ... echo 'p:malloc /usr/lib64/libc.so.6:0x0a4704 size=3D%r4:u64' > uprobe_events echo 'p:free /usr/lib64/libc.so.6:0x0a4d50 ptr=3D%r4:x64' >> uprobe_events echo 'comm =3D=3D "demo"' > ./events/uprobes/malloc/filter echo 'comm =3D=3D "demo"' > ./events/uprobes/free/filter echo 1 > ./options/userstacktrace echo 1 > ./options/sym-userobj ... Signed-off-by: Qing Zhang --- arch/loongarch/Kconfig | 1 + arch/loongarch/include/asm/stacktrace.h | 5 +++ arch/loongarch/kernel/stacktrace.c | 41 +++++++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 8143774f99cb..9842fd023bcc 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -108,6 +108,7 @@ config LOONGARCH select SWIOTLB select TRACE_IRQFLAGS_SUPPORT select USE_PERCPU_NUMA_NODE_ID + select USER_STACKTRACE_SUPPORT select ZONE_DMA32 select MMU_GATHER_MERGE_VMAS if MMU =20 diff --git a/arch/loongarch/include/asm/stacktrace.h b/arch/loongarch/inclu= de/asm/stacktrace.h index 49cb89213aeb..77fdb8ad662d 100644 --- a/arch/loongarch/include/asm/stacktrace.h +++ b/arch/loongarch/include/asm/stacktrace.h @@ -21,6 +21,11 @@ struct stack_info { unsigned long begin, end, next_sp; }; =20 +struct stack_frame { + unsigned long fp; + unsigned long ra; +}; + bool in_task_stack(unsigned long stack, struct task_struct *task, struct stack_info *info); bool in_irq_stack(unsigned long stack, struct stack_info *info); diff --git a/arch/loongarch/kernel/stacktrace.c b/arch/loongarch/kernel/sta= cktrace.c index f4f4b8ad3917..cba1b6ab8a1a 100644 --- a/arch/loongarch/kernel/stacktrace.c +++ b/arch/loongarch/kernel/stacktrace.c @@ -6,6 +6,7 @@ */ #include #include +#include =20 #include #include @@ -35,3 +36,43 @@ void arch_stack_walk(stack_trace_consume_fn consume_entr= y, void *cookie, break; } } + +static int +copy_stack_frame(unsigned long fp, struct stack_frame *frame) +{ + int ret =3D 1; + unsigned long err; + unsigned long __user *user_frame_tail; + + user_frame_tail =3D (unsigned long *)(fp - sizeof(struct stack_frame)); + if (!access_ok(user_frame_tail, sizeof(*frame))) + return 0; + + pagefault_disable(); + err =3D (__copy_from_user_inatomic(frame, user_frame_tail, sizeof(*frame)= )); + if (err || (unsigned long)user_frame_tail >=3D frame->fp) + ret =3D 0; + pagefault_enable(); + + return ret; +} + +void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cook= ie, + const struct pt_regs *regs) +{ + unsigned long fp =3D regs->regs[22]; + + while (fp && !((unsigned long)fp & 0xf)) { + struct stack_frame frame; + + frame.fp =3D 0; + frame.ra =3D 0; + if (!copy_stack_frame(fp, &frame)) + break; + if (!frame.ra) + break; + if (!consume_entry(cookie, frame.ra)) + break; + fp =3D frame.fp; + } +} --=20 2.20.1