From nobody Tue Sep 16 20:07:42 2025 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 94948C4708D for ; Thu, 29 Dec 2022 06:16:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232778AbiL2GPw (ORCPT ); Thu, 29 Dec 2022 01:15:52 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33110 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229685AbiL2GPq (ORCPT ); Thu, 29 Dec 2022 01:15:46 -0500 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 8F29CB0F for ; Wed, 28 Dec 2022 22:15:44 -0800 (PST) Received: from loongson.cn (unknown [111.9.175.10]) by gateway (Coremail) with SMTP id _____8AxDOuPMK1jJDMJAA--.20485S3; Thu, 29 Dec 2022 14:15:43 +0800 (CST) Received: from localhost.localdomain (unknown [111.9.175.10]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Dxrb6OMK1jIiYPAA--.24618S3; Thu, 29 Dec 2022 14:15:43 +0800 (CST) From: Jinyang He To: Huacai Chen , WANG Xuerui , Qing Zhang Cc: loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Steven Rostedt , Masami Hiramatsu , Mark Rutland Subject: [PATCH v2 1/6] LoongArch: Get frame info in unwind_start when regs is not supported Date: Thu, 29 Dec 2022 14:15:12 +0800 Message-Id: <20221229061516.31671-2-hejinyang@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20221229061516.31671-1-hejinyang@loongson.cn> References: <20221229061516.31671-1-hejinyang@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf8Dxrb6OMK1jIiYPAA--.24618S3 X-CM-SenderInfo: pkhmx0p1dqwqxorr0wxvrqhubq/ X-Coremail-Antispam: 1Uk129KBjvJXoWxCr1rKFykXr47urWrCrWktFb_yoW5Zw13p3 9xCrs3Wr45uF9Fqr9rtw1kZr95Grn7uw12gF9rJ34rC3W7XFyxuwnYv34DZan0y3yvgw10 qFn5KrW5Ka1UJaUanT9S1TB71UUUUjUqnTZGkaVYY2UrUUUUj1kv1TuYvTs0mT0YCTnIWj qI5I8CrVACY4xI64kE6c02F40Ex7xfYxn0WfASr-VFAUDa7-sFnT9fnUUIcSsGvfJTRUUU bSxYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20xvaj40_Wr0E3s 1l1IIY67AEw4v_Jrv_JF1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxSw2x7M28EF7xv wVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwA2z4 x0Y4vEx4A2jsIE14v26r4UJVWxJr1l84ACjcxK6I8E87Iv6xkF7I0E14v26r4UJVWxJr1l n4kS14v26r1Y6r17M2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6x ACxx1l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1q6rW5McIj6I8E 87Iv67AKxVW8JVWxJwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lc7CjxV Aaw2AFwI0_JF0_Jw1l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1l4IxY O2xFxVAFwI0_Jrv_JF1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGV WUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_ Gr0_Xr1lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8VAvwI8IcIk0rV WUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I8E87Iv6xkF7I0E14v26r4j6r4U JbIYCTnIWIevJa73UjIFyTuYvjxUxhiSDUUUU Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" At unwind_start, it is better to try to get its frame info even we not support regs rather than get them outside. So that we can simply use unwind_{start, next_frame, done} outside. Signed-off-by: Jinyang He --- arch/loongarch/kernel/process.c | 12 +++--------- arch/loongarch/kernel/unwind_guess.c | 6 ++++++ arch/loongarch/kernel/unwind_prologue.c | 16 +++++++++++++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/arch/loongarch/kernel/process.c b/arch/loongarch/kernel/proces= s.c index 502b8b950057..6ef45174ad35 100644 --- a/arch/loongarch/kernel/process.c +++ b/arch/loongarch/kernel/process.c @@ -197,20 +197,14 @@ int copy_thread(struct task_struct *p, const struct k= ernel_clone_args *args) =20 unsigned long __get_wchan(struct task_struct *task) { - unsigned long pc; + unsigned long pc =3D 0; struct unwind_state state; =20 if (!try_get_task_stack(task)) return 0; =20 - 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)) { + for (unwind_start(&state, task, NULL); !unwind_done(&state); + unwind_next_frame(&state)) { pc =3D unwind_get_return_address(&state); if (!pc) break; diff --git a/arch/loongarch/kernel/unwind_guess.c b/arch/loongarch/kernel/u= nwind_guess.c index e2d2e4f3001f..a1bc7c852000 100644 --- a/arch/loongarch/kernel/unwind_guess.c +++ b/arch/loongarch/kernel/unwind_guess.c @@ -26,6 +26,12 @@ void unwind_start(struct unwind_state *state, struct tas= k_struct *task, if (regs) { state->sp =3D regs->regs[3]; state->pc =3D regs->csr_era; + } else if (task =3D=3D current || task =3D=3D NULL) { + state->sp =3D (unsigned long)__builtin_frame_address(0); + state->pc =3D (unsigned long)__builtin_return_address(0); + } else { + state->sp =3D thread_saved_fp(task); + state->pc =3D thread_saved_ra(task); } =20 state->task =3D task; diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kerne= l/unwind_prologue.c index 0f8d1451ebb8..b8b830b69a48 100644 --- a/arch/loongarch/kernel/unwind_prologue.c +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -141,12 +141,22 @@ void unwind_start(struct unwind_state *state, struct = task_struct *task, struct pt_regs *regs) { memset(state, 0, sizeof(*state)); + state->type =3D UNWINDER_PROLOGUE; =20 - if (regs && __kernel_text_address(regs->csr_era)) { - state->pc =3D regs->csr_era; + if (regs) { state->sp =3D regs->regs[3]; + state->pc =3D regs->csr_era; state->ra =3D regs->regs[1]; - state->type =3D UNWINDER_PROLOGUE; + if (!__kernel_text_address(state->pc)) + state->type =3D UNWINDER_GUESS; + } else if (task =3D=3D current || task =3D=3D NULL) { + state->sp =3D (unsigned long)__builtin_frame_address(0); + state->pc =3D (unsigned long)__builtin_return_address(0); + state->ra =3D 0; + } else { + state->sp =3D thread_saved_fp(task); + state->pc =3D thread_saved_ra(task); + state->ra =3D 0; } =20 state->task =3D task; --=20 2.34.3 From nobody Tue Sep 16 20:07:42 2025 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 6D4A1C3DA79 for ; Thu, 29 Dec 2022 06:16:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232883AbiL2GPz (ORCPT ); Thu, 29 Dec 2022 01:15:55 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33116 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230335AbiL2GPr (ORCPT ); Thu, 29 Dec 2022 01:15:47 -0500 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A76CB1020 for ; Wed, 28 Dec 2022 22:15:45 -0800 (PST) Received: from loongson.cn (unknown [111.9.175.10]) by gateway (Coremail) with SMTP id _____8DxtfCQMK1jKjMJAA--.20047S3; Thu, 29 Dec 2022 14:15:44 +0800 (CST) Received: from localhost.localdomain (unknown [111.9.175.10]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Dxrb6OMK1jIiYPAA--.24618S4; Thu, 29 Dec 2022 14:15:43 +0800 (CST) From: Jinyang He To: Huacai Chen , WANG Xuerui , Qing Zhang Cc: loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Steven Rostedt , Masami Hiramatsu , Mark Rutland Subject: [PATCH v2 2/6] LoongArch: Use correct sp value to get graph addr in unwinder guess Date: Thu, 29 Dec 2022 14:15:13 +0800 Message-Id: <20221229061516.31671-3-hejinyang@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20221229061516.31671-1-hejinyang@loongson.cn> References: <20221229061516.31671-1-hejinyang@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf8Dxrb6OMK1jIiYPAA--.24618S4 X-CM-SenderInfo: pkhmx0p1dqwqxorr0wxvrqhubq/ X-Coremail-Antispam: 1Uk129KBjvJXoW3Gw1fAFWUCF43CF43XFWfuFg_yoWxJr4kpF 9xCas3GrWxWryqgrnrXr1jvrn5Crn2kw12gFyDJ34FkFnrXry3Grn0v3yqvF4DJ3y8Wr48 XFn5GrW5KanrG3JanT9S1TB71UUUUjUqnTZGkaVYY2UrUUUUj1kv1TuYvTs0mT0YCTnIWj qI5I8CrVACY4xI64kE6c02F40Ex7xfYxn0WfASr-VFAUDa7-sFnT9fnUUIcSsGvfJTRUUU bSxYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20xvaj40_Wr0E3s 1l1IIY67AEw4v_Jrv_JF1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxSw2x7M28EF7xv wVC0I7IYx2IY67AKxVW5JVW7JwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwA2z4 x0Y4vEx4A2jsIE14v26r4UJVWxJr1l84ACjcxK6I8E87Iv6xkF7I0E14v26r4UJVWxJr1l n4kS14v26r1Y6r17M2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6x ACxx1l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1q6rW5McIj6I8E 87Iv67AKxVW8JVWxJwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lc7CjxV Aaw2AFwI0_JF0_Jw1l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1l4IxY O2xFxVAFwI0_Jrv_JF1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGV WUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_ Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8VAvwI8IcIk0rV WUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I8E87Iv6xkF7I0E14v26r4j6r4U JbIYCTnIWIevJa73UjIFyTuYvjxUxhiSDUUUU Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The stack frame when function_graph enable like follows, --------- <- function sp_on_entry | | | FAKE_RA <- sp_on_entry - sizeof(pt_regs) + PT_R1 | --------- <- sp_on_entry - sizeof(pt_regs) So if we want to get the &FAKE_RA we should get sp_on_entry first. In unwinder_prologue case, we can get the sp_on_entry as state->sp, because we try to calculate each CFA and the ra saved address. But in unwinder_guess case, we cannot get it because we do not try to calculate the CFA. Although LoongArch have not fixed frame, the $ra is saved at CFA - 8 in most cases, we can try guess, too. As we store the pc in state, we not need to dereference state->sp, too. Signed-off-by: Jinyang He --- arch/loongarch/include/asm/ftrace.h | 2 -- arch/loongarch/include/asm/unwind.h | 9 +++++++++ arch/loongarch/kernel/unwind_guess.c | 12 ++++-------- arch/loongarch/kernel/unwind_prologue.c | 22 ++++++---------------- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/arch/loongarch/include/asm/ftrace.h b/arch/loongarch/include/a= sm/ftrace.h index 90f9d3399b2a..3418d32d4fc7 100644 --- a/arch/loongarch/include/asm/ftrace.h +++ b/arch/loongarch/include/asm/ftrace.h @@ -10,8 +10,6 @@ #define FTRACE_REGS_PLT_IDX 1 #define NR_FTRACE_PLTS 2 =20 -#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_reg= s, regs[1])) - #ifdef CONFIG_FUNCTION_TRACER =20 #define MCOUNT_INSN_SIZE 4 /* sizeof mcount call */ diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/a= sm/unwind.h index f2b52b9ea93d..6ece48f0ff77 100644 --- a/arch/loongarch/include/asm/unwind.h +++ b/arch/loongarch/include/asm/unwind.h @@ -7,8 +7,10 @@ #ifndef _ASM_UNWIND_H #define _ASM_UNWIND_H =20 +#include #include =20 +#include #include =20 enum unwinder_type { @@ -40,4 +42,11 @@ static inline bool unwind_error(struct unwind_state *sta= te) return state->error; } =20 +#define GRAPH_FAKE_OFFSET (sizeof(struct pt_regs) - offsetof(struct pt_reg= s, regs[1])) +static inline unsigned long unwind_graph_addr(struct unwind_state *state, + unsigned long pc, unsigned long cfa) +{ + return ftrace_graph_ret_addr(state->task, &state->graph_idx, + pc, (unsigned long *)(cfa - GRAPH_FAKE_OFFSET)); +} #endif /* _ASM_UNWIND_H */ diff --git a/arch/loongarch/kernel/unwind_guess.c b/arch/loongarch/kernel/u= nwind_guess.c index a1bc7c852000..935d24f8c95c 100644 --- a/arch/loongarch/kernel/unwind_guess.c +++ b/arch/loongarch/kernel/unwind_guess.c @@ -11,10 +11,7 @@ unsigned long unwind_get_return_address(struct unwind_st= ate *state) { if (unwind_done(state)) return 0; - else if (state->first) - return state->pc; - - return *(unsigned long *)(state->sp); + return state->pc; } EXPORT_SYMBOL_GPL(unwind_get_return_address); =20 @@ -36,7 +33,7 @@ void unwind_start(struct unwind_state *state, struct task= _struct *task, =20 state->task =3D task; state->first =3D true; - + state->pc =3D unwind_graph_addr(state, state->pc, state->sp); get_stack_info(state->sp, state->task, &state->stack_info); =20 if (!unwind_done(state) && !__kernel_text_address(state->pc)) @@ -60,9 +57,8 @@ bool unwind_next_frame(struct unwind_state *state) state->sp < info->end; state->sp +=3D sizeof(unsigned long)) { addr =3D *(unsigned long *)(state->sp); - state->pc =3D ftrace_graph_ret_addr(state->task, &state->graph_idx, - addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); - if (__kernel_text_address(addr)) + state->pc =3D unwind_graph_addr(state, addr, state->sp + 8); + if (__kernel_text_address(state->pc)) return true; } =20 diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kerne= l/unwind_prologue.c index b8b830b69a48..3fbb9c65d64e 100644 --- a/arch/loongarch/kernel/unwind_prologue.c +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -21,16 +21,9 @@ static inline void unwind_state_fixup(struct unwind_stat= e *state) =20 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); - + return state->pc; } EXPORT_SYMBOL_GPL(unwind_get_return_address); =20 @@ -43,9 +36,8 @@ static bool unwind_by_guess(struct unwind_state *state) state->sp < info->end; state->sp +=3D sizeof(unsigned long)) { addr =3D *(unsigned long *)(state->sp); - state->pc =3D ftrace_graph_ret_addr(state->task, &state->graph_idx, - addr, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); - if (__kernel_text_address(addr)) + state->pc =3D unwind_graph_addr(state, addr, state->sp + 8); + if (__kernel_text_address(state->pc)) return true; } =20 @@ -161,7 +153,7 @@ void unwind_start(struct unwind_state *state, struct ta= sk_struct *task, =20 state->task =3D task; state->first =3D true; - + state->pc =3D unwind_graph_addr(state, state->pc, state->sp); get_stack_info(state->sp, state->task, &state->stack_info); =20 if (!unwind_done(state) && !__kernel_text_address(state->pc)) @@ -188,8 +180,7 @@ bool unwind_next_frame(struct unwind_state *state) =20 case UNWINDER_PROLOGUE: if (unwind_by_prologue(state)) { - state->pc =3D ftrace_graph_ret_addr(state->task, &state->graph_idx, - state->pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); + state->pc =3D unwind_graph_addr(state, state->pc, state->sp); return true; } =20 @@ -204,8 +195,7 @@ bool unwind_next_frame(struct unwind_state *state) state->first =3D true; state->ra =3D regs->regs[1]; state->sp =3D regs->regs[3]; - state->pc =3D ftrace_graph_ret_addr(state->task, &state->graph_idx, - pc, (unsigned long *)(state->sp - GRAPH_FAKE_OFFSET)); + state->pc =3D pc; get_stack_info(state->sp, state->task, info); =20 return true; --=20 2.34.3 From nobody Tue Sep 16 20:07:42 2025 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 B9D0BC4708E for ; Thu, 29 Dec 2022 06:16:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232939AbiL2GP6 (ORCPT ); Thu, 29 Dec 2022 01:15:58 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33122 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232179AbiL2GPs (ORCPT ); Thu, 29 Dec 2022 01:15:48 -0500 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 162775FAE for ; Wed, 28 Dec 2022 22:15:46 -0800 (PST) Received: from loongson.cn (unknown [111.9.175.10]) by gateway (Coremail) with SMTP id _____8DxdPCRMK1jMDMJAA--.20548S3; Thu, 29 Dec 2022 14:15:45 +0800 (CST) Received: from localhost.localdomain (unknown [111.9.175.10]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Dxrb6OMK1jIiYPAA--.24618S5; Thu, 29 Dec 2022 14:15:44 +0800 (CST) From: Jinyang He To: Huacai Chen , WANG Xuerui , Qing Zhang Cc: loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Steven Rostedt , Masami Hiramatsu , Mark Rutland Subject: [PATCH v2 3/6] LoongArch: Adjust PC value when unwind next frame in prologue unwinder Date: Thu, 29 Dec 2022 14:15:14 +0800 Message-Id: <20221229061516.31671-4-hejinyang@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20221229061516.31671-1-hejinyang@loongson.cn> References: <20221229061516.31671-1-hejinyang@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf8Dxrb6OMK1jIiYPAA--.24618S5 X-CM-SenderInfo: pkhmx0p1dqwqxorr0wxvrqhubq/ X-Coremail-Antispam: 1Uk129KBjvJXoW7ZryUAFyftF47urWUCry8Zrb_yoW8JFy8pr Z3ArZ5Gr40qr13G39rtr4DuF95CrykCr42gFZrtry8u3Z0qFn7uFn09r909anYq34kJr10 q3WFg3yakF4UJw7anT9S1TB71UUUUjUqnTZGkaVYY2UrUUUUj1kv1TuYvTs0mT0YCTnIWj qI5I8CrVACY4xI64kE6c02F40Ex7xfYxn0WfASr-VFAUDa7-sFnT9fnUUIcSsGvfJTRUUU bSxYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20xvaj40_Wr0E3s 1l1IIY67AEw4v_Jrv_JF1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxSw2x7M28EF7xv wVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwA2z4 x0Y4vEx4A2jsIE14v26r4UJVWxJr1l84ACjcxK6I8E87Iv6xkF7I0E14v26r4UJVWxJr1l n4kS14v26r1Y6r17M2AIxVAIcxkEcVAq07x20xvEncxIr21l57IF6xkI12xvs2x26I8E6x ACxx1l5I8CrVACY4xI64kE6c02F40Ex7xfMcIj6xIIjxv20xvE14v26r1q6rW5McIj6I8E 87Iv67AKxVW8JVWxJwAm72CE4IkC6x0Yz7v_Jr0_Gr1lF7xvr2IYc2Ij64vIr41lc7CjxV Aaw2AFwI0_JF0_Jw1l42xK82IYc2Ij64vIr41l4I8I3I0E4IkC6x0Yz7v_Jr0_Gr1l4IxY O2xFxVAFwI0_Jrv_JF1lx2IqxVAqx4xG67AKxVWUJVWUGwC20s026x8GjcxK67AKxVWUGV WUWwC2zVAF1VAY17CE14v26r1q6r43MIIYrxkI7VAKI48JMIIF0xvE2Ix0cI8IcVAFwI0_ Xr0_Ar1lIxAIcVC0I7IYx2IY6xkF7I0E14v26r4j6F4UMIIF0xvE42xK8VAvwI8IcIk0rV WUJVWUCwCI42IY6I8E87Iv67AKxVW8JVWxJwCI42IY6I8E87Iv6xkF7I0E14v26r4j6r4U JbIYCTnIWIevJa73UjIFyTuYvjxUxhiSDUUUU Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" When state->first is not set, the PC is a return address in the previous frame. We need to adjust it value in case overflow to the next symbol. Signed-off-by: Jinyang He --- arch/loongarch/kernel/unwind_prologue.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kerne= l/unwind_prologue.c index 3fbb9c65d64e..f7994ed05f04 100644 --- a/arch/loongarch/kernel/unwind_prologue.c +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -48,7 +48,7 @@ static bool unwind_by_prologue(struct unwind_state *state) { long frame_ra =3D -1; unsigned long frame_size =3D 0; - unsigned long size, offset, pc =3D state->pc; + unsigned long size, offset, pc; struct pt_regs *regs; struct stack_info *info =3D &state->stack_info; union loongarch_instruction *ip, *ip_end; @@ -70,6 +70,10 @@ static bool unwind_by_prologue(struct unwind_state *stat= e) return true; } =20 + /* When first is not set, the PC is a return address in the previous fram= e. + * We need to adjust it value in case overflow to the next symbol. + */ + pc =3D state->pc - (state->first ? 0 : LOONGARCH_INSN_SIZE); if (!kallsyms_lookup_size_offset(pc, &size, &offset)) return false; =20 --=20 2.34.3 From nobody Tue Sep 16 20:07:42 2025 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 CAA7DC5479D for ; Thu, 29 Dec 2022 06:16:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232963AbiL2GQC (ORCPT ); Thu, 29 Dec 2022 01:16:02 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33134 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232624AbiL2GPu (ORCPT ); Thu, 29 Dec 2022 01:15:50 -0500 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7498865AB for ; Wed, 28 Dec 2022 22:15:48 -0800 (PST) Received: from loongson.cn (unknown [111.9.175.10]) by gateway (Coremail) with SMTP id _____8AxxvCSMK1jNjMJAA--.19829S3; Thu, 29 Dec 2022 14:15:46 +0800 (CST) Received: from localhost.localdomain (unknown [111.9.175.10]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Dxrb6OMK1jIiYPAA--.24618S6; Thu, 29 Dec 2022 14:15:46 +0800 (CST) From: Jinyang He To: Huacai Chen , WANG Xuerui , Qing Zhang Cc: loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Steven Rostedt , Masami Hiramatsu , Mark Rutland Subject: [PATCH v2 4/6] LoongArch: Strip guess_unwinder out from prologue_unwinder Date: Thu, 29 Dec 2022 14:15:15 +0800 Message-Id: <20221229061516.31671-5-hejinyang@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20221229061516.31671-1-hejinyang@loongson.cn> References: <20221229061516.31671-1-hejinyang@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf8Dxrb6OMK1jIiYPAA--.24618S6 X-CM-SenderInfo: pkhmx0p1dqwqxorr0wxvrqhubq/ X-Coremail-Antispam: 1Uk129KBjvAXoW3KrykCw4fZF45GF1xZrWUurg_yoW8Gry7Xo WSyF4agrW8X3y5t3yjyryUtFyYgr4jka1DA3y3trn8WF42y343urWjqasxJFyIqwn5KrWU Cr42gF4rXan7Arn3n29KB7ZKAUJUUUU7529EdanIXcx71UUUUU7KY7ZEXasCq-sGcSsGvf J3Ic02F40EFcxC0VAKzVAqx4xG6I80ebIjqfuFe4nvWSU5nxnvy29KBjDU0xBIdaVrnRJU UUBab4IE77IF4wAFF20E14v26r1j6r4UM7CY07I20VC2zVCF04k26cxKx2IYs7xG6rWj6s 0DM7CIcVAFz4kK6r1Y6r17M28lY4IEw2IIxxk0rwA2F7IY1VAKz4vEj48ve4kI8wA2z4x0 Y4vE2Ix0cI8IcVAFwI0_Ar0_tr1l84ACjcxK6xIIjxv20xvEc7CjxVAFwI0_Cr0_Gr1UM2 8EF7xvwVC2z280aVAFwI0_Gr1j6F4UJwA2z4x0Y4vEx4A2jsIEc7CjxVAFwI0_Gr1j6F4U JwAaw2AFwI0_Jrv_JF1le2I262IYc4CY6c8Ij28IcVAaY2xG8wAqjxCEc2xF0cIa020Ex4 CE44I27wAqx4xG64xvF2IEw4CE5I8CrVC2j2WlYx0E2Ix0cI8IcVAFwI0_Wrv_ZF1lYx0E x4A2jsIE14v26r4j6F4UMcvjeVCFs4IE7xkEbVWUJVW8JwACjcxG0xvY0x0EwIxGrwCY1x 0262kKe7AKxVWUAVWUtwCF04k20xvY0x0EwIxGrwCFx2IqxVCFs4IE7xkEbVWUJVW8JwCF I7km07C267AKxVWUXVWUAwC20s026c02F40E14v26r1j6r18MI8I3I0E7480Y4vE14v26r 106r1rMI8E67AF67kF1VAFwI0_Jw0_GFylIxkGc2Ij64vIr41lIxAIcVC0I7IYx2IY67AK xVW5JVW7JwCI42IY6xIIjxv20xvEc7CjxVAFwI0_Gr0_Cr1lIxAIcVCF04k26cxKx2IYs7 xG6r1j6r1xMIIF0xvEx4A2jsIE14v26r4j6F4UMIIF0xvEx4A2jsIEc7CjxVAFwI0_Gr0_ Gr1UYxBIdaVFxhVjvjDU0xZFpf9x07jqRRiUUUUU= Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" The prolugue unwinder rely on symbol info. When PC is not in kernel text address, it cannot find relative symbol info and it will be broken. The guess unwinder will be used in this case. And the guess unwinder codes in prolugue unwinder is redundant. Strip it out and set the unwinder info in unwind_state. Signed-off-by: Jinyang He --- arch/loongarch/include/asm/unwind.h | 26 ++++- arch/loongarch/kernel/Makefile | 3 +- arch/loongarch/kernel/traps.c | 3 - arch/loongarch/kernel/unwind.c | 52 +++++++++ arch/loongarch/kernel/unwind_guess.c | 41 ++------ arch/loongarch/kernel/unwind_prologue.c | 133 +++++++++--------------- 6 files changed, 132 insertions(+), 126 deletions(-) create mode 100644 arch/loongarch/kernel/unwind.c diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/a= sm/unwind.h index 6ece48f0ff77..4a55fd7b77ad 100644 --- a/arch/loongarch/include/asm/unwind.h +++ b/arch/loongarch/include/asm/unwind.h @@ -13,20 +13,30 @@ #include #include =20 -enum unwinder_type { - UNWINDER_GUESS, - UNWINDER_PROLOGUE, -}; +struct unwinder_ops; =20 struct unwind_state { - char type; /* UNWINDER_XXX */ struct stack_info stack_info; struct task_struct *task; bool first, error, is_ftrace; int graph_idx; unsigned long sp, pc, ra; + const struct unwinder_ops *ops; +}; + +struct unwinder_ops { + 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); }; =20 +extern const struct unwinder_ops *default_unwinder; +extern const struct unwinder_ops unwinder_guess; +#ifdef CONFIG_UNWINDER_PROLOGUE +extern const struct unwinder_ops unwinder_prologue; +#endif + void unwind_start(struct unwind_state *state, struct task_struct *task, struct pt_regs *regs); bool unwind_next_frame(struct unwind_state *state); @@ -49,4 +59,10 @@ static inline unsigned long unwind_graph_addr(struct unw= ind_state *state, return ftrace_graph_ret_addr(state->task, &state->graph_idx, pc, (unsigned long *)(cfa - GRAPH_FAKE_OFFSET)); } + +static inline void unwind_register_unwinder(struct unwind_state *state, + const struct unwinder_ops *unwinder) +{ + state->ops =3D unwinder; +} #endif /* _ASM_UNWIND_H */ diff --git a/arch/loongarch/kernel/Makefile b/arch/loongarch/kernel/Makefile index 7ca65195f7f8..cb6029ea3ea9 100644 --- a/arch/loongarch/kernel/Makefile +++ b/arch/loongarch/kernel/Makefile @@ -8,7 +8,7 @@ extra-y :=3D vmlinux.lds obj-y +=3D head.o cpu-probe.o cacheinfo.o env.o setup.o entry.o genex.o \ traps.o irq.o idle.o process.o dma.o mem.o io.o reset.o switch.o \ elf.o syscall.o signal.o time.o topology.o inst.o ptrace.o vdso.o \ - alternative.o unaligned.o + alternative.o unaligned.o unwind.o unwind_guess.o =20 obj-$(CONFIG_ACPI) +=3D acpi.o obj-$(CONFIG_EFI) +=3D efi.o @@ -42,7 +42,6 @@ obj-$(CONFIG_MAGIC_SYSRQ) +=3D sysrq.o obj-$(CONFIG_KEXEC) +=3D machine_kexec.o relocate_kernel.o obj-$(CONFIG_CRASH_DUMP) +=3D crash_dump.o =20 -obj-$(CONFIG_UNWINDER_GUESS) +=3D unwind_guess.o obj-$(CONFIG_UNWINDER_PROLOGUE) +=3D unwind_prologue.o =20 obj-$(CONFIG_PERF_EVENTS) +=3D perf_event.o perf_regs.o diff --git a/arch/loongarch/kernel/traps.c b/arch/loongarch/kernel/traps.c index 3adc44832205..1ea14f6c18d3 100644 --- a/arch/loongarch/kernel/traps.c +++ b/arch/loongarch/kernel/traps.c @@ -72,9 +72,6 @@ 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.c b/arch/loongarch/kernel/unwind.c new file mode 100644 index 000000000000..24d2cf99bfb6 --- /dev/null +++ b/arch/loongarch/kernel/unwind.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2022 Loongson Technology Corporation Limited + */ +#include + +#if defined(CONFIG_UNWINDER_GUESS) +const struct unwinder_ops *default_unwinder =3D &unwinder_guess; +#elif defined(CONFIG_UNWINDER_PROLOGUE) +const struct unwinder_ops *default_unwinder =3D &unwinder_prologue; +#endif + +unsigned long unwind_get_return_address(struct unwind_state *state) +{ + if (!state->ops || unwind_done(state)) + return 0; + return state->ops->unwind_get_return_address(state); +} +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)); + unwind_register_unwinder(state, default_unwinder); + if (regs) { + state->sp =3D regs->regs[3]; + state->pc =3D regs->csr_era; + state->ra =3D regs->regs[1]; + } else if (task =3D=3D current || task =3D=3D NULL) { + state->sp =3D (unsigned long)__builtin_frame_address(0); + state->pc =3D (unsigned long)__builtin_return_address(0); + state->ra =3D 0; + } else { + state->sp =3D thread_saved_fp(task); + state->pc =3D thread_saved_ra(task); + state->ra =3D 0; + } + state->task =3D task; + get_stack_info(state->sp, state->task, &state->stack_info); + state->pc =3D unwind_graph_addr(state, state->pc, state->sp); + state->ops->unwind_start(state, task, regs); +} +EXPORT_SYMBOL_GPL(unwind_start); + +bool unwind_next_frame(struct unwind_state *state) +{ + if (!state->ops || unwind_done(state)) + return false; + return state->ops->unwind_next_frame(state); +} +EXPORT_SYMBOL_GPL(unwind_next_frame); diff --git a/arch/loongarch/kernel/unwind_guess.c b/arch/loongarch/kernel/u= nwind_guess.c index 935d24f8c95c..b7ca2b88ac63 100644 --- a/arch/loongarch/kernel/unwind_guess.c +++ b/arch/loongarch/kernel/unwind_guess.c @@ -7,51 +7,23 @@ =20 #include =20 -unsigned long unwind_get_return_address(struct unwind_state *state) +static unsigned long get_return_address(struct unwind_state *state) { - if (unwind_done(state)) - return 0; return state->pc; } -EXPORT_SYMBOL_GPL(unwind_get_return_address); =20 -void unwind_start(struct unwind_state *state, struct task_struct *task, +static void 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; - } else if (task =3D=3D current || task =3D=3D NULL) { - state->sp =3D (unsigned long)__builtin_frame_address(0); - state->pc =3D (unsigned long)__builtin_return_address(0); - } else { - state->sp =3D thread_saved_fp(task); - state->pc =3D thread_saved_ra(task); - } - - state->task =3D task; - state->first =3D true; - state->pc =3D unwind_graph_addr(state, state->pc, state->sp); - 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 -bool unwind_next_frame(struct unwind_state *state) +static bool next_frame(struct unwind_state *state) { struct stack_info *info =3D &state->stack_info; unsigned long addr; =20 - 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; @@ -68,4 +40,9 @@ bool unwind_next_frame(struct unwind_state *state) =20 return false; } -EXPORT_SYMBOL_GPL(unwind_next_frame); + +const struct unwinder_ops unwinder_guess =3D { + .unwind_start =3D start, + .unwind_next_frame =3D next_frame, + .unwind_get_return_address =3D get_return_address, +}; diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kerne= l/unwind_prologue.c index f7994ed05f04..beb57ea24da2 100644 --- a/arch/loongarch/kernel/unwind_prologue.c +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -19,31 +19,19 @@ static inline void unwind_state_fixup(struct unwind_sta= te *state) #endif } =20 -unsigned long unwind_get_return_address(struct unwind_state *state) +static unsigned long get_return_address(struct unwind_state *state) { - if (unwind_done(state)) - return 0; return state->pc; } -EXPORT_SYMBOL_GPL(unwind_get_return_address); - -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); - state->pc =3D unwind_graph_addr(state, addr, state->sp + 8); - if (__kernel_text_address(state->pc)) - return true; - } - - return false; -} =20 +/* + * LoongArch function prologue like follows, + * [others instructions not use stack var] + * addi.d sp, sp, -imm + * st.d xx, sp, offset <- save callee saved regs and + * st.d yy, sp, offset save ra if function is nest. + * [others instructions] + */ static bool unwind_by_prologue(struct unwind_state *state) { long frame_ra =3D -1; @@ -89,6 +77,10 @@ static bool unwind_by_prologue(struct unwind_state *stat= e) ip++; } =20 + /* + * Not find stack alloc action, PC may be in a leaf function. Only the + * first being true is reasonable, otherwise indicate analysis is broken. + */ if (!frame_size) { if (state->first) goto first; @@ -106,6 +98,7 @@ static bool unwind_by_prologue(struct unwind_state *stat= e) ip++; } =20 + /* Not find save $ra action, PC may be in a leaf function, too. */ if (frame_ra < 0) { if (state->first) { state->sp =3D state->sp + frame_size; @@ -114,96 +107,63 @@ static bool unwind_by_prologue(struct unwind_state *s= tate) return false; } =20 - if (state->first) - state->first =3D false; - state->pc =3D *(unsigned long *)(state->sp + frame_ra); state->sp =3D state->sp + frame_size; goto out; =20 first: - state->first =3D false; - if (state->pc =3D=3D state->ra) - return false; - state->pc =3D state->ra; =20 out: + state->first =3D false; unwind_state_fixup(state); return !!__kernel_text_address(state->pc); } =20 -void unwind_start(struct unwind_state *state, struct task_struct *task, +static void start(struct unwind_state *state, struct task_struct *task, struct pt_regs *regs) { - memset(state, 0, sizeof(*state)); - state->type =3D UNWINDER_PROLOGUE; - - if (regs) { - state->sp =3D regs->regs[3]; - state->pc =3D regs->csr_era; - state->ra =3D regs->regs[1]; - if (!__kernel_text_address(state->pc)) - state->type =3D UNWINDER_GUESS; - } else if (task =3D=3D current || task =3D=3D NULL) { - state->sp =3D (unsigned long)__builtin_frame_address(0); - state->pc =3D (unsigned long)__builtin_return_address(0); - state->ra =3D 0; - } else { - state->sp =3D thread_saved_fp(task); - state->pc =3D thread_saved_ra(task); - state->ra =3D 0; - } - - state->task =3D task; state->first =3D true; - state->pc =3D unwind_graph_addr(state, state->pc, state->sp); - get_stack_info(state->sp, state->task, &state->stack_info); =20 - if (!unwind_done(state) && !__kernel_text_address(state->pc)) - unwind_next_frame(state); + /* + * The current PC is not kernel text address, we cannot find its + * relative symbol. Thus, prologue analysis will be broken. Luckly, + * we can use the guess unwinder. + */ + if (!__kernel_text_address(state->pc)) { + unwind_register_unwinder(state, &unwinder_guess); + if (!unwind_done(state)) + unwind_next_frame(state); + } } -EXPORT_SYMBOL_GPL(unwind_start); =20 -bool unwind_next_frame(struct unwind_state *state) +static bool next_frame(struct unwind_state *state) { struct stack_info *info =3D &state->stack_info; struct pt_regs *regs; unsigned long pc; =20 - if (unwind_done(state)) - return false; - do { - switch (state->type) { - case UNWINDER_GUESS: - state->first =3D false; - if (unwind_by_guess(state)) - return true; - break; - - case UNWINDER_PROLOGUE: - if (unwind_by_prologue(state)) { - state->pc =3D unwind_graph_addr(state, state->pc, state->sp); - return true; - } + if (unwind_by_prologue(state)) { + state->pc =3D unwind_graph_addr(state, state->pc, state->sp); + return true; + } =20 - 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 (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; =20 - if (user_mode(regs) || !__kernel_text_address(pc)) - return false; + if (user_mode(regs) || !__kernel_text_address(pc)) + return false; =20 - state->first =3D true; - state->ra =3D regs->regs[1]; - state->sp =3D regs->regs[3]; - state->pc =3D pc; - get_stack_info(state->sp, state->task, info); + state->first =3D true; + state->ra =3D regs->regs[1]; + state->sp =3D regs->regs[3]; + state->pc =3D pc; + get_stack_info(state->sp, state->task, info); =20 - return true; - } + return true; } =20 state->sp =3D info->next_sp; @@ -212,4 +172,9 @@ bool unwind_next_frame(struct unwind_state *state) =20 return false; } -EXPORT_SYMBOL_GPL(unwind_next_frame); + +const struct unwinder_ops unwinder_prologue =3D { + .unwind_start =3D start, + .unwind_next_frame =3D next_frame, + .unwind_get_return_address =3D get_return_address, +}; --=20 2.34.3 From nobody Tue Sep 16 20:07:42 2025 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 A5065C3DA7A for ; Thu, 29 Dec 2022 06:16:31 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232979AbiL2GQF (ORCPT ); Thu, 29 Dec 2022 01:16:05 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33156 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232868AbiL2GPy (ORCPT ); Thu, 29 Dec 2022 01:15:54 -0500 Received: from loongson.cn (mail.loongson.cn [114.242.206.163]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 22B535FAE for ; Wed, 28 Dec 2022 22:15:52 -0800 (PST) Received: from loongson.cn (unknown [111.9.175.10]) by gateway (Coremail) with SMTP id _____8CxI_CWMK1jTTMJAA--.20716S3; Thu, 29 Dec 2022 14:15:50 +0800 (CST) Received: from localhost.localdomain (unknown [111.9.175.10]) by localhost.localdomain (Coremail) with SMTP id AQAAf8Dxrb6OMK1jIiYPAA--.24618S7; Thu, 29 Dec 2022 14:15:49 +0800 (CST) From: Jinyang He To: Huacai Chen , WANG Xuerui , Qing Zhang Cc: loongarch@lists.linux.dev, linux-kernel@vger.kernel.org, Steven Rostedt , Masami Hiramatsu , Mark Rutland Subject: [PATCH v2 5/6] LoongArch: Add generic ex-handler unwind in prologue unwinder Date: Thu, 29 Dec 2022 14:15:16 +0800 Message-Id: <20221229061516.31671-6-hejinyang@loongson.cn> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20221229061516.31671-1-hejinyang@loongson.cn> References: <20221229061516.31671-1-hejinyang@loongson.cn> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: AQAAf8Dxrb6OMK1jIiYPAA--.24618S7 X-CM-SenderInfo: pkhmx0p1dqwqxorr0wxvrqhubq/ X-Coremail-Antispam: 1Uk129KBjvJXoW3XF15XF48Wr4DWF48ZrW8WFg_yoWxAF4fpF 9akrn5Gr4rKr9FqrW7Jryq9r98Aw4kCw12gF9rKas5CF1Iqry3WrnYy34qvF1DJ3y8WFyI qFsxXrya9a1UJa7anT9S1TB71UUUUjUqnTZGkaVYY2UrUUUUj1kv1TuYvTs0mT0YCTnIWj qI5I8CrVACY4xI64kE6c02F40Ex7xfYxn0WfASr-VFAUDa7-sFnT9fnUUIcSsGvfJTRUUU bSkYFVCjjxCrM7AC8VAFwI0_Jr0_Gr1l1xkIjI8I6I8E6xAIw20EY4v20xvaj40_Wr0E3s 1l1IIY67AEw4v_Jrv_JF1l8cAvFVAK0II2c7xJM28CjxkF64kEwVA0rcxSw2x7M28EF7xv wVC0I7IYx2IY67AKxVW7JVWDJwA2z4x0Y4vE2Ix0cI8IcVCY1x0267AKxVWxJVW8Jr1l84 ACjcxK6I8E87Iv67AKxVW8Jr0_Cr1UM28EF7xvwVC2z280aVCY1x0267AKxVW8Jr0_Cr1U M2kKe7AKxVWUXVWUAwAS0I0E0xvYzxvE52x082IY62kv0487Mc804VCY07AIYIkI8VC2zV CFFI0UMc02F40EFcxC0VAKzVAqx4xG6I80ewAv7VC0I7IYx2IY67AKxVWrXVW3AwAv7VC2 z280aVAFwI0_Gr0_Cr1lOx8S6xCaFVCjc4AY6r1j6r4UM4x0Y48IcxkI7VAKI48JMxkF7I 0En4kS14v26r126r1DMxAIw28IcxkI7VAKI48JMxC20s026xCaFVCjc4AY6r1j6r4UMxCI bckI1I0E14v26r1Y6r17MI8I3I0E5I8CrVAFwI0_Jr0_Jr4lx2IqxVCjr7xvwVAFwI0_Jr I_JrWlx4CE17CEb7AF67AKxVWUtVW8ZwCIc40Y0x0EwIxGrwCI42IY6xIIjxv20xvE14v2 6ryj6F1UMIIF0xvE2Ix0cI8IcVCY1x0267AKxVW8JVWxJwCI42IY6xAIw20EY4v20xvaj4 0_Jr0_JF4lIxAIcVC2z280aVAFwI0_Gr0_Cr1lIxAIcVC2z280aVCY1x0267AKxVW8JVW8 JrUvcSsGvfC2KfnxnUUI43ZEXa7IUneRRtUUUUU== Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" When exception is triggered, code flow go handle_\exception in some cases. One of stackframe in this case as follows, high -> +-------+ | REGS | <- a pt_regs | | | | <- ex trigger | REGS | <- ex pt_regs <-+ | | | | | | low -> +-------+ ->unwind-+ When unwinder unwind to handler_\exception it cannot go on prologue analysis. It is asynchronous code flow, we should get the next frame PC from regs->csr_era but not from regs->regs[1]. And we copy the handler codes to eentry in the early time and copy the handler codes to NUMA-relative memory named pcpu_handlers if NUMA is enabled. Thus, unwinder cannot unwind normally. Therefore, try to give some hint in handler_\exception and fixup it in unwind_next_frame. Reported-by: Qing Zhang Signed-off-by: Jinyang He --- arch/loongarch/include/asm/unwind.h | 2 +- arch/loongarch/kernel/genex.S | 3 + arch/loongarch/kernel/unwind_prologue.c | 100 +++++++++++++++++++++--- arch/loongarch/mm/tlb.c | 2 +- 4 files changed, 92 insertions(+), 15 deletions(-) diff --git a/arch/loongarch/include/asm/unwind.h b/arch/loongarch/include/a= sm/unwind.h index 4a55fd7b77ad..1eb6d7f771a8 100644 --- a/arch/loongarch/include/asm/unwind.h +++ b/arch/loongarch/include/asm/unwind.h @@ -18,7 +18,7 @@ struct unwinder_ops; struct unwind_state { struct stack_info stack_info; struct task_struct *task; - bool first, error, is_ftrace; + bool first, error, reset; int graph_idx; unsigned long sp, pc, ra; const struct unwinder_ops *ops; diff --git a/arch/loongarch/kernel/genex.S b/arch/loongarch/kernel/genex.S index 75e5be807a0d..7e5c293ed89f 100644 --- a/arch/loongarch/kernel/genex.S +++ b/arch/loongarch/kernel/genex.S @@ -67,14 +67,17 @@ SYM_FUNC_END(except_vec_cex) .macro BUILD_HANDLER exception handler prep .align 5 SYM_FUNC_START(handle_\exception) + 666: BACKUP_T0T1 SAVE_ALL build_prep_\prep move a0, sp la.abs t0, do_\handler jirl ra, t0, 0 + 668: RESTORE_ALL_AND_RET SYM_FUNC_END(handle_\exception) + SYM_DATA(unwind_hint_\exception, .word 668b - 666b) .endm =20 BUILD_HANDLER ade ade badv diff --git a/arch/loongarch/kernel/unwind_prologue.c b/arch/loongarch/kerne= l/unwind_prologue.c index beb57ea24da2..edce9eba6b52 100644 --- a/arch/loongarch/kernel/unwind_prologue.c +++ b/arch/loongarch/kernel/unwind_prologue.c @@ -2,21 +2,100 @@ /* * Copyright (C) 2022 Loongson Technology Corporation Limited */ +#include #include #include =20 #include +#include #include +#include #include =20 -static inline void unwind_state_fixup(struct unwind_state *state) +extern const int unwind_hint_ade; +extern const int unwind_hint_ale; +extern const int unwind_hint_bp; +extern const int unwind_hint_fpe; +extern const int unwind_hint_fpu; +extern const int unwind_hint_lsx; +extern const int unwind_hint_lasx; +extern const int unwind_hint_lbt; +extern const int unwind_hint_ri; +extern const int unwind_hint_watch; +extern unsigned long eentry; +#ifdef CONFIG_NUMA +extern unsigned long pcpu_handlers[NR_CPUS]; +#endif + +static inline bool scan_handler(unsigned long entry_offset) { -#ifdef CONFIG_DYNAMIC_FTRACE - static unsigned long ftrace =3D (unsigned long)ftrace_call + 4; + int idx, offset; =20 - if (state->pc =3D=3D ftrace) - state->is_ftrace =3D true; + if (entry_offset >=3D EXCCODE_INT_START * VECSIZE) + return false; + + idx =3D entry_offset / VECSIZE; + offset =3D entry_offset % VECSIZE; + switch (idx) { + case EXCCODE_ADE: + return offset =3D=3D unwind_hint_ade; + case EXCCODE_ALE: + return offset =3D=3D unwind_hint_ale; + case EXCCODE_BP: + return offset =3D=3D unwind_hint_bp; + case EXCCODE_FPE: + return offset =3D=3D unwind_hint_fpe; + case EXCCODE_FPDIS: + return offset =3D=3D unwind_hint_fpu; + case EXCCODE_LSXDIS: + return offset =3D=3D unwind_hint_lsx; + case EXCCODE_LASXDIS: + return offset =3D=3D unwind_hint_lasx; + case EXCCODE_BTDIS: + return offset =3D=3D unwind_hint_lbt; + case EXCCODE_INE: + return offset =3D=3D unwind_hint_ri; + case EXCCODE_WATCH: + return offset =3D=3D unwind_hint_watch; + default: + return false; + } +} + +static inline bool fix_exceptions(unsigned long pc) +{ +#ifdef CONFIG_NUMA + int cpu; + + for_each_possible_cpu(cpu) { + if (!pcpu_handlers[cpu]) + continue; + if (scan_handler(pc - pcpu_handlers[cpu])) + return true; + } #endif + return scan_handler(pc - eentry); +} + +/* + * As we meet ftrace_regs_entry, reset first flag like first doing + * tracing. Prologue analysis will stop soon because PC is at entry. + */ +static inline bool fix_ftrace(unsigned long pc) +{ +#ifdef CONFIG_DYNAMIC_FTRACE + return pc =3D=3D (unsigned long)ftrace_call + LOONGARCH_INSN_SIZE; +#else + return false; +#endif +} + +static inline bool unwind_state_fixup(struct unwind_state *state) +{ + if (!fix_exceptions(state->pc) && !fix_ftrace(state->pc)) + return false; + state->reset =3D true; + return true; } =20 static unsigned long get_return_address(struct unwind_state *state) @@ -44,14 +123,10 @@ static bool unwind_by_prologue(struct unwind_state *st= ate) if (state->sp >=3D info->end || state->sp < info->begin) return false; =20 - if (state->is_ftrace) { - /* - * As we meet ftrace_regs_entry, reset first flag like first doing - * tracing. Prologue analysis will stop soon because PC is at entry. - */ + if (state->reset) { regs =3D (struct pt_regs *)state->sp; state->first =3D true; - state->is_ftrace =3D false; + state->reset =3D false; state->pc =3D regs->csr_era; state->ra =3D regs->regs[1]; state->sp =3D regs->regs[3]; @@ -116,8 +191,7 @@ static bool unwind_by_prologue(struct unwind_state *sta= te) =20 out: state->first =3D false; - unwind_state_fixup(state); - return !!__kernel_text_address(state->pc); + return unwind_state_fixup(state) || __kernel_text_address(state->pc); } =20 static void start(struct unwind_state *state, struct task_struct *task, diff --git a/arch/loongarch/mm/tlb.c b/arch/loongarch/mm/tlb.c index da3681f131c8..8bad6b0cff59 100644 --- a/arch/loongarch/mm/tlb.c +++ b/arch/loongarch/mm/tlb.c @@ -251,7 +251,7 @@ static void output_pgtable_bits_defines(void) } =20 #ifdef CONFIG_NUMA -static unsigned long pcpu_handlers[NR_CPUS]; +unsigned long pcpu_handlers[NR_CPUS]; #endif extern long exception_handlers[VECSIZE * 128 / sizeof(long)]; =20 --=20 2.34.3