Author: Lassi Tuura <lat@cern.ch>
Date:   2011-03-29 12:33:35 +0200

    Drop one call frame in tdep_trace instead of calling unw_step in

unw_backtrace.

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               |   11 +++---
 tests/Gtest-trace.c               |   68 ++++++++++++++++++++++---------------
 tests/check-namespace.sh.in       |    2 -
 20 files changed, 124 insertions(+), 127 deletions(-)

diff --git a/include/libunwind-arm.h b/include/libunwind-arm.h
index a764b15..492331e 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 04eacee..74ea70d 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 72480d2..fb2fbfe 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 b05e740..91f7001 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 dca2a74..b40a84e 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 7370f60..66420b3 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 60c97bf..32533df 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 153c43a..50b4de2 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 0cb4a71..cd18292 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 4e6c1c3..d5ba7ab 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 3193a64..ec20338 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 2e6fc4f..17876d5 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 7db2b39..23bf2d1 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 6c46e1a..5e96bee 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 88ab246..739320e 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 a427af3..90dea77 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;
@@ -175,6 +196,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(trace)
 #define x86_64_r_uc_addr                UNW_OBJ(r_uc_addr)
 
 #ifdef UNW_LOCAL_ONLY
@@ -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 5ff58f1..7aa1218 100644
--- a/src/mi/backtrace.c
+++ b/src/mi/backtrace.c
@@ -32,15 +32,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
 /* See glibc manual for a description of this function.  */
 
 static 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 (unlikely (unw_init_local (&cursor, &uc) < 0))
+  if (unlikely (unw_init_local (&cursor, uc) < 0))
     return 0;
 
   while (unw_step (&cursor) > 0)
@@ -61,21 +59,16 @@ unw_backtrace (void **buffer, int size)
   unw_cursor_t cursor;
   unw_context_t uc;
   int n = size;
-  int ret;
 
   unw_getcontext (&uc);
 
   if (unlikely (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 (unlikely (unw_tdep_trace (&cursor, buffer, &n) < 0))
+  if (unlikely (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 11669bb..a709597 100644
--- a/src/x86_64/Gtrace.c
+++ b/src/x86_64/Gtrace.c
@@ -392,8 +392,8 @@ trace_lookup (unw_cursor_t *cursor,
        }
      }
 */
-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,8 +449,9 @@ 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;
+    /* Record this address in stack trace, but skip first address. */
+    if (likely (++depth > 1))
+      buffer[depth - 2] = (void *) rip;
 
     /* If we don't have information for this frame, give up. */
     if (unlikely(! f))
@@ -534,6 +535,6 @@ unw_tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
 #if UNW_DEBUG
   Debug (1, "returning %d, depth %d\n", ret, depth);
 #endif
-  *size = depth;
+  *size = depth-1;
   return ret;
 }
diff --git a/tests/Gtest-trace.c b/tests/Gtest-trace.c
index 47a7d57..1e966b2 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 642b118..0608607 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
