From patchwork Fri Nov 22 19:26:06 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Martin X-Patchwork-Id: 3224061 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 7671EC045B for ; Fri, 22 Nov 2013 19:26:52 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 935D8207AF for ; Fri, 22 Nov 2013 19:26:51 +0000 (UTC) Received: from casper.infradead.org (casper.infradead.org [85.118.1.10]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0E54A207B2 for ; Fri, 22 Nov 2013 19:26:50 +0000 (UTC) Received: from merlin.infradead.org ([2001:4978:20e::2]) by casper.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VjwNF-0006yA-R6; Fri, 22 Nov 2013 19:26:41 +0000 Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1VjwND-000076-8I; Fri, 22 Nov 2013 19:26:39 +0000 Received: from fw-tnat.cambridge.arm.com ([217.140.96.21] helo=cam-smtp0.cambridge.arm.com) by merlin.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1VjwN8-0008VX-SI for linux-arm-kernel@lists.infradead.org; Fri, 22 Nov 2013 19:26:36 +0000 Received: from e103592.cambridge.arm.com (e103592.cambridge.arm.com [10.1.203.160]) by cam-smtp0.cambridge.arm.com (8.13.8/8.13.8) with ESMTP id rAMJQ6bM009240; Fri, 22 Nov 2013 19:26:06 GMT From: Dave Martin To: linux-arm-kernel@lists.infradead.org Subject: [PATCH] ARM: unwind: Fix fp/r7 mishandling for Thumb-2 Date: Fri, 22 Nov 2013 19:26:06 +0000 Message-Id: <1385148366-31492-1-git-send-email-Dave.Martin@arm.com> X-Mailer: git-send-email 1.7.9.5 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20131122_142635_138714_C7D377E3 X-CRM114-Status: GOOD ( 14.95 ) X-Spam-Score: -3.1 (---) Cc: Catalin Marinas , Will Deacon X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-4.7 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_MED, RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP The Thumb-2 ABI does not have a framepointer, but GCC sort-of- always uses the old ATPCS Thumb framepointer register (r7) when making non-trivial changes to a frame's sp. EABI allows the sp to be saved any old where, but GCC doesn't take advantage of this so we get away with it. The existing kernel backtrace implementation pretends that r7 is really fp for the purpose of maintining struct stackframe. However, this mapping is _not_ reflected in the way the unwinder virtual registers are maintained. This means that an unwinder opcode that fetches r7 obtains uninitialised grabage instead of the actual saved value of r7 (a.k.a. stackframe->fp). This results in failed backtraces when GCC saves a frame's sp in r7, which now appears to happen often, at least for threads sleeping in __switch_to. This patch initialises the unwinder virtual registers consistently so that the thread's saved r7 really does propagate into the virtual r7, and so that the pseudo-framepointer is passed correctly from one frame to the next. A minor refactoring in thread_info.h is included to make it easier to fetch an arbitrary saved register for a task. These changes should mean that the Magic SysRq 't' command now prints proper backtraces for sleeping threads with CONFIG_THUMB2_KERNEL=y (among other things). Someday this may need to be fixed more comprehensively, but for now the r7-is-the-framepointer-even-though-there-is-no-framepointer assumption seems to be fairly deeply hardwired into GCC for Thumb code. Signed-off-by: Dave Martin --- arch/arm/include/asm/thread_info.h | 12 ++++++------ arch/arm/kernel/unwind.c | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h index df5e13d..24e0019 100644 --- a/arch/arm/include/asm/thread_info.h +++ b/arch/arm/include/asm/thread_info.h @@ -110,12 +110,12 @@ static inline struct thread_info *current_thread_info(void) return (struct thread_info *)(sp & ~(THREAD_SIZE - 1)); } -#define thread_saved_pc(tsk) \ - ((unsigned long)(task_thread_info(tsk)->cpu_context.pc)) -#define thread_saved_sp(tsk) \ - ((unsigned long)(task_thread_info(tsk)->cpu_context.sp)) -#define thread_saved_fp(tsk) \ - ((unsigned long)(task_thread_info(tsk)->cpu_context.fp)) +#define thread_saved_reg(tsk, reg) \ + ((unsigned long)(task_thread_info(tsk)->cpu_context.reg)) + +#define thread_saved_pc(tsk) thread_saved_reg(tsk, pc) +#define thread_saved_sp(tsk) thread_saved_reg(tsk, sp) +#define thread_saved_fp(tsk) thread_saved_reg(tsk, fp) extern void crunch_task_disable(struct thread_info *); extern void crunch_task_copy(struct thread_info *, void *); diff --git a/arch/arm/kernel/unwind.c b/arch/arm/kernel/unwind.c index 00df012..cc619ff 100644 --- a/arch/arm/kernel/unwind.c +++ b/arch/arm/kernel/unwind.c @@ -74,8 +74,10 @@ struct unwind_ctrl_block { enum regs { #ifdef CONFIG_THUMB2_KERNEL +#define FP_REG r7 FP = 7, #else +#define FP_REG r11 FP = 11, #endif SP = 13, @@ -429,7 +431,7 @@ void unwind_backtrace(struct pt_regs *regs, struct task_struct *tsk) frame.pc = (unsigned long)unwind_backtrace; } else { /* task blocked in __switch_to */ - frame.fp = thread_saved_fp(tsk); + frame.fp = thread_saved_reg(tsk, FP_REG); frame.sp = thread_saved_sp(tsk); /* * The function calling __switch_to cannot be a leaf function