From 5f38f35d5d6c78aafa6da20845d9ceff74af00f8 Mon Sep 17 00:00:00 2001 From: Lassi Tuura Date: Thu, 31 Mar 2011 23:47:20 -0700 Subject: [PATCH] Drop a call frame in tdep_trace and avoid a call to unw_step. Dropping the extra frame for unw_backtrace itself using unw_step is approximately 15% slower than skipping the frame in tdep_trace. So drop the frame in the latter, and make the function a private implementation detail for libunwind, not an exported interface. Also moves unw_getcontext call back into unw_backtrace to avoid an extra call frame in case slow_backtrace does not get inlined into unw_backtrace. --- include/libunwind-arm.h | 8 ---- include/libunwind-hppa.h | 8 ---- include/libunwind-ia64.h | 8 ---- include/libunwind-mips.h | 8 ---- include/libunwind-ppc32.h | 8 ---- include/libunwind-ppc64.h | 8 ---- include/libunwind-x86.h | 8 ---- include/libunwind-x86_64.h | 24 ----------- include/tdep-arm/libunwind_i.h | 7 ++++ include/tdep-hppa/libunwind_i.h | 7 ++++ include/tdep-ia64/libunwind_i.h | 7 ++++ include/tdep-mips/libunwind_i.h | 7 ++++ include/tdep-ppc32/libunwind_i.h | 7 ++++ include/tdep-ppc64/libunwind_i.h | 7 ++++ include/tdep-x86/libunwind_i.h | 7 ++++ include/tdep-x86_64/libunwind_i.h | 24 +++++++++++ src/mi/backtrace.c | 17 +++----- src/x86_64/Gtrace.c | 37 ++++++++--------- tests/Gtest-trace.c | 68 ++++++++++++++++++------------- tests/check-namespace.sh.in | 2 - 20 files changed, 135 insertions(+), 142 deletions(-) diff --git a/include/libunwind-arm.h b/include/libunwind-arm.h index a764b155..492331e4 100644 --- a/include/libunwind-arm.h +++ b/include/libunwind-arm.h @@ -286,19 +286,11 @@ typedef struct } unw_tdep_proc_info_t; -typedef struct - { - /* no arm-specific fast trace */ - } -unw_tdep_frame_t; - #include "libunwind-common.h" #define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) extern int unw_tdep_is_fpreg (int); -#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO) - #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/libunwind-hppa.h b/include/libunwind-hppa.h index 04eacee5..74ea70da 100644 --- a/include/libunwind-hppa.h +++ b/include/libunwind-hppa.h @@ -103,12 +103,6 @@ unw_tdep_save_loc_t; /* On PA-RISC, we can directly use ucontext_t as the unwind context. */ typedef ucontext_t unw_tdep_context_t; -typedef struct - { - /* no hppa-specific fast trace */ - } -unw_tdep_frame_t; - #define unw_tdep_is_fpreg(r) ((unsigned) ((r) - UNW_HPPA_FR) < 32) #include "libunwind-dynamic.h" @@ -124,8 +118,6 @@ unw_tdep_proc_info_t; #define unw_tdep_getcontext UNW_ARCH_OBJ (getcontext) extern int unw_tdep_getcontext (unw_tdep_context_t *); -#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO) - #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/libunwind-ia64.h b/include/libunwind-ia64.h index 72480d24..fb2fbfe5 100644 --- a/include/libunwind-ia64.h +++ b/include/libunwind-ia64.h @@ -150,12 +150,6 @@ unw_tdep_save_loc_t; /* On IA-64, we can directly use ucontext_t as the unwind context. */ typedef ucontext_t unw_tdep_context_t; -typedef struct - { - /* no ia64-specific fast trace */ - } -unw_tdep_frame_t; - #define unw_tdep_is_fpreg(r) ((unsigned) ((r) - UNW_IA64_FR) < 128) #include "libunwind-dynamic.h" @@ -193,8 +187,6 @@ extern unw_word_t _Uia64_find_dyn_list (unw_addr_space_t, unw_dyn_info_t *, signal-safe. */ extern int _Uia64_get_kernel_table (unw_dyn_info_t *); -#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO) - #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/libunwind-mips.h b/include/libunwind-mips.h index b05e7406..91f70015 100644 --- a/include/libunwind-mips.h +++ b/include/libunwind-mips.h @@ -137,12 +137,6 @@ typedef struct } unw_tdep_proc_info_t; -typedef struct - { - /* no mips-specific fast trace */ - } -unw_tdep_frame_t; - #include "libunwind-common.h" /* There is no getcontext() on MIPS. Use a stub version which only saves GP @@ -154,8 +148,6 @@ extern int unw_tdep_getcontext (ucontext_t *uc); #define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) extern int unw_tdep_is_fpreg (int); -#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO) - #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/libunwind-ppc32.h b/include/libunwind-ppc32.h index dca2a74e..b40a84ef 100644 --- a/include/libunwind-ppc32.h +++ b/include/libunwind-ppc32.h @@ -195,19 +195,11 @@ typedef struct } unw_tdep_proc_info_t; -typedef struct - { - /* no ppc32-specific fast trace */ - } -unw_tdep_frame_t; - #include "libunwind-common.h" #define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) extern int unw_tdep_is_fpreg (int); -#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO) - #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/libunwind-ppc64.h b/include/libunwind-ppc64.h index 7370f603..66420b33 100644 --- a/include/libunwind-ppc64.h +++ b/include/libunwind-ppc64.h @@ -252,19 +252,11 @@ typedef struct } unw_tdep_proc_info_t; -typedef struct - { - /* no ppc64-specific fast trace */ - } -unw_tdep_frame_t; - #include "libunwind-common.h" #define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) extern int unw_tdep_is_fpreg (int); -#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO) - #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/libunwind-x86.h b/include/libunwind-x86.h index 60c97bf6..32533df9 100644 --- a/include/libunwind-x86.h +++ b/include/libunwind-x86.h @@ -172,12 +172,6 @@ typedef struct } unw_tdep_proc_info_t; -typedef struct - { - /* no x86-specific fast trace */ - } -unw_tdep_frame_t; - #include "libunwind-common.h" #define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext) @@ -186,8 +180,6 @@ extern int unw_tdep_getcontext (unw_tdep_context_t *); #define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) extern int unw_tdep_is_fpreg (int); -#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO) - #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/libunwind-x86_64.h b/include/libunwind-x86_64.h index 153c43a5..50b4de21 100644 --- a/include/libunwind-x86_64.h +++ b/include/libunwind-x86_64.h @@ -104,39 +104,15 @@ typedef struct } unw_tdep_proc_info_t; -typedef enum - { - UNW_X86_64_FRAME_STANDARD = -2, /* regular rbp, rsp +/- offset */ - UNW_X86_64_FRAME_SIGRETURN = -1, /* special sigreturn frame */ - UNW_X86_64_FRAME_OTHER = 0, /* not cacheable (special or unrecognised) */ - UNW_X86_64_FRAME_GUESSED = 1 /* guessed it was regular, but not known */ - } -unw_tdep_frame_type_t; - -typedef struct - { - uint64_t virtual_address; - int64_t frame_type : 2; /* unw_tdep_frame_type_t classification */ - int64_t last_frame : 1; /* non-zero if last frame in chain */ - int64_t cfa_reg_rsp : 1; /* cfa dwarf base register is rsp vs. rbp */ - int64_t cfa_reg_offset : 30; /* cfa is at this offset from base register value */ - int64_t rbp_cfa_offset : 15; /* rbp saved at this offset from cfa (-1 = not saved) */ - int64_t rsp_cfa_offset : 15; /* rsp saved at this offset from cfa (-1 = not saved) */ - } -unw_tdep_frame_t; - #include "libunwind-dynamic.h" #include "libunwind-common.h" #define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext) #define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg) -#define unw_tdep_trace UNW_OBJ(trace) extern int unw_tdep_getcontext (unw_tdep_context_t *); extern int unw_tdep_is_fpreg (int); -extern int unw_tdep_trace (unw_cursor_t *cursor, void **addresses, int *n); - #if defined(__cplusplus) || defined(c_plusplus) } #endif diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h index 0cb4a719..cd18292e 100644 --- a/include/tdep-arm/libunwind_i.h +++ b/include/tdep-arm/libunwind_i.h @@ -36,6 +36,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "dwarf.h" #include "ex_tables.h" +typedef struct + { + /* no arm-specific fast trace */ + } +unw_tdep_frame_t; + struct unw_addr_space { struct unw_accessors acc; @@ -222,6 +228,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_cache_frame(c,rs) do {} while(0) #define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ diff --git a/include/tdep-hppa/libunwind_i.h b/include/tdep-hppa/libunwind_i.h index 4e6c1c3a..d5ba7ab0 100644 --- a/include/tdep-hppa/libunwind_i.h +++ b/include/tdep-hppa/libunwind_i.h @@ -35,6 +35,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "elf32.h" #include "dwarf.h" +typedef struct + { + /* no hppa-specific fast trace */ + } +unw_tdep_frame_t; + struct unw_addr_space { struct unw_accessors acc; @@ -228,6 +234,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_cache_frame(c,rs) do {} while(0) #define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ diff --git a/include/tdep-ia64/libunwind_i.h b/include/tdep-ia64/libunwind_i.h index 3193a646..ec20338d 100644 --- a/include/tdep-ia64/libunwind_i.h +++ b/include/tdep-ia64/libunwind_i.h @@ -32,6 +32,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "elf64.h" #include "mempool.h" +typedef struct + { + /* no ia64-specific fast trace */ + } +unw_tdep_frame_t; + enum ia64_pregnum { /* primary unat: */ @@ -224,6 +230,7 @@ struct ia64_global_unwind_state #define tdep_cache_frame(c,rs) do {} while(0) #define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) #define tdep_get_as(c) ((c)->as) #define tdep_get_as_arg(c) ((c)->as_arg) #define tdep_get_ip(c) ((c)->ip) diff --git a/include/tdep-mips/libunwind_i.h b/include/tdep-mips/libunwind_i.h index 2e6fc4fd..17876d54 100644 --- a/include/tdep-mips/libunwind_i.h +++ b/include/tdep-mips/libunwind_i.h @@ -39,6 +39,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "mempool.h" #include "dwarf.h" +typedef struct + { + /* no mips-specific fast trace */ + } +unw_tdep_frame_t; + struct unw_addr_space { struct unw_accessors acc; @@ -283,6 +289,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_cache_frame(c,rs) do {} while(0) #define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ diff --git a/include/tdep-ppc32/libunwind_i.h b/include/tdep-ppc32/libunwind_i.h index 7db2b393..23bf2d11 100644 --- a/include/tdep-ppc32/libunwind_i.h +++ b/include/tdep-ppc32/libunwind_i.h @@ -42,6 +42,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "mempool.h" #include "dwarf.h" +typedef struct + { + /* no ppc32-specific fast trace */ + } +unw_tdep_frame_t; + struct unw_addr_space { struct unw_accessors acc; @@ -258,6 +264,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_cache_frame(c,rs) do {} while(0) #define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) #define tdep_get_func_addr UNW_OBJ(get_func_addr) #ifdef UNW_LOCAL_ONLY diff --git a/include/tdep-ppc64/libunwind_i.h b/include/tdep-ppc64/libunwind_i.h index 6c46e1a7..5e96bee2 100644 --- a/include/tdep-ppc64/libunwind_i.h +++ b/include/tdep-ppc64/libunwind_i.h @@ -42,6 +42,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "mempool.h" #include "dwarf.h" +typedef struct + { + /* no ppc64-specific fast trace */ + } +unw_tdep_frame_t; + struct unw_addr_space { struct unw_accessors acc; @@ -258,6 +264,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_cache_frame(c,rs) do {} while(0) #define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) #define tdep_get_func_addr UNW_OBJ(get_func_addr) #ifdef UNW_LOCAL_ONLY diff --git a/include/tdep-x86/libunwind_i.h b/include/tdep-x86/libunwind_i.h index 88ab2467..739320ee 100644 --- a/include/tdep-x86/libunwind_i.h +++ b/include/tdep-x86/libunwind_i.h @@ -36,6 +36,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "mempool.h" #include "dwarf.h" +typedef struct + { + /* no x86-specific fast trace */ + } +unw_tdep_frame_t; + struct unw_addr_space { struct unw_accessors acc; @@ -244,6 +250,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) #define tdep_cache_frame(c,rs) do {} while(0) #define tdep_reuse_frame(c,rs) do {} while(0) #define tdep_stash_frame(c,rs) do {} while(0) +#define tdep_trace(cur,addr,n) (-UNW_ENOINFO) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ diff --git a/include/tdep-x86_64/libunwind_i.h b/include/tdep-x86_64/libunwind_i.h index b076bd18..a707efe4 100644 --- a/include/tdep-x86_64/libunwind_i.h +++ b/include/tdep-x86_64/libunwind_i.h @@ -38,6 +38,27 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "mempool.h" #include "dwarf.h" +typedef enum + { + UNW_X86_64_FRAME_STANDARD = -2, /* regular rbp, rsp +/- offset */ + UNW_X86_64_FRAME_SIGRETURN = -1, /* special sigreturn frame */ + UNW_X86_64_FRAME_OTHER = 0, /* not cacheable (special or unrecognised) */ + UNW_X86_64_FRAME_GUESSED = 1 /* guessed it was regular, but not known */ + } +unw_tdep_frame_type_t; + +typedef struct + { + uint64_t virtual_address; + int64_t frame_type : 2; /* unw_tdep_frame_type_t classification */ + int64_t last_frame : 1; /* non-zero if last frame in chain */ + int64_t cfa_reg_rsp : 1; /* cfa dwarf base register is rsp vs. rbp */ + int64_t cfa_reg_offset : 30; /* cfa is at this offset from base register value */ + int64_t rbp_cfa_offset : 15; /* rbp saved at this offset from cfa (-1 = not saved) */ + int64_t rsp_cfa_offset : 15; /* rsp saved at this offset from cfa (-1 = not saved) */ + } +unw_tdep_frame_t; + struct unw_addr_space { struct unw_accessors acc; @@ -176,6 +197,7 @@ dwarf_put (struct dwarf_cursor *c, dwarf_loc_t loc, unw_word_t val) # define tdep_reuse_frame(c,rs) do {} while(0) #endif #define tdep_stash_frame UNW_OBJ(stash_frame) +#define tdep_trace UNW_OBJ(tdep_trace) #ifdef UNW_LOCAL_ONLY # define tdep_find_proc_info(c,ip,n) \ @@ -222,4 +244,6 @@ extern void tdep_stash_frame (struct dwarf_cursor *c, struct dwarf_reg_state *rs); #endif +extern int tdep_trace (unw_cursor_t *cursor, void **addresses, int *n); + #endif /* X86_64_LIBUNWIND_I_H */ diff --git a/src/mi/backtrace.c b/src/mi/backtrace.c index d01049f1..128a77e5 100644 --- a/src/mi/backtrace.c +++ b/src/mi/backtrace.c @@ -33,15 +33,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* See glibc manual for a description of this function. */ static ALWAYS_INLINE int -slow_backtrace (void **buffer, int size) +slow_backtrace (void **buffer, int size, unw_context_t *uc) { unw_cursor_t cursor; - unw_context_t uc; unw_word_t ip; int n = 0; - unw_getcontext (&uc); - if (unw_init_local (&cursor, &uc) < 0) + if (unw_init_local (&cursor, uc) < 0) return 0; while (unw_step (&cursor) > 0) @@ -62,21 +60,16 @@ unw_backtrace (void **buffer, int size) unw_cursor_t cursor; unw_context_t uc; int n = size; - int ret; unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) return 0; - /* We don't need backtrace() to show up in buffer */ - ret = unw_step (&cursor); - if (ret < 0) - return ret; - - if (unw_tdep_trace (&cursor, buffer, &n) < 0) + if (tdep_trace (&cursor, buffer, &n) < 0) { - return slow_backtrace(buffer, size); + unw_getcontext (&uc); + return slow_backtrace (buffer, size, &uc); } return n; diff --git a/src/x86_64/Gtrace.c b/src/x86_64/Gtrace.c index fb6e84ad..dc82bac0 100644 --- a/src/x86_64/Gtrace.c +++ b/src/x86_64/Gtrace.c @@ -328,13 +328,13 @@ trace_lookup (unw_cursor_t *cursor, /* Fast stack backtrace for x86-64. - Intended for use when the application makes frequent queries to the - current call stack without any desire to unwind. Somewhat like the - GLIBC backtrace() function: fills BUFFER with the call tree from - CURSOR upwards, and SIZE with the number of stack levels so found. - When called, SIZE should tell the maximum number of entries that - can be stored in BUFFER. An internal thread-specific cache is used - to accelerate the stack queries. + This is used by backtrace() implementation to accelerate frequent + queries for current stack, without any desire to unwind. It fills + BUFFER with the call tree from CURSOR upwards for at most SIZE + stack levels. The first frame, backtrace itself, is omitted. When + called, SIZE should give the maximum number of entries that can be + stored into BUFFER. Uses an internal thread-specific cache to + accelerate queries. The caller should fall back to a unw_step() loop if this function fails by returning -UNW_ESTOPUNWIND, meaning the routine hit a @@ -351,7 +351,7 @@ trace_lookup (unw_cursor_t *cursor, they are at the outermost (final) frame or can conservatively be assumed to be frame-pointer based. - Any other stack layout will cause the routine to give up. There + Any other stack layout will cause the routine to give up. There are only a handful of relatively rarely used functions which do not have a stack in the standard form: vfork, longjmp, setcontext and _dl_runtime_profile on common linux systems for example. @@ -369,31 +369,28 @@ trace_lookup (unw_cursor_t *cursor, Callers of this function would normally look like this: unw_cursor_t cur; - unw_context_t ctx, saved; + unw_context_t ctx; void addrs[128]; int depth = 128; int ret; unw_getcontext(&ctx); - memcpy(&saved, &ctx, sizeof(ctx)); - unw_init_local(&cur, &ctx); if ((ret = unw_tdep_trace(&cur, addrs, &depth)) < 0) { depth = 0; - unw_init_local(&cur, &saved); - while (depth < 128) + unw_getcontext(&ctx); + unw_init_local(&cur, &ctx); + while ((ret = unw_step(&cur)) > 0 && depth < 128) { unw_word_t ip; unw_get_reg(&cur, UNW_REG_IP, &ip); addresses[depth++] = (void *) ip; - if ((ret = unw_step(&cur)) <= 0) - break; } } */ -int -unw_tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) +HIDDEN int +tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) { struct cursor *c = (struct cursor *) cursor; struct dwarf_cursor *d = &c->dwarf; @@ -449,9 +446,6 @@ unw_tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) for common failures. */ unw_tdep_frame_t *f = trace_lookup (cursor, cache, cfa, rip, rbp, rsp); - /* Record this address in stack trace. */ - buffer[depth++] = (void *) rip; - /* If we don't have information for this frame, give up. */ if (! f) { @@ -530,6 +524,9 @@ unw_tdep_trace (unw_cursor_t *cursor, void **buffer, int *size) /* If we failed on ended up somewhere bogus, stop. */ if (ret < 0 || rip < 0x4000) break; + + /* Record this address in stack trace. We skipped the first address. */ + buffer[depth++] = (void *) (rip - d->use_prev_instr); } #if UNW_DEBUG diff --git a/tests/Gtest-trace.c b/tests/Gtest-trace.c index 47a7d578..1e966b21 100644 --- a/tests/Gtest-trace.c +++ b/tests/Gtest-trace.c @@ -50,7 +50,7 @@ int num_errors; /* These variables are global because they * cause the signal stack to overflow */ char buf[512], name[256]; -void *addresses[2][128]; +void *addresses[3][128]; unw_cursor_t cursor; ucontext_t uc; @@ -59,42 +59,28 @@ do_backtrace (void) { unw_word_t ip; int ret = -UNW_ENOINFO; - int depth = 128; - int i, n; + int depth = 0; + int i, n, m; if (verbose) - printf ("\tfast backtrace:\n"); + printf ("\tnormal trace:\n"); unw_getcontext (&uc); if (unw_init_local (&cursor, &uc) < 0) panic ("unw_init_local failed!\n"); -#if UNW_TARGET_X86_64 - if ((ret = unw_tdep_trace (&cursor, addresses[0], &depth)) < 0) + do { unw_get_reg (&cursor, UNW_REG_IP, &ip); - printf ("FAILURE: unw_tdep_trace() returned %d for ip=%lx\n", ret, (long) ip); - ++num_errors; + addresses[0][depth] = (void *) ip; } -#endif + while ((ret = unw_step (&cursor)) > 0 && ++depth < 128); if (ret < 0) { - i = 0; - do - { - unw_get_reg (&cursor, UNW_REG_IP, &ip); - addresses[0][i] = (void *) ip; - } - while ((ret = unw_step (&cursor)) > 0 && ++i < 128); - - if (ret < 0) - { - unw_get_reg (&cursor, UNW_REG_IP, &ip); - printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip); - ++num_errors; - } - depth = i; + unw_get_reg (&cursor, UNW_REG_IP, &ip); + printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip); + ++num_errors; } if (verbose) @@ -110,17 +96,43 @@ do_backtrace (void) for (i = 0; i < n; ++i) printf ("\t #%-3d ip=%p\n", i, addresses[1][i]); - if (n != depth) + if (verbose) + printf ("\n\tvia unw_backtrace():\n"); + + m = unw_backtrace (addresses[2], 128); + + if (verbose) + for (i = 0; i < m; ++i) + printf ("\t #%-3d ip=%p\n", i, addresses[2][i]); + + if (m != depth+1) { - printf ("FAILURE: unw_tdep_trace() and backtrace() depths differ: %d vs. %d\n", depth, n); + printf ("FAILURE: unw_step() loop and unw_backtrace() depths differ: %d vs. %d\n", depth, m); ++num_errors; } - else + + if (n != depth+1) + { + printf ("FAILURE: unw_step() loop and backtrace() depths differ: %d vs. %d\n", depth, n); + ++num_errors; + } + + if (n == m) + for (i = 1; i < n; ++i) + /* Allow one in difference in comparison, trace returns adjusted addresses. */ + if (labs((unw_word_t) addresses[1][i] - (unw_word_t) addresses[2][i]) > 1) + { + printf ("FAILURE: backtrace() and unw_backtrace() addresses differ at %d: %p vs. %p\n", + i, addresses[1][n], addresses[2][n]); + ++num_errors; + } + + if (n == depth+1) for (i = 1; i < depth; ++i) /* Allow one in difference in comparison, trace returns adjusted addresses. */ if (labs((unw_word_t) addresses[0][i] - (unw_word_t) addresses[1][i]) > 1) { - printf ("FAILURE: unw_tdep_trace() and backtrace() addresses differ at %d: %p vs. %p\n", + printf ("FAILURE: unw_step() loop and backtrace() addresses differ at %d: %p vs. %p\n", i, addresses[0][n], addresses[1][n]); ++num_errors; } diff --git a/tests/check-namespace.sh.in b/tests/check-namespace.sh.in index 642b1184..06086078 100644 --- a/tests/check-namespace.sh.in +++ b/tests/check-namespace.sh.in @@ -124,7 +124,6 @@ check_local_unw_abi () { match _U${plat}_is_fpreg match _UL${plat}_dwarf_search_unwind_table match _U${plat}_setcontext - match _UL${plat}_trace ;; *) match _U${plat}_is_fpreg @@ -188,7 +187,6 @@ check_generic_unw_abi () { match _U${plat}_get_elf_image match _U${plat}_is_fpreg match _U${plat}_dwarf_search_unwind_table - match _U${plat}_trace ;; *) match _U${plat}_is_fpreg