From patchwork Mon Oct 1 14:16:58 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Torsten Duwe X-Patchwork-Id: 10622249 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 9A2B61515 for ; Mon, 1 Oct 2018 14:38:10 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B04AD28F5D for ; Mon, 1 Oct 2018 14:38:09 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A43B028F8C; Mon, 1 Oct 2018 14:38:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 3AC7028F5D for ; Mon, 1 Oct 2018 14:38:09 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:From:Date: Message-Id:References:In-Reply-To:Subject:To:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=uweiZeJD7WlldpQnFCS8HPys2lIolADgMg5p/61ftyo=; b=FuzOM5KaM68u+lYYlu699wEap6 A2+7nYeTSAZRDWXOrBj/lV8uZN0vhAD27pSlfloInQTNvdvOrR+lexIIl4fWobz7pIjpAw16v3sS1 aIG07BvAvtY89o7EwHZ5PQHDKStyNc5hoSTmXEfZ3Kf3qSltzNhMxQRtAAqbOSsJyhtg3k6H+zEW3 2gSiFxiPDpngiLSE6VAbVSck0mJ+n3jlehfRsfVr0faltbEiDQLlu9O4M80fokIZ6OSI717wCdYNF HbnzT1I4zQEbezaSbEE1AhsP1k6aDbpp911oAhbH52cBp57VNDhfxFPCYSs8qvTKk861QB+BRgzJ9 CQUCc8Qg==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1g6zKm-00019W-Rr; Mon, 01 Oct 2018 14:38:04 +0000 Received: from casper.infradead.org ([85.118.1.10]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1g6zEF-0005to-FN for linux-arm-kernel@bombadil.infradead.org; Mon, 01 Oct 2018 14:31:19 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=From:Date:Message-Id:References: In-Reply-To:Subject:Cc:To:Sender:Reply-To:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=FbXGPB7jFkMLuQ2gifkWmni08AdrCWwRJG2BX8Hm+xI=; b=gxGWH97QwV0YTJwUN0jvY4xXi HDYIGaa/73dmsNSuzGnUL857cMosAk5IUefsM6XQ7yuG9G8kF+J4BrjowmY9vFVsWQGP7LKVdp/me b9UFDSxUpzZk8gUCZp+PJ2N+wc14PQi4j9hIgDHrsotExoG2xgZkt8geW+0mHTcF7dN1zcrRJizSG 5zWHQNoePnvo34dTssQjMYA5XRFQyZgxZgMO6g02utHyG5JhQWpsDGZCbc+nsCCCeHK8JTM59M1Ar FIJYYCOz1nyUYaDzbegqLyrqJugMKH/ihYprsOSg96+r7q2nZZXHtmQ5DEqS4cl1bWZ66b4An597r hofZk+YpA==; Received: from verein.lst.de ([213.95.11.211] helo=newverein.lst.de) by casper.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1g6z0X-0004i8-H4 for linux-arm-kernel@lists.infradead.org; Mon, 01 Oct 2018 14:17:12 +0000 Received: by newverein.lst.de (Postfix, from userid 2005) id A856D68BC7; Mon, 1 Oct 2018 16:16:58 +0200 (CEST) To: Will Deacon , Catalin Marinas , Julien Thierry , Steven Rostedt , Josh Poimboeuf , Ingo Molnar , Ard Biesheuvel , Arnd Bergmann , AKASHI Takahiro Subject: [PATCH v3 4/4] arm64: reliable stacktraces In-Reply-To: <20181001140910.086E768BC7@newverein.lst.de> References: <20181001140910.086E768BC7@newverein.lst.de> Message-Id: <20181001141658.A856D68BC7@newverein.lst.de> Date: Mon, 1 Oct 2018 16:16:58 +0200 (CEST) From: duwe@lst.de (Torsten Duwe) X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20181001_151709_653972_247A50E7 X-CRM114-Status: GOOD ( 15.84 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: live-patching@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Make unwind_frame() report whether it had to stop normally or due to an error condition; walk_stackframe() will pass that info. __save_stack_trace() is used to check the validity of a frame; save_stack_trace_tsk_reliable() can now trivially be implemented. Modify arch/arm64/kernel/time.c for the new semantics. Signed-off-by: Torsten Duwe --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -127,8 +127,9 @@ config ARM64 select HAVE_PERF_EVENTS select HAVE_PERF_REGS select HAVE_PERF_USER_STACK_DUMP - select HAVE_REGS_AND_STACK_ACCESS_API select HAVE_RCU_TABLE_FREE + select HAVE_REGS_AND_STACK_ACCESS_API + select HAVE_RELIABLE_STACKTRACE select HAVE_STACKPROTECTOR select HAVE_SYSCALL_TRACEPOINTS select HAVE_KPROBES --- a/arch/arm64/include/asm/stacktrace.h +++ b/arch/arm64/include/asm/stacktrace.h @@ -33,7 +33,7 @@ struct stackframe { }; extern int unwind_frame(struct task_struct *tsk, struct stackframe *frame); -extern void walk_stackframe(struct task_struct *tsk, struct stackframe *frame, +extern int walk_stackframe(struct task_struct *tsk, struct stackframe *frame, int (*fn)(struct stackframe *, void *), void *data); extern void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk); --- a/arch/arm64/kernel/stacktrace.c +++ b/arch/arm64/kernel/stacktrace.c @@ -40,6 +40,13 @@ * ldp x29, x30, [sp] * add sp, sp, #0x10 */ + +/* + * unwind_frame -- unwind a single stack frame. + * Returns 0 when there are more frames to go. + * 1 means reached end of stack; negative (error) + * means stopped because information is not reliable. + */ int notrace unwind_frame(struct task_struct *tsk, struct stackframe *frame) { unsigned long fp = frame->fp; @@ -81,23 +88,27 @@ int notrace unwind_frame(struct task_str * both are NULL. */ if (!frame->fp && !frame->pc) - return -EINVAL; + return 1; return 0; } -void notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, +int notrace walk_stackframe(struct task_struct *tsk, struct stackframe *frame, int (*fn)(struct stackframe *, void *), void *data) { while (1) { int ret; - if (fn(frame, data)) - break; + ret = fn(frame, data); + if (ret) + return ret; ret = unwind_frame(tsk, frame); if (ret < 0) + return ret; + if (ret > 0) break; } + return 0; } #ifdef CONFIG_STACKTRACE @@ -145,14 +156,15 @@ void save_stack_trace_regs(struct pt_reg trace->entries[trace->nr_entries++] = ULONG_MAX; } -static noinline void __save_stack_trace(struct task_struct *tsk, +static noinline int __save_stack_trace(struct task_struct *tsk, struct stack_trace *trace, unsigned int nosched) { struct stack_trace_data data; struct stackframe frame; + int ret; if (!try_get_task_stack(tsk)) - return; + return -EBUSY; data.trace = trace; data.skip = trace->skip; @@ -171,11 +183,12 @@ static noinline void __save_stack_trace( frame.graph = tsk->curr_ret_stack; #endif - walk_stackframe(tsk, &frame, save_trace, &data); + ret = walk_stackframe(tsk, &frame, save_trace, &data); if (trace->nr_entries < trace->max_entries) trace->entries[trace->nr_entries++] = ULONG_MAX; put_task_stack(tsk); + return ret; } EXPORT_SYMBOL_GPL(save_stack_trace_tsk); @@ -190,4 +203,12 @@ void save_stack_trace(struct stack_trace } EXPORT_SYMBOL_GPL(save_stack_trace); + +int save_stack_trace_tsk_reliable(struct task_struct *tsk, + struct stack_trace *trace) +{ + return __save_stack_trace(tsk, trace, 1); +} +EXPORT_SYMBOL_GPL(save_stack_trace_tsk_reliable); + #endif --- a/arch/arm64/kernel/time.c +++ b/arch/arm64/kernel/time.c @@ -56,7 +56,7 @@ unsigned long profile_pc(struct pt_regs #endif do { int ret = unwind_frame(NULL, &frame); - if (ret < 0) + if (ret) return 0; } while (in_lock_functions(frame.pc));