Re: [kvm-unit-tests v2 5/8] lib: backtrace printing

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Mar 02, 2016 at 05:09:35PM -0800, Peter Feiner wrote:
> Functions to walk stack and print backtrace. The stack's unadorned as
> 
> 	STACK: addr addr addr ...
> 
> A follow-up patch post-processes the output to pretty-print the stack.
> 
> Stack walker is just a stub on arm and ppc.
> 
> Signed-off-by: Peter Feiner <pfeiner@xxxxxxxxxx>
> ---
>  Makefile                 |  3 ++-
>  arm/Makefile.common      |  1 +
>  lib/arm/dump_stack.c     |  6 ++++++
>  lib/libcflat.h           |  4 ++++
>  lib/powerpc/dump_stack.c |  6 ++++++
>  lib/printf.c             | 37 +++++++++++++++++++++++++++++++++++++
>  lib/x86/dump_stack.c     | 24 ++++++++++++++++++++++++
>  powerpc/Makefile.common  |  1 +
>  x86/Makefile.common      |  4 ++++
>  9 files changed, 85 insertions(+), 1 deletion(-)
>  create mode 100644 lib/arm/dump_stack.c
>  create mode 100644 lib/powerpc/dump_stack.c
>  create mode 100644 lib/x86/dump_stack.c
> 
> diff --git a/Makefile b/Makefile
> index ddba941..40ea4ec 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -42,7 +42,8 @@ cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \
>  
>  CFLAGS += -g
>  CFLAGS += $(autodepend-flags) -Wall
> -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, "")
>  
> diff --git a/arm/Makefile.common b/arm/Makefile.common
> index dd3a0ca..054bdee 100644
> --- a/arm/Makefile.common
> +++ b/arm/Makefile.common
> @@ -39,6 +39,7 @@ cflatobjs += lib/arm/mmu.o
>  cflatobjs += lib/arm/bitops.o
>  cflatobjs += lib/arm/psci.o
>  cflatobjs += lib/arm/smp.o
> +cflatobjs += lib/arm/dump_stack.o
>  
>  libeabi = lib/arm/libeabi.a
>  eabiobjs = lib/arm/eabi_compat.o
> diff --git a/lib/arm/dump_stack.c b/lib/arm/dump_stack.c
> new file mode 100644
> index 0000000..528ba63
> --- /dev/null
> +++ b/lib/arm/dump_stack.c
> @@ -0,0 +1,6 @@
> +#include "libcflat.h"
> +
> +int walk_stack(unsigned long bp, unsigned long *stack, int max_depth)
> +{
> +	return 0;
> +}
> diff --git a/lib/libcflat.h b/lib/libcflat.h
> index 1f0049c..42c94df 100644
> --- a/lib/libcflat.h
> +++ b/lib/libcflat.h
> @@ -65,6 +65,10 @@ 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);
>  
> +int walk_stack(unsigned long bp, unsigned long *stack, int max_depth);
> +void dump_stack(unsigned long ip, unsigned long bp);
> +void dump_current_stack(void);

The inputs are a bit x86ish. On ARM, for example, we call them pc and
fp. Acutally, how about we implement backtrace(3) instead? And then wrap
print_current_stack(void) around that.

Also, instead of building on a single arch function, walk_stack, how about
two

  void *arch_frame_address(unsigned int level);
  void *arch_return_address(void *frame, unsigned int level);

The architecture may be able to easily implement these with gcc builtins,
or not. I've added *frame to arch_return_address' parameters in case
__builtin_return_address(level) doesn't work. 

And, let's just require the architectures to have the functions, not that
they have a dump_stack.c file. If we include lib/asm/<ARCH>/stack.h, or
whatever you want to call it, then the arch could just supply some inlines
there.

> +
>  #define ARRAY_SIZE(_a) (sizeof(_a)/sizeof((_a)[0]))
>  
>  #define container_of(ptr, type, member) ({				\
> diff --git a/lib/powerpc/dump_stack.c b/lib/powerpc/dump_stack.c
> new file mode 100644
> index 0000000..528ba63
> --- /dev/null
> +++ b/lib/powerpc/dump_stack.c
> @@ -0,0 +1,6 @@
> +#include "libcflat.h"
> +
> +int walk_stack(unsigned long bp, unsigned long *stack, int max_depth)
> +{
> +	return 0;
> +}
> diff --git a/lib/printf.c b/lib/printf.c
> index 2aec59a..e97fca9 100644
> --- a/lib/printf.c
> +++ b/lib/printf.c
> @@ -259,3 +259,40 @@ int printf(const char *fmt, ...)
>      puts(buf);
>      return r;
>  }
> +
> +static void print_stack(unsigned long *stack, int depth,
> +			bool top_is_return_address)
> +{
> +	int i;
> +
> +	printf("\tSTACK: " );
> +	for (i = 0; i < depth; i++) {
> +		int offset = -1;
> +		if (i == 0 && !top_is_return_address)
> +			offset = 0;
> +		printf(" %lx", stack[i] + offset);

I'm afraid I don't understand the use of offset here. I fear it may
be x86-ness leaked into the arch-neutral print_stack().

> +	}
> +	printf("\n");
> +}
> +
> +#define MAX_DEPTH 10
> +
> +void dump_stack(unsigned long ip, unsigned long bp)
> +{
> +	unsigned long stack[MAX_DEPTH];
> +	int depth;
> +
> +	stack[0] = ip;
> +	depth = walk_stack(bp, &stack[1], MAX_DEPTH - 1);
> +	print_stack(stack, depth + 1, false);
> +}

When would dump_stack() be useful, as opposed to dump_current_stack?

> +
> +void dump_current_stack(void)
> +{
> +	unsigned long stack[MAX_DEPTH];
> +	int depth;
> +
> +	depth = walk_stack((unsigned long)__builtin_frame_address(1), stack,
> +			   MAX_DEPTH);
> +	print_stack(stack, depth, true);
> +}
> diff --git a/lib/x86/dump_stack.c b/lib/x86/dump_stack.c
> new file mode 100644
> index 0000000..6e9d126
> --- /dev/null
> +++ b/lib/x86/dump_stack.c
> @@ -0,0 +1,24 @@
> +#include "libcflat.h"
> +
> +int walk_stack(unsigned long bp, unsigned long *stack, int max_depth)
> +{
> +	static int walking;
> +	int depth = 0;
> +	unsigned long *frame = (unsigned long *) bp;
> +
> +	if (walking) {
> +		printf("RECURSIVE STACK WALK!!!\n");
> +		return 0;
> +	}
> +	walking = 1;
> +
> +	for (depth = 0; depth < max_depth; depth++) {
> +		stack[depth] = frame[1];
> +		if (stack[depth] == 0)
> +			break;
> +		frame = (unsigned long *) frame[0];
> +	}
> +
> +	walking = 0;
> +	return depth;
> +}
> diff --git a/powerpc/Makefile.common b/powerpc/Makefile.common
> index 2ce6494..694dea0 100644
> --- a/powerpc/Makefile.common
> +++ b/powerpc/Makefile.common
> @@ -30,6 +30,7 @@ cflatobjs += lib/powerpc/io.o
>  cflatobjs += lib/powerpc/hcall.o
>  cflatobjs += lib/powerpc/setup.o
>  cflatobjs += lib/powerpc/rtas.o
> +cflatobjs += lib/powerpc/dump_stack.o
>  
>  FLATLIBS = $(libcflat) $(LIBFDT_archive)
>  %.elf: CFLAGS += $(arch_CFLAGS)
> diff --git a/x86/Makefile.common b/x86/Makefile.common
> index 3a14fea..d7c7eab 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/dump_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)
> -- 
> 2.7.0.rc3.207.g0ac5344

Thanks,
drew
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux