Debugging aids
Subsystems (3)
cover Debugging aids
Some aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
N.B. I haven't tried compiling on arm or ppc.
Peter Feiner (5):
lib: print failing assert cond
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on abort()
scripts: pretty print stack traces
Makefile | 2 +- arm/Makefile.common | 1 + lib/arm/dump_stack.c | 6 ++++ lib/libcflat.h | 11 +++++-- lib/powerpc/dump_stack.c | 6 ++++ lib/printf.c | 37 ++++++++++++++++++++++ lib/x86/desc.c | 69 ++++++++++++++++++++++++++++++++++++++---- lib/x86/dump_stack.c | 24 +++++++++++++++ powerpc/Makefile.common | 1 + run_tests.sh | 10 ++++-- scripts/pretty_print_stacks.py | 61 +++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 1 + 12 files changed, 218 insertions(+), 11 deletions(-) create mode 100644 lib/arm/dump_stack.c create mode 100644 lib/powerpc/dump_stack.c create mode 100644 lib/x86/dump_stack.c create mode 100755 scripts/pretty_print_stacks.py
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH 1/5 lib: print failing assert cond
--- lib/libcflat.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
lib/libcflat.h +2 -1
@@ -74,7 +74,8 @@ extern int report_summary(void);#define assert (cond) \ do { \ if (!(cond)) \ - printf("%s:%d: assert failed\n", __FILE__, __LINE__), \ + printf("%s:%d: assert failed: %s\n", \ + __FILE__, __LINE__, #cond), \ abort(); \ } while (0)
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests 1/5] lib: print failing assert cond
Quoted 1 line · Peter Feiner
Signed-off-by Peter Feiner <[email protected]>
Quoted 25 lines
--- lib/libcflat.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)lib/libcflat.h +2
-1@@ -74,7 +74,8 @@ extern int report_summary(void);#define assert (cond) \ do { \ if (!(cond)) \ - printf("%s:%d: assert failed\n", __FILE__, __LINE__), \ + printf("%s:%d: assert failed: %s\n", \ + __FILE__, __LINE__, #cond), \ abort(); \ } while (0)Signature · 6 lines
2.7.0.rc3.207.g0ac5344 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH 2/5 lib: backtrace printing
In reply to Peter FeinerFunctions 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.
--- Makefile | 2 +- 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 | 1 + 9 files changed, 81 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
Makefile +1 -1
@@ -42,7 +42,7 @@ 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, "") +CFLAGS += $(call cc-option, -fno-omit-frame-pointer, "") CFLAGS += $(call cc-option, -fno-stack-protector, "") CFLAGS += $(call cc-option, -fno-stack-protector-all, "")
arm/Makefile.common +1 -0
@@ -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
lib/arm/dump_stack.c new file +6 -0
@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}
lib/libcflat.h +4 -0
@@ -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 ); +#define ARRAY_SIZE (_a) (sizeof(_a)/sizeof((_a)[0]))#define container_of (ptr, type, member) ({ \
lib/powerpc/dump_stack.c new file +6 -0
@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}
lib/printf.c +37 -0
@@ -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); + } +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); +} + +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); +}
lib/x86/dump_stack.c new file +24 -0
@@ -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; +}
powerpc/Makefile.common +1 -0
@@ -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: LDFLAGS = $(arch_LDFLAGS) -nostdlib -pie
x86/Makefile.common +1 -0
@@ -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
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests 2/5] lib: backtrace printing
Makefile cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ · line 45
Quoted 2 lines · Peter Feiner
Makefile +1
-1-CFLAGS += $(call cc-option, -fomit-frame-pointer, "") +CFLAGS += $(call cc-option, -fno-omit-frame-pointer, "")
Please hold off on this series for now. -fno-omit-frame-pointer seems to break x86/emulator.flat. I'll look into it and reply when I've figured things out.
Re: [kvm-unit-tests 2/5] lib: backtrace printing
Quoted 7 lines · Peter Feiner
Makefile cc-option = $(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null \ · line 45
Quoted 2 lines · Peter Feiner
Makefile +1
-1-CFLAGS += $(call cc-option, -fomit-frame-pointer, "") +CFLAGS += $(call cc-option, -fno-omit-frame-pointer, "")Please hold off on this series for now. -fno-omit-frame-pointer seems to break x86/emulator.flat. I'll look into it and reply when I've figured things out.
Apparently x86/emulator.flat is very fickle:
-O0 causes #PF
-fno-omit-frame-pointer causes triple fault
-fno-omit-frame-pointer and -O0 causes #GP
Oye!
PATCH 3/5 x86: lib: debug dump on unhandled exceptions
In reply to Peter FeinerPrints the stack trace and registers.
--- lib/x86/desc.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-)
lib/x86/desc.c +63 -6
@@ -38,6 +38,67 @@ struct ex_record {extern struct ex_record exception_table_start, exception_table_end; +static const char *exception_mnemonic (int vector) +{ +switch (vector) { +case 0 :return "#DE" ; +case 1 :return "#DB" ; +case 2 :return "#NMI" ; +case 3 :return "#BP" ; +case 4 :return "#OF" ; +case 5 :return "#BR" ; +case 6 :return "#UD" ; +case 7 :return "#NM" ; +case 8 :return "#DF" ; +case 10 :return "#TS" ; +case 11 :return "#NP" ; +case 12 :return "#SS" ; +case 13 :return "#GP" ; +case 14 :return "#PF" ; +case 16 :return "#MF" ; +case 17 :return "#AC" ; +case 18 :return "#MC" ; +case 19 :return "#XM" ; +default :return "#??" ; + } +} + +static void unhandled_exception (struct ex_regs *regs,bool cpu) +{ +printf ("Unhandled %sexception %ld %s at ip %016lx\n" , + cpu ?"cpu " :"" , regs->vector, +exception_mnemonic (regs->vector), regs->rip); +if (regs->vector ==14 ) +printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); + + printf("error_code=%04lx rflags=%08lx cs=%08lx\n" + "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n" + "rbp=%016lx rsi=%016lx rdi=%016lx\n" +#ifdef __x86_64__ + " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n" + "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n" +#endif +"cr0=%016lx cr2=%016lx cr3=%016lx cr4=%016lx\n" +#ifdef __x86_64__ +"cr8=%016lx\n" +#endif + , + regs->error_code, regs->rflags, regs->cs, + regs->rax, regs->rcx, regs->rdx, regs->rbx, + regs->rbp, regs->rsi, regs->rdi, +#ifdef __x86_64__ + regs->r8, regs->r9, regs->r10, regs->r11, + regs->r12, regs->r13, regs->r14, regs->r15, +#endif +read_cr0 (),read_cr2 (),read_cr3 (),read_cr4 () +#ifdef __x86_64__ + ,read_cr8 () +#endif + ); +dump_stack (regs->rip, regs->rbp); +exit (7 ); +} +static void check_exception_table (struct ex_regs *regs) {struct ex_record *ex;
@@ -53,8 +114,7 @@ static void check_exception_table(struct ex_regs *regs)return ; } } -printf ("unhandled exception %d\n" , regs->vector); -exit (7 ); +unhandled_exception (regs, false); }static void (*exception_handlers[32 ])(struct ex_regs *regs);
@@ -75,10 +135,7 @@ void do_handle_exception(struct ex_regs *regs) exception_handlers[regs->vector](regs);return ; } -printf ("unhandled cpu exception %d\n" , regs->vector); -if (regs->vector ==14 ) -printf ("PF at %p addr %p\n" , regs->rip,read_cr2 ()); -exit (7 ); +unhandled_exception (regs, true); }#define EX (NAME ,N ) extern char NAME##_fault; \
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH 4/5 lib: dump stack on abort()
In reply to Peter Feiner--- lib/libcflat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
lib/libcflat.h +4 -2
@@ -77,10 +77,12 @@ void dump_current_stack(void);#define assert (cond) \ do { \ - if (!(cond)) \ + if (!(cond)) { \ printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond), \ + __FILE__, __LINE__, #cond); \ + dump_current_stack(); \ abort(); \ + } \ } while (0)#endif
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests 4/5] lib: dump stack on abort()
subject should be "[kvm-unit-tests 4/5] lib: dump stack on failed assert()"
Quoted 27 lines · Peter Feiner
Signed-off-by Peter Feiner <[email protected]>--- lib/libcflat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)lib/libcflat.h +4
-3@@ -77,10 +77,12 @@ void dump_current_stack(void);#define assert (cond) \ do { \ - if (!(cond)) \ + if (!(cond)) { \ printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond), \ + __FILE__, __LINE__, #cond); \ + dump_current_stack(); \ abort(); \ + } \ } while (0)#endif --2.7.0.rc3.207.g0ac5344
PATCH 5/5 scripts: pretty print stack traces
In reply to Peter FeinerOptionally pretty print stacks in test.log with 'run_tests.sh -p'.
The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5: ac_test_exec at x86/access.c:818
}
> ac_test_setup_pte(at, pool);
r = ac_test_do_access(at);
0x004014dd: ac_test_run at x86/access.c:852
++tests;
> successes += ac_test_exec(&at, &pool);
} while (ac_test_bump(&at));
0x0040157d: main at x86/access.c:873
printf("starting test\n\n");
> r = ac_test_run();
return r ? 0 : 1;0x0040028e: start64 at x86/cstart64.S:206
lea __argv(%rip), %rsi
> call main
mov %eax, %edi
--- run_tests.sh | 10 +++++-- scripts/pretty_print_stacks.py | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.py
run_tests.sh +8 -2
@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"
@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.
@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log" -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG
@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;; *) exit ;; esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log echo > test.log
scripts/pretty_print_stacks.py new file +61 -0
61 lines not on this page · raw message
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Paolo Bonzini
maintainerRe: [kvm-unit-tests 5/5] scripts: pretty print stack traces
Quoted 137 lines · Peter Feiner
Optionally pretty print stacks in test.log with '
run_tests.sh-p'.The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5:ac_test_execatx86/access.c:818} > ac_test_setup_pte(at, pool); r = ac_test_do_access(at); 0x004014dd: ac_test_run at x86/access.c:852 ++tests; > successes += ac_test_exec(&at, &pool); } while (ac_test_bump(&at)); 0x0040157d: main at x86/access.c:873 printf("starting test\n\n"); > r = ac_test_run(); return r ? 0 : 1;
0x0040028e: start64 atx86/cstart64.S:206
lea__argv(%rip), %rsi
> call main
mov %eax, %ediSigned-off-by Peter Feiner <[email protected]>--- run_tests.sh | 10 +++++-- scripts/pretty_print_stacks.py | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.pyrun_tests.sh +8
-2@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log" -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;; *) exit ;; esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log echo > test.logscripts/pretty_print_stacks.py new file +51
-0@@ -0,0 +1,61 @@ +#!/usr/bin/env python + +import re +import subprocess +import sys + +if len(sys.argv) != 2: + sys.stderr.write('usage: %s <kernel>\n' % sys.argv[0]) + sys.exit(1) + +binary = sys.argv[1] + +# Subvert output buffering. +def puts(string): + sys.stdout.write(string) + sys.stdout.flush() + +try: + while True: + # Subvert input buffering. + line = sys.stdin.readline() + if line == '': + break + + if not line.strip().startswith('STACK:'): + puts(line) + continue + + addrs = line.split()[1:] + # Output like this: + # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 + # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) + cmd = ['addr2line', '-e', binary, '-i', '-f', '--pretty', '--address'] + cmd.extend(addrs) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + puts(line) + continue + + for line in out.splitlines(): + m = re.match('(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) + if m is None: + puts('%s\n' % line) + continue + + head, path, line, tail = m.groups() + line = int(line) + puts('%s at %s:%d%s\n' % (head, path, line, tail)) + try:
scripts/pretty_print_stacks.py line 61
Quoted 10 lines
scripts/pretty_print_stacks.py new file +10
-0+ lines = open(path).readlines() + except IOError: + continue + if line > 1: + puts(' %s\n' % lines[line - 2].rstrip()) + puts(' > %s\n' % lines[line - 1].rstrip()) + if line < len(lines): + puts(' %s\n' % lines[line].rstrip()) +except: + sys.exit(1)
For now I've committed only the script; I'd like Drew to take a look at run_tests.sh and see if it's possible/worthwhile to include the pretty printing script in mkstandalone.sh. But even without integration in run_tests.sh the scripts is nice and useful.
Queued, will push tomorrow together with the rest.
Paolo
Re: [kvm-unit-tests 5/5] scripts: pretty print stack traces
Quoted 156 lines · Paolo Bonzini
Quoted 137 lines · Peter Feiner
Optionally pretty print stacks in test.log with '
run_tests.sh-p'.The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5:ac_test_execatx86/access.c:818} > ac_test_setup_pte(at, pool); r = ac_test_do_access(at); 0x004014dd: ac_test_run at x86/access.c:852 ++tests; > successes += ac_test_exec(&at, &pool); } while (ac_test_bump(&at)); 0x0040157d: main at x86/access.c:873 printf("starting test\n\n"); > r = ac_test_run(); return r ? 0 : 1;
0x0040028e: start64 atx86/cstart64.S:206
lea__argv(%rip), %rsi
> call main
mov %eax, %ediSigned-off-by Peter Feiner <[email protected]>--- run_tests.sh | 10 +++++-- scripts/pretty_print_stacks.py | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.pyrun_tests.sh +8
-2@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log" -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;; *) exit ;; esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log echo > test.logscripts/pretty_print_stacks.py new file +51
-0@@ -0,0 +1,61 @@ +#!/usr/bin/env python + +import re +import subprocess +import sys + +if len(sys.argv) != 2: + sys.stderr.write('usage: %s <kernel>\n' % sys.argv[0]) + sys.exit(1) + +binary = sys.argv[1] + +# Subvert output buffering. +def puts(string): + sys.stdout.write(string) + sys.stdout.flush() + +try: + while True: + # Subvert input buffering. + line = sys.stdin.readline() + if line == '': + break + + if not line.strip().startswith('STACK:'): + puts(line) + continue + + addrs = line.split()[1:] + # Output like this: + # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 + # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) + cmd = ['addr2line', '-e', binary, '-i', '-f', '--pretty', '--address'] + cmd.extend(addrs) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + puts(line) + continue + + for line in out.splitlines(): + m = re.match('(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) + if m is None: + puts('%s\n' % line) + continue + + head, path, line, tail = m.groups() + line = int(line) + puts('%s at %s:%d%s\n' % (head, path, line, tail)) + try:scripts/pretty_print_stacks.py line 61
Quoted 10 lines
scripts/pretty_print_stacks.py new file +10
-0+ lines = open(path).readlines() + except IOError: + continue + if line > 1: + puts(' %s\n' % lines[line - 2].rstrip()) + puts(' > %s\n' % lines[line - 1].rstrip()) + if line < len(lines): + puts(' %s\n' % lines[line].rstrip()) +except: + sys.exit(1)For now I've committed only the script; I'd like Drew to take a look at
run_tests.shand see if it's possible/worthwhile to include the pretty printing script inmkstandalone.sh. But even without integration inrun_tests.shthe scripts is nice and useful.
Quoted 1 line
Queued, will push tomorrow together with the rest.
It should be possible, just another "temp_file", I think. But then we expect the standalone test to be executed somewhere with pyhon (likely) and addr2line (not as likely). Also, without the source available, then it probably isn't all the useful to the user executing the test, and anybody they send the results to can copy+paste the backtrace line directly into addr2line themselves.
Long story short, I vote we don't add it to mkstandalone.
Now, one addition that may make sense, wrt mkstandalone, is that we output what HEAD was when mkstandalone was used to build the tests. That would be useful just by itself to know what code is running, and extra useful when using addr2line.
drew
Paolo Bonzini
maintainerRe: [kvm-unit-tests 5/5] scripts: pretty print stack traces
Quoted 3 lines · Andrew Jones
wrt to enabling/disabling it though, how about we create a new configure command line option instead. One that defaults to on, if the architecture supports pretty-printing, but can be switched off.
Which architectures don't? But I like a
--enable/disable-pretty-print-stacks option.
Quoted 8 lines
It should be possible, just another "
temp_file", I think. But then we expect the standalone test to be executed somewhere with pyhon (likely) and addr2line (not as likely). Also, without the source available, then it probably isn't all the useful to the user executing the test, and anybody they send the results to can copy+paste the backtrace line directly into addr2line themselves.Long story short, I vote we don't add it to mkstandalone.
I agree. Something like
scripts/mkstandalone.sh +0 -0
@@ -41,6 +41,10 @@ generate_test () echo "#!/bin/bash" echo "export STANDALONE=yes" echo "export HOST=\$(uname -m | sed -e s/i.86/i386/ | sed -e
's/arm.*/arm/')"
+
+ # do not require addr2line on the test machine
+ echo "export PRETTY_PRINT_STACKS=no"
+
config_export ARCH
config_export ARCH_NAME
config_export PROCESSOR
if we go with your suggestion of configurable pretty printing.
Quoted 4 lines
Now, one addition that may make sense, wrt mkstandalone, is that we output what HEAD was when mkstandalone was used to build the tests. That would be useful just by itself to know what code is running, and extra useful when using addr2line.
That makes sense. Can you send a patch (Drew)?
Paolo
Re: [kvm-unit-tests 5/5] scripts: pretty print stack traces
Quoted 9 lines · Paolo Bonzini
Quoted 3 lines · Andrew Jones
wrt to enabling/disabling it though, how about we create a new configure command line option instead. One that defaults to on, if the architecture supports pretty-printing, but can be switched off.
Which architectures don't? But I like a
--enable/disable-pretty-print-stacks option.
Eventually, probably none.
Quoted 29 lines
Quoted 9 lines
It should be possible, just another "
temp_file", I think. But then we expect the standalone test to be executed somewhere with pyhon (likely) and addr2line (not as likely). Also, without the source available, then it probably isn't all the useful to the user executing the test, and anybody they send the results to can copy+paste the backtrace line directly into addr2line themselves.Long story short, I vote we don't add it to mkstandalone.
I agree. Something like
scripts/mkstandalone.sh +0
-0@@ -41,6 +41,10 @@ generate_test () echo "#!/bin/bash" echo "export STANDALONE=yes" echo "export HOST=\$(uname -m | sed -e s/i.86/i386/ | sed -e's/arm.*/arm/')"
scripts/mkstandalone.sh +4
-0+ + # do not require addr2line on the test machine + echo "export PRETTY_PRINT_STACKS=no" + config_export ARCH config_export ARCH_NAME config_export PROCESSOR
Quoted 1 line
if we go with your suggestion of configurable pretty printing.
yeah, exactly.
Quoted 7 lines
Quoted 5 lines
Now, one addition that may make sense, wrt mkstandalone, is that we output what HEAD was when mkstandalone was used to build the tests. That would be useful just by itself to know what code is running, and extra useful when using addr2line.
That makes sense. Can you send a patch (Drew)?
Yup, got it on the ol' TODO already :-)
drew
v2 cover Debugging aids
In reply to Peter FeinerSome aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
N.B. I haven't tried compiling on arm or ppc.
v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.
Peter Feiner (8):
x86: emulator: asm fixes
x86: emulator: disable test_lldt
x86: realmode: fix test_sgdt_sidt overflow
x86: eventinj: make test work with -O0
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on abort()
scripts: pretty print stack traces
Makefile | 3 +- arm/Makefile.common | 1 + lib/arm/dump_stack.c | 6 ++++ lib/libcflat.h | 10 ++++-- lib/powerpc/dump_stack.c | 6 ++++ lib/printf.c | 37 +++++++++++++++++++++ lib/x86/desc.c | 69 +++++++++++++++++++++++++++++++++++---- lib/x86/dump_stack.c | 24 ++++++++++++++ powerpc/Makefile.common | 1 + run_tests.sh | 10 ++++-- scripts/pretty_print_stacks.py | 61 ++++++++++++++++++++++++++++++++++ x86/Makefile.common | 4 +++ x86/emulator.c | 74 +++++++++++++++++++++++++++--------------- x86/eventinj.c | 3 +- x86/realmode.c | 23 ++++++------- 15 files changed, 281 insertions(+), 51 deletions(-) create mode 100644 lib/arm/dump_stack.c create mode 100644 lib/powerpc/dump_stack.c create mode 100644 lib/x86/dump_stack.c create mode 100755 scripts/pretty_print_stacks.py
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v2 1/8 x86: emulator: asm fixes
Found several problems in the emulator test when trying to compile with various combinations of -fno-omit-frame-pointer and -O{0,1}.
Fixed register clobbering in several tests. It's not good enough to save & restore a register with I/O operands because the compiler can use the register to effect the I/O! Fixing %rbp was tricky because it can't be listed in the clobber list when -fno-omit-frame-pointer is in effect; thus %rbp has to be saved manually using a scratch register that's declared as clobbered.
The length of the jmp instruction in test_jmp_noncanonical was 2, not
3. This patch makes the exception handler more robust by using the computed instruction length.
--- x86/emulator.c | 60 +++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 24 deletions(-)
x86/emulator.c +36 -24
@@ -260,24 +260,30 @@ void test_pop(void *mem)report ("ret" ,1 ); stack_top[-1 ] =0x778899 ; - asmvolatile ("mov %%rsp, %[tmp] \n\t" -"mov %%rbp, %[tmp3] \n\t" -"mov %[stack_top], %%rbp \n\t" + asmvolatile ("mov %[stack_top], %%r8 \n\t" +"mov %%rsp, %%r9 \n\t" +"xchg %%rbp, %%r8 \n\t" "leave \n\t" -"xchg %%rsp, %[tmp] \n\t" -"xchg %%rbp, %[tmp3]" +"xchg %%rsp, %%r9 \n\t" +"xchg %%rbp, %%r8 \n\t" +"mov %%r9, %[tmp] \n\t" +"mov %%r8, %[tmp3]" : [tmp]"=&r" (tmp), [tmp3]"=&r" (tmp3) : [stack_top]"r" (stack_top-1 ) - :"memory" ); + :"memory" ,"r8" ,"r9" );report ("leave" , tmp == (ulong )stack_top && tmp3 ==0x778899 ); rbp =0xaa55aa55bb66bb66ULL ; rsp = (unsigned long )stack_top; - asmvolatile ("xchg %%rsp, %[rsp] \n\t" -"xchg %%rbp, %[rbp] \n\t" + asmvolatile ("mov %[rsp], %%r8 \n\t" +"mov %[rbp], %%r9 \n\t" +"xchg %%rsp, %%r8 \n\t" +"xchg %%rbp, %%r9 \n\t" "enter $0x1238, $0 \n\t" -"xchg %%rsp, %[rsp] \n\t" -"xchg %%rbp, %[rbp]" - : [rsp]"+a" (rsp), [rbp]"+b" (rbp) : :"memory" ); +"xchg %%rsp, %%r8 \n\t" +"xchg %%rbp, %%r9 \n\t" +"xchg %%r8, %[rsp] \n\t" +"xchg %%r9, %[rbp]" + : [rsp]"+a" (rsp), [rbp]"+b" (rbp) : :"memory" ,"r8" ,"r9" );report ("enter" , rsp == (unsigned long )stack_top -8 -0x1238 && rbp == (unsigned long)stack_top - 8
@@ -405,7 +411,7 @@ void test_xchg(void *mem) "mov %%rax, %[rax]\n\t" : [rax]"=r"(rax) : [memq]"r"(memq) - : "memory"); + : "memory", "rax"); report("xchg reg, r/m (1)" , rax ==0xfedcba98765432ef && *memq ==0x123456789abcd10 );
@@ -416,7 +422,7 @@ void test_xchg(void *mem) "mov %%rax, %[rax]\n\t" : [rax]"=r"(rax) : [memq]"r"(memq) - : "memory"); + : "memory", "rax"); report("xchg reg, r/m (2)" , rax ==0xfedcba987654cdef && *memq ==0x123456789ab3210 );
@@ -427,7 +433,7 @@ void test_xchg(void *mem) "mov %%rax, %[rax]\n\t" : [rax]"=r"(rax) : [memq]"r"(memq) - : "memory"); + : "memory", "rax"); report("xchg reg, r/m (3)" , rax ==0x89abcdef && *memq ==0x123456776543210 );
@@ -438,7 +444,7 @@ void test_xchg(void *mem) "mov %%rax, %[rax]\n\t" : [rax]"=r"(rax) : [memq]"r"(memq) - : "memory"); + : "memory", "rax"); report("xchg reg, r/m (4)" , rax ==0x123456789abcdef && *memq ==0xfedcba9876543210 ); }
@@ -455,7 +461,7 @@ void test_xadd(void *mem) "mov %%rax, %[rax]\n\t" : [rax]"=r"(rax) : [memq]"r"(memq) - : "memory"); + : "memory", "rax"); report("xadd reg, r/m (1)" , rax ==0xfedcba98765432ef && *memq ==0x123456789abcdff );
@@ -466,7 +472,7 @@ void test_xadd(void *mem) "mov %%rax, %[rax]\n\t" : [rax]"=r"(rax) : [memq]"r"(memq) - : "memory"); + : "memory", "rax"); report("xadd reg, r/m (2)" , rax ==0xfedcba987654cdef && *memq ==0x123456789abffff );
@@ -477,7 +483,7 @@ void test_xadd(void *mem) "mov %%rax, %[rax]\n\t" : [rax]"=r"(rax) : [memq]"r"(memq) - : "memory"); + : "memory", "rax"); report("xadd reg, r/m (3)" , rax ==0x89abcdef && *memq ==0x1234567ffffffff );
@@ -488,7 +494,7 @@ void test_xadd(void *mem) "mov %%rax, %[rax]\n\t" : [rax]"=r"(rax) : [memq]"r"(memq) - : "memory"); + : "memory", "rax"); report("xadd reg, r/m (4)" , rax ==0x123456789abcdef && *memq ==0xffffffffffffffff ); }
@@ -804,10 +810,12 @@ static void trap_emulator(uint64_t *mem, void *alt_insn_page, outregs = save; } -static void advance_rip_by_3_and_note_exception (struct ex_regs *regs) +static unsigned long rip_advance; + +static void advance_rip_and_note_exception (struct ex_regs *regs) { ++exceptions; - regs->rip +=3 ; + regs->rip += rip_advance; } static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,
@@ -819,11 +827,12 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,write_cr0 (read_cr0 () & ~6 );/* TS, EM */ exceptions =0 ; -handle_exception (MF_VECTOR , advance_rip_by_3_and_note_exception); +handle_exception (MF_VECTOR , advance_rip_and_note_exception); asmvolatile ("fninit; fldcw %0" : :"m" (fcw)); asmvolatile ("fldz; fldz; fdivp" );/* generate exception */ MK_INSN (mmx_movq_mf,"movq %mm0, (%rax) \n\t" ); + rip_advance = insn_mmx_movq_mf.len; inregs = (struct regs ){ .rsp=(u64 )stack+1024 };trap_emulator (mem, alt_insn_page, &insn_mmx_movq_mf);/* exit MMX mode */
@@ -834,11 +843,14 @@ static void test_mmx_movq_mf(uint64_t *mem, uint8_t *insn_page,static void test_jmp_noncanonical (uint64_t *mem) { +extern char nc_jmp_start, nc_jmp_end; + *mem =0x1111111111111111ul ; exceptions =0 ; -handle_exception (GP_VECTOR , advance_rip_by_3_and_note_exception); - asmvolatile ("jmp *%0" : :"m" (*mem)); + rip_advance = &nc_jmp_end - &nc_jmp_start; +handle_exception (GP_VECTOR , advance_rip_and_note_exception); + asmvolatile ("nc_jmp_start: jmp *%0; nc_jmp_end:" : :"m" (*mem));report ("jump to non-canonical address" , exceptions ==1 );handle_exception (GP_VECTOR ,0 ); }
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v2 2/8 x86: emulator: disable test_lldt
In reply to Peter FeinerWhen compiled with -fno-omit-frame-pointer, test_lldt causes a triple fault, which insta-reboots the guest. I couldn't figure out why the triple-fault was happening, so I disabled the test outright. Knowing that the other emulator.c tests pass is more useful than a VM stuck in a reboot loop.
On x86-64, this test was adding little value since it was broken to begin with: an LDT descriptor is 16 bytes on x86-64. The GDT limit was also bogus. I've fixed these problems for posterity.
N.B. I only tested this on Linux 4.3.5. Perhaps lldt emulation has been fixed since then.
--- x86/emulator.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-)
x86/emulator.c +11 -3
@@ -1006,10 +1006,17 @@ static void test_sreg(volatile uint16_t *mem)write_ss (ss); } +/* Broken emulation causes triple fault, which skips the other tests. */ +#if 0 static void test_lldt (volatile uint16_t *mem) { -u64 gdt[] = {0 ,0x0000f82000000ffffull /* ldt descriptor */ }; -struct descriptor_table_ptr gdt_ptr = { .limit =0xffff , .base = (ulong)&gdt }; +u64 gdt[] = {0 ,/* null descriptor */ +#ifdef __X86_64__ +0 ,/* ldt descriptor is 16 bytes in long mode */ +#endif +0x0000f82000000ffffull /* ldt descriptor */ }; +struct descriptor_table_ptr gdt_ptr = { .limit =sizeof (gdt) -1 , + .base = (ulong)&gdt };struct descriptor_table_ptr orig_gdt;cli ();
@@ -1021,6 +1028,7 @@ static void test_lldt(volatile uint16_t *mem)sti (); report("lldt", sldt() == *mem); } +#endif static void test_ltr (volatile uint16_t *mem) {
@@ -1139,7 +1147,7 @@ int main()test_shld_shrd (mem);//test_lgdt_lidt(mem); test_sreg (mem); -test_lldt (mem); +//test_lldt(mem); test_ltr (mem);test_cmov (mem);
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v2 3/8 x86: realmode: fix test_sgdt_sidt overflow
In reply to Peter FeinerIn real mode, both sgdt and sidt write 6 bytes to the given memory
address: 2 byte limit, 3 byte address, 1 zero byte. However, the test was only allocating 4 bytes. Given an inopportune stack layout, the output was being overwritten and the assertion failed.
I discovered this problem when compiling with -fno-omit-stack-pointer.
--- x86/realmode.c | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-)
x86/realmode.c +12 -11
@@ -116,16 +116,18 @@ struct regs {u32 eip, eflags; }; +struct table_descr { +u16 limit; +void *base; +} __attribute__((packed)); +static u64 gdt[] = {0 ,0x00cf9b000000ffffull ,// flat 32-bit code segment 0x00cf93000000ffffull ,// flat 32-bit data segment }; -static struct { -u16 limit; -void *base; -} __attribute__((packed)) gdt_descr = { +static struct table_descr gdt_descr = {sizeof (gdt) -1 , gdt, };
@@ -1417,21 +1419,23 @@ static void test_ss_base_for_esp_ebp(void)report ("ss relative addressing (2)" ,R_AX |R_BX , outregs.ebx ==0x87654321 ); } +extern unsigned long long r_gdt[]; +static void test_sgdt_sidt (void ) {MK_INSN (sgdt,"sgdtw (%eax)" );MK_INSN (sidt,"sidtw (%eax)" ); -unsigned x, y; +struct table_descr x, y; inregs.eax = (unsigned )&y; asmvolatile ("sgdtw %0" :"=m" (x));exec_in_big_real_mode (&insn_sgdt); -report ("sgdt" ,0 , x == y); +report ("sgdt" ,0 , x.limit == y.limit && x.base == y.base); inregs.eax = (unsigned )&y; asmvolatile ("sidtw %0" :"=m" (x));exec_in_big_real_mode (&insn_sidt); -report ("sidt" ,0 , x == y); +report ("sidt" ,0 , x.limit == y.limit && x.base == y.base); }static void test_sahf (void )
@@ -1734,10 +1738,7 @@ void realmode_start(void)unsigned long long r_gdt[] = {0 ,0x9b000000ffff ,0x93000000ffff }; -struct __attribute__((packed)) { -unsigned short limit; -void *base; -} r_gdt_descr = {sizeof (r_gdt) -1 , &r_gdt }; +struct table_descr r_gdt_descr = {sizeof (r_gdt) -1 , &r_gdt }; asm( ".section .init \n\t"
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v2 4/8 x86: eventinj: make test work with -O0
In reply to Peter FeinerWith optimizations disabled, the compiler generated a call for irq_enable() -- rather than just inlining an sti instruction as expected. Thus the irq_enable ret would run in the sti shadow and the vectors would fire in the wrong order.
--- x86/eventinj.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
x86/eventinj.c +1 -2
@@ -296,8 +296,7 @@ int main()apic_self_ipi (32 );flush_stack ();io_delay (); -irq_enable (); - asmvolatile ("int $33" ); + asmvolatile ("sti; int $33" );irq_disable ();printf ("After vec 32 and int $33\n" );report ("vec 32/int $33" , test_count ==2 );
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Paolo Bonzini
maintainerRe: [kvm-unit-tests v2 4/8] x86: eventinj: make test work with -O0
Quoted 16 lines · Peter Feiner
With optimizations disabled, the compiler generated a call for
irq_enable()-- rather than just inlining an sti instruction as expected. Thus theirq_enableret would run in the sti shadow and the vectors would fire in the wrong order.Signed-off-by Peter Feiner <[email protected]>--- x86/eventinj.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)x86/eventinj.c +0
-0
x86/eventinj.c int main() · line 302
Quoted 9 lines
x86/eventinj.c +1
-2@@ -296,8 +296,7 @@ int main()apic_self_ipi (32 );flush_stack ();io_delay (); -irq_enable (); - asmvolatile ("int $33" ); + asmvolatile ("sti; int $33" );irq_disable ();printf ("After vec 32 and int $33\n" );report ("vec 32/int $33" , test_count ==2 );
I've added a comment to irq_enable too:
/* Note that irq_enable() does not ensure an interrupt shadow due
* to the vagaries of compiler optimizations. If you need the
* shadow, use a single asm with "sti" and the instruction after it. */
Paolo
PATCH v2 5/8 lib: backtrace printing
In reply to Peter FeinerFunctions 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.
--- 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
Makefile +2 -1
@@ -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, "")
arm/Makefile.common +1 -0
@@ -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
lib/arm/dump_stack.c new file +6 -0
@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}
lib/libcflat.h +4 -0
@@ -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 ); +#define ARRAY_SIZE (_a) (sizeof(_a)/sizeof((_a)[0]))#define container_of (ptr, type, member) ({ \
lib/powerpc/dump_stack.c new file +6 -0
@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}
lib/printf.c +37 -0
@@ -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); + } +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); +} + +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); +}
lib/x86/dump_stack.c new file +24 -0
@@ -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; +}
powerpc/Makefile.common +1 -0
@@ -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)
x86/Makefile.common +4 -0
@@ -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)
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests v2 5/8] lib: backtrace printing
Quoted 67 lines · Peter Feiner
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 <[email protected]>--- 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.cMakefile +2
-1@@ -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, "")arm/Makefile.common +1
-0@@ -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.olib/arm/dump_stack.c new file +6
-0@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}lib/libcflat.h +0
-0
lib/libcflat.h extern void report_xfail(const char *msg_fmt, bool xfail, bool pass, ...); · line 70
Quoted 6 lines
lib/libcflat.h +3
-0@@ -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.
Quoted 26 lines
lib/libcflat.h +1
-0+#define ARRAY_SIZE (_a) (sizeof(_a)/sizeof((_a)[0]))#define container_of (ptr, type, member) ({ \lib/powerpc/dump_stack.c new file +6
-0@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}lib/printf.c +2
-0@@ -259,3 +259,40 @@ int printf(const char *fmt, ...)puts (buf);return r; } + +static void print_stack(unsigned long *stack, int depth,
lib/printf.c int printf(const char *fmt, ...) · line 273
Quoted 10 lines
lib/printf.c +10
-0+ 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().
Quoted 5 lines
lib/printf.c +5
-0+ } +printf ("\n" ); +} + +#define MAX_DEPTH 10
lib/printf.c int printf(const char *fmt, ...) · line 288
Quoted 10 lines
lib/printf.c +10
-0+ +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?
Quoted 76 lines
lib/printf.c +10
-0+ +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); +}lib/x86/dump_stack.c new file +24
-0@@ -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; +}powerpc/Makefile.common +1
-0@@ -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)x86/Makefile.common +4
-0@@ -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)Signature · 1 line
2.7.0.rc3.207.g0ac5344
Thanks,
drew
Re: [kvm-unit-tests v2 5/8] lib: backtrace printing
Quoted 71 lines · Andrew Jones
Quoted 70 lines · Peter Feiner
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 <[email protected]>--- 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.cMakefile +2
-1@@ -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, "")arm/Makefile.common +1
-0@@ -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.olib/arm/dump_stack.c new file +6
-0@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}lib/libcflat.h +0
-0@@ -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 );
Quoted 7 lines
lib/libcflat.h extern void report_xfail(const char *msg_fmt, bool xfail, bool pass, ...); · line 70
Quoted 3 lines
lib/libcflat.h +3
-0+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.
I'm indifferent w.r.t. input names. I can change them to void *instruction and void *frame.
I didn't go with backtrace() because I wanted to give the frame pointer as an argument. The frame pointer argument is essential for dumping stacks of unhandled exceptions. See the 6th patch in the series, "
x86: lib: debug dump on unhandled exceptions".
Quoted 5 lines
Also, instead of building on a single arch function,
walk_stack, how about twovoid *arch_frame_address(unsigned int level); void *arch_return_address(void *frame, unsigned int level);
This would entail O(level^2) frame pointer traversals to print a stack trace. The extra CPU overhead doesn't bother me *too much*, but the inevitable debugging burden does. Every once and a while, I have to stick a printf() in walk_stack to see where a frame pointer is causing a #PF :-) So I'd like to stick with a function that returns an array of pointers.
I can call it
int arch_return_addresses(const void *frame, void **addresses, int max_depth);
(is the arch_ prefix necessary given that there's no non-arch_ variant?)
Here's the best of both worlds:
/* return addresses starting from the given frame. needs arch-specific code. */ int backtrace_frame(const void *frame, void **addresses, int max_depth);
/* return addresses from the current frame. Can use repeated calls to __builtin_return_address. */
int backtrace(void **addresses, int max_depth);
I'll use backtrace() in dump_current_stack() and backtrace_frame in dump_stack(). I'll also rename dump_current_stack to dump_stack and dump_stack to dump_frame_stack for some consistency.
Wow, I should've just written the patch instead of writing all of this crap out :-)
Quoted 8 lines
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.cfile. If we include lib/asm/<ARCH>/stack.h, or whatever you want to call it, then the arch could just supply some inlines there.
That's a good suggestion. I'll change things.
Quoted 31 lines
Quoted 31 lines
lib/libcflat.h +1
-0+#define ARRAY_SIZE (_a) (sizeof(_a)/sizeof((_a)[0]))#define container_of (ptr, type, member) ({ \lib/powerpc/dump_stack.c new file +6
-0@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}lib/printf.c +7
-0@@ -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: " );
Quoted 8 lines
lib/printf.c int printf(const char *fmt, ...) · line 273
Quoted 5 lines
lib/printf.c +5
-0+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().
It's not x86-ness, but it's certainly not self explanatory :-) Return addresses are stored on the stack. Thus walk_stack returns an array of pointers to instructions that we'll *return to* when the stack unwinds. If you give those return addresses to addr2line, you'll get the line numbers of the code following function calls. For example,
1: void foo(void) {
2: dump_current_stack();
3: return;
4: }
5: int main(void) {
6: foo();
7: return 0;
8: }
addr2line would print lines 3 & 7, i.e., the return addresses! With offset = -1, the addresses of some code within call instructions (or some other code generated to effect the function calls) are printed, and add2line prints lines 6 & 2.
The special case of offset = 0 is for when the first address isn't the return address but the address of the faulting instruction, which is the case for unhandled exceptions. I.e., iret re-tries the interrupted / faulting instruction. I suppose I could've just done stack[0] = ip + 1 in dump_stack then unconditionally subtracted 1 in print_stack and gotten rid of the top_is_return_address argument. Yes, I'll do that since it'll be cleaner on all accounts. I'll also change the name of the argument from "stack" to "return_addrs".
One disadvantage of all of this address twiddling is that the stack will look like nonsense for people not using the pretty printer because the'll see addresses in the middle of call instructions. I could do the subtraction in the pretty printer, but then I'd have to annotate the stack[0] = ip case somehow. Perhaps something like:
STACK: @ip ret ret ret
That's pretty simple and most useful everybody. Let me know what you think Drew.
Quoted 10 lines
Quoted 10 lines
lib/printf.c +9
-0+ } +printf ("\n" ); +} + +#define MAX_DEPTH 10 + +void dump_stack (unsigned long ip,unsigned long bp) +{ +unsigned long stack[MAX_DEPTH ];
Quoted 8 lines
lib/printf.c int printf(const char *fmt, ...) · line 288
Quoted 6 lines
lib/printf.c +6
-0+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 todump_current_stack?
Exception handler.
Quoted 74 lines
Quoted 74 lines
lib/printf.c +10
-0+ +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); +}lib/x86/dump_stack.c new file +24
-0@@ -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; +}powerpc/Makefile.common +1
-0@@ -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)x86/Makefile.common +4
-0@@ -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)
Quoted 6 lines
Quoted 3 lines
x86/Makefile.common +0
-1FLATLIBS = lib/libcflat.a $(libgcc) --2.7.0.rc3.207.g0ac5344
Thanks,
drew
Thanks for the review!
Re: [kvm-unit-tests v2 5/8] lib: backtrace printing
Quoted 102 lines · Peter Feiner
Quoted 71 lines · Andrew Jones
Quoted 70 lines · Peter Feiner
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 <[email protected]>--- 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.cMakefile +2
-1@@ -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, "")arm/Makefile.common +1
-0@@ -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.olib/arm/dump_stack.c new file +6
-0@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}lib/libcflat.h +0
-0@@ -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 );Quoted 7 lines
lib/libcflat.h extern void report_xfail(const char *msg_fmt, bool xfail, bool pass, ...); · line 70
Quoted 3 lines
lib/libcflat.h +3
-0+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.I'm indifferent w.r.t. input names. I can change them to void *instruction and void *frame.
I didn't go with
backtrace()because I wanted to give the frame pointer as an argument. The frame pointer argument is essential for dumping stacks of unhandled exceptions. See the 6th patch in the series, "
x86: lib: debug dump on unhandled exceptions".Quoted 5 lines
Also, instead of building on a single arch function,
walk_stack, how about twovoid *arch_frame_address(unsigned int level); void *arch_return_address(void *frame, unsigned int level);This would entail O(level^2) frame pointer traversals to print a stack trace. The extra CPU overhead doesn't bother me *too much*, but the inevitable debugging burden does. Every once and a while, I have to stick a
printf()inwalk_stackto see where a frame pointer is causing a #PF :-) So I'd like to stick with a function that returns an array of pointers.
Quoted 5 lines
I can call it
int
arch_return_addresses(const void *frame, void **addresses, int max_depth);(is the
arch_prefix necessary given that there's no non-arch_ variant?)
yeah, you're right, arch_ isn't really necessary here.
Quoted 10 lines
Here's the best of both worlds:
/* return addresses starting from the given frame. needs arch-specific code. */ int
backtrace_frame(const void *frame, void **addresses, int max_depth);/* return addresses from the current frame. Can use repeated calls to
__builtin_return_address. */
intbacktrace(void **addresses, int max_depth);
Quoted 6 lines
I'll use
backtrace()indump_current_stack()andbacktrace_frameindump_stack(). I'll also renamedump_current_stacktodump_stackanddump_stacktodump_frame_stackfor some consistency.Wow, I should've just written the patch instead of writing all of this crap out :-)
:-)
Quoted 87 lines
Quoted 9 lines
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.cfile. If we include lib/asm/<ARCH>/stack.h, or whatever you want to call it, then the arch could just supply some inlines there.That's a good suggestion. I'll change things.
Quoted 31 lines
Quoted 31 lines
lib/libcflat.h +1
-0+#define ARRAY_SIZE (_a) (sizeof(_a)/sizeof((_a)[0]))#define container_of (ptr, type, member) ({ \lib/powerpc/dump_stack.c new file +6
-0@@ -0,0 +1,6 @@ +#include "libcflat.h" + +int walk_stack (unsigned long bp,unsigned long *stack,int max_depth) +{ +return 0 ; +}lib/printf.c +7
-0@@ -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: " );Quoted 8 lines
lib/printf.c int printf(const char *fmt, ...) · line 273
Quoted 5 lines
lib/printf.c +5
-0+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().It's not x86-ness, but it's certainly not self explanatory :-) Return addresses are stored on the stack. Thus
walk_stackreturns an array of pointers to instructions that we'll *return to* when the stack unwinds. If you give those return addresses to addr2line, you'll get the line numbers of the code following function calls. For example,1: void foo(void) {
2:dump_current_stack();
3: return;
4: }
5: int main(void) {
6:foo();
7: return 0;
8: }addr2line would print lines 3 & 7, i.e., the return addresses! With offset = -1, the addresses of some code within call instructions (or some other code generated to effect the function calls) are printed, and add2line prints lines 6 & 2.
The special case of offset = 0 is for when the first address isn't the return address but the address of the faulting instruction, which is the case for unhandled exceptions. I.e., iret re-tries the interrupted / faulting instruction. I suppose I could've just done stack[0] = ip + 1 in
dump_stackthen unconditionally subtracted 1 inprint_stackand gotten rid of thetop_is_return_addressargument. Yes, I'll do that since it'll be cleaner on all accounts. I'll also change the name of the argument from "stack" to "return_addrs".One disadvantage of all of this address twiddling is that the stack will look like nonsense for people not using the pretty printer because the'll see addresses in the middle of call instructions. I could do the subtraction in the pretty printer, but then I'd have to annotate the stack[0] = ip case somehow. Perhaps something like:
Quoted 3 lines
STACK: @ip ret ret ret
That's pretty simple and most useful everybody. Let me know what you think Drew.
Sounds good to me. Thanks!
Quoted 108 lines
Quoted 11 lines
Quoted 11 lines
lib/printf.c +9
-0+ } +printf ("\n" ); +} + +#define MAX_DEPTH 10 + +void dump_stack (unsigned long ip,unsigned long bp) +{ +unsigned long stack[MAX_DEPTH ];Quoted 8 lines
lib/printf.c int printf(const char *fmt, ...) · line 288
Quoted 6 lines
lib/printf.c +6
-0+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 todump_current_stack?Exception handler.
Quoted 74 lines
Quoted 74 lines
lib/printf.c +10
-0+ +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); +}lib/x86/dump_stack.c new file +24
-0@@ -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; +}powerpc/Makefile.common +1
-0@@ -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)x86/Makefile.common +4
-0@@ -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)Quoted 6 lines
Quoted 3 lines
x86/Makefile.common +0
-1FLATLIBS = lib/libcflat.a $(libgcc) --2.7.0.rc3.207.g0ac5344
Thanks,
drewThanks for the review!
--
To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 6/8 x86: lib: debug dump on unhandled exceptions
In reply to Peter FeinerPrints the stack trace and registers.
--- lib/x86/desc.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-)
lib/x86/desc.c +63 -6
@@ -38,6 +38,67 @@ struct ex_record {extern struct ex_record exception_table_start, exception_table_end; +static const char *exception_mnemonic (int vector) +{ +switch (vector) { +case 0 :return "#DE" ; +case 1 :return "#DB" ; +case 2 :return "#NMI" ; +case 3 :return "#BP" ; +case 4 :return "#OF" ; +case 5 :return "#BR" ; +case 6 :return "#UD" ; +case 7 :return "#NM" ; +case 8 :return "#DF" ; +case 10 :return "#TS" ; +case 11 :return "#NP" ; +case 12 :return "#SS" ; +case 13 :return "#GP" ; +case 14 :return "#PF" ; +case 16 :return "#MF" ; +case 17 :return "#AC" ; +case 18 :return "#MC" ; +case 19 :return "#XM" ; +default :return "#??" ; + } +} + +static void unhandled_exception (struct ex_regs *regs,bool cpu) +{ +printf ("Unhandled %sexception %ld %s at ip %016lx\n" , + cpu ?"cpu " :"" , regs->vector, +exception_mnemonic (regs->vector), regs->rip); +if (regs->vector ==14 ) +printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); + + printf("error_code=%04lx rflags=%08lx cs=%08lx\n" + "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n" + "rbp=%016lx rsi=%016lx rdi=%016lx\n" +#ifdef __x86_64__ + " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n" + "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n" +#endif +"cr0=%016lx cr2=%016lx cr3=%016lx cr4=%016lx\n" +#ifdef __x86_64__ +"cr8=%016lx\n" +#endif + , + regs->error_code, regs->rflags, regs->cs, + regs->rax, regs->rcx, regs->rdx, regs->rbx, + regs->rbp, regs->rsi, regs->rdi, +#ifdef __x86_64__ + regs->r8, regs->r9, regs->r10, regs->r11, + regs->r12, regs->r13, regs->r14, regs->r15, +#endif +read_cr0 (),read_cr2 (),read_cr3 (),read_cr4 () +#ifdef __x86_64__ + ,read_cr8 () +#endif + ); +dump_stack (regs->rip, regs->rbp); +exit (7 ); +} +static void check_exception_table (struct ex_regs *regs) {struct ex_record *ex;
@@ -53,8 +114,7 @@ static void check_exception_table(struct ex_regs *regs)return ; } } -printf ("unhandled exception %d\n" , regs->vector); -exit (7 ); +unhandled_exception (regs, false); }static void (*exception_handlers[32 ])(struct ex_regs *regs);
@@ -75,10 +135,7 @@ void do_handle_exception(struct ex_regs *regs) exception_handlers[regs->vector](regs);return ; } -printf ("unhandled cpu exception %d\n" , regs->vector); -if (regs->vector ==14 ) -printf ("PF at %p addr %p\n" , regs->rip,read_cr2 ()); -exit (7 ); +unhandled_exception (regs, true); }#define EX (NAME ,N ) extern char NAME##_fault; \
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v2 7/8 lib: dump stack on abort()
In reply to Peter Feiner--- lib/libcflat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
lib/libcflat.h +4 -2
@@ -77,10 +77,12 @@ void dump_current_stack(void);#define assert (cond) \ do { \ - if (!(cond)) \ + if (!(cond)) { \ printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond), \ + __FILE__, __LINE__, #cond); \ + dump_current_stack(); \ abort(); \ + } \ } while (0)#endif
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests v2 7/8] lib: dump stack on abort()
Looks like you forgot to update $SUBJECT; s/abort/assert/
drew
Quoted 31 lines · Peter Feiner
Signed-off-by Peter Feiner <[email protected]>--- lib/libcflat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)lib/libcflat.h +4
-2@@ -77,10 +77,12 @@ void dump_current_stack(void);#define assert (cond) \ do { \ - if (!(cond)) \ + if (!(cond)) { \ printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond), \ + __FILE__, __LINE__, #cond); \ + dump_current_stack(); \ abort(); \ + } \ } while (0)#endif Signature · 6 lines
2.7.0.rc3.207.g0ac5344 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
PATCH v2 8/8 scripts: pretty print stack traces
In reply to Peter FeinerOptionally pretty print stacks in test.log with 'run_tests.sh -p'.
The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5: ac_test_exec at x86/access.c:818
}
> ac_test_setup_pte(at, pool);
r = ac_test_do_access(at);
0x004014dd: ac_test_run at x86/access.c:852
++tests;
> successes += ac_test_exec(&at, &pool);
} while (ac_test_bump(&at));
0x0040157d: main at x86/access.c:873
printf("starting test\n\n");
> r = ac_test_run();
return r ? 0 : 1;0x0040028e: start64 at x86/cstart64.S:206
lea __argv(%rip), %rsi
> call main
mov %eax, %edi
--- run_tests.sh | 10 +++++-- scripts/pretty_print_stacks.py | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.py
run_tests.sh +8 -2
@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"
@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.
@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log" -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG
@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;; *) exit ;; esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log echo > test.log
scripts/pretty_print_stacks.py new file +61 -0
61 lines not on this page · raw message
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests v2 8/8] scripts: pretty print stack traces
Quoted 148 lines · Peter Feiner
Optionally pretty print stacks in test.log with '
run_tests.sh-p'.The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5:ac_test_execatx86/access.c:818} > ac_test_setup_pte(at, pool); r = ac_test_do_access(at); 0x004014dd: ac_test_run at x86/access.c:852 ++tests; > successes += ac_test_exec(&at, &pool); } while (ac_test_bump(&at)); 0x0040157d: main at x86/access.c:873 printf("starting test\n\n"); > r = ac_test_run(); return r ? 0 : 1;
0x0040028e: start64 atx86/cstart64.S:206
lea__argv(%rip), %rsi
> call main
mov %eax, %ediSigned-off-by Peter Feiner <[email protected]>--- run_tests.sh | 10 +++++-- scripts/pretty_print_stacks.py | 61 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.pyrun_tests.sh +8
-2@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log" -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;; *) exit ;; esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log echo > test.logscripts/pretty_print_stacks.py new file +61
-0@@ -0,0 +1,61 @@ +#!/usr/bin/env python + +import re +import subprocess +import sys + +if len(sys.argv) != 2: + sys.stderr.write('usage: %s <kernel>\n' % sys.argv[0]) + sys.exit(1) + +binary = sys.argv[1] + +# Subvert output buffering. +def puts(string): + sys.stdout.write(string) + sys.stdout.flush() + +try: + while True: + # Subvert input buffering. + line = sys.stdin.readline() + if line == '': + break + + if not line.strip().startswith('STACK:'): + puts(line) + continue + + addrs = line.split()[1:] + # Output like this: + # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 + # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) + cmd = ['addr2line', '-e', binary, '-i', '-f', '--pretty', '--address'] + cmd.extend(addrs) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + puts(line) + continue + + for line in out.splitlines(): + m = re.match('(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) + if m is None: + puts('%s\n' % line) + continue + + head, path, line, tail = m.groups() + line = int(line) + puts('%s at %s:%d%s\n' % (head, path, line, tail)) + try: + lines = open(path).readlines() + except IOError: + continue + if line > 1: + puts(' %s\n' % lines[line - 2].rstrip()) + puts(' > %s\n' % lines[line - 1].rstrip()) + if line < len(lines): + puts(' %s\n' % lines[line].rstrip()) +except: + sys.exit(1)Signature · 1 line
2.7.0.rc3.207.g0ac5344
I think this probably could have been written in bash, but I'm not overly opposed to adding python scripts, as I think we're pretty safe adding that dependency, particularly when its use can be disabled.
wrt to enabling/disabling it though, how about we create a new configure command line option instead. One that defaults to on, if the architecture supports pretty-printing, but can be switched off. Then, run_tests.sh, which sources config.mak, can just turn pretty printing on by default when it's available, rather than introducing the -p option, which I think we'd always want to use when we can.
Thanks,
drew
Paolo Bonzini
maintainerQuoted 10 lines · Peter Feiner
Some aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
N.B. I haven't tried compiling on arm or ppc.
v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.
ARM and PPC have fewer tests and even less inline assembly, so hopefully they're safe. But, I agree with adding support one architecture at a time.
Drew had comments so for now I'm applying patches 1-4. Thanks a lot for them!
Paolo
v3 cover Debugging aids
In reply to Peter FeinerSome aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
I _have_ compiled on ppc64 and arm64 :-)
v3:
* Renamed functions to match standard backtrace functions
* Added asm-generic stack walker that uses __builtin_return_address.
* Moved offset out of libcflat and into pretty printer
* Made pretty printer more robust w.r.t. errors: now it just continues printing.
v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.
Peter Feiner (4):
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on failed assert()
scripts: pretty print stack traces
Makefile | 3 +- arm/Makefile.common | 1 + lib/arm/asm/stack.h | 1 + lib/arm64/asm/stack.h | 1 + lib/asm-generic/stack.c | 53 +++++++++++++++++++++++++ lib/asm-generic/stack.h | 14 +++++++ lib/libcflat.h | 9 ++++- lib/powerpc/asm/stack.h | 1 + lib/ppc64/asm/stack.h | 1 + lib/printf.c | 42 ++++++++++++++++++++ lib/x86/asm/stack.c | 25 ++++++++++++ lib/x86/asm/stack.h | 12 ++++++ lib/x86/desc.c | 69 +++++++++++++++++++++++++++++--- powerpc/Makefile.common | 1 + run_tests.sh | 10 ++++- scripts/pretty_print_stacks.py | 89 ++++++++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 4 ++ 17 files changed, 325 insertions(+), 11 deletions(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/asm-generic/stack.c create mode 100644 lib/asm-generic/stack.h create mode 100644 lib/powerpc/asm/stack.h create mode 100644 lib/ppc64/asm/stack.h create mode 100644 lib/x86/asm/stack.c create mode 100644 lib/x86/asm/stack.h create mode 100755 scripts/pretty_print_stacks.py
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v3 1/4 lib: backtrace printing
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.
--- Makefile | 3 ++- arm/Makefile.common | 1 + lib/arm/asm/stack.h | 1 + lib/arm64/asm/stack.h | 1 + lib/asm-generic/stack.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/asm-generic/stack.h | 14 +++++++++++++ lib/libcflat.h | 3 +++ lib/powerpc/asm/stack.h | 1 + lib/ppc64/asm/stack.h | 1 + lib/printf.c | 42 +++++++++++++++++++++++++++++++++++++++ lib/x86/asm/stack.c | 25 +++++++++++++++++++++++ lib/x86/asm/stack.h | 12 +++++++++++ powerpc/Makefile.common | 1 + x86/Makefile.common | 4 ++++ 14 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/asm-generic/stack.c create mode 100644 lib/asm-generic/stack.h create mode 100644 lib/powerpc/asm/stack.h create mode 100644 lib/ppc64/asm/stack.h create mode 100644 lib/x86/asm/stack.c create mode 100644 lib/x86/asm/stack.h
Makefile +2 -1
@@ -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, "")
arm/Makefile.common +1 -0
@@ -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/asm-generic/stack.o libeabi = lib/arm/libeabi.a eabiobjs = lib/arm/eabi_compat.o
lib/arm/asm/stack.h new file +1 -0
@@ -0,0 +1 @@ +#include <asm-generic/stack.h>
lib/arm64/asm/stack.h new file +1 -0
@@ -0,0 +1 @@ +#include <asm-generic/stack.h>
lib/asm-generic/stack.c new file +53 -0
53 lines not on this page · raw message
lib/asm-generic/stack.h new file +14 -0
@@ -0,0 +1,14 @@ +#ifndef _ASMGENERIC_STACK_H_ +#define _ASMGENERIC_STACK_H_ + +static inline int +backtrace_frame (const void *frame __attribute__((unused)), +const void **return_addrs __attribute__((unused)), +int max_depth __attribute__((unused))) +{ +return 0 ; +} + +int backtrace (const void **return_addrs,int max_depth); + +#endif
lib/libcflat.h +3 -0
@@ -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) ({ \
lib/powerpc/asm/stack.h new file +1 -0
@@ -0,0 +1 @@ +#include <asm-generic/stack.h>
lib/ppc64/asm/stack.h new file +1 -0
@@ -0,0 +1 @@ +#include <asm-generic/stack.h>
lib/printf.c +42 -0
49 lines not on this page · raw message
lib/x86/asm/stack.c new file +25 -0
@@ -0,0 +1,25 @@ +#include <libcflat.h> +#include <asm/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; +}
lib/x86/asm/stack.h new file +12 -0
@@ -0,0 +1,12 @@ +#ifndef _X86ASM_STACK_H_ +#define _X86ASM_STACK_H_ + +int backtrace_frame (const void *frame,const void **return_addrs,int max_depth); + +static inline int backtrace (const void **return_addrs,int max_depth) +{ +return backtrace_frame (__builtin_frame_address (0 ), return_addrs, + max_depth); +} + +#endif
powerpc/Makefile.common +1 -0
@@ -31,6 +31,7 @@ cflatobjs += lib/powerpc/io.o cflatobjs += lib/powerpc/hcall.o cflatobjs += lib/powerpc/setup.o cflatobjs += lib/powerpc/rtas.o +cflatobjs += lib/asm-generic/stack.o FLATLIBS = $(libcflat) $(LIBFDT_archive) %.elf: CFLAGS += $(arch_CFLAGS)
x86/Makefile.common +4 -0
@@ -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/asm/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)
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests v3 1/4] lib: backtrace printing
Quoted 27 lines · Peter Feiner
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 <[email protected]>--- Makefile | 3 ++- arm/Makefile.common | 1 + lib/arm/asm/stack.h | 1 + lib/arm64/asm/stack.h | 1 + lib/asm-generic/stack.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ lib/asm-generic/stack.h | 14 +++++++++++++ lib/libcflat.h | 3 +++ lib/powerpc/asm/stack.h | 1 + lib/ppc64/asm/stack.h | 1 + lib/printf.c | 42 +++++++++++++++++++++++++++++++++++++++ lib/x86/asm/stack.c | 25 +++++++++++++++++++++++ lib/x86/asm/stack.h | 12 +++++++++++ powerpc/Makefile.common | 1 + x86/Makefile.common | 4 ++++ 14 files changed, 161 insertions(+), 1 deletion(-)
Quoted 8 lines
create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/asm-generic/stack.c create mode 100644 lib/asm-generic/stack.h create mode 100644 lib/powerpc/asm/stack.h create mode 100644 lib/ppc64/asm/stack.h create mode 100644 lib/x86/asm/stack.c create mode 100644 lib/x86/asm/stack.h
It's not usual to put C files in the asm directories, at least Linux doesn't do that. So I'd prefer
lib/stack.c: the common backtrace() lib/<ARCH>/stack.c: arch specific backtrace* functions
I'm tempted to suggest that print_stack() and the dump*stack functions also go in lib/stack.c, instead of lib/printf.c, but then we need some
#ifndef backtrace
#define backtrace backtrace
int backtrace(...)
{
}
#endif
ugliness to allow the common backtrace() to be overridden. Although, it might still be better to move those functions out of printf, as I don't feel they really fit there.
Quoted 47 lines
Makefile +2
-1@@ -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, "")arm/Makefile.common +1
-0@@ -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/asm-generic/stack.o libeabi = lib/arm/libeabi.a eabiobjs = lib/arm/eabi_compat.olib/arm/asm/stack.h new file +1
-0@@ -0,0 +1 @@ +#include <asm-generic/stack.h> lib/arm64/asm/stack.h new file +1
-0@@ -0,0 +1 @@ +#include <asm-generic/stack.h> lib/asm-generic/stack.c new file +0
-0
lib/asm-generic/stack.c line 2
Quoted 2 lines
lib/asm-generic/stack.c new file +2
-0@@ -0,0 +1,53 @@ +#include <libcflat.h> +#include <asm-generic/stack.h>
nit: including asm-generic/stack.h doesn't appear to be necessary.
Actually, if there was something needed from stack.h, then we should probably get it from asm/stack.h, in case the arch wanted to override it.
Quoted 125 lines
lib/asm-generic/stack.c new file +51
-0+ +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; +}lib/asm-generic/stack.h new file +14
-0@@ -0,0 +1,14 @@ +#ifndef _ASMGENERIC_STACK_H_ +#define _ASMGENERIC_STACK_H_ + +static inline int +backtrace_frame (const void *frame __attribute__((unused)), +const void **return_addrs __attribute__((unused)), +int max_depth __attribute__((unused))) +{ +return 0 ; +} + +int backtrace (const void **return_addrs,int max_depth); + +#endif lib/libcflat.h +3
-0@@ -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) ({ \lib/powerpc/asm/stack.h new file +1
-0@@ -0,0 +1 @@ +#include <asm-generic/stack.h> lib/ppc64/asm/stack.h new file +1
-0@@ -0,0 +1 @@ +#include <asm-generic/stack.h> lib/printf.c +13
-0@@ -1,4 +1,5 @@#include "libcflat.h" +#include "asm/stack.h" #define BUFSZ 2000@@ -259,3 +260,44 @@ int printf(const char *fmt, ...)puts (buf);return r; } + +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 ]);
lib/printf.c int printf(const char *fmt, ...) · line 284
Quoted 10 lines
lib/printf.c +10
-0+ i++; + } + +for (; i < depth; i++) { +printf (" %lx" , (unsigned long ) return_addrs[i]); + } +printf ("\n" ); +} + +#define MAX_DEPTH 10
How about 20, like the common backtrace() supports?
Quoted 104 lines
lib/printf.c +19
-0+ +void dump_stack (void ) +{ +const void *return_addrs[MAX_DEPTH ]; +int depth; + + depth =backtrace (return_addrs,MAX_DEPTH ); +print_stack (return_addrs, depth, 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); +}lib/x86/asm/stack.c new file +25
-0@@ -0,0 +1,25 @@ +#include <libcflat.h> +#include <asm/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; +}lib/x86/asm/stack.h new file +12
-0@@ -0,0 +1,12 @@ +#ifndef _X86ASM_STACK_H_ +#define _X86ASM_STACK_H_ + +int backtrace_frame (const void *frame,const void **return_addrs,int max_depth); + +static inline int backtrace (const void **return_addrs,int max_depth) +{ +return backtrace_frame (__builtin_frame_address (0 ), return_addrs, + max_depth); +} + +#endif powerpc/Makefile.common +1
-0@@ -31,6 +31,7 @@ cflatobjs += lib/powerpc/io.o cflatobjs += lib/powerpc/hcall.o cflatobjs += lib/powerpc/setup.o cflatobjs += lib/powerpc/rtas.o +cflatobjs += lib/asm-generic/stack.o FLATLIBS = $(libcflat) $(LIBFDT_archive) %.elf: CFLAGS += $(arch_CFLAGS)x86/Makefile.common +4
-0@@ -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/asm/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)Signature · 1 line
2.7.0.rc3.207.g0ac5344
Other than my desire to keep C out of asm directories, then this looks good to me.
Thanks,
drew
PATCH v3 2/4 x86: lib: debug dump on unhandled exceptions
In reply to Peter FeinerPrints the stack trace and registers.
--- lib/x86/desc.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-)
lib/x86/desc.c +63 -6
@@ -38,6 +38,67 @@ struct ex_record {extern struct ex_record exception_table_start, exception_table_end; +static const char *exception_mnemonic (int vector) +{ +switch (vector) { +case 0 :return "#DE" ; +case 1 :return "#DB" ; +case 2 :return "#NMI" ; +case 3 :return "#BP" ; +case 4 :return "#OF" ; +case 5 :return "#BR" ; +case 6 :return "#UD" ; +case 7 :return "#NM" ; +case 8 :return "#DF" ; +case 10 :return "#TS" ; +case 11 :return "#NP" ; +case 12 :return "#SS" ; +case 13 :return "#GP" ; +case 14 :return "#PF" ; +case 16 :return "#MF" ; +case 17 :return "#AC" ; +case 18 :return "#MC" ; +case 19 :return "#XM" ; +default :return "#??" ; + } +} + +static void unhandled_exception (struct ex_regs *regs,bool cpu) +{ +printf ("Unhandled %sexception %ld %s at ip %016lx\n" , + cpu ?"cpu " :"" , regs->vector, +exception_mnemonic (regs->vector), regs->rip); +if (regs->vector ==14 ) +printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); + + printf("error_code=%04lx rflags=%08lx cs=%08lx\n" + "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n" + "rbp=%016lx rsi=%016lx rdi=%016lx\n" +#ifdef __x86_64__ + " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n" + "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n" +#endif +"cr0=%016lx cr2=%016lx cr3=%016lx cr4=%016lx\n" +#ifdef __x86_64__ +"cr8=%016lx\n" +#endif + , + regs->error_code, regs->rflags, regs->cs, + regs->rax, regs->rcx, regs->rdx, regs->rbx, + regs->rbp, regs->rsi, regs->rdi, +#ifdef __x86_64__ + regs->r8, regs->r9, regs->r10, regs->r11, + regs->r12, regs->r13, regs->r14, regs->r15, +#endif +read_cr0 (),read_cr2 (),read_cr3 (),read_cr4 () +#ifdef __x86_64__ + ,read_cr8 () +#endif + ); +dump_frame_stack ((void *) regs->rip, (void *) regs->rbp); +exit (7 ); +} +static void check_exception_table (struct ex_regs *regs) {struct ex_record *ex;
@@ -53,8 +114,7 @@ static void check_exception_table(struct ex_regs *regs)return ; } } -printf ("unhandled exception %lu\n" , regs->vector); -abort (); +unhandled_exception (regs, false); }static void (*exception_handlers[32 ])(struct ex_regs *regs);
@@ -75,10 +135,7 @@ void do_handle_exception(struct ex_regs *regs) exception_handlers[regs->vector](regs);return ; } -printf ("unhandled cpu exception %lu\n" , regs->vector); -if (regs->vector ==14 ) -printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); -abort (); +unhandled_exception (regs, true); }#define EX (NAME ,N ) extern char NAME##_fault; \
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v3 3/4 lib: dump stack on failed assert()
In reply to Peter Feiner--- lib/libcflat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
lib/libcflat.h +4 -2
@@ -92,10 +92,12 @@ extern void dump_frame_stack(const void *instruction, const void *frame);#define assert (cond) \ do { \ - if (!(cond)) \ + if (!(cond)) { \ printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond), \ + __FILE__, __LINE__, #cond); \ + dump_stack(); \ abort(); \ + } \ } while (0)#endif
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests v3 3/4] lib: dump stack on failed assert()
Quoted 1 line · Peter Feiner
Signed-off-by Peter Feiner <[email protected]>
PATCH v3 4/4 scripts: pretty print stack traces
In reply to Peter FeinerOptionally pretty print stacks in test.log with 'run_tests.sh -p'.
The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5: ac_test_exec at x86/access.c:818
}
> ac_test_setup_pte(at, pool);
r = ac_test_do_access(at);
0x004014dd: ac_test_run at x86/access.c:852
++tests;
> successes += ac_test_exec(&at, &pool);
} while (ac_test_bump(&at));
0x0040157d: main at x86/access.c:873
printf("starting test\n\n");
> r = ac_test_run();
return r ? 0 : 1;0x0040028e: start64 at x86/cstart64.S:206
lea __argv(%rip), %rsi
> call main
mov %eax, %edi
--- run_tests.sh | 10 ++++- scripts/pretty_print_stacks.py | 89 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.py
run_tests.sh +8 -2
@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"
@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.
@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log" -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG
@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;; *) exit 1 ;; esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log printf "BUILD_HEAD=$(cat build-head)\n\n" > test.log
scripts/pretty_print_stacks.py new file +89 -0
89 lines not on this page · raw message
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [kvm-unit-tests v3 4/4] scripts: pretty print stack traces
Quoted 62 lines · Peter Feiner
Optionally pretty print stacks in test.log with '
run_tests.sh-p'.The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5:ac_test_execatx86/access.c:818} > ac_test_setup_pte(at, pool); r = ac_test_do_access(at); 0x004014dd: ac_test_run at x86/access.c:852 ++tests; > successes += ac_test_exec(&at, &pool); } while (ac_test_bump(&at)); 0x0040157d: main at x86/access.c:873 printf("starting test\n\n"); > r = ac_test_run(); return r ? 0 : 1;
0x0040028e: start64 atx86/cstart64.S:206
lea__argv(%rip), %rsi
> call main
mov %eax, %ediSigned-off-by Peter Feiner <[email protected]>--- run_tests.sh | 10 ++++- scripts/pretty_print_stacks.py | 89 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.pyrun_tests.sh +4
-1@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log" -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG
run_tests.sh while getopts "g:hv" opt; do · line 48
Quoted 6 lines
run_tests.sh +3
-0@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;;
What about the idea of turning this on by default, and only turning it off if it was configured off?
drew
Re: [kvm-unit-tests v3 4/4] scripts: pretty print stack traces
Quoted 57 lines · Andrew Jones
Quoted 56 lines · Peter Feiner
Optionally pretty print stacks in test.log with '
run_tests.sh-p'.The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5:ac_test_execatx86/access.c:818} > ac_test_setup_pte(at, pool); r = ac_test_do_access(at); 0x004014dd: ac_test_run at x86/access.c:852 ++tests; > successes += ac_test_exec(&at, &pool); } while (ac_test_bump(&at)); 0x0040157d: main at x86/access.c:873 printf("starting test\n\n"); > r = ac_test_run(); return r ? 0 : 1;
0x0040028e: start64 atx86/cstart64.S:206
lea__argv(%rip), %rsi
> call main
mov %eax, %ediSigned-off-by Peter Feiner <[email protected]>--- run_tests.sh | 10 ++++- scripts/pretty_print_stacks.py | 89 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.pyrun_tests.sh +3
-0@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log"
Quoted 15 lines
run_tests.sh while getopts "g:hv" opt; do · line 48
Quoted 12 lines
run_tests.sh +4
-1-while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;;What about the idea of turning this on by default, and only turning it off if it was configured off?
I was waiting for the config option to be added. I had thought you were going to send that patch. I'll add the config option to the series and make it on-by-default.
Peter
Re: [kvm-unit-tests v3 4/4] scripts: pretty print stack traces
Quoted 74 lines · Peter Feiner
Quoted 57 lines · Andrew Jones
Quoted 56 lines · Peter Feiner
Optionally pretty print stacks in test.log with '
run_tests.sh-p'.The script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5:ac_test_execatx86/access.c:818} > ac_test_setup_pte(at, pool); r = ac_test_do_access(at); 0x004014dd: ac_test_run at x86/access.c:852 ++tests; > successes += ac_test_exec(&at, &pool); } while (ac_test_bump(&at)); 0x0040157d: main at x86/access.c:873 printf("starting test\n\n"); > r = ac_test_run(); return r ? 0 : 1;
0x0040028e: start64 atx86/cstart64.S:206
lea__argv(%rip), %rsi
> call main
mov %eax, %ediSigned-off-by Peter Feiner <[email protected]>--- run_tests.sh | 10 ++++- scripts/pretty_print_stacks.py | 89 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 2 deletions(-) create mode 100755 scripts/pretty_print_stacks.pyrun_tests.sh +3
-0@@ -1,6 +1,7 @@ #!/bin/bash verbose="no" +pretty="no" if [ ! -f config.mak ]; then echo "run ./configure && make first. See ./configure -h"@@ -18,6 +19,7 @@ Usage: $0 [-g group] [-h] [-v] -g: Only execute tests in the given group -h: Output this help text -v: Enables verbose mode + -p: Pretty print stack traces in test.log Set the environment variable QEMU=/path/to/qemu-system-ARCH to specify the appropriate qemu binary for ARCH-run.@@ -27,8 +29,9 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash +log_redir=">> test.log"Quoted 15 lines
run_tests.sh while getopts "g:hv" opt; do · line 48
Quoted 12 lines
run_tests.sh +4
-1-while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG@@ -40,13 +43,16 @@ while getopts "g:hv" opt; do v) verbose="yes" ;; + p) + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" + ;;What about the idea of turning this on by default, and only turning it off if it was configured off?
Quoted 3 lines
I was waiting for the config option to be added. I had thought you were going to send that patch. I'll add the config option to the series and make it on-by-default.
Ah, yeah, I was thinking you'd do it, since the '-p' option can just be dropped, once we have it on by default, and thus no reason to commit this, and then commit a patch taking it away.
Thanks,
drew
Quoted 6 lines
Peter
--
To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
v4 cover Debugging aids
In reply to Peter FeinerSome aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
Compiled on ppc64, arm64, i386, x86_64.
v4:
* Moved around arch and asm files per Linux style (hopefully).
* Added --[enable|disable]-pretty-print-stacks to ./configure. This has obviated the -p command-line option in ./run_tests.sh that I introduced in v1.
* Fixed arch-neutral backtrace so backtrace itself isn't included.
v3:
* Renamed functions to match standard backtrace functions
* Added asm-generic stack walker that uses __builtin_return_address.
* Moved offset out of libcflat and into pretty printer
* Made pretty printer more robust w.r.t. errors: now it just continues printing.
v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.
Peter Feiner (5):
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on failed assert()
scripts: pretty print stack traces
scripts: automatically pretty print stacks
Makefile | 6 ++- configure | 10 +++++ lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/asm-generic/stack.c | 3 ++ lib/libcflat.h | 9 +++- 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 | 18 ++++++++ lib/x86/desc.c | 69 +++++++++++++++++++++++++++--- lib/x86/stack.c | 25 +++++++++++ run_tests.sh | 10 ++++- scripts/mkstandalone.sh | 4 ++ scripts/pretty_print_stacks.py | 89 +++++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 4 ++ 17 files changed, 351 insertions(+), 12 deletions(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/asm-generic/stack.c 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 create mode 100755 scripts/pretty_print_stacks.py
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v4 1/5 lib: backtrace printing
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.
--- Makefile | 6 ++-- lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/asm-generic/stack.c | 3 ++ 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 | 18 ++++++++++ lib/x86/stack.c | 25 +++++++++++++ x86/Makefile.common | 4 +++ 12 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/asm-generic/stack.c 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
Makefile +4 -2
@@ -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 -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, "")
lib/arm/asm/stack.h new file +0 -0
lib/arm64/asm/stack.h new file +0 -0
lib/asm-generic/stack.c new file +3 -0
@@ -0,0 +1,3 @@ +#include <libcflat.h> +#include <asm-generic/stack.h> +
lib/libcflat.h +3 -0
@@ -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) ({ \
lib/powerpc/asm/stack.h new file +0 -0
lib/ppc64/asm/stack.h new file +0 -0
lib/stack.c new file +96 -0
96 lines not on this page · raw message
lib/stack.h new file +20 -0
@@ -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
lib/x86/asm/stack.h new file +18 -0
@@ -0,0 +1,18 @@ +#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 +static inline int backtrace (const void **return_addrs,int max_depth) +{ +return backtrace_frame (__builtin_frame_address (0 ), return_addrs, + max_depth); +} + +#endif
lib/x86/stack.c new file +25 -0
@@ -0,0 +1,25 @@ +#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; +}
x86/Makefile.common +4 -0
@@ -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)
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v4 2/5 x86: lib: debug dump on unhandled exceptions
In reply to Peter FeinerPrints the stack trace and registers.
--- lib/x86/desc.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-)
lib/x86/desc.c +63 -6
@@ -38,6 +38,67 @@ struct ex_record {extern struct ex_record exception_table_start, exception_table_end; +static const char *exception_mnemonic (int vector) +{ +switch (vector) { +case 0 :return "#DE" ; +case 1 :return "#DB" ; +case 2 :return "#NMI" ; +case 3 :return "#BP" ; +case 4 :return "#OF" ; +case 5 :return "#BR" ; +case 6 :return "#UD" ; +case 7 :return "#NM" ; +case 8 :return "#DF" ; +case 10 :return "#TS" ; +case 11 :return "#NP" ; +case 12 :return "#SS" ; +case 13 :return "#GP" ; +case 14 :return "#PF" ; +case 16 :return "#MF" ; +case 17 :return "#AC" ; +case 18 :return "#MC" ; +case 19 :return "#XM" ; +default :return "#??" ; + } +} + +static void unhandled_exception (struct ex_regs *regs,bool cpu) +{ +printf ("Unhandled %sexception %ld %s at ip %016lx\n" , + cpu ?"cpu " :"" , regs->vector, +exception_mnemonic (regs->vector), regs->rip); +if (regs->vector ==14 ) +printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); + + printf("error_code=%04lx rflags=%08lx cs=%08lx\n" + "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n" + "rbp=%016lx rsi=%016lx rdi=%016lx\n" +#ifdef __x86_64__ + " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n" + "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n" +#endif +"cr0=%016lx cr2=%016lx cr3=%016lx cr4=%016lx\n" +#ifdef __x86_64__ +"cr8=%016lx\n" +#endif + , + regs->error_code, regs->rflags, regs->cs, + regs->rax, regs->rcx, regs->rdx, regs->rbx, + regs->rbp, regs->rsi, regs->rdi, +#ifdef __x86_64__ + regs->r8, regs->r9, regs->r10, regs->r11, + regs->r12, regs->r13, regs->r14, regs->r15, +#endif +read_cr0 (),read_cr2 (),read_cr3 (),read_cr4 () +#ifdef __x86_64__ + ,read_cr8 () +#endif + ); +dump_frame_stack ((void *) regs->rip, (void *) regs->rbp); +exit (7 ); +} +static void check_exception_table (struct ex_regs *regs) {struct ex_record *ex;
@@ -53,8 +114,7 @@ static void check_exception_table(struct ex_regs *regs)return ; } } -printf ("unhandled exception %lu\n" , regs->vector); -abort (); +unhandled_exception (regs, false); }static void (*exception_handlers[32 ])(struct ex_regs *regs);
@@ -75,10 +135,7 @@ void do_handle_exception(struct ex_regs *regs) exception_handlers[regs->vector](regs);return ; } -printf ("unhandled cpu exception %lu\n" , regs->vector); -if (regs->vector ==14 ) -printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); -abort (); +unhandled_exception (regs, true); }#define EX (NAME ,N ) extern char NAME##_fault; \
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v4 3/5 lib: dump stack on failed assert()
In reply to Peter Feiner--- lib/libcflat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
lib/libcflat.h +4 -2
@@ -92,10 +92,12 @@ extern void dump_frame_stack(const void *instruction, const void *frame);#define assert (cond) \ do { \ - if (!(cond)) \ + if (!(cond)) { \ printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond), \ + __FILE__, __LINE__, #cond); \ + dump_stack(); \ abort(); \ + } \ } while (0)#endif
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v4 4/5 scripts: pretty print stack traces
In reply to Peter FeinerThe script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5: ac_test_exec at x86/access.c:818
}
> ac_test_setup_pte(at, pool);
r = ac_test_do_access(at);
0x004014dd: ac_test_run at x86/access.c:852
++tests;
> successes += ac_test_exec(&at, &pool);
} while (ac_test_bump(&at));
0x0040157d: main at x86/access.c:873
printf("starting test\n\n");
> r = ac_test_run();
return r ? 0 : 1;0x0040028e: start64 at x86/cstart64.S:206
lea __argv(%rip), %rsi
> call main
mov %eax, %edi
--- scripts/pretty_print_stacks.py | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100755 scripts/pretty_print_stacks.py
scripts/pretty_print_stacks.py new file +89 -0
@@ -0,0 +1,89 @@ +#!/usr/bin/env python + +import re +import subprocess +import sys +import traceback + +# Subvert output buffering. +def puts(string): + sys.stdout.write(string) + sys.stdout.flush() + +def pretty_print_stack(binary, line): + addrs = line.split()[1:] + # Addresses are return addresses unless preceded by a '@'. We want the + # caller address so line numbers are more intuitive. Thus we subtract 1 + # from the address to get the call code. + for i in range(len(addrs)): + addr = addrs[i] + if addr.startswith('@'): + addrs[i] = addr[1:] + else: + addrs[i] = '%lx' % (int(addrs[i], 16) - 1) + + # Output like this: + # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 + # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) + cmd = ['addr2line', '-e', binary, '-i', '-f', '--pretty', '--address'] + cmd.extend(addrs) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + puts(line) + return + + for line in out.splitlines(): + m = re.match('(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) + if m is None: + puts('%s\n' % line) + return + + head, path, line, tail = m.groups() + line = int(line) + puts('%s at %s:%d%s\n' % (head, path, line, tail)) + try: + lines = open(path).readlines() + except IOError: + continue + if line > 1: + puts(' %s\n' % lines[line - 2].rstrip()) + puts(' > %s\n' % lines[line - 1].rstrip()) + if line < len(lines): + puts(' %s\n' % lines[line].rstrip()) + +def main(): + if len(sys.argv) != 2: + sys.stderr.write('usage: %s <kernel>\n' % sys.argv[0]) + sys.exit(1) + + binary = sys.argv[1] + + try: + while True: + # Subvert input buffering. + line = sys.stdin.readline() + if line == '': + break + + if not line.strip().startswith('STACK:'): + puts(line) + continue + + try: + pretty_print_stack(binary, line) + except Exception: + puts('Error pretty printing stack:\n') + puts(traceback.format_exc()) + puts('Continuing without pretty printing...\n') + while True: + puts(line) + line = sys.stdin.readline() + if line == '': + break + except: + sys.exit(1) + +if __name__ == '__main__': + main()
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v4 5/5 scripts: automatically pretty print stacks
In reply to Peter FeinerNow run_tests.sh automatically pipes test output through scripts/pretty_print_stacks.py. Can be disabled with ./configure --disable-pretty-print-stacks.
Pretty printing disabled on standalone tests because there's no binary.
--- configure | 10 ++++++++++ run_tests.sh | 10 ++++++++-- scripts/mkstandalone.sh | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-)
configure +10 -0
@@ -11,6 +11,7 @@ arch=`uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'` host=$arch cross_prefix= endian="" +pretty_print_stacks=yes usage() { cat <<-EOF
@@ -25,6 +26,8 @@ usage() { --prefix=PREFIX where to install things ($prefix) --kerneldir=DIR kernel build directory for kvm.h ($kerneldir) --endian=ENDIAN endianness to compile for (little or big, ppc64 only) + --[enable|disable]-pretty-print-stacks + enable or disable pretty stack printing (enabled by default) EOF exit 1 }
@@ -61,6 +64,12 @@ while [[ "$1" = -* ]]; do --ld) ld="$arg" ;; + --enable-pretty-print-stacks) + pretty_print_stacks=yes + ;; + --disable-pretty-print-stacks) + pretty_print_stacks=no + ;; --help) usage ;;
@@ -149,4 +158,5 @@ API=$api TEST_DIR=$testdir FIRMWARE=$firmware ENDIAN=$endian +PRETTY_PRINT_STACKS=$pretty_print_stacks EOF
run_tests.sh +8 -2
@@ -28,7 +28,7 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do case $opt in g) only_group=$OPTARG
@@ -46,7 +46,13 @@ while getopts "g:hv" opt; do esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +if [ "$PRETTY_PRINT_STACKS" = "yes" ]; then + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" +else + log_redir=">> test.log" +fi + +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log printf "BUILD_HEAD=$(cat build-head)\n\n" > test.log
scripts/mkstandalone.sh +4 -0
@@ -41,6 +41,10 @@ generate_test () echo "#!/bin/bash" echo "export STANDALONE=yes" echo "export HOST=\$(uname -m | sed -e s/i.86/i386/ | sed -e 's/arm.*/arm/')" + + # Can't pretty print without binary. + echo "export PRETTY_PRINT_STACKS=no" + config_export ARCH config_export ARCH_NAME config_export PROCESSOR
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [PATCH kvm-unit-tests v4 5/5] scripts: automatically pretty print stacks
----- Original Message -----
Quoted 62 lines
Now
run_tests.shautomatically pipes test output throughscripts/pretty_print_stacks.py. Can be disabled with ./configure --disable-pretty-print-stacks.Pretty printing disabled on standalone tests because there's no binary.
Signed-off-by Peter Feiner <[email protected]>--- configure | 10 ++++++++++ run_tests.sh | 10 ++++++++-- scripts/mkstandalone.sh | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-)configure +0
-0@@ -11,6 +11,7 @@ arch=`uname -m | sed -e's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'`
host=$arch
cross_prefix=
endian=""configure +3
-0+pretty_print_stacks=yes usage() { cat <<-EOF@@ -25,6 +26,8 @@ usage() { --prefix=PREFIX where to install things ($prefix) --kerneldir=DIR kernel build directory for kvm.h ($kerneldir) --endian=ENDIAN endianness to compile for (little or big, ppc64 only) + --[enable|disable]-pretty-print-stacks + enable or disable pretty stack printing (enabled by default) EOFexit 1
}configure +7
-0@@ -61,6 +64,12 @@ while [[ "$1" = -* ]]; do --ld) ld="$arg" ;; + --enable-pretty-print-stacks) + pretty_print_stacks=yes + ;; + --disable-pretty-print-stacks) + pretty_print_stacks=no + ;; --help) usage ;;@@ -149,4 +158,5 @@ API=$api TEST_DIR=$testdir FIRMWARE=$firmware ENDIAN=$endian +PRETTY_PRINT_STACKS=$pretty_print_stacks EOFrun_tests.sh +0
-0
run_tests.sh EOF · line 31
Quoted 5 lines
run_tests.sh +1
-1@@ -28,7 +28,7 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; do
Forgot to remove the 'p' here.
Quoted 23 lines
run_tests.sh +7
-1case $opt in g) only_group=$OPTARG@@ -46,7 +46,13 @@ while getopts "g:hv" opt; do esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +if [ "$PRETTY_PRINT_STACKS" = "yes" ]; then + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" +else + log_redir=">> test.log" +fi + +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log printf "BUILD_HEAD=$(cat build-head)\n\n" > test.logscripts/mkstandalone.sh +0
-0
scripts/mkstandalone.sh generate_test () · line 47
Quoted 7 lines
scripts/mkstandalone.sh +3
-0@@ -41,6 +41,10 @@ generate_test () echo "#!/bin/bash" echo "export STANDALONE=yes" echo "export HOST=\$(uname -m | sed -e s/i.86/i386/ | sed -e 's/arm.*/arm/')" + + # Can't pretty print without binary. + echo "export PRETTY_PRINT_STACKS=no"
To be precise, "without the elf", because we do have the flat file. (And, for powerpc we actually even have the elf, so I guess we should
say "can't pretty print without the pretty print script" or something)
However, we don't even really need this right now, because the PRETTY_PRINT_STACKS variable is only consumed by run_tests.sh, which isn't used by standalone scripts. I don't mind adding the explicit =no here though, just in case something changes.
Quoted 8 lines
scripts/mkstandalone.sh +1
-0+ config_export ARCH config_export ARCH_NAME
config_exportPROCESSOR
--
2.7.0.rc3.207.g0ac5344
Re: [PATCH kvm-unit-tests v4 5/5] scripts: automatically pretty print stacks
Quoted 108 lines · Andrew Jones
----- Original Message -----
Quoted 62 lines
Now
run_tests.shautomatically pipes test output throughscripts/pretty_print_stacks.py. Can be disabled with ./configure --disable-pretty-print-stacks.Pretty printing disabled on standalone tests because there's no binary.
Signed-off-by Peter Feiner <[email protected]>--- configure | 10 ++++++++++ run_tests.sh | 10 ++++++++-- scripts/mkstandalone.sh | 4 ++++ 3 files changed, 22 insertions(+), 2 deletions(-)configure +0
-0@@ -11,6 +11,7 @@ arch=`uname -m | sed -e's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'`
host=$arch
cross_prefix=
endian=""configure +3
-0+pretty_print_stacks=yes usage() { cat <<-EOF@@ -25,6 +26,8 @@ usage() { --prefix=PREFIX where to install things ($prefix) --kerneldir=DIR kernel build directory for kvm.h ($kerneldir) --endian=ENDIAN endianness to compile for (little or big, ppc64 only) + --[enable|disable]-pretty-print-stacks + enable or disable pretty stack printing (enabled by default) EOFexit 1
}configure +7
-0@@ -61,6 +64,12 @@ while [[ "$1" = -* ]]; do --ld) ld="$arg" ;; + --enable-pretty-print-stacks) + pretty_print_stacks=yes + ;; + --disable-pretty-print-stacks) + pretty_print_stacks=no + ;; --help) usage ;;@@ -149,4 +158,5 @@ API=$api TEST_DIR=$testdir FIRMWARE=$firmware ENDIAN=$endian +PRETTY_PRINT_STACKS=$pretty_print_stacks EOFrun_tests.sh +0
-0run_tests.sh EOF · line 31
Quoted 5 lines
run_tests.sh +1
-1@@ -28,7 +28,7 @@ EOF RUNTIME_arch_run="./$TEST_DIR/run" source scripts/runtime.bash -while getopts "g:hv" opt; do +while getopts "g:hvp" opt; doForgot to remove the 'p' here.
Quoted 23 lines
run_tests.sh +7
-1case $opt in g) only_group=$OPTARG@@ -46,7 +46,13 @@ while getopts "g:hv" opt; do esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +if [ "$PRETTY_PRINT_STACKS" = "yes" ]; then + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" +else + log_redir=">> test.log" +fi + +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log printf "BUILD_HEAD=$(cat build-head)\n\n" > test.logscripts/mkstandalone.sh +0
-0scripts/mkstandalone.sh generate_test () · line 47
Quoted 7 lines
scripts/mkstandalone.sh +3
-0@@ -41,6 +41,10 @@ generate_test () echo "#!/bin/bash" echo "export STANDALONE=yes" echo "export HOST=\$(uname -m | sed -e s/i.86/i386/ | sed -e 's/arm.*/arm/')" + + # Can't pretty print without binary. + echo "export PRETTY_PRINT_STACKS=no"To be precise, "without the elf", because we do have the flat file. (And, for powerpc we actually even have the elf, so I guess we should
say "can't pretty print without the pretty print script" or something)
Quoted 4 lines
However, we don't even really need this right now, because the
PRETTY_PRINT_STACKSvariable is only consumed byrun_tests.sh, which isn't used by standalone scripts. I don't mind adding the explicit =no here though, just in case something changes.
All good points. I just removed the comment altogether :-)
Peter
Quoted 26 lines · Peter Feiner
Some aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
Compiled on ppc64, arm64, i386,
x86_64.v4:
* Moved around arch and asm files per Linux style (hopefully).
* Added --[enable|disable]-pretty-print-stacks to ./configure. This has obviated the -p command-line option in ./run_tests.sh that I introduced in v1.
* Fixed arch-neutral backtrace so backtrace itself isn't included.v3:
* Renamed functions to match standard backtrace functions
* Added asm-generic stack walker that uses__builtin_return_address.
* Moved offset out of libcflat and into pretty printer
* Made pretty printer more robust w.r.t. errors: now it just continues printing.v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.
Quoted 6 lines
Peter Feiner (5):
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on failedassert()
scripts: pretty print stack traces
scripts: automatically pretty print stacks
There are indeed only 5 patches in v4. The subject on this first email, "[PATCH kvm-unit-tests v4 0/6] Debugging aids", has a typo.
Peter
v5 cover Debugging aids
In reply to Peter FeinerSome aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
Compiled on ppc64, arm64, i386, x86_64.
v5:
* Removed unused "b" flag from run_tests.sh
* Removed misleading comment in mkstandalone.sh.
v4:
* Moved around arch and asm files per Linux style (hopefully).
* Added --[enable|disable]-pretty-print-stacks to ./configure. This has obviated the -p command-line option in ./run_tests.sh that I introduced in v1.
* Fixed arch-neutral backtrace so backtrace itself isn't included.
v3:
* Renamed functions to match standard backtrace functions
* Added asm-generic stack walker that uses __builtin_return_address.
* Moved offset out of libcflat and into pretty printer
* Made pretty printer more robust w.r.t. errors: now it just continues printing.
v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.
Peter Feiner (5):
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on failed assert()
scripts: pretty print stack traces
scripts: automatically pretty print stacks
Makefile | 6 ++- configure | 10 +++++ lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/asm-generic/stack.c | 3 ++ lib/libcflat.h | 9 +++- 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 | 18 ++++++++ lib/x86/desc.c | 69 +++++++++++++++++++++++++++--- lib/x86/stack.c | 25 +++++++++++ run_tests.sh | 8 +++- scripts/mkstandalone.sh | 2 + scripts/pretty_print_stacks.py | 89 +++++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 4 ++ 17 files changed, 348 insertions(+), 11 deletions(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/asm-generic/stack.c 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 create mode 100755 scripts/pretty_print_stacks.py
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v5 1/5 lib: backtrace printing
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.
--- Makefile | 6 ++-- lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/asm-generic/stack.c | 3 ++ 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 | 18 ++++++++++ lib/x86/stack.c | 25 +++++++++++++ x86/Makefile.common | 4 +++ 12 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/asm-generic/stack.c 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
Makefile +4 -2
@@ -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 -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, "")
lib/arm/asm/stack.h new file +0 -0
lib/arm64/asm/stack.h new file +0 -0
lib/asm-generic/stack.c new file +3 -0
@@ -0,0 +1,3 @@ +#include <libcflat.h> +#include <asm-generic/stack.h> +
lib/libcflat.h +3 -0
@@ -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) ({ \
lib/powerpc/asm/stack.h new file +0 -0
lib/ppc64/asm/stack.h new file +0 -0
lib/stack.c new file +96 -0
96 lines not on this page · raw message
lib/stack.h new file +20 -0
@@ -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
lib/x86/asm/stack.h new file +18 -0
@@ -0,0 +1,18 @@ +#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 +static inline int backtrace (const void **return_addrs,int max_depth) +{ +return backtrace_frame (__builtin_frame_address (0 ), return_addrs, + max_depth); +} + +#endif
lib/x86/stack.c new file +25 -0
@@ -0,0 +1,25 @@ +#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; +}
x86/Makefile.common +4 -0
@@ -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)
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Re: [PATCH kvm-unit-tests v5 1/5] lib: backtrace printing
Quoted 71 lines · Peter Feiner
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 <[email protected]>--- Makefile | 6 ++-- lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/asm-generic/stack.c | 3 ++ 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 | 18 ++++++++++ lib/x86/stack.c | 25 +++++++++++++ x86/Makefile.common | 4 +++ 12 files changed, 173 insertions(+), 2 deletions(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h create mode 100644 lib/asm-generic/stack.c 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.cMakefile +4
-2@@ -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 -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, "")lib/arm/asm/stack.h new file +0
-0lib/arm64/asm/stack.h new file +0
-0lib/asm-generic/stack.c new file +0
-0
lib/asm-generic/stack.c line 3
Quoted 3 lines
lib/asm-generic/stack.c new file +3
-0@@ -0,0 +1,3 @@ +#include <libcflat.h> +#include <asm-generic/stack.h> +
Looks like you forgot to remove this file.
Quoted 78 lines
lib/libcflat.h +3
-0@@ -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) ({ \lib/powerpc/asm/stack.h new file +0
-0lib/ppc64/asm/stack.h new file +0
-0lib/stack.c new file +52
-0@@ -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, depth, 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) {
lib/stack.c line 62
Quoted 10 lines
lib/stack.c new file +10
-0+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 + 1); \
Is the +1 to skip a level, which means addr is an address two levels up? If we do that, then won't we skip the callers of backtrace, which may or may not be dump_stack?
lib/stack.c line 65
Quoted 3 lines
lib/stack.c new file +3
-0+if (!addr) \ + goto done; \ + return_addrs[i] =__builtin_extract_return_addr (addr); \
So here we put the i+1th return address into return_addrs[i]. I find that a bit confusing. Maybe we should leave it to the callers of backtrace to do any level skipping they want, i.e. here we shouldn't skip anything, but dump_stack could start printing at i=1.
Quoted 141 lines
lib/stack.c new file +31
-0+ 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 */ lib/stack.h new file +20
-0@@ -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 lib/x86/asm/stack.h new file +18
-0@@ -0,0 +1,18 @@ +#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 +static inline int backtrace (const void **return_addrs,int max_depth) +{ +return backtrace_frame (__builtin_frame_address (0 ), return_addrs, + max_depth); +} + +#endif lib/x86/stack.c new file +25
-0@@ -0,0 +1,25 @@ +#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; +}x86/Makefile.common +4
-0@@ -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)Signature · 6 lines
2.7.0.rc3.207.g0ac5344 -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html
Thanks,
drew
Re: [PATCH kvm-unit-tests v5 1/5] lib: backtrace printing
Quoted 15 lines · Andrew Jones
Quoted 14 lines · Peter Feiner
lib/stack.c new file +14
-0+#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 */
Quoted 8 lines
lib/stack.c line 62
Quoted 4 lines
lib/stack.c new file +4
-0+#define GET_RETURN_ADDRESS (i) \ + if (max_depth == i) \ + goto done; \ + addr = __builtin_return_address(i + 1); \Is the +1 to skip a level, which means addr is an address two levels up? If we do that, then won't we skip the callers of backtrace, which may or may not be
dump_stack?
Right and right. In v6 dump_stack now does the skipping.
Quoted 10 lines
lib/stack.c line 65
Quoted 5 lines
lib/stack.c new file +3
-0+if (!addr) \ + goto done; \ + return_addrs[i] =__builtin_extract_return_addr (addr); \So here we put the i+1th return address into return_addrs[i]. I find that a bit confusing. Maybe we should leave it to the callers of backtrace to do any level skipping they want, i.e. here we shouldn't skip anything, but
dump_stackcould start printing at i=1.
Agreed. Changed in v6.
Peter
PATCH v5 2/5 x86: lib: debug dump on unhandled exceptions
In reply to Peter FeinerPrints the stack trace and registers.
--- lib/x86/desc.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-)
lib/x86/desc.c +63 -6
@@ -38,6 +38,67 @@ struct ex_record {extern struct ex_record exception_table_start, exception_table_end; +static const char *exception_mnemonic (int vector) +{ +switch (vector) { +case 0 :return "#DE" ; +case 1 :return "#DB" ; +case 2 :return "#NMI" ; +case 3 :return "#BP" ; +case 4 :return "#OF" ; +case 5 :return "#BR" ; +case 6 :return "#UD" ; +case 7 :return "#NM" ; +case 8 :return "#DF" ; +case 10 :return "#TS" ; +case 11 :return "#NP" ; +case 12 :return "#SS" ; +case 13 :return "#GP" ; +case 14 :return "#PF" ; +case 16 :return "#MF" ; +case 17 :return "#AC" ; +case 18 :return "#MC" ; +case 19 :return "#XM" ; +default :return "#??" ; + } +} + +static void unhandled_exception (struct ex_regs *regs,bool cpu) +{ +printf ("Unhandled %sexception %ld %s at ip %016lx\n" , + cpu ?"cpu " :"" , regs->vector, +exception_mnemonic (regs->vector), regs->rip); +if (regs->vector ==14 ) +printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); + + printf("error_code=%04lx rflags=%08lx cs=%08lx\n" + "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n" + "rbp=%016lx rsi=%016lx rdi=%016lx\n" +#ifdef __x86_64__ + " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n" + "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n" +#endif +"cr0=%016lx cr2=%016lx cr3=%016lx cr4=%016lx\n" +#ifdef __x86_64__ +"cr8=%016lx\n" +#endif + , + regs->error_code, regs->rflags, regs->cs, + regs->rax, regs->rcx, regs->rdx, regs->rbx, + regs->rbp, regs->rsi, regs->rdi, +#ifdef __x86_64__ + regs->r8, regs->r9, regs->r10, regs->r11, + regs->r12, regs->r13, regs->r14, regs->r15, +#endif +read_cr0 (),read_cr2 (),read_cr3 (),read_cr4 () +#ifdef __x86_64__ + ,read_cr8 () +#endif + ); +dump_frame_stack ((void *) regs->rip, (void *) regs->rbp); +exit (7 ); +} +static void check_exception_table (struct ex_regs *regs) {struct ex_record *ex;
@@ -53,8 +114,7 @@ static void check_exception_table(struct ex_regs *regs)return ; } } -printf ("unhandled exception %lu\n" , regs->vector); -abort (); +unhandled_exception (regs, false); }static void (*exception_handlers[32 ])(struct ex_regs *regs);
@@ -75,10 +135,7 @@ void do_handle_exception(struct ex_regs *regs) exception_handlers[regs->vector](regs);return ; } -printf ("unhandled cpu exception %lu\n" , regs->vector); -if (regs->vector ==14 ) -printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); -abort (); +unhandled_exception (regs, true); }#define EX (NAME ,N ) extern char NAME##_fault; \
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v5 3/5 lib: dump stack on failed assert()
In reply to Peter Feiner--- lib/libcflat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
lib/libcflat.h +4 -2
@@ -92,10 +92,12 @@ extern void dump_frame_stack(const void *instruction, const void *frame);#define assert (cond) \ do { \ - if (!(cond)) \ + if (!(cond)) { \ printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond), \ + __FILE__, __LINE__, #cond); \ + dump_stack(); \ abort(); \ + } \ } while (0)#endif
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v5 4/5 scripts: pretty print stack traces
In reply to Peter FeinerThe script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5: ac_test_exec at x86/access.c:818
}
> ac_test_setup_pte(at, pool);
r = ac_test_do_access(at);
0x004014dd: ac_test_run at x86/access.c:852
++tests;
> successes += ac_test_exec(&at, &pool);
} while (ac_test_bump(&at));
0x0040157d: main at x86/access.c:873
printf("starting test\n\n");
> r = ac_test_run();
return r ? 0 : 1;0x0040028e: start64 at x86/cstart64.S:206
lea __argv(%rip), %rsi
> call main
mov %eax, %edi
--- scripts/pretty_print_stacks.py | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100755 scripts/pretty_print_stacks.py
scripts/pretty_print_stacks.py new file +89 -0
@@ -0,0 +1,89 @@ +#!/usr/bin/env python + +import re +import subprocess +import sys +import traceback + +# Subvert output buffering. +def puts(string): + sys.stdout.write(string) + sys.stdout.flush() + +def pretty_print_stack(binary, line): + addrs = line.split()[1:] + # Addresses are return addresses unless preceded by a '@'. We want the + # caller address so line numbers are more intuitive. Thus we subtract 1 + # from the address to get the call code. + for i in range(len(addrs)): + addr = addrs[i] + if addr.startswith('@'): + addrs[i] = addr[1:] + else: + addrs[i] = '%lx' % (int(addrs[i], 16) - 1) + + # Output like this: + # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 + # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) + cmd = ['addr2line', '-e', binary, '-i', '-f', '--pretty', '--address'] + cmd.extend(addrs) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + puts(line) + return + + for line in out.splitlines(): + m = re.match('(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) + if m is None: + puts('%s\n' % line) + return + + head, path, line, tail = m.groups() + line = int(line) + puts('%s at %s:%d%s\n' % (head, path, line, tail)) + try: + lines = open(path).readlines() + except IOError: + continue + if line > 1: + puts(' %s\n' % lines[line - 2].rstrip()) + puts(' > %s\n' % lines[line - 1].rstrip()) + if line < len(lines): + puts(' %s\n' % lines[line].rstrip()) + +def main(): + if len(sys.argv) != 2: + sys.stderr.write('usage: %s <kernel>\n' % sys.argv[0]) + sys.exit(1) + + binary = sys.argv[1] + + try: + while True: + # Subvert input buffering. + line = sys.stdin.readline() + if line == '': + break + + if not line.strip().startswith('STACK:'): + puts(line) + continue + + try: + pretty_print_stack(binary, line) + except Exception: + puts('Error pretty printing stack:\n') + puts(traceback.format_exc()) + puts('Continuing without pretty printing...\n') + while True: + puts(line) + line = sys.stdin.readline() + if line == '': + break + except: + sys.exit(1) + +if __name__ == '__main__': + main()
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v5 5/5 scripts: automatically pretty print stacks
In reply to Peter FeinerNow run_tests.sh automatically pipes test output through scripts/pretty_print_stacks.py. Can be disabled with ./configure --disable-pretty-print-stacks.
Pretty printing disabled on standalone tests because there's no binary.
--- configure | 10 ++++++++++ run_tests.sh | 8 +++++++- scripts/mkstandalone.sh | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-)
configure +10 -0
@@ -11,6 +11,7 @@ arch=`uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'` host=$arch cross_prefix= endian="" +pretty_print_stacks=yes usage() { cat <<-EOF
@@ -25,6 +26,8 @@ usage() { --prefix=PREFIX where to install things ($prefix) --kerneldir=DIR kernel build directory for kvm.h ($kerneldir) --endian=ENDIAN endianness to compile for (little or big, ppc64 only) + --[enable|disable]-pretty-print-stacks + enable or disable pretty stack printing (enabled by default) EOF exit 1 }
@@ -61,6 +64,12 @@ while [[ "$1" = -* ]]; do --ld) ld="$arg" ;; + --enable-pretty-print-stacks) + pretty_print_stacks=yes + ;; + --disable-pretty-print-stacks) + pretty_print_stacks=no + ;; --help) usage ;;
@@ -149,4 +158,5 @@ API=$api TEST_DIR=$testdir FIRMWARE=$firmware ENDIAN=$endian +PRETTY_PRINT_STACKS=$pretty_print_stacks EOF
run_tests.sh +7 -1
@@ -46,7 +46,13 @@ while getopts "g:hv" opt; do esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +if [ "$PRETTY_PRINT_STACKS" = "yes" ]; then + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" +else + log_redir=">> test.log" +fi + +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log printf "BUILD_HEAD=$(cat build-head)\n\n" > test.log
scripts/mkstandalone.sh +2 -0
@@ -41,6 +41,8 @@ generate_test () echo "#!/bin/bash" echo "export STANDALONE=yes" echo "export HOST=\$(uname -m | sed -e s/i.86/i386/ | sed -e 's/arm.*/arm/')" + echo "export PRETTY_PRINT_STACKS=no" + config_export ARCH config_export ARCH_NAME config_export PROCESSOR
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Quoted 57 lines · Peter Feiner
Some aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
Compiled on ppc64, arm64, i386,
x86_64.v5:
* Removed unused "b" flag fromrun_tests.sh
* Removed misleading comment inmkstandalone.sh.v4:
* Moved around arch and asm files per Linux style (hopefully).
* Added --[enable|disable]-pretty-print-stacks to ./configure. This has obviated the -p command-line option in ./run_tests.sh that I introduced in v1.
* Fixed arch-neutral backtrace so backtrace itself isn't included.v3:
* Renamed functions to match standard backtrace functions
* Added asm-generic stack walker that uses__builtin_return_address.
* Moved offset out of libcflat and into pretty printer
* Made pretty printer more robust w.r.t. errors: now it just continues printing.v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.Peter Feiner (5):
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on failedassert()
scripts: pretty print stack traces
scripts: automatically pretty print stacksMakefile | 6 ++- configure | 10 +++++ lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/asm-generic/stack.c | 3 ++ lib/libcflat.h | 9 +++- 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 | 18 ++++++++ lib/x86/desc.c | 69 +++++++++++++++++++++++++++--- lib/x86/stack.c | 25 +++++++++++ run_tests.sh | 8 +++- scripts/mkstandalone.sh | 2 + scripts/pretty_print_stacks.py | 89 +++++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 4 ++ 17 files changed, 348 insertions(+), 11 deletions(-) create mode 100644 lib/arm/asm/stack.h create mode 100644 lib/arm64/asm/stack.h
Quoted 11 lines
create mode 100644 lib/asm-generic/stack.c 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 create mode 100755 scripts/pretty_print_stacks.pySignature · 1 line
2.7.0.rc3.207.g0ac5344
I had a couple comments on 1/5, otherwise the series looks good to me.
Thanks,
drew
v6 cover Debugging aids
In reply to Peter FeinerSome aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
Compiled on ppc64, arm64, i386, x86_64.
v6:
* Don't print dump_stack's call to backtrace() in the stack trace rather than having backtrace() skip over the first return address in the trace.
* Actually removed lib/asm-generic/stack.c.
v5:
* Removed unused "b" flag from run_tests.sh
* Removed misleading comment in mkstandalone.sh.
v4:
* Moved around arch and asm files per Linux style (hopefully).
* Added --[enable|disable]-pretty-print-stacks to ./configure. This has obviated the -p command-line option in ./run_tests.sh that I introduced in v1.
* Fixed arch-neutral backtrace so backtrace itself isn't included.
v3:
* Renamed functions to match standard backtrace functions
* Added asm-generic stack walker that uses __builtin_return_address.
* Moved offset out of libcflat and into pretty printer
* Made pretty printer more robust w.r.t. errors: now it just continues printing.
v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.
Peter Feiner (5):
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on failed assert()
scripts: pretty print stack traces
scripts: automatically pretty print stacks
Makefile | 6 ++- configure | 10 +++++ lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/libcflat.h | 9 +++- 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/desc.c | 69 +++++++++++++++++++++++++++--- lib/x86/stack.c | 31 ++++++++++++++ run_tests.sh | 8 +++- scripts/mkstandalone.sh | 2 + scripts/pretty_print_stacks.py | 89 +++++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 4 ++ 16 files changed, 347 insertions(+), 11 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 create mode 100755 scripts/pretty_print_stacks.py
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v6 1/5 lib: backtrace printing
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.
--- 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
Makefile +4 -2
@@ -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, "")
lib/arm/asm/stack.h new file +0 -0
lib/arm64/asm/stack.h new file +0 -0
lib/libcflat.h +3 -0
@@ -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) ({ \
lib/powerpc/asm/stack.h new file +0 -0
lib/ppc64/asm/stack.h new file +0 -0
lib/stack.c new file +96 -0
96 lines not on this page · raw message
lib/stack.h new file +20 -0
@@ -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
lib/x86/asm/stack.h new file +14 -0
@@ -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
lib/x86/stack.c new file +31 -0
@@ -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); +}
x86/Makefile.common +4 -0
@@ -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)
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v6 2/5 x86: lib: debug dump on unhandled exceptions
In reply to Peter FeinerPrints the stack trace and registers.
--- lib/x86/desc.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 63 insertions(+), 6 deletions(-)
lib/x86/desc.c +63 -6
@@ -38,6 +38,67 @@ struct ex_record {extern struct ex_record exception_table_start, exception_table_end; +static const char *exception_mnemonic (int vector) +{ +switch (vector) { +case 0 :return "#DE" ; +case 1 :return "#DB" ; +case 2 :return "#NMI" ; +case 3 :return "#BP" ; +case 4 :return "#OF" ; +case 5 :return "#BR" ; +case 6 :return "#UD" ; +case 7 :return "#NM" ; +case 8 :return "#DF" ; +case 10 :return "#TS" ; +case 11 :return "#NP" ; +case 12 :return "#SS" ; +case 13 :return "#GP" ; +case 14 :return "#PF" ; +case 16 :return "#MF" ; +case 17 :return "#AC" ; +case 18 :return "#MC" ; +case 19 :return "#XM" ; +default :return "#??" ; + } +} + +static void unhandled_exception (struct ex_regs *regs,bool cpu) +{ +printf ("Unhandled %sexception %ld %s at ip %016lx\n" , + cpu ?"cpu " :"" , regs->vector, +exception_mnemonic (regs->vector), regs->rip); +if (regs->vector ==14 ) +printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); + + printf("error_code=%04lx rflags=%08lx cs=%08lx\n" + "rax=%016lx rcx=%016lx rdx=%016lx rbx=%016lx\n" + "rbp=%016lx rsi=%016lx rdi=%016lx\n" +#ifdef __x86_64__ + " r8=%016lx r9=%016lx r10=%016lx r11=%016lx\n" + "r12=%016lx r13=%016lx r14=%016lx r15=%016lx\n" +#endif +"cr0=%016lx cr2=%016lx cr3=%016lx cr4=%016lx\n" +#ifdef __x86_64__ +"cr8=%016lx\n" +#endif + , + regs->error_code, regs->rflags, regs->cs, + regs->rax, regs->rcx, regs->rdx, regs->rbx, + regs->rbp, regs->rsi, regs->rdi, +#ifdef __x86_64__ + regs->r8, regs->r9, regs->r10, regs->r11, + regs->r12, regs->r13, regs->r14, regs->r15, +#endif +read_cr0 (),read_cr2 (),read_cr3 (),read_cr4 () +#ifdef __x86_64__ + ,read_cr8 () +#endif + ); +dump_frame_stack ((void *) regs->rip, (void *) regs->rbp); +exit (7 ); +} +static void check_exception_table (struct ex_regs *regs) {struct ex_record *ex;
@@ -53,8 +114,7 @@ static void check_exception_table(struct ex_regs *regs)return ; } } -printf ("unhandled exception %lu\n" , regs->vector); -abort (); +unhandled_exception (regs, false); }static void (*exception_handlers[32 ])(struct ex_regs *regs);
@@ -75,10 +135,7 @@ void do_handle_exception(struct ex_regs *regs) exception_handlers[regs->vector](regs);return ; } -printf ("unhandled cpu exception %lu\n" , regs->vector); -if (regs->vector ==14 ) -printf ("PF at 0x%lx addr 0x%lx\n" , regs->rip,read_cr2 ()); -abort (); +unhandled_exception (regs, true); }#define EX (NAME ,N ) extern char NAME##_fault; \
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v6 3/5 lib: dump stack on failed assert()
In reply to Peter Feiner--- lib/libcflat.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
lib/libcflat.h +4 -2
@@ -92,10 +92,12 @@ extern void dump_frame_stack(const void *instruction, const void *frame);#define assert (cond) \ do { \ - if (!(cond)) \ + if (!(cond)) { \ printf("%s:%d: assert failed: %s\n", \ - __FILE__, __LINE__, #cond), \ + __FILE__, __LINE__, #cond); \ + dump_stack(); \ abort(); \ + } \ } while (0)#endif
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v6 4/5 scripts: pretty print stack traces
In reply to Peter FeinerThe script runs addresses through addr2line to get file names and line numbers. Also prints out source code lines if files are available. For example
0x004013f5: ac_test_exec at x86/access.c:818
}
> ac_test_setup_pte(at, pool);
r = ac_test_do_access(at);
0x004014dd: ac_test_run at x86/access.c:852
++tests;
> successes += ac_test_exec(&at, &pool);
} while (ac_test_bump(&at));
0x0040157d: main at x86/access.c:873
printf("starting test\n\n");
> r = ac_test_run();
return r ? 0 : 1;0x0040028e: start64 at x86/cstart64.S:206
lea __argv(%rip), %rsi
> call main
mov %eax, %edi
--- scripts/pretty_print_stacks.py | 89 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100755 scripts/pretty_print_stacks.py
scripts/pretty_print_stacks.py new file +89 -0
@@ -0,0 +1,89 @@ +#!/usr/bin/env python + +import re +import subprocess +import sys +import traceback + +# Subvert output buffering. +def puts(string): + sys.stdout.write(string) + sys.stdout.flush() + +def pretty_print_stack(binary, line): + addrs = line.split()[1:] + # Addresses are return addresses unless preceded by a '@'. We want the + # caller address so line numbers are more intuitive. Thus we subtract 1 + # from the address to get the call code. + for i in range(len(addrs)): + addr = addrs[i] + if addr.startswith('@'): + addrs[i] = addr[1:] + else: + addrs[i] = '%lx' % (int(addrs[i], 16) - 1) + + # Output like this: + # 0x004002be: start64 at path/to/kvm-unit-tests/x86/cstart64.S:208 + # (inlined by) test_ept_violation at path/to/kvm-unit-tests/x86/vmx_tests.c:1719 (discriminator 1) + cmd = ['addr2line', '-e', binary, '-i', '-f', '--pretty', '--address'] + cmd.extend(addrs) + + p = subprocess.Popen(cmd, stdout=subprocess.PIPE) + out, err = p.communicate() + if p.returncode != 0: + puts(line) + return + + for line in out.splitlines(): + m = re.match('(.*) at [^ ]*/kvm-unit-tests/([^ ]*):([0-9]+)(.*)', line) + if m is None: + puts('%s\n' % line) + return + + head, path, line, tail = m.groups() + line = int(line) + puts('%s at %s:%d%s\n' % (head, path, line, tail)) + try: + lines = open(path).readlines() + except IOError: + continue + if line > 1: + puts(' %s\n' % lines[line - 2].rstrip()) + puts(' > %s\n' % lines[line - 1].rstrip()) + if line < len(lines): + puts(' %s\n' % lines[line].rstrip()) + +def main(): + if len(sys.argv) != 2: + sys.stderr.write('usage: %s <kernel>\n' % sys.argv[0]) + sys.exit(1) + + binary = sys.argv[1] + + try: + while True: + # Subvert input buffering. + line = sys.stdin.readline() + if line == '': + break + + if not line.strip().startswith('STACK:'): + puts(line) + continue + + try: + pretty_print_stack(binary, line) + except Exception: + puts('Error pretty printing stack:\n') + puts(traceback.format_exc()) + puts('Continuing without pretty printing...\n') + while True: + puts(line) + line = sys.stdin.readline() + if line == '': + break + except: + sys.exit(1) + +if __name__ == '__main__': + main()
Signature · 1 line
2.7.0.rc3.207.g0ac5344
PATCH v6 5/5 scripts: automatically pretty print stacks
In reply to Peter FeinerNow run_tests.sh automatically pipes test output through scripts/pretty_print_stacks.py. Can be disabled with ./configure --disable-pretty-print-stacks.
Pretty printing disabled on standalone tests because there's no binary.
--- configure | 10 ++++++++++ run_tests.sh | 8 +++++++- scripts/mkstandalone.sh | 2 ++ 3 files changed, 19 insertions(+), 1 deletion(-)
configure +10 -0
@@ -11,6 +11,7 @@ arch=`uname -m | sed -e 's/i.86/i386/;s/arm.*/arm/;s/ppc64.*/ppc64/'` host=$arch cross_prefix= endian="" +pretty_print_stacks=yes usage() { cat <<-EOF
@@ -25,6 +26,8 @@ usage() { --prefix=PREFIX where to install things ($prefix) --kerneldir=DIR kernel build directory for kvm.h ($kerneldir) --endian=ENDIAN endianness to compile for (little or big, ppc64 only) + --[enable|disable]-pretty-print-stacks + enable or disable pretty stack printing (enabled by default) EOF exit 1 }
@@ -61,6 +64,12 @@ while [[ "$1" = -* ]]; do --ld) ld="$arg" ;; + --enable-pretty-print-stacks) + pretty_print_stacks=yes + ;; + --disable-pretty-print-stacks) + pretty_print_stacks=no + ;; --help) usage ;;
@@ -149,4 +158,5 @@ API=$api TEST_DIR=$testdir FIRMWARE=$firmware ENDIAN=$endian +PRETTY_PRINT_STACKS=$pretty_print_stacks EOF
run_tests.sh +7 -1
@@ -46,7 +46,13 @@ while getopts "g:hv" opt; do esac done -RUNTIME_arch_run="./$TEST_DIR/run >> test.log" +if [ "$PRETTY_PRINT_STACKS" = "yes" ]; then + log_redir="> >(./scripts/pretty_print_stacks.py \$kernel >> test.log)" +else + log_redir=">> test.log" +fi + +RUNTIME_arch_run="./$TEST_DIR/run $log_redir" config=$TEST_DIR/unittests.cfg rm -f test.log printf "BUILD_HEAD=$(cat build-head)\n\n" > test.log
scripts/mkstandalone.sh +2 -0
@@ -41,6 +41,8 @@ generate_test () echo "#!/bin/bash" echo "export STANDALONE=yes" echo "export HOST=\$(uname -m | sed -e s/i.86/i386/ | sed -e 's/arm.*/arm/')" + echo "export PRETTY_PRINT_STACKS=no" + config_export ARCH config_export ARCH_NAME config_export PROCESSOR
Signature · 1 line
2.7.0.rc3.207.g0ac5344
Quoted 63 lines · Peter Feiner
Some aids for debugging: stack dumping, register dumping, and printing failing assertion conditions.
Compiled on ppc64, arm64, i386,
x86_64.v6:
* Don't print dump_stack's call tobacktrace()in the stack trace rather than havingbacktrace()skip over the first return address in the trace.
* Actually removedlib/asm-generic/stack.c.v5:
* Removed unused "b" flag fromrun_tests.sh
* Removed misleading comment inmkstandalone.sh.v4:
* Moved around arch and asm files per Linux style (hopefully).
* Added --[enable|disable]-pretty-print-stacks to ./configure. This has obviated the -p command-line option in ./run_tests.sh that I introduced in v1.
* Fixed arch-neutral backtrace so backtrace itself isn't included.v3:
* Renamed functions to match standard backtrace functions
* Added asm-generic stack walker that uses__builtin_return_address.
* Moved offset out of libcflat and into pretty printer
* Made pretty printer more robust w.r.t. errors: now it just continues printing.v2:
* Fixed a bunch tests on x86 that broke with -fno-omit-frame-pointer.
* Only use -fno-omit-frame-pointer on x86. I suspect arm & ppc will have similar problems that I fixed for x86.Peter Feiner (5):
lib: backtrace printing
x86: lib: debug dump on unhandled exceptions
lib: dump stack on failedassert()
scripts: pretty print stack traces
scripts: automatically pretty print stacksMakefile | 6 ++- configure | 10 +++++ lib/arm/asm/stack.h | 0 lib/arm64/asm/stack.h | 0 lib/libcflat.h | 9 +++- 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/desc.c | 69 +++++++++++++++++++++++++++--- lib/x86/stack.c | 31 ++++++++++++++ run_tests.sh | 8 +++- scripts/mkstandalone.sh | 2 + scripts/pretty_print_stacks.py | 89 +++++++++++++++++++++++++++++++++++++++ x86/Makefile.common | 4 ++ 16 files changed, 347 insertions(+), 11 deletions(-) create mode 100644 lib/arm/asm/stack.h
Quoted 12 lines
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 create mode 100755 scripts/pretty_print_stacks.pySignature · 1 line
2.7.0.rc3.207.g0ac5344
Thanks for this series! It looks good to me (my r-b may be added to all patches)
drew