diff mbox

[kvm-unit-tests,v7,1/5] lib: backtrace printing

Message ID adc65c3511125ea46f0fe53a2fc53a062ada7924.1458689655.git.pfeiner@google.com (mailing list archive)
State New, archived
Headers show

Commit Message

Peter Feiner March 22, 2016, 11:35 p.m. UTC
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 <pfeiner@google.com>
Reviewed-By: Andrew Jones <drjones@redhat.com>
---
 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 mbox

Patch

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 <libcflat.h>
+#include <stack.h>
+
+#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 <libcflat.h>
+#include <asm/stack.h>
+
+#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 <asm/stack.h>. Just use <stack.h>.
+#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 <libcflat.h>
+#include <stack.h>
+
+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)