diff options
author | MyungJoo Ham <myungjoo.ham@samsung.com> | 2016-05-19 02:52:09 +0000 |
---|---|---|
committer | Dave Watson <davejwatson@fb.com> | 2017-08-15 10:34:09 -0700 |
commit | ed90c8387b0c6ea2df69a90391e55c5f8c6eff29 (patch) | |
tree | b7cb5916bf5edf1290200ab523ad4e35f5b05748 | |
parent | c4accd6ea2bd7893d44a2ffd253e972ab2c49099 (diff) | |
download | libunwind-ed90c8387b0c6ea2df69a90391e55c5f8c6eff29.tar.gz |
arm: Fix is_signal_frame bug for Thumb/Thumb2 mode
If Thumb is used, the least bit of the retrived IP value is set,
which makes the retrived opcode based on the IP invalid.
This patch fixes such behavior and adds a missed condition
found with glibc built for recent ARMv7l with Thumb2.
Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
CC: Yvan Roux
CC: Arun Sharma
CC: David Mosberger
-rw-r--r-- | src/arm/Gis_signal_frame.c | 15 |
1 files changed, 12 insertions, 3 deletions
diff --git a/src/arm/Gis_signal_frame.c b/src/arm/Gis_signal_frame.c index e8efe7f4..bfae4c6b 100644 --- a/src/arm/Gis_signal_frame.c +++ b/src/arm/Gis_signal_frame.c @@ -44,6 +44,13 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* Thumb sigreturn (two insns, syscall number is loaded into r7) */ #define THUMB_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_sigreturn) #define THUMB_RT_SIGRETURN (0xdf00UL << 16 | 0x2700 | ARM_NR_rt_sigreturn) + +/* Thumb2 sigreturn (mov.w r7, $SYS_ify(rt_sigreturn/sigreturn)) */ +#define THUMB2_SIGRETURN (((0x0700 | ARM_NR_sigreturn) << 16) | \ + 0xf04f) +#define THUMB2_RT_SIGRETURN (((0x0700 | ARM_NR_rt_sigreturn) << 16) | \ + 0xf04f) +/* TODO: with different toolchains, there are a lot more possibilities */ #endif /* __linux__ */ /* Returns 1 in case of a non-RT signal frame and 2 in case of a RT signal @@ -63,17 +70,19 @@ unw_is_signal_frame (unw_cursor_t *cursor) a = unw_get_accessors (as); arg = c->dwarf.as_arg; - ip = c->dwarf.ip; + /* The least bit denotes thumb/arm mode. Do not read there. */ + ip = c->dwarf.ip & ~0x1; if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0) return ret; /* Return 1 if the IP points to a non-RT sigreturn sequence. */ - if (w0 == MOV_R7_SIGRETURN || w0 == ARM_SIGRETURN || w0 == THUMB_SIGRETURN) + if (w0 == MOV_R7_SIGRETURN || w0 == ARM_SIGRETURN || w0 == THUMB_SIGRETURN + || w0 == THUMB2_SIGRETURN) return 1; /* Return 2 if the IP points to a RT sigreturn sequence. */ else if (w0 == MOV_R7_RT_SIGRETURN || w0 == ARM_RT_SIGRETURN - || w0 == THUMB_RT_SIGRETURN) + || w0 == THUMB_RT_SIGRETURN || w0 == THUMB2_RT_SIGRETURN) return 2; return 0; |