1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-11-16 21:27:38 +01:00

arm: FreeBSD/ARMv6 port

Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Konstantin Belousov 2016-02-18 11:39:50 +02:00 committed by Dave Watson
parent 60663c8f69
commit fd02fd59e7
21 changed files with 479 additions and 201 deletions

View file

@ -68,6 +68,15 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
# include <endian.h>
#elif defined(HAVE_SYS_ENDIAN_H)
# include <sys/endian.h>
# if defined(_LITTLE_ENDIAN) && !defined(__LITTLE_ENDIAN)
# define __LITTLE_ENDIAN _LITTLE_ENDIAN
# endif
# if defined(_BIG_ENDIAN) && !defined(__BIG_ENDIAN)
# define __BIG_ENDIAN _BIG_ENDIAN
# endif
# if defined(_BYTE_ORDER) && !defined(__BYTE_ORDER)
# define __BYTE_ORDER _BYTE_ORDER
# endif
#else
# define __LITTLE_ENDIAN 1234
# define __BIG_ENDIAN 4321

View file

@ -38,6 +38,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
typedef enum
{
UNW_ARM_FRAME_SYSCALL = -3, /* r7 saved in r12, sp offset zero */
UNW_ARM_FRAME_STANDARD = -2, /* regular r7, sp +/- offset */
UNW_ARM_FRAME_SIGRETURN = -1, /* special sigreturn frame */
UNW_ARM_FRAME_OTHER = 0, /* not cacheable (special or unrecognised) */
@ -48,7 +49,7 @@ unw_tdep_frame_type_t;
typedef struct
{
uint32_t virtual_address;
int32_t frame_type : 2; /* unw_tdep_frame_type_t classification */
int32_t frame_type : 3; /* unw_tdep_frame_type_t classification */
int32_t last_frame : 1; /* non-zero if last frame in chain */
int32_t cfa_reg_sp : 1; /* cfa dwarf base register is sp vs. r7 */
int32_t cfa_reg_offset : 30; /* cfa is at this offset from base register value */
@ -86,7 +87,9 @@ struct cursor
ARM_SCF_LINUX_SIGFRAME, /* non-RT signal frame, kernel >=2.6.18 */
ARM_SCF_LINUX_RT_SIGFRAME, /* RT signal frame, kernel >=2.6.18 */
ARM_SCF_LINUX_OLD_SIGFRAME, /* non-RT signal frame, kernel < 2.6.18 */
ARM_SCF_LINUX_OLD_RT_SIGFRAME /* RT signal frame, kernel < 2.6.18 */
ARM_SCF_LINUX_OLD_RT_SIGFRAME, /* RT signal frame, kernel < 2.6.18 */
ARM_SCF_FREEBSD_SIGFRAME, /* FreeBSD sigframe */
ARM_SCF_FREEBSD_SYSCALL, /* FreeBSD syscall stub */
}
sigcontext_format;
unw_word_t sigcontext_addr;

View file

@ -220,20 +220,23 @@ libunwind_la_SOURCES_arm_common = $(libunwind_la_SOURCES_common) \
# The list of files that go into libunwind:
libunwind_la_SOURCES_arm = $(libunwind_la_SOURCES_arm_common) \
$(libunwind_la_SOURCES_arm_os_local) \
$(libunwind_la_SOURCES_local) \
arm/getcontext.S \
arm/Lapply_reg_state.c arm/Lreg_states_iterate.c \
arm/Lcreate_addr_space.c arm/Lget_proc_info.c arm/Lget_save_loc.c \
arm/Lglobal.c arm/Linit.c arm/Linit_local.c arm/Linit_remote.c \
arm/Lis_signal_frame.c arm/Lregs.c arm/Lresume.c arm/Lstep.c \
arm/Lregs.c arm/Lresume.c arm/Lstep.c \
arm/Lex_tables.c arm/Lstash_frame.c arm/Ltrace.c
# The list of files that go into libunwind-arm:
libunwind_arm_la_SOURCES_arm = $(libunwind_la_SOURCES_arm_common) \
$(libunwind_la_SOURCES_arm_os) \
$(libunwind_la_SOURCES_generic) \
arm/Gapply_reg_state.c arm/Greg_states_iterate.c \
arm/Gcreate_addr_space.c arm/Gget_proc_info.c arm/Gget_save_loc.c \
arm/Gglobal.c arm/Ginit.c arm/Ginit_local.c arm/Ginit_remote.c \
arm/Gis_signal_frame.c arm/Gregs.c arm/Gresume.c arm/Gstep.c \
arm/Gregs.c arm/Gresume.c arm/Gstep.c \
arm/Gex_tables.c arm/Gstash_frame.c arm/Gtrace.c
# The list of files that go both into libunwind and libunwind-ia64:
@ -488,6 +491,7 @@ if OS_LINUX
libunwind_la_SOURCES_x86_os_local = x86/Los-linux.c
libunwind_la_SOURCES_x86_64_os = x86_64/Gos-linux.c
libunwind_la_SOURCES_x86_64_os_local = x86_64/Los-linux.c
libunwind_la_SOURCES_arm_os = arm/Gos-linux.c
libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_linux.c
endif
@ -504,12 +508,16 @@ if OS_FREEBSD
libunwind_la_SOURCES_x86_os_local = x86/Los-freebsd.c
libunwind_la_SOURCES_x86_64_os = x86_64/Gos-freebsd.c
libunwind_la_SOURCES_x86_64_os_local = x86_64/Los-freebsd.c
libunwind_la_SOURCES_arm_os = arm/Gos-freebsd.c
libunwind_la_SOURCES_arm_os_local = arm/Los-freebsd.c
libunwind_coredump_la_SOURCES += coredump/_UCD_access_reg_freebsd.c
endif
if OS_QNX
libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_qnx)
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_qnx_local)
libunwind_la_SOURCES_arm_os = arm/Gos-other.c
libunwind_la_SOURCES_arm_os_local = arm/Los-other.c
endif
if ARCH_AARCH64

View file

@ -1,96 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
Copyright 2011 Linaro Limited
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdio.h>
#include "unwind_i.h"
#ifdef __linux__
#define ARM_NR_sigreturn 119
#define ARM_NR_rt_sigreturn 173
#define ARM_NR_OABI_SYSCALL_BASE 0x900000
/* ARM EABI sigreturn (the syscall number is loaded into r7) */
#define MOV_R7_SIGRETURN (0xe3a07000UL | ARM_NR_sigreturn)
#define MOV_R7_RT_SIGRETURN (0xe3a07000UL | ARM_NR_rt_sigreturn)
/* ARM OABI sigreturn (using SWI) */
#define ARM_SIGRETURN \
(0xef000000UL | ARM_NR_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
#define ARM_RT_SIGRETURN \
(0xef000000UL | ARM_NR_rt_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
/* 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
frame. */
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
#ifdef __linux__
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
/* 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
|| 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 == THUMB2_RT_SIGRETURN)
return 2;
return 0;
#elif defined(__QNX__)
/* Not supported yet */
return 0;
#else
printf ("%s: implement me\n", __FUNCTION__);
return -UNW_ENOINFO;
#endif
}

129
src/arm/Gos-freebsd.c Normal file
View file

@ -0,0 +1,129 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
Copyright 2011 Linaro Limited
Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
Copyright 2015 The FreeBSD Foundation
Portions of this software were developed by Konstantin Belousov
under sponsorship from the FreeBSD Foundation.
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdio.h>
#include <signal.h>
#include "unwind_i.h"
#include "offsets.h"
#include "ex_tables.h"
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret, fmt;
unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0);
if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0)
return -UNW_EUNSPEC;
fmt = unw_is_signal_frame(cursor);
c->dwarf.pi_valid = 0;
if (fmt == UNW_ARM_FRAME_SYSCALL)
{
c->sigcontext_format = ARM_SCF_FREEBSD_SYSCALL;
c->frame_info.frame_type = UNW_ARM_FRAME_SYSCALL;
c->frame_info.cfa_reg_offset = 0;
c->dwarf.loc[UNW_ARM_R7] = c->dwarf.loc[UNW_ARM_R12];
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R14], &c->dwarf.ip);
return 1;
}
c->sigcontext_format = ARM_SCF_FREEBSD_SIGFRAME;
sc_addr = sp_addr;
/* Save the SP and PC to be able to return execution at this point
later in time (unw_resume). */
c->sigcontext_sp = c->dwarf.cfa;
c->sigcontext_pc = c->dwarf.ip;
c->sigcontext_addr = sc_addr;
c->frame_info.frame_type = UNW_ARM_FRAME_SIGRETURN;
c->frame_info.cfa_reg_offset = sc_addr - sp_addr;
/* Update the dwarf cursor.
Set the location of the registers to the corresponding addresses of the
uc_mcontext / sigcontext structure contents. */
#define ROFF(n) (FREEBSD_SC_UCONTEXT_OFF + FREEBSD_UC_MCONTEXT_OFF + \
FREEBSD_MC_R0_OFF + (n) * 4)
#define SL(n) \
c->dwarf.loc[UNW_ARM_R ## n] = DWARF_LOC (sc_addr + ROFF(n), 0);
SL(0); SL(1); SL(2); SL(3); SL(4); SL(5); SL(6); SL(7);
SL(8); SL(9); SL(10); SL(11); SL(12); SL(13); SL(14); SL(15);
#undef SL
#undef ROFF
/* Set SP/CFA and PC/IP. */
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R13], &c->dwarf.cfa);
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip);
return 1;
}
/* Returns 1 in case of a non-RT signal frame and 2 in case of a RT signal
frame. */
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, w2, w3, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
ip = c->dwarf.ip;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0)
return ret;
if ((ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0)
return ret;
if ((ret = (*a->access_mem) (as, ip + 8, &w2, 0, arg)) < 0)
return ret;
if ((ret = (*a->access_mem) (as, ip + 12, &w3, 0, arg)) < 0)
return ret;
if (w0 == 0xe1a0000d && w1 == 0xe2800040 && w2 == 0xe59f700c &&
w3 == 0xef0001a1)
return UNW_ARM_FRAME_SIGRETURN;
if ((ret = (*a->access_mem) (as, ip - 4, &w0, 0, arg)) < 0)
return ret;
if (w0 == 0xef000000)
return UNW_ARM_FRAME_SYSCALL;
return 0;
}

182
src/arm/Gos-linux.c Normal file
View file

@ -0,0 +1,182 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
Copyright 2011 Linaro Limited
Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdio.h>
#include <signal.h>
#include "unwind_i.h"
#include "offsets.h"
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0);
if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0)
return -UNW_EUNSPEC;
/* Obtain signal frame type (non-RT or RT). */
ret = unw_is_signal_frame (cursor);
/* Save the SP and PC to be able to return execution at this point
later in time (unw_resume). */
c->sigcontext_sp = c->dwarf.cfa;
c->sigcontext_pc = c->dwarf.ip;
/* Since kernel version 2.6.18 the non-RT signal frame starts with a
ucontext while the RT signal frame starts with a siginfo, followed
by a sigframe whose first element is an ucontext.
Prior 2.6.18 the non-RT signal frame starts with a sigcontext while
the RT signal frame starts with two pointers followed by a siginfo
and an ucontext. The first pointer points to the start of the siginfo
structure and the second one to the ucontext structure. */
if (ret == 1)
{
/* Handle non-RT signal frames. Check if the first word on the stack
is the magic number. */
if (sp == 0x5ac3c35a)
{
c->sigcontext_format = ARM_SCF_LINUX_SIGFRAME;
sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF;
}
else
{
c->sigcontext_format = ARM_SCF_LINUX_OLD_SIGFRAME;
sc_addr = sp_addr;
}
}
else if (ret == 2)
{
/* Handle RT signal frames. Check if the first word on the stack is a
pointer to the siginfo structure. */
if (sp == sp_addr + 8)
{
c->sigcontext_format = ARM_SCF_LINUX_OLD_RT_SIGFRAME;
sc_addr = sp_addr + 8 + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
}
else
{
c->sigcontext_format = ARM_SCF_LINUX_RT_SIGFRAME;
sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
}
}
else
return -UNW_EUNSPEC;
c->sigcontext_addr = sc_addr;
c->frame_info.frame_type = UNW_ARM_FRAME_SIGRETURN;
c->frame_info.cfa_reg_offset = sc_addr - sp_addr;
/* Update the dwarf cursor.
Set the location of the registers to the corresponding addresses of the
uc_mcontext / sigcontext structure contents. */
c->dwarf.loc[UNW_ARM_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0);
c->dwarf.loc[UNW_ARM_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0);
c->dwarf.loc[UNW_ARM_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0);
c->dwarf.loc[UNW_ARM_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0);
c->dwarf.loc[UNW_ARM_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0);
c->dwarf.loc[UNW_ARM_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0);
c->dwarf.loc[UNW_ARM_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0);
c->dwarf.loc[UNW_ARM_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0);
c->dwarf.loc[UNW_ARM_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0);
c->dwarf.loc[UNW_ARM_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0);
c->dwarf.loc[UNW_ARM_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0);
c->dwarf.loc[UNW_ARM_R11] = DWARF_LOC (sc_addr + LINUX_SC_FP_OFF, 0);
c->dwarf.loc[UNW_ARM_R12] = DWARF_LOC (sc_addr + LINUX_SC_IP_OFF, 0);
c->dwarf.loc[UNW_ARM_R13] = DWARF_LOC (sc_addr + LINUX_SC_SP_OFF, 0);
c->dwarf.loc[UNW_ARM_R14] = DWARF_LOC (sc_addr + LINUX_SC_LR_OFF, 0);
c->dwarf.loc[UNW_ARM_R15] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0);
/* Set SP/CFA and PC/IP. */
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R13], &c->dwarf.cfa);
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip);
c->dwarf.pi_valid = 0;
return 1;
}
#define ARM_NR_sigreturn 119
#define ARM_NR_rt_sigreturn 173
#define ARM_NR_OABI_SYSCALL_BASE 0x900000
/* ARM EABI sigreturn (the syscall number is loaded into r7) */
#define MOV_R7_SIGRETURN (0xe3a07000UL | ARM_NR_sigreturn)
#define MOV_R7_RT_SIGRETURN (0xe3a07000UL | ARM_NR_rt_sigreturn)
/* ARM OABI sigreturn (using SWI) */
#define ARM_SIGRETURN \
(0xef000000UL | ARM_NR_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
#define ARM_RT_SIGRETURN \
(0xef000000UL | ARM_NR_rt_sigreturn | ARM_NR_OABI_SYSCALL_BASE)
/* 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 */
/* Returns 1 in case of a non-RT signal frame and 2 in case of a RT signal
frame. */
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
/* 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
|| 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 == THUMB2_RT_SIGRETURN)
return 2;
return 0;
}

48
src/arm/Gos-other.c Normal file
View file

@ -0,0 +1,48 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2008 CodeSourcery
Copyright 2011 Linaro Limited
Copyright (C) 2012 Tommi Rantala <tt.rantala@gmail.com>
This file is part of libunwind.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdio.h>
#include <signal.h>
#include "unwind_i.h"
#include "offsets.h"
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
return -UNW_EUNSPEC;
}
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
#if defined(__QNX__)
/* Not supported yet */
return 0;
#else
printf ("%s: implement me\n", __FUNCTION__);
return -UNW_ENOINFO;
#endif
}

View file

@ -79,99 +79,6 @@ arm_exidx_step (struct cursor *c)
return (c->dwarf.ip == 0) ? 0 : 1;
}
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
unw_word_t sc_addr, sp, sp_addr = c->dwarf.cfa;
struct dwarf_loc sp_loc = DWARF_LOC (sp_addr, 0);
if ((ret = dwarf_get (&c->dwarf, sp_loc, &sp)) < 0)
return -UNW_EUNSPEC;
/* Obtain signal frame type (non-RT or RT). */
ret = unw_is_signal_frame (cursor);
/* Save the SP and PC to be able to return execution at this point
later in time (unw_resume). */
c->sigcontext_sp = c->dwarf.cfa;
c->sigcontext_pc = c->dwarf.ip;
/* Since kernel version 2.6.18 the non-RT signal frame starts with a
ucontext while the RT signal frame starts with a siginfo, followed
by a sigframe whose first element is an ucontext.
Prior 2.6.18 the non-RT signal frame starts with a sigcontext while
the RT signal frame starts with two pointers followed by a siginfo
and an ucontext. The first pointer points to the start of the siginfo
structure and the second one to the ucontext structure. */
if (ret == 1)
{
/* Handle non-RT signal frames. Check if the first word on the stack
is the magic number. */
if (sp == 0x5ac3c35a)
{
c->sigcontext_format = ARM_SCF_LINUX_SIGFRAME;
sc_addr = sp_addr + LINUX_UC_MCONTEXT_OFF;
}
else
{
c->sigcontext_format = ARM_SCF_LINUX_OLD_SIGFRAME;
sc_addr = sp_addr;
}
}
else if (ret == 2)
{
/* Handle RT signal frames. Check if the first word on the stack is a
pointer to the siginfo structure. */
if (sp == sp_addr + 8)
{
c->sigcontext_format = ARM_SCF_LINUX_OLD_RT_SIGFRAME;
sc_addr = sp_addr + 8 + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
}
else
{
c->sigcontext_format = ARM_SCF_LINUX_RT_SIGFRAME;
sc_addr = sp_addr + sizeof (siginfo_t) + LINUX_UC_MCONTEXT_OFF;
}
}
else
return -UNW_EUNSPEC;
c->sigcontext_addr = sc_addr;
c->frame_info.frame_type = UNW_ARM_FRAME_SIGRETURN;
c->frame_info.cfa_reg_offset = sc_addr - sp_addr;
/* Update the dwarf cursor.
Set the location of the registers to the corresponding addresses of the
uc_mcontext / sigcontext structure contents. */
c->dwarf.loc[UNW_ARM_R0] = DWARF_LOC (sc_addr + LINUX_SC_R0_OFF, 0);
c->dwarf.loc[UNW_ARM_R1] = DWARF_LOC (sc_addr + LINUX_SC_R1_OFF, 0);
c->dwarf.loc[UNW_ARM_R2] = DWARF_LOC (sc_addr + LINUX_SC_R2_OFF, 0);
c->dwarf.loc[UNW_ARM_R3] = DWARF_LOC (sc_addr + LINUX_SC_R3_OFF, 0);
c->dwarf.loc[UNW_ARM_R4] = DWARF_LOC (sc_addr + LINUX_SC_R4_OFF, 0);
c->dwarf.loc[UNW_ARM_R5] = DWARF_LOC (sc_addr + LINUX_SC_R5_OFF, 0);
c->dwarf.loc[UNW_ARM_R6] = DWARF_LOC (sc_addr + LINUX_SC_R6_OFF, 0);
c->dwarf.loc[UNW_ARM_R7] = DWARF_LOC (sc_addr + LINUX_SC_R7_OFF, 0);
c->dwarf.loc[UNW_ARM_R8] = DWARF_LOC (sc_addr + LINUX_SC_R8_OFF, 0);
c->dwarf.loc[UNW_ARM_R9] = DWARF_LOC (sc_addr + LINUX_SC_R9_OFF, 0);
c->dwarf.loc[UNW_ARM_R10] = DWARF_LOC (sc_addr + LINUX_SC_R10_OFF, 0);
c->dwarf.loc[UNW_ARM_R11] = DWARF_LOC (sc_addr + LINUX_SC_FP_OFF, 0);
c->dwarf.loc[UNW_ARM_R12] = DWARF_LOC (sc_addr + LINUX_SC_IP_OFF, 0);
c->dwarf.loc[UNW_ARM_R13] = DWARF_LOC (sc_addr + LINUX_SC_SP_OFF, 0);
c->dwarf.loc[UNW_ARM_R14] = DWARF_LOC (sc_addr + LINUX_SC_LR_OFF, 0);
c->dwarf.loc[UNW_ARM_R15] = DWARF_LOC (sc_addr + LINUX_SC_PC_OFF, 0);
/* Set SP/CFA and PC/IP. */
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R13], &c->dwarf.cfa);
dwarf_get (&c->dwarf, c->dwarf.loc[UNW_ARM_R15], &c->dwarf.ip);
c->dwarf.pi_valid = 0;
return 1;
}
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
@ -216,14 +123,18 @@ unw_step (unw_cursor_t *cursor)
/* Fall back on APCS frame parsing.
Note: This won't work in case the ARM EABI is used. */
#ifdef __FreeBSD__
if (0)
#else
if (unlikely (ret < 0))
#endif
{
if (UNW_TRY_METHOD(UNW_ARM_METHOD_FRAME))
{
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
ret = UNW_ESUCCESS;
/* DWARF unwinding failed, try to follow APCS/optimized APCS frame chain */
unw_word_t instr, i;
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
dwarf_loc_t ip_loc, fp_loc;
unw_word_t frame;
/* Mark all registers unsaved, since we don't know where
@ -266,7 +177,7 @@ unw_step (unw_cursor_t *cursor)
c->dwarf.loc[UNW_ARM_R12] = ip_loc;
c->dwarf.loc[UNW_ARM_R11] = fp_loc;
c->dwarf.pi_valid = 0;
Debug(15, "ip=%lx\n", c->dwarf.ip);
Debug(15, "ip=%x\n", c->dwarf.ip);
}
else
{

View file

@ -503,7 +503,7 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
case UNW_ARM_FRAME_SIGRETURN:
cfa = cfa + f->cfa_reg_offset; /* cfa now points to ucontext_t. */
#if defined(__linux__)
ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_PC_OFF, pc);
if (likely(ret >= 0))
ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_R7_OFF, r7);
@ -513,6 +513,9 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
doesn't save the link register in the prologue, e.g. kill. */
if (likely(ret >= 0))
ACCESS_MEM_FAST(ret, c->validate, d, cfa + LINUX_SC_LR_OFF, lr);
#elif defined(__FreeBSD__)
printf("XXX\n");
#endif
/* Resume stack at signal restoration point. The stack is not
necessarily continuous here, especially with sigaltstack(). */
@ -522,6 +525,10 @@ tdep_trace (unw_cursor_t *cursor, void **buffer, int *size)
d->use_prev_instr = 0;
break;
case UNW_ARM_FRAME_SYSCALL:
printf("XXX1\n");
break;
default:
/* We cannot trace through this frame, give up and tell the
caller we had to stop. Data collected so far may still be

5
src/arm/Los-freebsd.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gos-freebsd.c"
#endif

5
src/arm/Los-linux.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gos-linux.c"
#endif

5
src/arm/Los-other.c Normal file
View file

@ -0,0 +1,5 @@
#define UNW_LOCAL_ONLY
#include <libunwind.h>
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
#include "Gos-freebsd.c"
#endif

View file

@ -35,8 +35,15 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
_Uarm_getcontext:
stmfd sp!, {r0, r1}
@ store r0
#if defined(__linux__)
str r0, [r0, #LINUX_UC_MCONTEXT_OFF + LINUX_SC_R0_OFF]
add r0, r0, #LINUX_UC_MCONTEXT_OFF + LINUX_SC_R0_OFF
#elif defined(__FreeBSD__)
str r0, [r0, #FREEBSD_UC_MCONTEXT_OFF + FREEBSD_MC_R0_OFF]
add r0, r0, #FREEBSD_UC_MCONTEXT_OFF + FREEBSD_MC_R0_OFF
#else
#error Fix me
#endif
@ store r1 to r12
stmib r0, {r1-r12}
@ reconstruct r13 at call site, then store
@ -50,7 +57,7 @@ _Uarm_getcontext:
str r1, [r0, #15 * 4]
ldmfd sp!, {r0, r1}
bx lr
#ifdef __linux__
#if defined(__linux__) || defined(__FreeBSD__)
/* We do not need executable stack. */
.section .note.GNU-stack,"",%progbits
#endif

View file

@ -34,3 +34,9 @@
#define LINUX_SC_PC_OFF 0x48
#define LINUX_SC_CPSR_OFF 0x4C
#define LINUX_SC_FAULTADDR_OFF 0x50
/* FreeBSD-specific definitions: */
#define FREEBSD_SC_UCONTEXT_OFF 0x40
#define FREEBSD_UC_MCONTEXT_OFF 0x10
#define FREEBSD_MC_R0_OFF 0

View file

@ -76,7 +76,7 @@ _UCD_access_reg (unw_addr_space_t as,
default:
Debug(0, "bad regnum:%d\n", regnum);
return -UNW_EINVAL;
};
}
#elif defined(UNW_TARGET_X86_64)
switch (regnum) {
case UNW_X86_64_RAX:
@ -109,7 +109,26 @@ _UCD_access_reg (unw_addr_space_t as,
default:
Debug(0, "bad regnum:%d\n", regnum);
return -UNW_EINVAL;
};
}
#elif defined(UNW_TARGET_ARM)
if (regnum >= UNW_ARM_R0 && regnum <= UNW_ARM_R12) {
*valp = ui->prstatus->pr_reg.r[regnum];
} else {
switch (regnum) {
case UNW_ARM_R13:
*valp = ui->prstatus->pr_reg.r_sp;
break;
case UNW_ARM_R14:
*valp = ui->prstatus->pr_reg.r_lr;
break;
case UNW_ARM_R15:
*valp = ui->prstatus->pr_reg.r_pc;
break;
default:
Debug(0, "bad regnum:%d\n", regnum);
return -UNW_EINVAL;
}
}
#else
#error Port me
#endif

View file

@ -56,7 +56,7 @@ get_pid_by_tid(int tid)
size_t len, len1;
char *buf;
struct kinfo_proc *kv;
int i, pid;
unsigned i, pid;
len = 0;
mib[0] = CTL_KERN;

View file

@ -75,6 +75,18 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
pid_t pid = ui->pid;
fpregset_t fpreg;
#if defined(__amd64__)
if (1) /* XXXKIB */
return -UNW_EBADREG;
#elif defined(__i386__)
if ((unsigned) reg < UNW_X86_ST0 || (unsigned) reg > UNW_X86_ST7)
return -UNW_EBADREG;
#elif defined(__arm__)
if ((unsigned) reg < UNW_ARM_F0 || (unsigned) reg > UNW_ARM_F7)
return -UNW_EBADREG;
#else
#error Fix me
#endif
if ((unsigned) reg >= ARRAY_SIZE (_UPT_reg_offset))
return -UNW_EBADREG;
@ -85,6 +97,8 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
memcpy(&fpreg.fpr_xacc[reg], val, sizeof(unw_fpreg_t));
#elif defined(__i386__)
memcpy(&fpreg.fpr_acc[reg], val, sizeof(unw_fpreg_t));
#elif defined(__arm__)
memcpy(&fpreg.fpr[reg], val, sizeof(unw_fpreg_t));
#else
#error Fix me
#endif
@ -95,6 +109,8 @@ _UPT_access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
memcpy(val, &fpreg.fpr_xacc[reg], sizeof(unw_fpreg_t));
#elif defined(__i386__)
memcpy(val, &fpreg.fpr_acc[reg], sizeof(unw_fpreg_t));
#elif defined(__arm__)
memcpy(val, &fpreg.fpr[reg], sizeof(unw_fpreg_t));
#else
#error Fix me
#endif

View file

@ -484,6 +484,7 @@ const int _UPT_reg_offset[UNW_REG_LAST + 1] =
#endif
#elif defined(UNW_TARGET_ARM)
#if defined(__linux__) || defined(__FreeBSD__)
[UNW_ARM_R0] = 0x00,
[UNW_ARM_R1] = 0x04,
[UNW_ARM_R2] = 0x08,
@ -500,6 +501,9 @@ const int _UPT_reg_offset[UNW_REG_LAST + 1] =
[UNW_ARM_R13] = 0x34,
[UNW_ARM_R14] = 0x38,
[UNW_ARM_R15] = 0x3c,
#else
#error Fix me
#endif
#elif defined(UNW_TARGET_MIPS)
[UNW_MIPS_R0] = 0,
[UNW_MIPS_R1] = 1,

View file

@ -37,6 +37,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>
#include <libunwind.h>

View file

@ -36,6 +36,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>
#include <libunwind.h>
@ -212,7 +213,11 @@ sighandler (int signal, void *siginfo UNUSED, void *context)
printf (" @ %lx", (unsigned long) uc->uc_mcontext.mc_rip);
#endif
#elif defined UNW_TARGET_ARM
#if defined __linux__
printf (" @ %lx", (unsigned long) uc->uc_mcontext.arm_pc);
#elif defined __FreeBSD__
printf (" @ %lx", (unsigned long) uc->uc_mcontext.__gregs[_REG_PC]);
#endif
#endif
printf ("\n");
}

View file

@ -55,7 +55,11 @@ main (void)
for (n = 0; n < 30000; ++n)
{
if (mmap (NULL, 1, (n & 1) ? PROT_READ : PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE,
MAP_PRIVATE | MAP_ANONYMOUS
#ifdef MAP_NORESERVE
| MAP_NORESERVE
#endif
,
-1, 0) == MAP_FAILED)
{
printf ("Failed after %ld successful maps\n", n - 1);