@@ -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,7 +43,8 @@ cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
CFLAGS += -g
CFLAGS += $(autodepend-flags) -Wall -Werror
-CFLAGS += $(call cc-option, -fomit-frame-pointer, "")
+frame-pointer-flag=-f$(if $(KEEP_FRAME_POINTER),no-,)omit-frame-pointer
+CFLAGS += $(call cc-option, $(frame-pointer-flag), "")
CFLAGS += $(call cc-option, -fno-stack-protector, "")
CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
new file mode 100644
new file mode 100644
@@ -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) ({ \
new file mode 100644
new file mode 100644
new file mode 100644
@@ -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 */
new file mode 100644
@@ -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
new file mode 100644
@@ -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
new file mode 100644
@@ -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);
+}
@@ -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)
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> --- Makefile | 6 ++-- 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(+), 2 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