From nobody Sun Apr 12 02:49:43 2026 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 0851CC19F2A for ; Mon, 1 Aug 2022 12:38:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231464AbiHAMim (ORCPT ); Mon, 1 Aug 2022 08:38:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39408 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232212AbiHAMiU (ORCPT ); Mon, 1 Aug 2022 08:38:20 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7BC099EC62 for ; Mon, 1 Aug 2022 05:17:33 -0700 (PDT) Received: from localhost.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxAM9WxOdiKTUAAA--.1249S3; Mon, 01 Aug 2022 20:17:27 +0800 (CST) From: Qing Zhang To: Huacai Chen Cc: WANG Xuerui , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Jiaxun Yang , hejinyang@loongson.cn, zhangqing@loongson.cn Subject: [PATCH 1/4] LoongArch: Add guess unwinder support Date: Mon, 1 Aug 2022 20:17:23 +0800 Message-Id: <20220801121726.9681-2-zhangqing@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20220801121726.9681-1-zhangqing@loongson.cn> References: <20220801121726.9681-1-zhangqing@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxAM9WxOdiKTUAAA--.1249S3 X-Coremail-Antispam: 1UD129KBjvJXoW3Jr4fuFWktF1xGFyUur4kWFg_yoWfCr13pF 98C3Z3WrW5G34Igr9xXr18Zrn8Gr4kCw12gF9xtFyFkF12qFyfXrnaya4DZFs8J3ykW3Wx WF95KrZ8Ka1UXaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBI14x267AKxVW8JVW5JwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_Jr4l82xGYIkIc2 x26xkF7I0E14v26r1I6r4UM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_JFI_Gr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l84 ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_GcCE3s1le2I2 62IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcV AFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG 0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lc2xSY4AK67AK6ryUMxAIw28Icx kI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2Iq xVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUAVWUtwCIc40Y0x0EwIxGrwCI42 IY6xIIjxv20xvE14v26r1I6r4UMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY 6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aV CY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7VUUiF4tUUUUU== 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 | 22 ++++----- arch/loongarch/kernel/unwind_guess.c | 65 +++++++++++++++++++++++++ 7 files changed, 202 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..ef2c3aeb1dab 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,18 @@ 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; + + unwind_start(&state, task, pregs); =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_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..7eeb3e1a989d --- /dev/null +++ b/arch/loongarch/kernel/unwind_guess.c @@ -0,0 +1,65 @@ +// 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); + +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); + +void unwind_start(struct unwind_state *state, struct task_struct *task, + struct pt_regs *regs) +{ + memset(state, 0, sizeof(*state)); + + state->task =3D task; + + state->sp =3D regs->regs[3]; + state->pc =3D regs->csr_era; + 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); --=20 2.20.1 From nobody Sun Apr 12 02:49:43 2026 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 A8D46C00144 for ; Mon, 1 Aug 2022 12:38:55 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234798AbiHAMix (ORCPT ); Mon, 1 Aug 2022 08:38:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39404 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234737AbiHAMiV (ORCPT ); Mon, 1 Aug 2022 08:38:21 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C9F7F9EC6B for ; Mon, 1 Aug 2022 05:17:34 -0700 (PDT) Received: from localhost.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxAM9WxOdiKTUAAA--.1249S4; Mon, 01 Aug 2022 20:17:28 +0800 (CST) From: Qing Zhang To: Huacai Chen Cc: WANG Xuerui , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Jiaxun Yang , hejinyang@loongson.cn, zhangqing@loongson.cn Subject: [PATCH 2/4] LoongArch: Add prologue unwinder support Date: Mon, 1 Aug 2022 20:17:24 +0800 Message-Id: <20220801121726.9681-3-zhangqing@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20220801121726.9681-1-zhangqing@loongson.cn> References: <20220801121726.9681-1-zhangqing@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxAM9WxOdiKTUAAA--.1249S4 X-Coremail-Antispam: 1UD129KBjvJXoW3Gr43GF1xGFWUJw4rtw4UCFg_yoWfKw4fpF Z8Ar95Gr48Wr9agr9rXrs5urs5Grs29r12gFZxJw1rCF12qryxWrnYk34qvF4DJ3ykWF10 gFs5JrWagF4UJaDanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBI14x267AKxVW5JVWrJwAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_Jryl82xGYIkIc2 x26xkF7I0E14v26r4j6ryUM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l84 ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_GcCE3s1le2I2 62IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcV AFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG 0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lc2xSY4AK67AK6ryUMxAIw28Icx kI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2Iq xVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUAVWUtwCIc40Y0x0EwIxGrwCI42 IY6xIIjxv20xvE14v26r1I6r4UMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY 6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aV CY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7sRRv31JUUUUU== 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: unwind_frame, unwind_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 | 8 ++ arch/loongarch/kernel/Makefile | 1 + arch/loongarch/kernel/traps.c | 5 + arch/loongarch/kernel/unwind_prologue.c | 172 ++++++++++++++++++++++++ 6 files changed, 257 insertions(+) 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..f9f73a26504e 100644 --- a/arch/loongarch/include/asm/unwind.h +++ b/arch/loongarch/include/asm/unwind.h @@ -14,6 +14,14 @@ struct unwind_state { struct stack_info stack_info; struct task_struct *task; +#if defined(CONFIG_UNWINDER_PROLOGUE) + unsigned long ra; + bool enable; + /* + * Enable is the prologue analysis method + * otherwise is the way to guess. + */ +#endif unsigned long sp, pc; 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 ef2c3aeb1dab..3e904fa12d48 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -73,6 +73,11 @@ static void show_backtrace(struct task_struct *task, con= st struct pt_regs *regs, =20 unwind_start(&state, task, pregs); =20 +#ifdef CONFIG_UNWINDER_PROLOGUE + if (user_mode(regs)) + state.enable =3D false; +#endif + printk("%sCall Trace:", loglvl); for (; !unwind_done(&state); unwind_next_frame(&state)) { addr =3D unwind_get_return_address(&state); diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kerne= l/unwind_prologue.c new file mode 100644 index 000000000000..072d1f7bf4ac --- /dev/null +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -0,0 +1,172 @@ +// 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->enable) + 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; +} + +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->enable) { + 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); + +void unwind_start(struct unwind_state *state, struct task_struct *task, + struct pt_regs *regs) +{ + memset(state, 0, sizeof(*state)); + + if (__kernel_text_address(regs->csr_era)) + state->enable =3D true; + + state->task =3D task; + state->pc =3D regs->csr_era; + state->sp =3D regs->regs[3]; + state->ra =3D regs->regs[1]; + 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); --=20 2.20.1 From nobody Sun Apr 12 02:49:43 2026 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 6E2F1C00144 for ; Mon, 1 Aug 2022 12:39:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233610AbiHAMjC (ORCPT ); Mon, 1 Aug 2022 08:39:02 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40052 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232334AbiHAMiY (ORCPT ); Mon, 1 Aug 2022 08:38:24 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 514E49EC7D for ; Mon, 1 Aug 2022 05:17:35 -0700 (PDT) Received: from localhost.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxAM9WxOdiKTUAAA--.1249S5; Mon, 01 Aug 2022 20:17:29 +0800 (CST) From: Qing Zhang To: Huacai Chen Cc: WANG Xuerui , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Jiaxun Yang , hejinyang@loongson.cn, zhangqing@loongson.cn Subject: [PATCH 3/4] LoongArch: Add stacktrace support Date: Mon, 1 Aug 2022 20:17:25 +0800 Message-Id: <20220801121726.9681-4-zhangqing@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20220801121726.9681-1-zhangqing@loongson.cn> References: <20220801121726.9681-1-zhangqing@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxAM9WxOdiKTUAAA--.1249S5 X-Coremail-Antispam: 1UD129KBjvJXoW3JFyfGr4rZw4UJr13Gr4Uurg_yoWftFW3pF yDCwsrJr4I9r109FyDt345ur98twn7Ww4agF9xta4rAF12qFy5Xry8JasrZF4Yv3y8Ga1I qF1rK39rKFs8XaUanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBI14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JrWl82xGYIkIc2 x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l84 ACjcxK6I8E87Iv67AKxVW0oVCq3wA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_GcCE3s1le2I2 62IYc4CY6c8Ij28IcVAaY2xG8wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcV AFwI0_Jrv_JF1lYx0Ex4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG 0xvY0x0EwIxGrwACjI8F5VA0II8E6IAqYI8I648v4I1lc2xSY4AK67AK6ryUMxAIw28Icx kI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2Iq xVCjr7xvwVAFwI0_JrI_JrWlx4CE17CEb7AF67AKxVWUAVWUtwCIc40Y0x0EwIxGrwCI42 IY6xIIjxv20xvE14v26r1I6r4UMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY 6xAIw20EY4v20xvaj40_Jr0_JF4lIxAIcVC2z280aVAFwI0_Jr0_Gr1lIxAIcVC2z280aV CY1x0267AKxVW8JVW8JrUvcSsGvfC2KfnxnUUI43ZEXa7VUjhZ23UUUUU== X-CM-SenderInfo: x2kd0wptlqwqxorr0wxvrqhubq/ Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" Use common arch_stack_walk infrastructure to avoid duplicated code and avoid taking care of the stack storage and filtering. Add sra (means __schedule return address) and scfa (means __schedule call frame address) to thread_info and store it in switch_to(). Now we can print the process stack by cat /proc/*/stack and can better support ftrace. Signed-off-by: Qing Zhang Reported-by: kernel test robot --- arch/loongarch/Kconfig | 5 ++++ arch/loongarch/include/asm/processor.h | 9 +++++++ arch/loongarch/include/asm/switch_to.h | 14 ++++++---- arch/loongarch/include/asm/uaccess.h | 4 +-- arch/loongarch/kernel/Makefile | 1 + arch/loongarch/kernel/asm-offsets.c | 2 ++ arch/loongarch/kernel/process.c | 3 +++ arch/loongarch/kernel/stacktrace.c | 37 ++++++++++++++++++++++++++ arch/loongarch/kernel/switch.S | 2 ++ 9 files changed, 70 insertions(+), 7 deletions(-) create mode 100644 arch/loongarch/kernel/stacktrace.c diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 62b5b07fa4e1..85d0fa3147cd 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -38,6 +38,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 @@ -140,6 +141,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/include/asm/uaccess.h b/arch/loongarch/include/= asm/uaccess.h index 2b44edc604a2..a8ae2af4025a 100644 --- a/arch/loongarch/include/asm/uaccess.h +++ b/arch/loongarch/include/asm/uaccess.h @@ -229,13 +229,13 @@ extern unsigned long __copy_user(void *to, const void= *from, __kernel_size_t n); static inline unsigned long __must_check raw_copy_from_user(void *to, const void __user *from, unsigned long n) { - return __copy_user(to, from, n); + return __copy_user(to, (__force const void *)from, n); } =20 static inline unsigned long __must_check raw_copy_to_user(void __user *to, const void *from, unsigned long n) { - return __copy_user(to, from, n); + return __copy_user((__force void *)to, from, n); } =20 #define INLINE_COPY_FROM_USER 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..34c3f2148714 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 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 Sun Apr 12 02:49:43 2026 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 F2A6AC19F2A for ; Mon, 1 Aug 2022 12:39:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233317AbiHAMjE (ORCPT ); Mon, 1 Aug 2022 08:39:04 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37606 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232374AbiHAMiY (ORCPT ); Mon, 1 Aug 2022 08:38:24 -0400 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 10BD29F045 for ; Mon, 1 Aug 2022 05:17:36 -0700 (PDT) Received: from localhost.localdomain (unknown [113.200.148.30]) by mail.loongson.cn (Coremail) with SMTP id AQAAf9DxAM9WxOdiKTUAAA--.1249S6; Mon, 01 Aug 2022 20:17:30 +0800 (CST) From: Qing Zhang To: Huacai Chen Cc: WANG Xuerui , loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Jiaxun Yang , hejinyang@loongson.cn, zhangqing@loongson.cn Subject: [PATCH 4/4] LoongArch: Add USER_STACKTRACE support Date: Mon, 1 Aug 2022 20:17:26 +0800 Message-Id: <20220801121726.9681-5-zhangqing@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20220801121726.9681-1-zhangqing@loongson.cn> References: <20220801121726.9681-1-zhangqing@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf9DxAM9WxOdiKTUAAA--.1249S6 X-Coremail-Antispam: 1UD129KBjvJXoWxCryUZw1rCF1DtrW5KFWxWFg_yoW5ZFy5pF nFy3ZxtrWUWw4Skr9xZry8Xr98Jw4kG3y2gFZxta45Zr17Xry8Xr4IyFyvqFyUJ393Ja4S ga43Kr1qqF4DZa7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDU0xBIdaVrnRJUUUBv14x267AKxVWrJVCq3wAFc2x0x2IEx4CE42xK8VAvwI8IcIk0 rVWrJVCq3wAFIxvE14AKwVWUJVWUGwA2048vs2IY020E87I2jVAFwI0_JF0E3s1l82xGYI kIc2x26xkF7I0E14v26ryj6s0DM28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2 z4x0Y4vE2Ix0cI8IcVAFwI0_Gr0_Xr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr 1UM28EF7xvwVC2z280aVAFwI0_GcCE3s1l84ACjcxK6I8E87Iv6xkF7I0E14v26rxl6s0D M2AIxVAIcxkEcVAq07x20xvEncxIr21l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjx v20xvE14v26r1Y6r17McIj6I8E87Iv67AKxVW8JVWxJwAm72CE4IkC6x0Yz7v_Jr0_Gr1l F7xvr2IYc2Ij64vIr41lF7I21c0EjII2zVCS5cI20VAGYxC7MxkIecxEwVAFwVW5JwCF04 k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwC20s026c02F40E14v26r1j6r18 MI8I3I0E7480Y4vE14v26r106r1rMI8E67AF67kF1VAFwI0_JF0_Jw1lIxkGc2Ij64vIr4 1lIxAIcVC0I7IYx2IY67AKxVWUCVW8JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1l IxAIcVCF04k26cxKx2IYs7xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r1j6r4UMIIF0xvEx4 A2jsIEc7CjxVAFwI0_Gr0_Gr1UYxBIdaVFxhVjvjDU0xZFpf9x0JUseOJUUUUU= 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 | 42 +++++++++++++++++++++++++ 3 files changed, 48 insertions(+) diff --git a/arch/loongarch/Kconfig b/arch/loongarch/Kconfig index 85d0fa3147cd..05906384d564 100644 --- a/arch/loongarch/Kconfig +++ b/arch/loongarch/Kconfig @@ -107,6 +107,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..344224c7cb0e 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,44 @@ 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; + 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; + + ret =3D 1; + 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