1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2024-05-19 19:45:17 +02:00

Merge remote branch 'origin/master' into freebsd

Conflicts:
	src/x86/Gis_signal_frame.c
	src/x86/Gstep.c
	src/x86_64/Gis_signal_frame.c
	src/x86_64/Gstep.c
This commit is contained in:
Konstantin Belousov 2010-04-05 16:14:50 +03:00
commit fd88f41818
13 changed files with 408 additions and 271 deletions

View file

@ -220,6 +220,7 @@ unw_save_loc_t;
#define unw_set_fpreg UNW_OBJ(set_fpreg)
#define unw_get_save_loc UNW_OBJ(get_save_loc)
#define unw_is_signal_frame UNW_OBJ(is_signal_frame)
#define unw_handle_signal_frame UNW_OBJ(handle_signal_frame)
#define unw_get_proc_name UNW_OBJ(get_proc_name)
#define unw_set_caching_policy UNW_OBJ(set_caching_policy)
#define unw_regname UNW_ARCH_OBJ(regname)
@ -246,6 +247,7 @@ extern int unw_get_fpreg (unw_cursor_t *, int, unw_fpreg_t *);
extern int unw_set_fpreg (unw_cursor_t *, int, unw_fpreg_t);
extern int unw_get_save_loc (unw_cursor_t *, int, unw_save_loc_t *);
extern int unw_is_signal_frame (unw_cursor_t *);
extern int unw_handle_signal_frame (unw_cursor_t *);
extern int unw_get_proc_name (unw_cursor_t *, char *, size_t, unw_word_t *);
extern const char *unw_strerror (int);

View file

@ -223,22 +223,24 @@ libunwind_la_SOURCES_x86_common = $(libunwind_la_SOURCES_common) \
# The list of files that go into libunwind:
libunwind_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \
$(libunwind_la_SOURCES_x86_os_local) \
$(libunwind_la_SOURCES_local) \
$(dwarf_SOURCES_local) \
dwarf/Lfind_proc_info-lsb.c \
x86/Lcreate_addr_space.c x86/Lget_save_loc.c x86/Lglobal.c \
x86/Linit.c x86/Linit_local.c x86/Linit_remote.c \
x86/Lis_signal_frame.c x86/Lget_proc_info.c x86/Lregs.c \
x86/Lget_proc_info.c x86/Lregs.c \
x86/Lresume.c x86/Lstep.c x86/getcontext.S
# The list of files that go into libunwind-x86:
libunwind_x86_la_SOURCES_x86 = $(libunwind_la_SOURCES_x86_common) \
$(libunwind_la_SOURCES_x86_os) \
$(libunwind_la_SOURCES_generic) \
$(dwarf_SOURCES_generic) \
dwarf/Gfind_proc_info-lsb.c \
x86/Gcreate_addr_space.c x86/Gget_save_loc.c x86/Gglobal.c \
x86/Ginit.c x86/Ginit_local.c x86/Ginit_remote.c \
x86/Gis_signal_frame.c x86/Gget_proc_info.c x86/Gregs.c \
x86/Gget_proc_info.c x86/Gregs.c \
x86/Gresume.c x86/Gstep.c
# The list of files that go both into libunwind and libunwind-x86_64:
@ -250,23 +252,25 @@ libunwind_la_SOURCES_x86_64_common = $(libunwind_la_SOURCES_common) \
# The list of files that go into libunwind:
libunwind_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \
$(libunwind_la_SOURCES_x86_64_os_local) \
$(libunwind_la_SOURCES_local) \
$(dwarf_SOURCES_local) \
dwarf/Lfind_proc_info-lsb.c \
x86_64/setcontext.S \
x86_64/setcontext.S \
x86_64/Lcreate_addr_space.c x86_64/Lget_save_loc.c x86_64/Lglobal.c \
x86_64/Linit.c x86_64/Linit_local.c x86_64/Linit_remote.c \
x86_64/Lis_signal_frame.c x86_64/Lget_proc_info.c x86_64/Lregs.c \
x86_64/Lget_proc_info.c x86_64/Lregs.c \
x86_64/Lresume.c x86_64/Lstep.c x86_64/getcontext.S
# The list of files that go into libunwind-x86_64:
libunwind_x86_64_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \
$(libunwind_la_SOURCES_x86_64_os) \
$(libunwind_la_SOURCES_generic) \
$(dwarf_SOURCES_generic) \
dwarf/Gfind_proc_info-lsb.c \
x86_64/Gcreate_addr_space.c x86_64/Gget_save_loc.c x86_64/Gglobal.c \
x86_64/Ginit.c x86_64/Ginit_local.c x86_64/Ginit_remote.c \
x86_64/Gis_signal_frame.c x86_64/Gget_proc_info.c x86_64/Gregs.c \
x86_64/Gget_proc_info.c x86_64/Gregs.c \
x86_64/Gresume.c x86_64/Gstep.c
# The list of local files that go to Power 64 and 32:
@ -344,8 +348,12 @@ install-exec-hook:
endif
if OS_LINUX
libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_linux)
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_linux_local)
libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_linux)
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_linux_local)
libunwind_la_SOURCES_x86_os = x86/Gos-linux.c
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
endif
if OS_HPUX
@ -356,6 +364,10 @@ endif
if OS_FREEBSD
libunwind_la_SOURCES_os = $(libunwind_la_SOURCES_os_freebsd)
libunwind_la_SOURCES_os_local = $(libunwind_la_SOURCES_os_freebsd_local)
libunwind_la_SOURCES_x86_os = x86/Gos-freebsd.c
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
endif
if ARCH_ARM

View file

@ -1,6 +1,5 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2003 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
This file is part of libunwind.
@ -23,51 +22,21 @@ 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. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <signal.h>
#include <ucontext.h>
#include <machine/sigframe.h>
#include "unwind_i.h"
#include "offsets.h"
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
#if defined __linux__
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, 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;
/* Check if EIP points at sigreturn() sequence. On Linux, this is:
__restore:
0x58 pop %eax
0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
0xcd 0x80 int 0x80
without SA_SIGINFO, and
__restore_rt:
0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
0xcd 0x80 int 0x80
0x00
if SA_SIGINFO is specified.
*/
ip = c->dwarf.ip;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0)
return ret;
ret = X86_SCF_NONE;
if (w0 == 0x0077b858 && w1 == 0x80cd0000)
ret = X86_SCF_LINUX_SIGFRAME;
else if (w0 == 0x0000adb8 && (w1 & 0xffffff) == 0x80cd00)
ret = X86_SCF_LINUX_RT_SIGFRAME;
Debug (16, "returning %d\n", ret);
return ret;
#elif defined __FreeBSD__
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, w2, w3, w4, w5, ip;
unw_addr_space_t as;
@ -104,6 +73,7 @@ XXX
*/
ip = c->dwarf.ip;
ret = X86_SCF_NONE;
c->sigcontext_format = ret;
if ((*a->access_mem) (as, ip, &w0, 0, arg) < 0 ||
(*a->access_mem) (as, ip + 4, &w1, 0, arg) < 0 ||
(*a->access_mem) (as, ip + 8, &w2, 0, arg) < 0 ||
@ -121,9 +91,47 @@ XXX
ret = X86_SCF_FREEBSD_SIGFRAME;
}
Debug (16, "returning %d\n", ret);
c->sigcontext_format = ret;
return (ret);
#else
#error Port me
#endif
return -UNW_ENOINFO;
}
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
if (c->sigcontext_format == X86_SCF_FREEBSD_SIGFRAME) {
struct sigframe *sf;
uintptr_t uc_addr;
struct dwarf_loc esp_loc;
sf = (struct sigframe *)c->dwarf.cfa;
uc_addr = (uintptr_t)&(sf->sf_uc);
esp_loc = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0);
ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
c->dwarf.loc[EIP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EIP_OFF, 0);
c->dwarf.loc[ESP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0);
c->dwarf.loc[EAX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EAX_OFF, 0);
c->dwarf.loc[ECX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ECX_OFF, 0);
c->dwarf.loc[EDX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EDX_OFF, 0);
c->dwarf.loc[EBX] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBX_OFF, 0);
c->dwarf.loc[EBP] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBP_OFF, 0);
c->dwarf.loc[ESI] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESI_OFF, 0);
c->dwarf.loc[EDI] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EDI_OFF, 0);
c->dwarf.loc[EFLAGS] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EFLAGS_OFF, 0);
c->dwarf.loc[TRAPNO] = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_TRAPNO_OFF, 0);
c->dwarf.loc[ST0] = DWARF_NULL_LOC;
} else {
Debug (8, "Gstep: not handling frame format %d\n", c->sigcontext_format);
abort();
}
return 0;
}

137
src/x86/Gos-linux.c Normal file
View file

@ -0,0 +1,137 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002-2004 Hewlett-Packard Co
Contributed by David Mosberger-Tang <davidm@hpl.hp.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 "unwind_i.h"
#include "offsets.h"
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, 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;
/* Check if EIP points at sigreturn() sequence. On Linux, this is:
__restore:
0x58 pop %eax
0xb8 0x77 0x00 0x00 0x00 movl 0x77,%eax
0xcd 0x80 int 0x80
without SA_SIGINFO, and
__restore_rt:
0xb8 0xad 0x00 0x00 0x00 movl 0xad,%eax
0xcd 0x80 int 0x80
0x00
if SA_SIGINFO is specified.
*/
ip = c->dwarf.ip;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 4, &w1, 0, arg)) < 0)
return ret;
ret = ((w0 == 0x0077b858 && w1 == 0x80cd0000)
|| (w0 == 0x0000adb8 && (w1 & 0xffffff) == 0x80cd00));
Debug (16, "returning %d\n", ret);
return ret;
}
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
int ret;
/* c->esp points at the arguments to the handler. Without
SA_SIGINFO, the arguments consist of a signal number
followed by a struct sigcontext. With SA_SIGINFO, the
arguments consist a signal number, a siginfo *, and a
ucontext *. */
unw_word_t sc_addr;
unw_word_t siginfo_ptr_addr = c->dwarf.cfa + 4;
unw_word_t sigcontext_ptr_addr = c->dwarf.cfa + 8;
unw_word_t siginfo_ptr, sigcontext_ptr;
struct dwarf_loc esp_loc, siginfo_ptr_loc, sigcontext_ptr_loc;
siginfo_ptr_loc = DWARF_LOC (siginfo_ptr_addr, 0);
sigcontext_ptr_loc = DWARF_LOC (sigcontext_ptr_addr, 0);
ret = (dwarf_get (&c->dwarf, siginfo_ptr_loc, &siginfo_ptr)
| dwarf_get (&c->dwarf, sigcontext_ptr_loc, &sigcontext_ptr));
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
if (siginfo_ptr < c->dwarf.cfa
|| siginfo_ptr > c->dwarf.cfa + 256
|| sigcontext_ptr < c->dwarf.cfa
|| sigcontext_ptr > c->dwarf.cfa + 256)
{
/* Not plausible for SA_SIGINFO signal */
c->sigcontext_format = X86_SCF_LINUX_SIGFRAME;
c->sigcontext_addr = sc_addr = c->dwarf.cfa + 4;
}
else
{
/* If SA_SIGINFO were not specified, we actually read
various segment pointers instead. We believe that at
least fs and _fsh are always zero for linux, so it is
not just unlikely, but impossible that we would end
up here. */
c->sigcontext_format = X86_SCF_LINUX_RT_SIGFRAME;
c->sigcontext_addr = sigcontext_ptr;
sc_addr = sigcontext_ptr + LINUX_UC_MCONTEXT_OFF;
}
esp_loc = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
c->dwarf.loc[EAX] = DWARF_LOC (sc_addr + LINUX_SC_EAX_OFF, 0);
c->dwarf.loc[ECX] = DWARF_LOC (sc_addr + LINUX_SC_ECX_OFF, 0);
c->dwarf.loc[EDX] = DWARF_LOC (sc_addr + LINUX_SC_EDX_OFF, 0);
c->dwarf.loc[EBX] = DWARF_LOC (sc_addr + LINUX_SC_EBX_OFF, 0);
c->dwarf.loc[EBP] = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0);
c->dwarf.loc[ESI] = DWARF_LOC (sc_addr + LINUX_SC_ESI_OFF, 0);
c->dwarf.loc[EDI] = DWARF_LOC (sc_addr + LINUX_SC_EDI_OFF, 0);
c->dwarf.loc[EFLAGS] = DWARF_NULL_LOC;
c->dwarf.loc[TRAPNO] = DWARF_NULL_LOC;
c->dwarf.loc[ST0] = DWARF_NULL_LOC;
c->dwarf.loc[EIP] = DWARF_LOC (sc_addr + LINUX_SC_EIP_OFF, 0);
c->dwarf.loc[ESP] = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
return 0;
}

View file

@ -29,10 +29,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
#include <sys/types.h>
#include <signal.h>
#ifdef __FreeBSD__
#include <ucontext.h>
#include <machine/sigframe.h>
#endif
#include "unwind_i.h"
#include "offsets.h"
@ -66,122 +62,15 @@ unw_step (unw_cursor_t *cursor)
Debug (13, "dwarf_step() failed (ret=%d), trying frame-chain\n", ret);
format = unw_is_signal_frame (cursor);
if (format < 0) {
Debug (13, "unw_is_signal_frame() failed (ret=%d)\n", ret);
return format;
}
if (format != X86_SCF_NONE)
{
#if defined __linux__
/* XXX This code is Linux-specific! */
/* c->esp points at the arguments to the handler. Without
SA_SIGINFO, the arguments consist of a signal number
followed by a struct sigcontext. With SA_SIGINFO, the
arguments consist a signal number, a siginfo *, and a
ucontext *. */
unw_word_t sc_addr;
unw_word_t siginfo_ptr_addr = c->dwarf.cfa + 4;
unw_word_t sigcontext_ptr_addr = c->dwarf.cfa + 8;
unw_word_t siginfo_ptr, sigcontext_ptr;
struct dwarf_loc esp_loc, siginfo_ptr_loc, sigcontext_ptr_loc;
siginfo_ptr_loc = DWARF_LOC (siginfo_ptr_addr, 0);
sigcontext_ptr_loc = DWARF_LOC (sigcontext_ptr_addr, 0);
ret = (dwarf_get (&c->dwarf, siginfo_ptr_loc, &siginfo_ptr)
| dwarf_get (&c->dwarf, sigcontext_ptr_loc, &sigcontext_ptr));
if (unw_is_signal_frame (cursor))
{
ret = unw_handle_signal_frame(cursor);
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
if (siginfo_ptr < c->dwarf.cfa
|| siginfo_ptr > c->dwarf.cfa + 256
|| sigcontext_ptr < c->dwarf.cfa
|| sigcontext_ptr > c->dwarf.cfa + 256)
{
/* Not plausible for SA_SIGINFO signal */
c->sigcontext_format = X86_SCF_LINUX_SIGFRAME;
c->sigcontext_addr = sc_addr = c->dwarf.cfa + 4;
}
else
{
/* If SA_SIGINFO were not specified, we actually read
various segment pointers instead. We believe that at
least fs and _fsh are always zero for linux, so it is
not just unlikely, but impossible that we would end
up here. */
c->sigcontext_format = X86_SCF_LINUX_RT_SIGFRAME;
c->sigcontext_addr = sigcontext_ptr;
sc_addr = sigcontext_ptr + LINUX_UC_MCONTEXT_OFF;
}
esp_loc = DWARF_LOC (sc_addr + LINUX_SC_ESP_OFF, 0);
ebp_loc = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0);
eip_loc = DWARF_LOC (sc_addr + LINUX_SC_EIP_OFF, 0);
ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
c->dwarf.loc[EAX] = DWARF_LOC (sc_addr + LINUX_SC_EAX_OFF, 0);
c->dwarf.loc[ECX] = DWARF_LOC (sc_addr + LINUX_SC_ECX_OFF, 0);
c->dwarf.loc[EDX] = DWARF_LOC (sc_addr + LINUX_SC_EDX_OFF, 0);
c->dwarf.loc[EBX] = DWARF_LOC (sc_addr + LINUX_SC_EBX_OFF, 0);
c->dwarf.loc[EBP] = DWARF_LOC (sc_addr + LINUX_SC_EBP_OFF, 0);
c->dwarf.loc[ESI] = DWARF_LOC (sc_addr + LINUX_SC_ESI_OFF, 0);
c->dwarf.loc[EDI] = DWARF_LOC (sc_addr + LINUX_SC_EDI_OFF, 0);
c->dwarf.loc[EFLAGS] = DWARF_NULL_LOC;
c->dwarf.loc[TRAPNO] = DWARF_NULL_LOC;
c->dwarf.loc[ST0] = DWARF_NULL_LOC;
#elif defined __FreeBSD__
if (format == X86_SCF_FREEBSD_SIGFRAME) {
struct sigframe *sf;
uintptr_t uc_addr;
struct dwarf_loc esp_loc;
sf = (struct sigframe *)c->dwarf.cfa;
uc_addr = (uintptr_t)&(sf->sf_uc);
esp_loc = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_ESP_OFF, 0);
ret = dwarf_get (&c->dwarf, esp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning 0\n");
return 0;
}
ebp_loc = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EBP_OFF, 0);
eip_loc = DWARF_LOC (uc_addr + FREEBSD_UC_MCONTEXT_EIP_OFF, 0);
c->dwarf.loc[EAX] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_EAX_OFF, 0);
c->dwarf.loc[ECX] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_ECX_OFF, 0);
c->dwarf.loc[EDX] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_EDX_OFF, 0);
c->dwarf.loc[EBX] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_EBX_OFF, 0);
c->dwarf.loc[EBP] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_EBP_OFF, 0);
c->dwarf.loc[ESI] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_ESI_OFF, 0);
c->dwarf.loc[EDI] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_EDI_OFF, 0);
c->dwarf.loc[EFLAGS] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_EFLAGS_OFF, 0);
c->dwarf.loc[TRAPNO] = DWARF_LOC (uc_addr +
FREEBSD_UC_MCONTEXT_EFLAGS_OFF, 0);
c->dwarf.loc[ST0] = DWARF_NULL_LOC;
} else {
Debug (8, "Gstep: not handling frame format %d\n", format);
abort();
}
#else
#error Port me
#endif
}
}
else
{
ret = dwarf_get (&c->dwarf, c->dwarf.loc[EBP], &c->dwarf.cfa);
@ -203,9 +92,10 @@ unw_step (unw_cursor_t *cursor)
EIP. */
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
c->dwarf.loc[i] = DWARF_NULL_LOC;
c->dwarf.loc[EBP] = ebp_loc;
c->dwarf.loc[EIP] = eip_loc;
}
c->dwarf.loc[EBP] = ebp_loc;
c->dwarf.loc[EIP] = eip_loc;
c->dwarf.ret_addr_column = EIP;
if (!DWARF_IS_NULL_LOC (c->dwarf.loc[EBP]))

View file

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

5
src/x86/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

130
src/x86_64/Gos-freebsd.c Normal file
View file

@ -0,0 +1,130 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2010 Konstantin Belousov <kib@freebsd.org>
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. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/ucontext.h>
#include <machine/sigframe.h>
#include <signal.h>
#include <stddef.h>
#include "unwind_i.h"
#include "ucontext_i.h"
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
/* XXXKIB */
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, w2, b0, 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;
/* Check if RIP points at sigreturn sequence.
48 8d 7c 24 10 lea SIGF_UC(%rsp),%rdi
6a 00 pushq $0
48 c7 c0 a1 01 00 00 movq $SYS_sigreturn,%rax
0f 05 syscall
f4 0: hlt
eb fd jmp 0b
*/
ip = c->dwarf.ip;
c->sigcontext_format = X86_64_SCF_NONE;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 16, &w2, 0, arg)) < 0)
return 0;
w2 &= 0xffffff;
if (w0 == 0x48006a10247c8d48 &&
w1 == 0x050f000001a1c0c7 &&
w2 == 0x0000000000fdebf4)
{
c->sigcontext_format = X86_64_SCF_FREEBSD_SIGFRAME;
return (c->sigcontext_format);
}
/* Check if RIP points at standard syscall sequence.
49 89 ca mov %rcx,%r10
0f 05 syscall
*/
if ((ret = (*a->access_mem) (as, ip - 5, &b0, 0, arg)) < 0)
return (0);
b0 &= 0xffffffffff;
if (b0 == 0x000000050fca8949)
{
c->sigcontext_format = X86_64_SCF_FREEBSD_SYSCALL;
return (c->sigcontext_format);
}
return (X86_64_SCF_NONE);
}
PROTECTED int
unw_handle_signal_frame (unw_cursor_t *cursor)
{
struct cursor *c = (struct cursor *) cursor;
unw_word_t ucontext;
int ret;
if (c->sigcontext_format == X86_64_SCF_FREEBSD_SIGFRAME)
ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc);
else
return -UNW_EBADFRAME;
Debug(1, "signal frame, skip over trampoline\n");
struct dwarf_loc rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning %d\n", ret);
return ret;
}
c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0);
c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0);
c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0);
c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0);
c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0);
c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0);
c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
c->dwarf.loc[RSP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0);
c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0);
c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0);
c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0);
c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0);
c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0);
c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0);
c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0);
c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
return 0;
}

View file

@ -26,8 +26,8 @@ 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 "unwind_i.h"
#include "ucontext_i.h"
#ifdef __linux__
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
@ -54,63 +54,46 @@ unw_is_signal_frame (unw_cursor_t *cursor)
|| (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0)
return 0;
w1 &= 0xff;
return (w0 == 0x0f0000000fc0c748 && w1 == 0x05) ?
X86_64_SCF_LINUX_RT_SIGFRAME : X86_64_SCF_NONE;
return (w0 == 0x0f0000000fc0c748 && w1 == 0x05);
}
#elif defined(__FreeBSD__)
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
unw_handle_signal_frame (unw_cursor_t *cursor)
{
/* XXXKIB */
struct cursor *c = (struct cursor *) cursor;
unw_word_t w0, w1, w2, b0, ip;
unw_addr_space_t as;
unw_accessors_t *a;
void *arg;
int ret;
unw_word_t ucontext = c->dwarf.cfa;
as = c->dwarf.as;
a = unw_get_accessors (as);
arg = c->dwarf.as_arg;
Debug(1, "signal frame, skip over trampoline\n");
/* Check if RIP points at sigreturn sequence.
48 8d 7c 24 10 lea SIGF_UC(%rsp),%rdi
6a 00 pushq $0
48 c7 c0 a1 01 00 00 movq $SYS_sigreturn,%rax
0f 05 syscall
f4 0: hlt
eb fd jmp 0b
*/
c->sigcontext_format = X86_64_SCF_LINUX_RT_SIGFRAME;
c->sigcontext_addr = c->dwarf.cfa;
ip = c->dwarf.ip;
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 8, &w1, 0, arg)) < 0
|| (ret = (*a->access_mem) (as, ip + 16, &w2, 0, arg)) < 0)
return 0;
w2 &= 0xffffff;
if (w0 == 0x48006a10247c8d48 &&
w1 == 0x050f000001a1c0c7 &&
w2 == 0x0000000000fdebf4)
return X86_64_SCF_FREEBSD_SIGFRAME;
/* Check if RIP points at standard syscall sequence.
49 89 ca mov %rcx,%r10
0f 05 syscall
*/
if ((ret = (*a->access_mem) (as, ip - 5, &b0, 0, arg)) < 0)
return (0);
b0 &= 0xffffffffff;
if (b0 == 0x000000050fca8949)
return X86_64_SCF_FREEBSD_SYSCALL;
return X86_64_SCF_NONE;
struct dwarf_loc rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
if (ret < 0)
{
Debug (2, "returning %d\n", ret);
return ret;
}
c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0);
c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0);
c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0);
c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0);
c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0);
c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0);
c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
c->dwarf.loc[RSP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0);
c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0);
c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0);
c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0);
c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0);
c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0);
c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0);
c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0);
c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
return 0;
}
#else /* !__linux__ && !__FreeBSD__ */
PROTECTED int
unw_is_signal_frame (unw_cursor_t *cursor)
{
printf ("%s: implement me\n", __FUNCTION__);
return -UNW_ENOINFO;
}
#endif

View file

@ -26,15 +26,9 @@ 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 "unwind_i.h"
#include "ucontext_i.h"
#include <signal.h>
#include <stddef.h>
#if defined __FreeBSD__
#include <sys/ucontext.h>
#include <machine/sigframe.h>
#endif
PROTECTED int
unw_step (unw_cursor_t *cursor)
{
@ -102,49 +96,12 @@ unw_step (unw_cursor_t *cursor)
return 1;
} else if (c->sigcontext_format != X86_64_SCF_NONE)
{
unw_word_t ucontext;
Debug(1, "signal frame, skip over trampoline\n");
#if defined __linux__
ucontext = c->dwarf.cfa;
if (c->sigcontext_format != X86_64_SCF_LINUX_RT_SIGFRAME)
return -UNW_EBADFRAME;
#elif defined __FreeBSD__
if (c->sigcontext_format == X86_64_SCF_FREEBSD_SIGFRAME)
ucontext = c->dwarf.cfa + offsetof(struct sigframe, sf_uc);
else
return -UNW_EBADFRAME;
#endif
c->sigcontext_addr = c->dwarf.cfa;
rsp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSP, 0);
rbp_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
rip_loc = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
ret = dwarf_get (&c->dwarf, rsp_loc, &c->dwarf.cfa);
ret = unw_handle_signal_frame(cursor);
if (ret < 0)
{
Debug (2, "returning %d\n", ret);
return ret;
Debug (2, "returning 0\n");
return 0;
}
c->dwarf.loc[RAX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RAX, 0);
c->dwarf.loc[RDX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDX, 0);
c->dwarf.loc[RCX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RCX, 0);
c->dwarf.loc[RBX] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBX, 0);
c->dwarf.loc[RSI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RSI, 0);
c->dwarf.loc[RDI] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RDI, 0);
c->dwarf.loc[RBP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RBP, 0);
c->dwarf.loc[ R8] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R8, 0);
c->dwarf.loc[ R9] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R9, 0);
c->dwarf.loc[R10] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R10, 0);
c->dwarf.loc[R11] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R11, 0);
c->dwarf.loc[R12] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R12, 0);
c->dwarf.loc[R13] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R13, 0);
c->dwarf.loc[R14] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R14, 0);
c->dwarf.loc[R15] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_R15, 0);
c->dwarf.loc[RIP] = DWARF_LOC (ucontext + UC_MCONTEXT_GREGS_RIP, 0);
}
else
{
@ -185,11 +142,12 @@ unw_step (unw_cursor_t *cursor)
/* Mark all registers unsaved */
for (i = 0; i < DWARF_NUM_PRESERVED_REGS; ++i)
c->dwarf.loc[i] = DWARF_NULL_LOC;
c->dwarf.loc[RBP] = rbp_loc;
c->dwarf.loc[RSP] = rsp_loc;
c->dwarf.loc[RIP] = rip_loc;
}
c->dwarf.loc[RBP] = rbp_loc;
c->dwarf.loc[RSP] = rsp_loc;
c->dwarf.loc[RIP] = rip_loc;
c->dwarf.ret_addr_column = RIP;
if (!DWARF_IS_NULL_LOC (c->dwarf.loc[RBP]))

5
src/x86_64/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/x86_64/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

View file

@ -83,6 +83,7 @@ check_local_unw_abi () {
match _UL${plat}_init_local
match _UL${plat}_init_remote
match _UL${plat}_is_signal_frame
match _UL${plat}_handle_signal_frame
match _UL${plat}_local_addr_space
match _UL${plat}_resume
match _UL${plat}_set_caching_policy
@ -144,6 +145,7 @@ check_generic_unw_abi () {
match _U${plat}_init_local
match _U${plat}_init_remote
match _U${plat}_is_signal_frame
match _U${plat}_handle_signal_frame
match _U${plat}_local_addr_space
match _U${plat}_regname
match _U${plat}_resume