1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-06-02 09:22:36 +02:00

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.
This commit is contained in:
Lassi Tuura 2011-03-31 23:47:20 -07:00 committed by Arun Sharma
parent 50bc12afba
commit 5f38f35d5d
20 changed files with 135 additions and 142 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) \

View file

@ -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) \

View file

@ -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)

View file

@ -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) \

View file

@ -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

View file

@ -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

View file

@ -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) \

View file

@ -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 */

View file

@ -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;

View file

@ -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

View file

@ -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;
}

View file

@ -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