From 14c48b3d5166d5e33b79267f467b5d512c44a5d9 Mon Sep 17 00:00:00 2001 From: Doug Moore Date: Thu, 30 Mar 2017 14:35:35 -0700 Subject: [PATCH] unw_init_local_signal init_local, but *not* setting use_prev_instr. This is necessary to correctly unwind using ucontext argument to signal handlers. --- doc/Makefile.am | 1 + doc/unw_init_local.man | 31 +++++++++++++++++-------------- doc/unw_init_local.tex | 23 +++++++++++------------ doc/unw_init_local_signal.man | 1 + include/libunwind-common.h.in | 2 ++ src/aarch64/Ginit_local.c | 18 +++++++++++++++--- src/arm/Ginit_local.c | 18 +++++++++++++++--- src/hppa/Ginit_local.c | 18 +++++++++++++++--- src/mips/Ginit_local.c | 18 +++++++++++++++--- src/ppc/Ginit_local.c | 20 ++++++++++++++++---- src/sh/Ginit_local.c | 18 +++++++++++++++--- src/tilegx/Ginit_local.c | 18 +++++++++++++++--- src/x86/Ginit_local.c | 18 +++++++++++++++--- src/x86_64/Ginit_local.c | 18 +++++++++++++++--- tests/check-namespace.sh.in | 4 +++- 15 files changed, 171 insertions(+), 55 deletions(-) create mode 100644 doc/unw_init_local_signal.man diff --git a/doc/Makefile.am b/doc/Makefile.am index 577310c9..a3eb8238 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -11,6 +11,7 @@ man3_MANS = libunwind.man libunwind-dynamic.man libunwind-ia64.man \ unw_get_reg.man \ unw_getcontext.man \ unw_init_local.man unw_init_remote.man \ + unw_init_local_signal.man \ unw_is_fpreg.man \ unw_is_signal_frame.man \ unw_create_addr_space.man \ diff --git a/doc/unw_init_local.man b/doc/unw_init_local.man index 73b79886..bb598b22 100644 --- a/doc/unw_init_local.man +++ b/doc/unw_init_local.man @@ -1,5 +1,5 @@ '\" t -.\" Manual page created with latex2man on Thu Aug 16 09:44:45 MDT 2007 +.\" Manual page created with latex2man on Thu Mar 30 16:13:10 PDT 2017 .\" NOTE: This file is generated, DO NOT EDIT. .de Vb .ft CW @@ -10,7 +10,7 @@ .fi .. -.TH "UNW\\_INIT\\_LOCAL" "3" "16 August 2007" "Programming Library " "Programming Library " +.TH "UNW\\_INIT\\_LOCAL" "3" "30 March 2017" "Programming Library " "Programming Library " .SH NAME unw_init_local \-\- initialize cursor for local unwinding @@ -25,6 +25,10 @@ int unw_init_local(unw_cursor_t *c, unw_context_t *ctxt); .br +int +unw_init_local_signal(unw_cursor_t *c, +unw_context_t *ctxt); +.br .PP .SH DESCRIPTION @@ -37,7 +41,11 @@ pointed to by ctxt\&. As such, the machine\-state pointed to by ctxt identifies the initial stack frame at which unwinding -starts. The machine\-state must remain valid for the duration for +starts. The machine\-state is expected to be one provided by a call to +unw_getcontext; as such, the instruction pointer may point to the +instruction after the last instruction of a function, and libunwind +will back\-up the instruction pointer before beginning a walk up the +call stack. The machine\-state must remain valid for the duration for which the cursor c is in use. .PP @@ -46,17 +54,6 @@ routine can be used only for unwinding in the address space of the current process (i.e., for local unwinding). For all other cases, unw_init_remote() must be used instead. -From a behavioral point of view, the call: -.PP -.Vb - ret = unw_init_local(&cursor, &ucontext); -.Ve -is equivalent to: -.PP -.Vb - ret = unw_init_remote(&cursor, unw_local_addr_space, - &ucontext); -.Ve However, unwind performance may be better when using unw_init_local(). Also, unw_init_local() @@ -67,6 +64,12 @@ including , whereas unw_init_remote() is not. .PP +If the unw_context_t is known to be a signal frame (i.e., from the +third argument in a sigaction handler on linux), +unw_init_local_signal() +should be used for correct +initialization on some platforms. +.PP .SH RETURN VALUE .PP diff --git a/doc/unw_init_local.tex b/doc/unw_init_local.tex index 5cea673c..da6d5c29 100644 --- a/doc/unw_init_local.tex +++ b/doc/unw_init_local.tex @@ -13,6 +13,7 @@ \File{\#include $<$libunwind.h$>$}\\ \Type{int} \Func{unw\_init\_local}(\Type{unw\_cursor\_t~*}\Var{c}, \Type{unw\_context\_t~*}\Var{ctxt});\\ +\Type{int} \Func{unw\_init\_local_signal}(\Type{unw\_cursor\_t~*}\Var{c}, \Type{unw\_context\_t~*}\Var{ctxt});\\ \section{Description} @@ -20,29 +21,27 @@ The \Func{unw\_init\_local}() routine initializes the unwind cursor pointed to by \Var{c} with the machine-state in the context structure pointed to by \Var{ctxt}. As such, the machine-state pointed to by \Var{ctxt} identifies the initial stack frame at which unwinding -starts. The machine-state must remain valid for the duration for +starts. The machine-state is expected to be one provided by a call to +unw_getcontext; as such, the instruction pointer may point to the +instruction after the last instruction of a function, and libunwind +will back-up the instruction pointer before beginning a walk up the +call stack. The machine-state must remain valid for the duration for which the cursor \Var{c} is in use. The \Func{unw\_init\_local}() routine can be used only for unwinding in the address space of the current process (i.e., for local unwinding). For all other cases, \Func{unw\_init\_remote}() must be used instead. -From a behavioral point of view, the call: - -\begin{verbatim} - ret = unw_init_local(&cursor, &ucontext); -\end{verbatim} -is equivalent to: - -\begin{verbatim} - ret = unw_init_remote(&cursor, unw_local_addr_space, - &ucontext); -\end{verbatim} However, unwind performance may be better when using \Func{unw\_init\_local}(). Also, \Func{unw\_init\_local}() is available even when \Const{UNW\_LOCAL\_ONLY} has been defined before including \File{$<$libunwind.h$>$}, whereas \Func{unw\_init\_remote}() is not. +If the unw_context_t is known to be a signal frame (i.e., from the +third argument in a sigaction handler on linux), +\Func{unw\_init\_local\_signal}() should be used for correct +initialization on some platforms. + \section{Return Value} On successful completion, \Func{unw\_init\_local}() returns 0. diff --git a/doc/unw_init_local_signal.man b/doc/unw_init_local_signal.man new file mode 100644 index 00000000..6cbbf008 --- /dev/null +++ b/doc/unw_init_local_signal.man @@ -0,0 +1 @@ +.so man3/unw_init_local.3 diff --git a/include/libunwind-common.h.in b/include/libunwind-common.h.in index 7afd5726..8524cb01 100644 --- a/include/libunwind-common.h.in +++ b/include/libunwind-common.h.in @@ -211,6 +211,7 @@ unw_save_loc_t; #define unw_destroy_addr_space UNW_OBJ(destroy_addr_space) #define unw_get_accessors UNW_ARCH_OBJ(get_accessors) #define unw_init_local UNW_OBJ(init_local) +#define unw_init_local_signal UNW_OBJ(init_local_signal) #define unw_init_remote UNW_OBJ(init_remote) #define unw_step UNW_OBJ(step) #define unw_resume UNW_OBJ(resume) @@ -239,6 +240,7 @@ extern int unw_set_cache_size (unw_addr_space_t, size_t, int); extern const char *unw_regname (unw_regnum_t); extern int unw_init_local (unw_cursor_t *, unw_context_t *); +extern int unw_init_local_signal (unw_cursor_t *, unw_context_t *); extern int unw_init_remote (unw_cursor_t *, unw_addr_space_t, void *); extern int unw_step (unw_cursor_t *); extern int unw_resume (unw_cursor_t *); diff --git a/src/aarch64/Ginit_local.c b/src/aarch64/Ginit_local.c index dee6fd3b..45b1b300 100644 --- a/src/aarch64/Ginit_local.c +++ b/src/aarch64/Ginit_local.c @@ -36,8 +36,8 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +static int +unw_init_local_common (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -49,7 +49,19 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c, 1); + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/arm/Ginit_local.c b/src/arm/Ginit_local.c index e1cc30c6..f74d55e7 100644 --- a/src/arm/Ginit_local.c +++ b/src/arm/Ginit_local.c @@ -36,8 +36,8 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +static int +unw_init_local_common (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -49,7 +49,19 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c, 1); + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/hppa/Ginit_local.c b/src/hppa/Ginit_local.c index 0ad2f884..94583d9d 100644 --- a/src/hppa/Ginit_local.c +++ b/src/hppa/Ginit_local.c @@ -36,8 +36,8 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +static int +unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -48,7 +48,19 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c, 1); + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/mips/Ginit_local.c b/src/mips/Ginit_local.c index e5e1c5a3..d24e9ea5 100644 --- a/src/mips/Ginit_local.c +++ b/src/mips/Ginit_local.c @@ -35,8 +35,8 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +static int +unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -47,7 +47,19 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c, 1); + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local(unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal(unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/ppc/Ginit_local.c b/src/ppc/Ginit_local.c index 4ca2b25b..6c83b3b7 100644 --- a/src/ppc/Ginit_local.c +++ b/src/ppc/Ginit_local.c @@ -43,8 +43,8 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +static int +unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -56,10 +56,22 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; #ifdef UNW_TARGET_PPC64 - return common_init_ppc64 (c, 1); + return common_init_ppc64 (c, use_prev_instr); #else - return common_init_ppc32 (c, 1); + return common_init_ppc32 (c, use_prev_instr); #endif } +PROTECTED int +unw_init_local(unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal(unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); +} + #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/sh/Ginit_local.c b/src/sh/Ginit_local.c index e1cc30c6..598f708a 100644 --- a/src/sh/Ginit_local.c +++ b/src/sh/Ginit_local.c @@ -36,8 +36,8 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +static int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -49,7 +49,19 @@ unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c, 1); + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, unw_context_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/tilegx/Ginit_local.c b/src/tilegx/Ginit_local.c index f75c98f4..800dc00f 100644 --- a/src/tilegx/Ginit_local.c +++ b/src/tilegx/Ginit_local.c @@ -36,8 +36,8 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +static int +unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -51,7 +51,19 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as = unw_local_addr_space; c->dwarf.as_arg = uc; - return common_init (c, 1); + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/x86/Ginit_local.c b/src/x86/Ginit_local.c index 02fb994e..025c84cb 100644 --- a/src/x86/Ginit_local.c +++ b/src/x86/Ginit_local.c @@ -36,8 +36,8 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +static int +unw_init_local_common(unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -50,7 +50,19 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as_arg = c; c->uc = uc; c->validate = 0; - return common_init (c, 1); + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/src/x86_64/Ginit_local.c b/src/x86_64/Ginit_local.c index 07993896..2d2b1754 100644 --- a/src/x86_64/Ginit_local.c +++ b/src/x86_64/Ginit_local.c @@ -38,8 +38,8 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) #else /* !UNW_REMOTE_ONLY */ -PROTECTED int -unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +static int +unw_init_local_common (unw_cursor_t *cursor, ucontext_t *uc, unsigned use_prev_instr) { struct cursor *c = (struct cursor *) cursor; @@ -52,7 +52,19 @@ unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) c->dwarf.as_arg = c; c->uc = uc; c->validate = 0; - return common_init (c, 1); + return common_init (c, use_prev_instr); +} + +PROTECTED int +unw_init_local (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 1); +} + +PROTECTED int +unw_init_local_signal (unw_cursor_t *cursor, ucontext_t *uc) +{ + return unw_init_local_common(cursor, uc, 0); } #endif /* !UNW_REMOTE_ONLY */ diff --git a/tests/check-namespace.sh.in b/tests/check-namespace.sh.in index 44c1932f..d3b039fe 100644 --- a/tests/check-namespace.sh.in +++ b/tests/check-namespace.sh.in @@ -97,6 +97,7 @@ check_local_unw_abi () { match _UL${plat}_get_reg match _UL${plat}_get_save_loc match _UL${plat}_init_local + match _UL${plat}_init_local_signal match _UL${plat}_init_remote match _UL${plat}_is_signal_frame match _UL${plat}_handle_signal_frame @@ -172,7 +173,7 @@ check_local_unw_abi () { match _UL${plat}_local_addr_space_init match _U${plat}_get_elf_image match _U${plat}_get_exe_image_path - match ${plat}_lock + match ${plat}_lock ;; *) @@ -200,6 +201,7 @@ check_generic_unw_abi () { match _U${plat}_get_reg match _U${plat}_get_save_loc match _U${plat}_init_local + match _U${plat}_init_local_signal match _U${plat}_init_remote match _U${plat}_is_signal_frame match _U${plat}_handle_signal_frame