From nobody Mon May 11 05:34:31 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 DFB1AC433F5 for ; Wed, 13 Apr 2022 14:05:47 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236021AbiDMOIH (ORCPT ); Wed, 13 Apr 2022 10:08:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45160 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233401AbiDMOIE (ORCPT ); Wed, 13 Apr 2022 10:08:04 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0834025E8C; Wed, 13 Apr 2022 07:05:44 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id 0B0D520C34CA; Wed, 13 Apr 2022 07:05:42 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com 0B0D520C34CA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1649858743; bh=rq9hnVI/Y4H4vRXgmKmfpdtj1W5zhGVLrIDwQqVIs14=; h=From:To:Subject:Date:In-Reply-To:References:From; b=YnYthjC6iqx7LeDpXzExD1CxOuAjqVKKh4uIgRwTboHD90c5Icl2kMNXalfpKjKJ+ euHXz2aEmDqAZZ1h5hjufGIQdqXfTxdNhYhA537RlPEc3D3beHcZaqk3i0B31bkrFi O2pPULrCAKsQNHJh6Iv/dcQtJwkddF8hyr+/D/f4= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, ardb@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jmorris@namei.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [PATCH v14 1/7] arm64: Split unwind_init() Date: Wed, 13 Apr 2022 09:05:22 -0500 Message-Id: <20220413140528.3815-2-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220413140528.3815-1-madvenka@linux.microsoft.com> References: <20220413140528.3815-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" unwind_init() is currently a single function that initializes all of the unwind state. Split it into the following functions and call them appropriately: - unwind_init_from_regs() - initialize from regs passed by caller. - unwind_init_from_caller() - initialize for the current task from the caller of arch_stack_walk(). - unwind_init_from_task() - initialize from the saved state of a task other than the current task. In this case, the other task must not be running. This is done for two reasons: - the different ways of initializing are clear - specialized code can be added to each initializer in the future. Signed-off-by: Madhavan T. Venkataraman Reviewed-by: Mark Brown --- arch/arm64/kernel/stacktrace.c | 66 ++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 0467cb79f080..e44f93ff25f0 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -50,11 +50,8 @@ struct unwind_state { #endif }; =20 -static notrace void unwind_init(struct unwind_state *state, unsigned long = fp, - unsigned long pc) +static void unwind_init_common(struct unwind_state *state) { - state->fp =3D fp; - state->pc =3D pc; #ifdef CONFIG_KRETPROBES state->kr_cur =3D NULL; #endif @@ -72,7 +69,57 @@ static notrace void unwind_init(struct unwind_state *sta= te, unsigned long fp, state->prev_fp =3D 0; state->prev_type =3D STACK_TYPE_UNKNOWN; } -NOKPROBE_SYMBOL(unwind_init); + +/* + * Start an unwind from a pt_regs. + * + * The unwind will begin at the PC within the regs. + * + * The regs must be on a stack currently owned by the calling task. + */ +static inline void unwind_init_from_regs(struct unwind_state *state, + struct pt_regs *regs) +{ + unwind_init_common(state); + + state->fp =3D regs->regs[29]; + state->pc =3D regs->pc; +} + +/* + * Start an unwind from a caller. + * + * The unwind will begin at the caller of whichever function this is inlin= ed + * into. + * + * The function which invokes this must be noinline. + */ +static __always_inline void unwind_init_from_caller(struct unwind_state *s= tate) +{ + unwind_init_common(state); + + state->fp =3D (unsigned long)__builtin_frame_address(1); + state->pc =3D (unsigned long)__builtin_return_address(0); +} + +/* + * Start an unwind from a blocked task. + * + * The unwind will begin at the blocked tasks saved PC (i.e. the caller of + * cpu_switch_to()). + * + * The caller should ensure the task is blocked in cpu_switch_to() for the + * duration of the unwind, or the unwind will be bogus. It is never valid = to + * call this for the current task. + */ +static inline void unwind_init_from_task(struct unwind_state *state, + struct task_struct *task) +{ + unwind_init_common(state); + + state->fp =3D thread_saved_fp(task); + state->pc =3D thread_saved_pc(task); +} =20 /* * Unwind from one frame record (A) to the next frame record (B). @@ -213,14 +260,11 @@ noinline notrace void arch_stack_walk(stack_trace_con= sume_fn consume_entry, struct unwind_state state; =20 if (regs) - unwind_init(&state, regs->regs[29], regs->pc); + unwind_init_from_regs(&state, regs); else if (task =3D=3D current) - unwind_init(&state, - (unsigned long)__builtin_frame_address(1), - (unsigned long)__builtin_return_address(0)); + unwind_init_from_caller(&state); else - unwind_init(&state, thread_saved_fp(task), - thread_saved_pc(task)); + unwind_init_from_task(&state, task); =20 unwind(task, &state, consume_entry, cookie); } --=20 2.25.1 From nobody Mon May 11 05:34:31 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 63AD6C43217 for ; Wed, 13 Apr 2022 14:05:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236048AbiDMOIO (ORCPT ); Wed, 13 Apr 2022 10:08:14 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45176 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231740AbiDMOIF (ORCPT ); Wed, 13 Apr 2022 10:08:05 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id E22FA255A3; Wed, 13 Apr 2022 07:05:44 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id F19EE20C34CC; Wed, 13 Apr 2022 07:05:43 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com F19EE20C34CC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1649858744; bh=KOgylemXULSWKrdPAi67ieZBj5vfyVJl5HzFLzKmkho=; h=From:To:Subject:Date:In-Reply-To:References:From; b=S5jE7GT61Gs8LdhPjb8sokZY07qlBfYXhVovpHnlqaICQ5dS21wg4bWW1JRTAuKvS sP4n6b5Aj9SpTc/RfaXCBHKZxqI+0kB4+L7PZ1a++6IRWMGPfhvXs7IsUBR/hjYCXB 2kQgtJJD7pFbwK3j08/RR4k+s8js3PuODxP4XFSA= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, ardb@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jmorris@namei.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [PATCH v14 2/7] arm64: Copy the task argument to unwind_state Date: Wed, 13 Apr 2022 09:05:23 -0500 Message-Id: <20220413140528.3815-3-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220413140528.3815-1-madvenka@linux.microsoft.com> References: <20220413140528.3815-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Copy the task argument passed to arch_stack_walk() to unwind_state so that it can be passed to unwind functions via unwind_state rather than as a separate argument. The task is a fundamental part of the unwind state. Signed-off-by: Madhavan T. Venkataraman Reviewed-by: Mark Brown --- arch/arm64/kernel/stacktrace.c | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index e44f93ff25f0..8e43444d50e2 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -38,6 +38,8 @@ * @kr_cur: When KRETPROBES is selected, holds the kretprobe instance * associated with the most recently encountered replacement= lr * value. + * + * @task: The task being unwound. */ struct unwind_state { unsigned long fp; @@ -48,10 +50,13 @@ struct unwind_state { #ifdef CONFIG_KRETPROBES struct llist_node *kr_cur; #endif + struct task_struct *task; }; =20 -static void unwind_init_common(struct unwind_state *state) +static void unwind_init_common(struct unwind_state *state, + struct task_struct *task) { + state->task =3D task; #ifdef CONFIG_KRETPROBES state->kr_cur =3D NULL; #endif @@ -80,7 +85,7 @@ static void unwind_init_common(struct unwind_state *state) static inline void unwind_init_from_regs(struct unwind_state *state, struct pt_regs *regs) { - unwind_init_common(state); + unwind_init_common(state, current); =20 state->fp =3D regs->regs[29]; state->pc =3D regs->pc; @@ -96,7 +101,7 @@ static inline void unwind_init_from_regs(struct unwind_s= tate *state, */ static __always_inline void unwind_init_from_caller(struct unwind_state *s= tate) { - unwind_init_common(state); + unwind_init_common(state, current); =20 state->fp =3D (unsigned long)__builtin_frame_address(1); state->pc =3D (unsigned long)__builtin_return_address(0); @@ -115,7 +120,7 @@ static __always_inline void unwind_init_from_caller(str= uct unwind_state *state) static inline void unwind_init_from_task(struct unwind_state *state, struct task_struct *task) { - unwind_init_common(state); + unwind_init_common(state, task); =20 state->fp =3D thread_saved_fp(task); state->pc =3D thread_saved_pc(task); @@ -128,9 +133,9 @@ static inline void unwind_init_from_task(struct unwind_= state *state, * records (e.g. a cycle), determined based on the location and fp value o= f A * and the location (but not the fp value) of B. */ -static int notrace unwind_next(struct task_struct *tsk, - struct unwind_state *state) +static int notrace unwind_next(struct unwind_state *state) { + struct task_struct *tsk =3D state->task; unsigned long fp =3D state->fp; struct stack_info info; =20 @@ -204,8 +209,7 @@ static int notrace unwind_next(struct task_struct *tsk, } NOKPROBE_SYMBOL(unwind_next); =20 -static void notrace unwind(struct task_struct *tsk, - struct unwind_state *state, +static void notrace unwind(struct unwind_state *state, stack_trace_consume_fn consume_entry, void *cookie) { while (1) { @@ -213,7 +217,7 @@ static void notrace unwind(struct task_struct *tsk, =20 if (!consume_entry(cookie, state->pc)) break; - ret =3D unwind_next(tsk, state); + ret =3D unwind_next(state); if (ret < 0) break; } @@ -259,12 +263,15 @@ noinline notrace void arch_stack_walk(stack_trace_con= sume_fn consume_entry, { struct unwind_state state; =20 - if (regs) + if (regs) { + if (task !=3D current) + return; unwind_init_from_regs(&state, regs); - else if (task =3D=3D current) + } else if (task =3D=3D current) { unwind_init_from_caller(&state); - else + } else { unwind_init_from_task(&state, task); + } =20 - unwind(task, &state, consume_entry, cookie); + unwind(&state, consume_entry, cookie); } --=20 2.25.1 From nobody Mon May 11 05:34:31 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 EA5DEC433F5 for ; Wed, 13 Apr 2022 14:05:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236058AbiDMOIT (ORCPT ); Wed, 13 Apr 2022 10:08:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45196 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236014AbiDMOIH (ORCPT ); Wed, 13 Apr 2022 10:08:07 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id D9EBB25E8C; Wed, 13 Apr 2022 07:05:45 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id E2EF620C34CF; Wed, 13 Apr 2022 07:05:44 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com E2EF620C34CF DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1649858745; bh=ua+saCsW0mWHqIwTOqh4aD4MZ7FXZAniouHO3DFJtqM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=UEfYZJGGejOII3NG5+vz0MtM23kDqwCFIdaeo2gC9ELdjfksCRiKoMWPfqhdGuSLs JZPF8u9Ocm8VdWurlhbnW42PkcMH0XqURLXh/cK88SNNZt4JWw1Jmo9u0dN4FElj2R yK/O+pPOkXEVpVcmIuTzrH7LnAy6S0AID6B6Usw0= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, ardb@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jmorris@namei.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [PATCH v14 3/7] arm64: Make the unwind loop in unwind() similar to other architectures Date: Wed, 13 Apr 2022 09:05:24 -0500 Message-Id: <20220413140528.3815-4-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220413140528.3815-1-madvenka@linux.microsoft.com> References: <20220413140528.3815-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Change the loop in unwind() =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Change the unwind loop in unwind() to: while (unwind_continue(state, consume_entry, cookie)) unwind_next(state); This is easy to understand and maintain. New function unwind_continue() =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D Define a new function unwind_continue() that is used in the unwind loop to check for conditions that terminate a stack trace. The conditions checked are: - If the bottom of the stack (final frame) has been reached, terminate. - If the consume_entry() function returns false, the caller of unwind has asked to terminate the stack trace. So, terminate. - If unwind_next() failed for some reason (like stack corruption), terminate. Do not return an error value from unwind_next() =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D We want to check for terminating conditions only in unwind_continue() from the unwinder loop. So, do not return an error value from unwind_next(). Simply set a flag in unwind_state and check the flag in unwind_continue(). Final FP =3D=3D=3D=3D=3D=3D=3D=3D Introduce a new field "final_fp" in "struct unwind_state". Initialize this to the final frame of the stack trace: task_pt_regs(task)->stackframe This is where the stacktrace must terminate if it is successful. Add an explicit comment to that effect. Signed-off-by: Madhavan T. Venkataraman Reviewed-by: Mark Brown --- arch/arm64/kernel/stacktrace.c | 78 ++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 26 deletions(-) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 8e43444d50e2..c749129aba5a 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -40,6 +40,10 @@ * value. * * @task: The task being unwound. + * + * @final_fp: Pointer to the final frame. + * + * @failed: Unwind failed. */ struct unwind_state { unsigned long fp; @@ -51,6 +55,8 @@ struct unwind_state { struct llist_node *kr_cur; #endif struct task_struct *task; + unsigned long final_fp; + bool failed; }; =20 static void unwind_init_common(struct unwind_state *state, @@ -73,6 +79,10 @@ static void unwind_init_common(struct unwind_state *stat= e, bitmap_zero(state->stacks_done, __NR_STACK_TYPES); state->prev_fp =3D 0; state->prev_type =3D STACK_TYPE_UNKNOWN; + state->failed =3D false; + + /* Stack trace terminates here. */ + state->final_fp =3D (unsigned long)task_pt_regs(task)->stackframe; } =20 /* @@ -126,6 +136,25 @@ static inline void unwind_init_from_task(struct unwind= _state *state, state->pc =3D thread_saved_pc(task); } =20 +static bool notrace unwind_continue(struct unwind_state *state, + stack_trace_consume_fn consume_entry, + void *cookie) +{ + if (state->failed) { + /* PC is suspect. Cannot consume it. */ + return false; + } + + if (!consume_entry(cookie, state->pc)) { + /* Caller terminated the unwind. */ + state->failed =3D true; + return false; + } + + return state->fp !=3D state->final_fp; +} +NOKPROBE_SYMBOL(unwind_continue); + /* * Unwind from one frame record (A) to the next frame record (B). * @@ -133,24 +162,26 @@ static inline void unwind_init_from_task(struct unwin= d_state *state, * records (e.g. a cycle), determined based on the location and fp value o= f A * and the location (but not the fp value) of B. */ -static int notrace unwind_next(struct unwind_state *state) +static void notrace unwind_next(struct unwind_state *state) { struct task_struct *tsk =3D state->task; unsigned long fp =3D state->fp; struct stack_info info; =20 - /* Final frame; nothing to unwind */ - if (fp =3D=3D (unsigned long)task_pt_regs(tsk)->stackframe) - return -ENOENT; - - if (fp & 0x7) - return -EINVAL; + if (fp & 0x7) { + state->failed =3D true; + return; + } =20 - if (!on_accessible_stack(tsk, fp, 16, &info)) - return -EINVAL; + if (!on_accessible_stack(tsk, fp, 16, &info)) { + state->failed =3D true; + return; + } =20 - if (test_bit(info.type, state->stacks_done)) - return -EINVAL; + if (test_bit(info.type, state->stacks_done)) { + state->failed =3D true; + return; + } =20 /* * As stacks grow downward, any valid record on the same stack must be @@ -166,8 +197,10 @@ static int notrace unwind_next(struct unwind_state *st= ate) * stack. */ if (info.type =3D=3D state->prev_type) { - if (fp <=3D state->prev_fp) - return -EINVAL; + if (fp <=3D state->prev_fp) { + state->failed =3D true; + return; + } } else { set_bit(state->prev_type, state->stacks_done); } @@ -195,8 +228,10 @@ static int notrace unwind_next(struct unwind_state *st= ate) */ orig_pc =3D ftrace_graph_ret_addr(tsk, NULL, state->pc, (void *)state->fp); - if (WARN_ON_ONCE(state->pc =3D=3D orig_pc)) - return -EINVAL; + if (WARN_ON_ONCE(state->pc =3D=3D orig_pc)) { + state->failed =3D true; + return; + } state->pc =3D orig_pc; } #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ @@ -204,23 +239,14 @@ static int notrace unwind_next(struct unwind_state *s= tate) if (is_kretprobe_trampoline(state->pc)) state->pc =3D kretprobe_find_ret_addr(tsk, (void *)state->fp, &state->kr= _cur); #endif - - return 0; } NOKPROBE_SYMBOL(unwind_next); =20 static void notrace unwind(struct unwind_state *state, stack_trace_consume_fn consume_entry, void *cookie) { - while (1) { - int ret; - - if (!consume_entry(cookie, state->pc)) - break; - ret =3D unwind_next(state); - if (ret < 0) - break; - } + while (unwind_continue(state, consume_entry, cookie)) + unwind_next(state); } NOKPROBE_SYMBOL(unwind); =20 --=20 2.25.1 From nobody Mon May 11 05:34:31 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 2C22CC433F5 for ; Wed, 13 Apr 2022 14:06:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236080AbiDMOId (ORCPT ); Wed, 13 Apr 2022 10:08:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45206 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236023AbiDMOIH (ORCPT ); Wed, 13 Apr 2022 10:08:07 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id CB1DF5F8ED; Wed, 13 Apr 2022 07:05:46 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id D352E20C34D0; Wed, 13 Apr 2022 07:05:45 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com D352E20C34D0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1649858746; bh=7x/ixErefSqMKfios87LlUDWmbSdZZSR+nkVTJ31BrI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=S1BTqFS+QYIyqBtHuAshhgDWqUx+SV6OAxoVDph4mhpei1Kd/r31bWzcCjn811nrO QBsXB+V2EtKhXO7vr3IMsr2X2SN9Il544AVyjt+Bb9LXS5mhhKNAVzLl6tRQBUtb1s h1AqZ/oOJR7CwpfjY2T4P0VNKsaUy6Q5ckh83S2c= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, ardb@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jmorris@namei.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [PATCH v14 4/7] arm64: Introduce stack trace reliability checks in the unwinder Date: Wed, 13 Apr 2022 09:05:25 -0500 Message-Id: <20220413140528.3815-5-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220413140528.3815-1-madvenka@linux.microsoft.com> References: <20220413140528.3815-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" There are some kernel features and conditions that make a stack trace unreliable. Callers may require the unwinder to detect these cases. E.g., livepatch. Introduce a new function called unwind_check_reliability() that will detect these cases and set a flag in the stack frame. Call unwind_check_reliability() for every frame in unwind(). Introduce the first reliability check in unwind_check_reliability() - If a return PC is not a valid kernel text address, consider the stack trace unreliable. It could be some generated code. Other reliability checks will be added in the future. Let unwind() return a boolean to indicate if the stack trace is reliable. Signed-off-by: Madhavan T. Venkataraman Reviewed-by: Mark Brown --- arch/arm64/kernel/stacktrace.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index c749129aba5a..5ef2ce217324 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -44,6 +44,8 @@ * @final_fp: Pointer to the final frame. * * @failed: Unwind failed. + * + * @reliable: Stack trace is reliable. */ struct unwind_state { unsigned long fp; @@ -57,6 +59,7 @@ struct unwind_state { struct task_struct *task; unsigned long final_fp; bool failed; + bool reliable; }; =20 static void unwind_init_common(struct unwind_state *state, @@ -80,6 +83,7 @@ static void unwind_init_common(struct unwind_state *state, state->prev_fp =3D 0; state->prev_type =3D STACK_TYPE_UNKNOWN; state->failed =3D false; + state->reliable =3D true; =20 /* Stack trace terminates here. */ state->final_fp =3D (unsigned long)task_pt_regs(task)->stackframe; @@ -242,11 +246,34 @@ static void notrace unwind_next(struct unwind_state *= state) } NOKPROBE_SYMBOL(unwind_next); =20 -static void notrace unwind(struct unwind_state *state, +/* + * Check the stack frame for conditions that make further unwinding unreli= able. + */ +static void unwind_check_reliability(struct unwind_state *state) +{ + if (state->fp =3D=3D state->final_fp) { + /* Final frame; no more unwind, no need to check reliability */ + return; + } + + /* + * If the PC is not a known kernel text address, then we cannot + * be sure that a subsequent unwind will be reliable, as we + * don't know that the code follows our unwind requirements. + */ + if (!__kernel_text_address(state->pc)) + state->reliable =3D false; +} + +static bool notrace unwind(struct unwind_state *state, stack_trace_consume_fn consume_entry, void *cookie) { - while (unwind_continue(state, consume_entry, cookie)) + unwind_check_reliability(state); + while (unwind_continue(state, consume_entry, cookie)) { unwind_next(state); + unwind_check_reliability(state); + } + return !state->failed && state->reliable; } NOKPROBE_SYMBOL(unwind); =20 --=20 2.25.1 From nobody Mon May 11 05:34:31 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 0164DC433F5 for ; Wed, 13 Apr 2022 14:06:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236068AbiDMOIY (ORCPT ); Wed, 13 Apr 2022 10:08:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45232 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236027AbiDMOIJ (ORCPT ); Wed, 13 Apr 2022 10:08:09 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id B82585FF02; Wed, 13 Apr 2022 07:05:47 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id C5C8720C34D3; Wed, 13 Apr 2022 07:05:46 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com C5C8720C34D3 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1649858747; bh=QTQiWJbZvy4H9n+ZDkQWbDZDgb6qzExGsQm68AwKzTY=; h=From:To:Subject:Date:In-Reply-To:References:From; b=BkCawjOBy/LuJ2RLeuuG+z9w2yW134uhPMb6D+XT+2YE/hs3E+0IK+EbQoJ9ewNxN FRXmOZviQVPvbjVAsPjoGD8GZr3yut3UEUaSkOvgMTcwhRaFbcZuMSONByZAK2VQAJ n0QHd104gnceHuX+Kvt4hy/2APeJY1nXQtgih1cQ= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, ardb@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jmorris@namei.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [PATCH v14 5/7] arm64: Create a list of SYM_CODE functions, check return PC against list Date: Wed, 13 Apr 2022 09:05:26 -0500 Message-Id: <20220413140528.3815-6-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220413140528.3815-1-madvenka@linux.microsoft.com> References: <20220413140528.3815-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" SYM_CODE functions don't follow the usual calling conventions. Check if the return PC in a stack frame falls in any of these. If it does, consider the stack trace unreliable. Define a special section for unreliable functions =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Define a SYM_CODE_END() macro for arm64 that adds the function address range to a new section called "sym_code_functions". Linker file =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Include the "sym_code_functions" section under read-only data in vmlinux.lds.S. Initialization =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Define an early_initcall() to create a sym_code_functions[] array from the linker data. Unwinder check =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D Add a reliability check in unwind_check_reliability() that compares a return PC with sym_code_functions[]. If there is a match, then return failure. Signed-off-by: Madhavan T. Venkataraman Reviewed-by: Mark Brown --- arch/arm64/include/asm/linkage.h | 11 +++++++ arch/arm64/include/asm/sections.h | 1 + arch/arm64/kernel/stacktrace.c | 55 +++++++++++++++++++++++++++++++ arch/arm64/kernel/vmlinux.lds.S | 10 ++++++ 4 files changed, 77 insertions(+) diff --git a/arch/arm64/include/asm/linkage.h b/arch/arm64/include/asm/link= age.h index 43f8c25b3fda..d4058de4af78 100644 --- a/arch/arm64/include/asm/linkage.h +++ b/arch/arm64/include/asm/linkage.h @@ -39,4 +39,15 @@ SYM_START(name, SYM_L_WEAK, SYM_A_NONE) \ bti c ; =20 +/* + * Record the address range of each SYM_CODE function in a struct code_ran= ge + * in a special section. + */ +#define SYM_CODE_END(name) \ + SYM_END(name, SYM_T_NONE) ;\ +99: .pushsection "sym_code_functions", "aw" ;\ + .quad name ;\ + .quad 99b ;\ + .popsection + #endif diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sec= tions.h index 40971ac1303f..50cfd1083563 100644 --- a/arch/arm64/include/asm/sections.h +++ b/arch/arm64/include/asm/sections.h @@ -22,6 +22,7 @@ extern char __irqentry_text_start[], __irqentry_text_end[= ]; extern char __mmuoff_data_start[], __mmuoff_data_end[]; extern char __entry_tramp_text_start[], __entry_tramp_text_end[]; extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[]; +extern char __sym_code_functions_start[], __sym_code_functions_end[]; =20 static inline size_t entry_tramp_text_size(void) { diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index 5ef2ce217324..eda8581f7dbe 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -62,6 +62,31 @@ struct unwind_state { bool reliable; }; =20 +struct code_range { + unsigned long start; + unsigned long end; +}; + +static struct code_range *sym_code_functions; +static int num_sym_code_functions; + +int __init init_sym_code_functions(void) +{ + size_t size =3D (unsigned long)__sym_code_functions_end - + (unsigned long)__sym_code_functions_start; + + sym_code_functions =3D (struct code_range *)__sym_code_functions_start; + /* + * Order it so that sym_code_functions is not visible before + * num_sym_code_functions. + */ + smp_mb(); + num_sym_code_functions =3D size / sizeof(struct code_range); + + return 0; +} +early_initcall(init_sym_code_functions); + static void unwind_init_common(struct unwind_state *state, struct task_struct *task) { @@ -251,6 +276,10 @@ NOKPROBE_SYMBOL(unwind_next); */ static void unwind_check_reliability(struct unwind_state *state) { + const struct code_range *range; + unsigned long pc; + int i; + if (state->fp =3D=3D state->final_fp) { /* Final frame; no more unwind, no need to check reliability */ return; @@ -263,6 +292,32 @@ static void unwind_check_reliability(struct unwind_sta= te *state) */ if (!__kernel_text_address(state->pc)) state->reliable =3D false; + + /* + * Check the return PC against sym_code_functions[]. If there is a + * match, then the consider the stack frame unreliable. + * + * As SYM_CODE functions don't follow the usual calling conventions, + * we assume by default that any SYM_CODE function cannot be unwound + * reliably. + * + * Note that this includes: + * + * - Exception handlers and entry assembly + * - Trampoline assembly (e.g., ftrace, kprobes) + * - Hypervisor-related assembly + * - Hibernation-related assembly + * - CPU start-stop, suspend-resume assembly + * - Kernel relocation assembly + */ + pc =3D state->pc; + for (i =3D 0; i < num_sym_code_functions; i++) { + range =3D &sym_code_functions[i]; + if (pc >=3D range->start && pc < range->end) { + state->reliable =3D false; + return; + } + } } =20 static bool notrace unwind(struct unwind_state *state, diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.ld= s.S index edaf0faf766f..55b61fefb643 100644 --- a/arch/arm64/kernel/vmlinux.lds.S +++ b/arch/arm64/kernel/vmlinux.lds.S @@ -122,6 +122,14 @@ jiffies =3D jiffies_64; #define TRAMP_TEXT #endif =20 +#define SYM_CODE_FUNCTIONS \ + . =3D ALIGN(16); \ + .symcode : AT(ADDR(.symcode) - LOAD_OFFSET) { \ + __sym_code_functions_start =3D .; \ + KEEP(*(sym_code_functions)) \ + __sym_code_functions_end =3D .; \ + } + /* * The size of the PE/COFF section that covers the kernel image, which * runs from _stext to _edata, must be a round multiple of the PE/COFF @@ -209,6 +217,8 @@ SECTIONS swapper_pg_dir =3D .; . +=3D PAGE_SIZE; =20 + SYM_CODE_FUNCTIONS + . =3D ALIGN(SEGMENT_ALIGN); __init_begin =3D .; __inittext_begin =3D .; --=20 2.25.1 From nobody Mon May 11 05:34:31 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 681DDC433EF for ; Wed, 13 Apr 2022 14:06:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236065AbiDMOIk (ORCPT ); Wed, 13 Apr 2022 10:08:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45238 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236029AbiDMOIJ (ORCPT ); Wed, 13 Apr 2022 10:08:09 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A9F84606D2; Wed, 13 Apr 2022 07:05:48 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id B8FB220C34D4; Wed, 13 Apr 2022 07:05:47 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com B8FB220C34D4 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1649858748; bh=f/N9Y3AhHP+6L0TxuoLGQXAr5xuXJnauRqGxyO1ZK4A=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Yy4A1rcENqnynxGYVqOz9YprcPsMzJ/nG7o3/WWZQhe6MrXhKE0lZPK9CwLfBLoDh 5Fo8NqKsS/71ebUW91iSA5V5R3jN0bT7GGpJT4cIk7bpcuRq9ewvLW/9L6x43fkuq+ X0YN7Lak/1EcMQfQsIS+VtEPhUB8CUK/1JJXkhOA= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, ardb@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jmorris@namei.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [PATCH v14 6/7] arm64: Introduce arch_stack_walk_reliable() Date: Wed, 13 Apr 2022 09:05:27 -0500 Message-Id: <20220413140528.3815-7-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220413140528.3815-1-madvenka@linux.microsoft.com> References: <20220413140528.3815-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Introduce arch_stack_walk_reliable() for ARM64. This works like arch_stack_walk() except that it returns -EINVAL if the stack trace is not reliable. Until all the reliability checks are in place, arch_stack_walk_reliable() may not be used by livepatch. But it may be used by debug and test code. Signed-off-by: Madhavan T. Venkataraman Reviewed-by: Mark Brown --- arch/arm64/kernel/stacktrace.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/arch/arm64/kernel/stacktrace.c b/arch/arm64/kernel/stacktrace.c index eda8581f7dbe..8016ba0e2c96 100644 --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -383,3 +383,26 @@ noinline notrace void arch_stack_walk(stack_trace_cons= ume_fn consume_entry, =20 unwind(&state, consume_entry, cookie); } + +/* + * arch_stack_walk_reliable() may not be used for livepatch until all of + * the reliability checks are in place in unwind_consume(). However, + * debug and test code can choose to use it even if all the checks are not + * in place. + */ +noinline int notrace arch_stack_walk_reliable( + stack_trace_consume_fn consume_entry, + void *cookie, + struct task_struct *task) +{ + struct unwind_state state; + bool reliable; + + if (task =3D=3D current) + unwind_init_from_caller(&state); + else + unwind_init_from_task(&state, task); + + reliable =3D unwind(&state, consume_entry, cookie); + return reliable ? 0 : -EINVAL; +} --=20 2.25.1 From nobody Mon May 11 05:34:31 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 E0FBEC433EF for ; Wed, 13 Apr 2022 14:06:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S236081AbiDMOIg (ORCPT ); Wed, 13 Apr 2022 10:08:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45256 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S236032AbiDMOIL (ORCPT ); Wed, 13 Apr 2022 10:08:11 -0400 Received: from linux.microsoft.com (linux.microsoft.com [13.77.154.182]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 9ACF9606D8; Wed, 13 Apr 2022 07:05:49 -0700 (PDT) Received: from x64host.home (unknown [47.189.24.195]) by linux.microsoft.com (Postfix) with ESMTPSA id AB40620C34D6; Wed, 13 Apr 2022 07:05:48 -0700 (PDT) DKIM-Filter: OpenDKIM Filter v2.11.0 linux.microsoft.com AB40620C34D6 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.microsoft.com; s=default; t=1649858749; bh=8+0+tmm79ZrOnS9Zex8wU0cF214m6bSiOKEXuw55Khc=; h=From:To:Subject:Date:In-Reply-To:References:From; b=Pw/QzKvPDTcghlquUWShrj8eWjhVvq+I6/fEsHWC7vHYZj3fZi5gHMm1Eu4Bhioh1 jL2NcGP4CU7Av09C35RGurajGnUFZXPW2rgAChufHAM9pdhrbEUclP1kZEsVXFBZkC 5+KYLZz1GWTmC80X0mkhryl4YonZFe8f/AHvuYgg= From: madvenka@linux.microsoft.com To: mark.rutland@arm.com, broonie@kernel.org, jpoimboe@redhat.com, ardb@kernel.org, nobuta.keiya@fujitsu.com, sjitindarsingh@gmail.com, catalin.marinas@arm.com, will@kernel.org, jmorris@namei.org, linux-arm-kernel@lists.infradead.org, live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, madvenka@linux.microsoft.com Subject: [PATCH v14 7/7] arm64: Select HAVE_RELIABLE_STACKTRACE Date: Wed, 13 Apr 2022 09:05:28 -0500 Message-Id: <20220413140528.3815-8-madvenka@linux.microsoft.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20220413140528.3815-1-madvenka@linux.microsoft.com> References: <20220413140528.3815-1-madvenka@linux.microsoft.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Type: text/plain; charset="utf-8" From: "Madhavan T. Venkataraman" Select HAVE_RELIABLE_STACKTRACE in arm64/Kconfig to allow arch_stack_walk_reliable() to be used. Note that this is conditional upon STACK_VALIDATION which will be added when frame pointer validation is implemented (say via objtool). Signed-off-by: Madhavan T. Venkataraman --- arch/arm64/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 57c4c995965f..f7b9d0fecf95 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -225,6 +225,7 @@ config ARM64 select THREAD_INFO_IN_TASK select HAVE_ARCH_USERFAULTFD_MINOR if USERFAULTFD select TRACE_IRQFLAGS_SUPPORT + select HAVE_RELIABLE_STACKTRACE if FRAME_POINTER && STACK_VALIDATION help ARM 64-bit (AArch64) Linux support. =20 --=20 2.25.1