mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-22 23:47:39 +01: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:
parent
50bc12afba
commit
5f38f35d5d
20 changed files with 135 additions and 142 deletions
|
@ -286,19 +286,11 @@ typedef struct
|
||||||
}
|
}
|
||||||
unw_tdep_proc_info_t;
|
unw_tdep_proc_info_t;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
/* no arm-specific fast trace */
|
|
||||||
}
|
|
||||||
unw_tdep_frame_t;
|
|
||||||
|
|
||||||
#include "libunwind-common.h"
|
#include "libunwind-common.h"
|
||||||
|
|
||||||
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
||||||
extern int unw_tdep_is_fpreg (int);
|
extern int unw_tdep_is_fpreg (int);
|
||||||
|
|
||||||
#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -103,12 +103,6 @@ unw_tdep_save_loc_t;
|
||||||
/* On PA-RISC, we can directly use ucontext_t as the unwind context. */
|
/* On PA-RISC, we can directly use ucontext_t as the unwind context. */
|
||||||
typedef ucontext_t unw_tdep_context_t;
|
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)
|
#define unw_tdep_is_fpreg(r) ((unsigned) ((r) - UNW_HPPA_FR) < 32)
|
||||||
|
|
||||||
#include "libunwind-dynamic.h"
|
#include "libunwind-dynamic.h"
|
||||||
|
@ -124,8 +118,6 @@ unw_tdep_proc_info_t;
|
||||||
#define unw_tdep_getcontext UNW_ARCH_OBJ (getcontext)
|
#define unw_tdep_getcontext UNW_ARCH_OBJ (getcontext)
|
||||||
extern int unw_tdep_getcontext (unw_tdep_context_t *);
|
extern int unw_tdep_getcontext (unw_tdep_context_t *);
|
||||||
|
|
||||||
#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -150,12 +150,6 @@ unw_tdep_save_loc_t;
|
||||||
/* On IA-64, we can directly use ucontext_t as the unwind context. */
|
/* On IA-64, we can directly use ucontext_t as the unwind context. */
|
||||||
typedef ucontext_t unw_tdep_context_t;
|
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)
|
#define unw_tdep_is_fpreg(r) ((unsigned) ((r) - UNW_IA64_FR) < 128)
|
||||||
|
|
||||||
#include "libunwind-dynamic.h"
|
#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. */
|
signal-safe. */
|
||||||
extern int _Uia64_get_kernel_table (unw_dyn_info_t *);
|
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)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -137,12 +137,6 @@ typedef struct
|
||||||
}
|
}
|
||||||
unw_tdep_proc_info_t;
|
unw_tdep_proc_info_t;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
/* no mips-specific fast trace */
|
|
||||||
}
|
|
||||||
unw_tdep_frame_t;
|
|
||||||
|
|
||||||
#include "libunwind-common.h"
|
#include "libunwind-common.h"
|
||||||
|
|
||||||
/* There is no getcontext() on MIPS. Use a stub version which only saves GP
|
/* 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)
|
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
||||||
extern int unw_tdep_is_fpreg (int);
|
extern int unw_tdep_is_fpreg (int);
|
||||||
|
|
||||||
#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -195,19 +195,11 @@ typedef struct
|
||||||
}
|
}
|
||||||
unw_tdep_proc_info_t;
|
unw_tdep_proc_info_t;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
/* no ppc32-specific fast trace */
|
|
||||||
}
|
|
||||||
unw_tdep_frame_t;
|
|
||||||
|
|
||||||
#include "libunwind-common.h"
|
#include "libunwind-common.h"
|
||||||
|
|
||||||
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
||||||
extern int unw_tdep_is_fpreg (int);
|
extern int unw_tdep_is_fpreg (int);
|
||||||
|
|
||||||
#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -252,19 +252,11 @@ typedef struct
|
||||||
}
|
}
|
||||||
unw_tdep_proc_info_t;
|
unw_tdep_proc_info_t;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
/* no ppc64-specific fast trace */
|
|
||||||
}
|
|
||||||
unw_tdep_frame_t;
|
|
||||||
|
|
||||||
#include "libunwind-common.h"
|
#include "libunwind-common.h"
|
||||||
|
|
||||||
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
||||||
extern int unw_tdep_is_fpreg (int);
|
extern int unw_tdep_is_fpreg (int);
|
||||||
|
|
||||||
#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -172,12 +172,6 @@ typedef struct
|
||||||
}
|
}
|
||||||
unw_tdep_proc_info_t;
|
unw_tdep_proc_info_t;
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
/* no x86-specific fast trace */
|
|
||||||
}
|
|
||||||
unw_tdep_frame_t;
|
|
||||||
|
|
||||||
#include "libunwind-common.h"
|
#include "libunwind-common.h"
|
||||||
|
|
||||||
#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext)
|
#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)
|
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
||||||
extern int unw_tdep_is_fpreg (int);
|
extern int unw_tdep_is_fpreg (int);
|
||||||
|
|
||||||
#define unw_tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
|
||||||
|
|
||||||
#if defined(__cplusplus) || defined(c_plusplus)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -104,39 +104,15 @@ typedef struct
|
||||||
}
|
}
|
||||||
unw_tdep_proc_info_t;
|
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-dynamic.h"
|
||||||
#include "libunwind-common.h"
|
#include "libunwind-common.h"
|
||||||
|
|
||||||
#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext)
|
#define unw_tdep_getcontext UNW_ARCH_OBJ(getcontext)
|
||||||
#define unw_tdep_is_fpreg UNW_ARCH_OBJ(is_fpreg)
|
#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_getcontext (unw_tdep_context_t *);
|
||||||
extern int unw_tdep_is_fpreg (int);
|
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)
|
#if defined(__cplusplus) || defined(c_plusplus)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,6 +36,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "dwarf.h"
|
#include "dwarf.h"
|
||||||
#include "ex_tables.h"
|
#include "ex_tables.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* no arm-specific fast trace */
|
||||||
|
}
|
||||||
|
unw_tdep_frame_t;
|
||||||
|
|
||||||
struct unw_addr_space
|
struct unw_addr_space
|
||||||
{
|
{
|
||||||
struct unw_accessors acc;
|
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_cache_frame(c,rs) do {} while(0)
|
||||||
#define tdep_reuse_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_stash_frame(c,rs) do {} while(0)
|
||||||
|
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
||||||
|
|
||||||
#ifdef UNW_LOCAL_ONLY
|
#ifdef UNW_LOCAL_ONLY
|
||||||
# define tdep_find_proc_info(c,ip,n) \
|
# define tdep_find_proc_info(c,ip,n) \
|
||||||
|
|
|
@ -35,6 +35,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "elf32.h"
|
#include "elf32.h"
|
||||||
#include "dwarf.h"
|
#include "dwarf.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* no hppa-specific fast trace */
|
||||||
|
}
|
||||||
|
unw_tdep_frame_t;
|
||||||
|
|
||||||
struct unw_addr_space
|
struct unw_addr_space
|
||||||
{
|
{
|
||||||
struct unw_accessors acc;
|
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_cache_frame(c,rs) do {} while(0)
|
||||||
#define tdep_reuse_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_stash_frame(c,rs) do {} while(0)
|
||||||
|
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
||||||
|
|
||||||
#ifdef UNW_LOCAL_ONLY
|
#ifdef UNW_LOCAL_ONLY
|
||||||
# define tdep_find_proc_info(c,ip,n) \
|
# define tdep_find_proc_info(c,ip,n) \
|
||||||
|
|
|
@ -32,6 +32,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "elf64.h"
|
#include "elf64.h"
|
||||||
#include "mempool.h"
|
#include "mempool.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* no ia64-specific fast trace */
|
||||||
|
}
|
||||||
|
unw_tdep_frame_t;
|
||||||
|
|
||||||
enum ia64_pregnum
|
enum ia64_pregnum
|
||||||
{
|
{
|
||||||
/* primary unat: */
|
/* primary unat: */
|
||||||
|
@ -224,6 +230,7 @@ struct ia64_global_unwind_state
|
||||||
#define tdep_cache_frame(c,rs) do {} while(0)
|
#define tdep_cache_frame(c,rs) do {} while(0)
|
||||||
#define tdep_reuse_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_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(c) ((c)->as)
|
||||||
#define tdep_get_as_arg(c) ((c)->as_arg)
|
#define tdep_get_as_arg(c) ((c)->as_arg)
|
||||||
#define tdep_get_ip(c) ((c)->ip)
|
#define tdep_get_ip(c) ((c)->ip)
|
||||||
|
|
|
@ -39,6 +39,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "mempool.h"
|
#include "mempool.h"
|
||||||
#include "dwarf.h"
|
#include "dwarf.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* no mips-specific fast trace */
|
||||||
|
}
|
||||||
|
unw_tdep_frame_t;
|
||||||
|
|
||||||
struct unw_addr_space
|
struct unw_addr_space
|
||||||
{
|
{
|
||||||
struct unw_accessors acc;
|
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_cache_frame(c,rs) do {} while(0)
|
||||||
#define tdep_reuse_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_stash_frame(c,rs) do {} while(0)
|
||||||
|
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
||||||
|
|
||||||
#ifdef UNW_LOCAL_ONLY
|
#ifdef UNW_LOCAL_ONLY
|
||||||
# define tdep_find_proc_info(c,ip,n) \
|
# define tdep_find_proc_info(c,ip,n) \
|
||||||
|
|
|
@ -42,6 +42,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "mempool.h"
|
#include "mempool.h"
|
||||||
#include "dwarf.h"
|
#include "dwarf.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* no ppc32-specific fast trace */
|
||||||
|
}
|
||||||
|
unw_tdep_frame_t;
|
||||||
|
|
||||||
struct unw_addr_space
|
struct unw_addr_space
|
||||||
{
|
{
|
||||||
struct unw_accessors acc;
|
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_cache_frame(c,rs) do {} while(0)
|
||||||
#define tdep_reuse_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_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)
|
#define tdep_get_func_addr UNW_OBJ(get_func_addr)
|
||||||
|
|
||||||
#ifdef UNW_LOCAL_ONLY
|
#ifdef UNW_LOCAL_ONLY
|
||||||
|
|
|
@ -42,6 +42,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "mempool.h"
|
#include "mempool.h"
|
||||||
#include "dwarf.h"
|
#include "dwarf.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* no ppc64-specific fast trace */
|
||||||
|
}
|
||||||
|
unw_tdep_frame_t;
|
||||||
|
|
||||||
struct unw_addr_space
|
struct unw_addr_space
|
||||||
{
|
{
|
||||||
struct unw_accessors acc;
|
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_cache_frame(c,rs) do {} while(0)
|
||||||
#define tdep_reuse_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_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)
|
#define tdep_get_func_addr UNW_OBJ(get_func_addr)
|
||||||
|
|
||||||
#ifdef UNW_LOCAL_ONLY
|
#ifdef UNW_LOCAL_ONLY
|
||||||
|
|
|
@ -36,6 +36,12 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "mempool.h"
|
#include "mempool.h"
|
||||||
#include "dwarf.h"
|
#include "dwarf.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
/* no x86-specific fast trace */
|
||||||
|
}
|
||||||
|
unw_tdep_frame_t;
|
||||||
|
|
||||||
struct unw_addr_space
|
struct unw_addr_space
|
||||||
{
|
{
|
||||||
struct unw_accessors acc;
|
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_cache_frame(c,rs) do {} while(0)
|
||||||
#define tdep_reuse_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_stash_frame(c,rs) do {} while(0)
|
||||||
|
#define tdep_trace(cur,addr,n) (-UNW_ENOINFO)
|
||||||
|
|
||||||
#ifdef UNW_LOCAL_ONLY
|
#ifdef UNW_LOCAL_ONLY
|
||||||
# define tdep_find_proc_info(c,ip,n) \
|
# define tdep_find_proc_info(c,ip,n) \
|
||||||
|
|
|
@ -38,6 +38,27 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#include "mempool.h"
|
#include "mempool.h"
|
||||||
#include "dwarf.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_addr_space
|
||||||
{
|
{
|
||||||
struct unw_accessors acc;
|
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)
|
# define tdep_reuse_frame(c,rs) do {} while(0)
|
||||||
#endif
|
#endif
|
||||||
#define tdep_stash_frame UNW_OBJ(stash_frame)
|
#define tdep_stash_frame UNW_OBJ(stash_frame)
|
||||||
|
#define tdep_trace UNW_OBJ(tdep_trace)
|
||||||
|
|
||||||
#ifdef UNW_LOCAL_ONLY
|
#ifdef UNW_LOCAL_ONLY
|
||||||
# define tdep_find_proc_info(c,ip,n) \
|
# 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);
|
struct dwarf_reg_state *rs);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern int tdep_trace (unw_cursor_t *cursor, void **addresses, int *n);
|
||||||
|
|
||||||
#endif /* X86_64_LIBUNWIND_I_H */
|
#endif /* X86_64_LIBUNWIND_I_H */
|
||||||
|
|
|
@ -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. */
|
/* See glibc manual for a description of this function. */
|
||||||
|
|
||||||
static ALWAYS_INLINE int
|
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_cursor_t cursor;
|
||||||
unw_context_t uc;
|
|
||||||
unw_word_t ip;
|
unw_word_t ip;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
|
|
||||||
unw_getcontext (&uc);
|
if (unw_init_local (&cursor, uc) < 0)
|
||||||
if (unw_init_local (&cursor, &uc) < 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (unw_step (&cursor) > 0)
|
while (unw_step (&cursor) > 0)
|
||||||
|
@ -62,21 +60,16 @@ unw_backtrace (void **buffer, int size)
|
||||||
unw_cursor_t cursor;
|
unw_cursor_t cursor;
|
||||||
unw_context_t uc;
|
unw_context_t uc;
|
||||||
int n = size;
|
int n = size;
|
||||||
int ret;
|
|
||||||
|
|
||||||
unw_getcontext (&uc);
|
unw_getcontext (&uc);
|
||||||
|
|
||||||
if (unw_init_local (&cursor, &uc) < 0)
|
if (unw_init_local (&cursor, &uc) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* We don't need backtrace() to show up in buffer */
|
if (tdep_trace (&cursor, buffer, &n) < 0)
|
||||||
ret = unw_step (&cursor);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
if (unw_tdep_trace (&cursor, buffer, &n) < 0)
|
|
||||||
{
|
{
|
||||||
return slow_backtrace(buffer, size);
|
unw_getcontext (&uc);
|
||||||
|
return slow_backtrace (buffer, size, &uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
|
|
|
@ -328,13 +328,13 @@ trace_lookup (unw_cursor_t *cursor,
|
||||||
|
|
||||||
/* Fast stack backtrace for x86-64.
|
/* Fast stack backtrace for x86-64.
|
||||||
|
|
||||||
Intended for use when the application makes frequent queries to the
|
This is used by backtrace() implementation to accelerate frequent
|
||||||
current call stack without any desire to unwind. Somewhat like the
|
queries for current stack, without any desire to unwind. It fills
|
||||||
GLIBC backtrace() function: fills BUFFER with the call tree from
|
BUFFER with the call tree from CURSOR upwards for at most SIZE
|
||||||
CURSOR upwards, and SIZE with the number of stack levels so found.
|
stack levels. The first frame, backtrace itself, is omitted. When
|
||||||
When called, SIZE should tell the maximum number of entries that
|
called, SIZE should give the maximum number of entries that can be
|
||||||
can be stored in BUFFER. An internal thread-specific cache is used
|
stored into BUFFER. Uses an internal thread-specific cache to
|
||||||
to accelerate the stack queries.
|
accelerate queries.
|
||||||
|
|
||||||
The caller should fall back to a unw_step() loop if this function
|
The caller should fall back to a unw_step() loop if this function
|
||||||
fails by returning -UNW_ESTOPUNWIND, meaning the routine hit a
|
fails by returning -UNW_ESTOPUNWIND, meaning the routine hit a
|
||||||
|
@ -369,31 +369,28 @@ trace_lookup (unw_cursor_t *cursor,
|
||||||
Callers of this function would normally look like this:
|
Callers of this function would normally look like this:
|
||||||
|
|
||||||
unw_cursor_t cur;
|
unw_cursor_t cur;
|
||||||
unw_context_t ctx, saved;
|
unw_context_t ctx;
|
||||||
void addrs[128];
|
void addrs[128];
|
||||||
int depth = 128;
|
int depth = 128;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
unw_getcontext(&ctx);
|
unw_getcontext(&ctx);
|
||||||
memcpy(&saved, &ctx, sizeof(ctx));
|
|
||||||
|
|
||||||
unw_init_local(&cur, &ctx);
|
unw_init_local(&cur, &ctx);
|
||||||
if ((ret = unw_tdep_trace(&cur, addrs, &depth)) < 0)
|
if ((ret = unw_tdep_trace(&cur, addrs, &depth)) < 0)
|
||||||
{
|
{
|
||||||
depth = 0;
|
depth = 0;
|
||||||
unw_init_local(&cur, &saved);
|
unw_getcontext(&ctx);
|
||||||
while (depth < 128)
|
unw_init_local(&cur, &ctx);
|
||||||
|
while ((ret = unw_step(&cur)) > 0 && depth < 128)
|
||||||
{
|
{
|
||||||
unw_word_t ip;
|
unw_word_t ip;
|
||||||
unw_get_reg(&cur, UNW_REG_IP, &ip);
|
unw_get_reg(&cur, UNW_REG_IP, &ip);
|
||||||
addresses[depth++] = (void *) ip;
|
addresses[depth++] = (void *) ip;
|
||||||
if ((ret = unw_step(&cur)) <= 0)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
int
|
HIDDEN int
|
||||||
unw_tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
|
tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
|
||||||
{
|
{
|
||||||
struct cursor *c = (struct cursor *) cursor;
|
struct cursor *c = (struct cursor *) cursor;
|
||||||
struct dwarf_cursor *d = &c->dwarf;
|
struct dwarf_cursor *d = &c->dwarf;
|
||||||
|
@ -449,9 +446,6 @@ unw_tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
|
||||||
for common failures. */
|
for common failures. */
|
||||||
unw_tdep_frame_t *f = trace_lookup (cursor, cache, cfa, rip, rbp, rsp);
|
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 we don't have information for this frame, give up. */
|
||||||
if (! f)
|
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 we failed on ended up somewhere bogus, stop. */
|
||||||
if (ret < 0 || rip < 0x4000)
|
if (ret < 0 || rip < 0x4000)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Record this address in stack trace. We skipped the first address. */
|
||||||
|
buffer[depth++] = (void *) (rip - d->use_prev_instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNW_DEBUG
|
#if UNW_DEBUG
|
||||||
|
|
|
@ -50,7 +50,7 @@ int num_errors;
|
||||||
/* These variables are global because they
|
/* These variables are global because they
|
||||||
* cause the signal stack to overflow */
|
* cause the signal stack to overflow */
|
||||||
char buf[512], name[256];
|
char buf[512], name[256];
|
||||||
void *addresses[2][128];
|
void *addresses[3][128];
|
||||||
unw_cursor_t cursor;
|
unw_cursor_t cursor;
|
||||||
ucontext_t uc;
|
ucontext_t uc;
|
||||||
|
|
||||||
|
@ -59,34 +59,22 @@ do_backtrace (void)
|
||||||
{
|
{
|
||||||
unw_word_t ip;
|
unw_word_t ip;
|
||||||
int ret = -UNW_ENOINFO;
|
int ret = -UNW_ENOINFO;
|
||||||
int depth = 128;
|
int depth = 0;
|
||||||
int i, n;
|
int i, n, m;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf ("\tfast backtrace:\n");
|
printf ("\tnormal trace:\n");
|
||||||
|
|
||||||
unw_getcontext (&uc);
|
unw_getcontext (&uc);
|
||||||
if (unw_init_local (&cursor, &uc) < 0)
|
if (unw_init_local (&cursor, &uc) < 0)
|
||||||
panic ("unw_init_local failed!\n");
|
panic ("unw_init_local failed!\n");
|
||||||
|
|
||||||
#if UNW_TARGET_X86_64
|
|
||||||
if ((ret = unw_tdep_trace (&cursor, addresses[0], &depth)) < 0)
|
|
||||||
{
|
|
||||||
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
|
||||||
printf ("FAILURE: unw_tdep_trace() returned %d for ip=%lx\n", ret, (long) ip);
|
|
||||||
++num_errors;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
i = 0;
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
unw_get_reg (&cursor, UNW_REG_IP, &ip);
|
||||||
addresses[0][i] = (void *) ip;
|
addresses[0][depth] = (void *) ip;
|
||||||
}
|
}
|
||||||
while ((ret = unw_step (&cursor)) > 0 && ++i < 128);
|
while ((ret = unw_step (&cursor)) > 0 && ++depth < 128);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
|
@ -94,8 +82,6 @@ do_backtrace (void)
|
||||||
printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip);
|
printf ("FAILURE: unw_step() returned %d for ip=%lx\n", ret, (long) ip);
|
||||||
++num_errors;
|
++num_errors;
|
||||||
}
|
}
|
||||||
depth = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
for (i = 0; i < depth; ++i)
|
for (i = 0; i < depth; ++i)
|
||||||
|
@ -110,17 +96,43 @@ do_backtrace (void)
|
||||||
for (i = 0; i < n; ++i)
|
for (i = 0; i < n; ++i)
|
||||||
printf ("\t #%-3d ip=%p\n", i, addresses[1][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;
|
++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)
|
for (i = 1; i < depth; ++i)
|
||||||
/* Allow one in difference in comparison, trace returns adjusted addresses. */
|
/* 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)
|
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]);
|
i, addresses[0][n], addresses[1][n]);
|
||||||
++num_errors;
|
++num_errors;
|
||||||
}
|
}
|
||||||
|
|
|
@ -124,7 +124,6 @@ check_local_unw_abi () {
|
||||||
match _U${plat}_is_fpreg
|
match _U${plat}_is_fpreg
|
||||||
match _UL${plat}_dwarf_search_unwind_table
|
match _UL${plat}_dwarf_search_unwind_table
|
||||||
match _U${plat}_setcontext
|
match _U${plat}_setcontext
|
||||||
match _UL${plat}_trace
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
match _U${plat}_is_fpreg
|
match _U${plat}_is_fpreg
|
||||||
|
@ -188,7 +187,6 @@ check_generic_unw_abi () {
|
||||||
match _U${plat}_get_elf_image
|
match _U${plat}_get_elf_image
|
||||||
match _U${plat}_is_fpreg
|
match _U${plat}_is_fpreg
|
||||||
match _U${plat}_dwarf_search_unwind_table
|
match _U${plat}_dwarf_search_unwind_table
|
||||||
match _U${plat}_trace
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
match _U${plat}_is_fpreg
|
match _U${plat}_is_fpreg
|
||||||
|
|
Loading…
Reference in a new issue