From patchwork Tue Mar 22 23:35:02 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Feiner X-Patchwork-Id: 8646521 Return-Path: X-Original-To: patchwork-kvm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 624D0C0553 for ; Tue, 22 Mar 2016 23:35:24 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 3ACC220398 for ; Tue, 22 Mar 2016 23:35:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 72E5C203A5 for ; Tue, 22 Mar 2016 23:35:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751351AbcCVXfN (ORCPT ); Tue, 22 Mar 2016 19:35:13 -0400 Received: from mail-pf0-f180.google.com ([209.85.192.180]:36140 "EHLO mail-pf0-f180.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750826AbcCVXfK (ORCPT ); Tue, 22 Mar 2016 19:35:10 -0400 Received: by mail-pf0-f180.google.com with SMTP id u190so331841494pfb.3 for ; Tue, 22 Mar 2016 16:35:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:in-reply-to:references :in-reply-to:references; bh=Izr+r9Gv0L1g655D7i9hpULz8e0r8INzXhmLmAbHeLA=; b=OPD/95N2M9Wxvu/6LmBeTVSPozImsH1AyjxZfLc39+JmJjWtBjEintKvCiRIoRfLgB MbzbBkdVa84tWsmamUlSb9YzeKkioGHFY5HoOlBU05TLyGjsmf25Hhu4lMeauqAiEaRB D4eqh3UTGiQvvNNDCnWDKE6Sz5NqlkDtDqP/cja4C3lFbkQ77NJ1sEUWHPcFx/MhlK0s yNr3RXkXNQ110owuVT757UfXgT5n8Yn/6u7NBoFdbsCKsAesb+eqk6jAGfLKs3QYtoZ3 EZ7Y6TUiEj98E4sVhOKe0QvNBQoDdOiyUWQTYFletMQw8kws5JZULMlqC2503Km9nHdO /F7w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:in-reply-to:references; bh=Izr+r9Gv0L1g655D7i9hpULz8e0r8INzXhmLmAbHeLA=; b=JE+BDJBywf6EijXnyREGx14QtFLdtkpH1tu91HlZ+1+4UtCjpuu8SCYOLP56baeHbA TvCTwB/YH8Wn0j+OOZFC8YfU9eWNGmnTyzjbK1mGCTIDOyeGJOsPo7CYVD4liEKkkOMW 5A01zAofqB+FuY5dSaZmd/hVlrb/11bEQTVa/IegM473y/5L2HjtA9cnn1DNvnIXP6Zk V7hi8H4lmCy/sE0FhtbK3iUyYAEuuyQYw0Ss+PSa3gz87V7C51sf4LfYsJ0lzWXy7orP yhPH5lcHWILHqcGfQHUN26aBjW5n70Ylf2eVmP7ouVxgrrzznbEZPHz7vUbaDrIt0/9t oM+g== X-Gm-Message-State: AD7BkJJUvrvFoFhPB5IVKWDO5ZWb+Tjb2ig0HXCevKI3DeJuP/Q7ayH363jydkYz8/TyTRjk X-Received: by 10.98.74.6 with SMTP id x6mr57611909pfa.80.1458689709462; Tue, 22 Mar 2016 16:35:09 -0700 (PDT) Received: from localhost ([2620:0:1009:3:4fb:9875:8ad2:ab82]) by smtp.gmail.com with ESMTPSA id g70sm50781208pfj.13.2016.03.22.16.35.08 (version=TLS1_2 cipher=AES128-SHA bits=128/128); Tue, 22 Mar 2016 16:35:08 -0700 (PDT) From: Peter Feiner To: drjones@redhat.com, pbonzini@redhat.com, kvm@vger.kernel.org Cc: pfeiner@google.com Subject: [PATCH kvm-unit-tests v7 1/5] lib: backtrace printing Date: Tue, 22 Mar 2016 16:35:02 -0700 Message-Id: X-Mailer: git-send-email 2.8.0.rc3.226.g39d4020 In-Reply-To: References: In-Reply-To: References: Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED,RCVD_IN_DNSWL_HI,T_DKIM_INVALID,T_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 Functions to walk stack and print backtrace. The stack's unadorned as STACK: [@]addr addr addr ... where the optional @ indicates that addr isn't a return address. A follow-up patch post-processes the output to pretty-print the stack. Frame stack walker is just a stub on arm and ppc. Signed-off-by: Peter Feiner Reviewed-By: Andrew Jones --- Makefile | 7 ++-- lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/libcflat.h | 3 ++ lib/powerpc/asm/stack.h | 0 lib/ppc64/asm/stack.h | 0 lib/stack.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/stack.h | 20 +++++++++++ lib/x86/asm/stack.h | 14 ++++++++ lib/x86/stack.c | 31 ++++++++++++++++ x86/Makefile.common | 4 +++ 11 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/powerpc/asm/stack.h create mode 100644 lib/ppc64/asm/stack.h create mode 100644 lib/stack.c create mode 100644 lib/stack.h create mode 100644 lib/x86/asm/stack.h create mode 100644 lib/x86/stack.c diff --git a/Makefile b/Makefile index 2a2d942..5d7506e 100644 --- a/Makefile +++ b/Makefile @@ -22,7 +22,8 @@ cflatobjs := \ lib/printf.o \ lib/string.o \ lib/abort.o \ - lib/report.o + lib/report.o \ + lib/stack.o # libfdt paths LIBFDT_objdir = lib/libfdt @@ -42,8 +43,8 @@ cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ CFLAGS += -g CFLAGS += $(autodepend-flags) -Wall -Werror - -fomit_frame_pointer := $(call cc-option, -fomit-frame-pointer, "") +frame-pointer-flag=-f$(if $(KEEP_FRAME_POINTER),no-,)omit-frame-pointer +fomit_frame_pointer := $(call cc-option, $(frame-pointer-flag), "") fnostack_protector := $(call cc-option, -fno-stack-protector, "") fnostack_protector_all := $(call cc-option, -fno-stack-protector-all, "") CFLAGS += $(fomit_frame_pointer) diff --git a/lib/arm/asm/stack.h b/lib/arm/asm/stack.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/arm64/asm/stack.h b/lib/arm64/asm/stack.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/libcflat.h b/lib/libcflat.h index b58a8a1..55bddca 100644 --- a/lib/libcflat.h +++ b/lib/libcflat.h @@ -81,6 +81,9 @@ extern void report_xfail(const char *msg_fmt, bool xfail, bool pass, ...); extern void report_abort(const char *msg_fmt, ...); extern int report_summary(void); +extern void dump_stack(void); +extern void dump_frame_stack(const void *instruction, const void *frame); + #define ARRAY_SIZE(_a) (sizeof(_a)/sizeof((_a)[0])) #define container_of(ptr, type, member) ({ \ diff --git a/lib/powerpc/asm/stack.h b/lib/powerpc/asm/stack.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/ppc64/asm/stack.h b/lib/ppc64/asm/stack.h new file mode 100644 index 0000000..e69de29 diff --git a/lib/stack.c b/lib/stack.c new file mode 100644 index 0000000..b0a0295 --- /dev/null +++ b/lib/stack.c @@ -0,0 +1,96 @@ +#include +#include + +#define MAX_DEPTH 20 + +static void print_stack(const void **return_addrs, int depth, + bool top_is_return_address) +{ + int i = 0; + + printf("\tSTACK:"); + + /* @addr indicates a non-return address, as expected by the stack + * pretty printer script. */ + if (depth > 0 && !top_is_return_address) { + printf(" @%lx", (unsigned long) return_addrs[0]); + i++; + } + + for (; i < depth; i++) { + printf(" %lx", (unsigned long) return_addrs[i]); + } + printf("\n"); +} + +void dump_stack(void) +{ + const void *return_addrs[MAX_DEPTH]; + int depth; + + depth = backtrace(return_addrs, MAX_DEPTH); + print_stack(&return_addrs[1], depth ? depth - 1 : 0, true); +} + +void dump_frame_stack(const void *instruction, const void *frame) +{ + const void *return_addrs[MAX_DEPTH]; + int depth; + + return_addrs[0] = instruction; + depth = backtrace_frame(frame, &return_addrs[1], MAX_DEPTH - 1); + print_stack(return_addrs, depth + 1, false); +} + +#ifndef HAVE_ARCH_BACKTRACE +int backtrace(const void **return_addrs, int max_depth) +{ + static int walking; + int depth = 0; + void *addr; + + if (walking) { + printf("RECURSIVE STACK WALK!!!\n"); + return 0; + } + walking = 1; + + /* __builtin_return_address requires a compile-time constant argument */ +#define GET_RETURN_ADDRESS(i) \ + if (max_depth == i) \ + goto done; \ + addr = __builtin_return_address(i); \ + if (!addr) \ + goto done; \ + return_addrs[i] = __builtin_extract_return_addr(addr); \ + depth = i + 1; \ + + GET_RETURN_ADDRESS(0) + GET_RETURN_ADDRESS(1) + GET_RETURN_ADDRESS(2) + GET_RETURN_ADDRESS(3) + GET_RETURN_ADDRESS(4) + GET_RETURN_ADDRESS(5) + GET_RETURN_ADDRESS(6) + GET_RETURN_ADDRESS(7) + GET_RETURN_ADDRESS(8) + GET_RETURN_ADDRESS(9) + GET_RETURN_ADDRESS(10) + GET_RETURN_ADDRESS(11) + GET_RETURN_ADDRESS(12) + GET_RETURN_ADDRESS(13) + GET_RETURN_ADDRESS(14) + GET_RETURN_ADDRESS(15) + GET_RETURN_ADDRESS(16) + GET_RETURN_ADDRESS(17) + GET_RETURN_ADDRESS(18) + GET_RETURN_ADDRESS(19) + GET_RETURN_ADDRESS(20) + +#undef GET_RETURN_ADDRESS + +done: + walking = 0; + return depth; +} +#endif /* HAVE_ARCH_BACKTRACE */ diff --git a/lib/stack.h b/lib/stack.h new file mode 100644 index 0000000..bb6b9aa --- /dev/null +++ b/lib/stack.h @@ -0,0 +1,20 @@ +#ifndef _STACK_H_ +#define _STACK_H_ + +#include +#include + +#ifndef HAVE_ARCH_BACKTRACE_FRAME +static inline int +backtrace_frame(const void *frame __unused, const void **return_addrs __unused, + int max_depth __unused) +{ + return 0; +} +#endif + +#ifndef HAVE_ARCH_BACKTRACE +int backtrace(const void **return_addrs, int max_depth); +#endif + +#endif diff --git a/lib/x86/asm/stack.h b/lib/x86/asm/stack.h new file mode 100644 index 0000000..fc4766d --- /dev/null +++ b/lib/x86/asm/stack.h @@ -0,0 +1,14 @@ +#ifndef _X86ASM_STACK_H_ +#define _X86ASM_STACK_H_ + +#ifndef _STACK_H_ +#error Do not directly include . Just use . +#endif + +#define HAVE_ARCH_BACKTRACE_FRAME +int backtrace_frame(const void *frame, const void **return_addrs, int max_depth); + +#define HAVE_ARCH_BACKTRACE +int backtrace(const void **return_addrs, int max_depth); + +#endif diff --git a/lib/x86/stack.c b/lib/x86/stack.c new file mode 100644 index 0000000..d75c0be --- /dev/null +++ b/lib/x86/stack.c @@ -0,0 +1,31 @@ +#include +#include + +int backtrace_frame(const void *frame, const void **return_addrs, int max_depth) +{ + static int walking; + int depth = 0; + const unsigned long *bp = (unsigned long *) frame; + + if (walking) { + printf("RECURSIVE STACK WALK!!!\n"); + return 0; + } + walking = 1; + + for (depth = 0; depth < max_depth; depth++) { + return_addrs[depth] = (void *) bp[1]; + if (return_addrs[depth] == 0) + break; + bp = (unsigned long *) bp[0]; + } + + walking = 0; + return depth; +} + +int backtrace(const void **return_addrs, int max_depth) +{ + return backtrace_frame(__builtin_frame_address(0), return_addrs, + max_depth); +} diff --git a/x86/Makefile.common b/x86/Makefile.common index 3a14fea..ca80367 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -12,6 +12,7 @@ cflatobjs += lib/x86/atomic.o cflatobjs += lib/x86/desc.o cflatobjs += lib/x86/isr.o cflatobjs += lib/x86/acpi.o +cflatobjs += lib/x86/stack.o $(libcflat): LDFLAGS += -nostdlib $(libcflat): CFLAGS += -ffreestanding -I lib @@ -19,6 +20,9 @@ $(libcflat): CFLAGS += -ffreestanding -I lib CFLAGS += -m$(bits) CFLAGS += -O1 +# dump_stack.o relies on frame pointers. +KEEP_FRAME_POINTER := y + libgcc := $(shell $(CC) -m$(bits) --print-libgcc-file-name) FLATLIBS = lib/libcflat.a $(libgcc)