mirror of
https://github.com/tobast/libunwind-eh_elf.git
synced 2024-11-21 23:27:39 +01:00
Support powerpc64le-linux platform
This patch adds support for the powerpc64le-linux platform. It consists of two main features: - Support little-endian byte order This is done via a "big_endian" member of struct unw_addr_space, which is evaluated by common code via the dwarf_is_big_endian macro, and also in endian-aware code in unw_is_signal_frame. - Support the ELFv2 ABI This is done via an "abi" member of struct unw_addr_space. This is currently only needed in tdep_get_func_addr, since the ELFv2 ABI does not use function descriptors. Both new members are initialized in unw_create_addr_space and ppc64_local_addr_space_init, following the mips precedent. Since ppc32 and ppc64 now no longer share the unw_create_addr_space implementation, the file is duplicated from the ppc directory into ppc32/ppc64. Tested on powerpc64-linux and powerpc64le-linux. Support on LE seems to be as good as existing BE support; I have not attempted to fix the existing shortcomings of PPC support that already cause a number to tests to fail due to unimplemented features. Signed-off-by: Ulrich Weigand <uweigand@de.ibm.com>
This commit is contained in:
parent
4c62c4a955
commit
da0b1a146f
11 changed files with 130 additions and 17 deletions
|
@ -222,6 +222,13 @@ typedef enum
|
||||||
}
|
}
|
||||||
ppc64_regnum_t;
|
ppc64_regnum_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
UNW_PPC64_ABI_ELFv1,
|
||||||
|
UNW_PPC64_ABI_ELFv2
|
||||||
|
}
|
||||||
|
ppc64_abi_t;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* According to David Edelsohn, GNU gcc uses R3, R4, R5, and maybe R6 for
|
* According to David Edelsohn, GNU gcc uses R3, R4, R5, and maybe R6 for
|
||||||
* passing parameters to exception handlers.
|
* passing parameters to exception handlers.
|
||||||
|
|
|
@ -38,7 +38,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
#define DWARF_REGNUM_MAP_LENGTH 115
|
#define DWARF_REGNUM_MAP_LENGTH 115
|
||||||
|
|
||||||
/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */
|
/* Return TRUE if the ADDR_SPACE uses big-endian byte-order. */
|
||||||
#define dwarf_is_big_endian(addr_space) 1
|
#define dwarf_is_big_endian(addr_space) ((addr_space)->big_endian)
|
||||||
|
|
||||||
/* Convert a pointer to a dwarf_cursor structure to a pointer to
|
/* Convert a pointer to a dwarf_cursor structure to a pointer to
|
||||||
unw_cursor_t. */
|
unw_cursor_t. */
|
||||||
|
|
|
@ -51,6 +51,8 @@ unw_tdep_frame_t;
|
||||||
struct unw_addr_space
|
struct unw_addr_space
|
||||||
{
|
{
|
||||||
struct unw_accessors acc;
|
struct unw_accessors acc;
|
||||||
|
int big_endian;
|
||||||
|
ppc64_abi_t abi;
|
||||||
unw_caching_policy_t caching_policy;
|
unw_caching_policy_t caching_policy;
|
||||||
#ifdef HAVE_ATOMIC_OPS_H
|
#ifdef HAVE_ATOMIC_OPS_H
|
||||||
AO_t cache_generation;
|
AO_t cache_generation;
|
||||||
|
@ -289,7 +291,7 @@ extern int tdep_fetch_proc_info_post (struct dwarf_cursor *c, unw_word_t ip,
|
||||||
#define tdep_get_as(c) ((c)->dwarf.as)
|
#define tdep_get_as(c) ((c)->dwarf.as)
|
||||||
#define tdep_get_as_arg(c) ((c)->dwarf.as_arg)
|
#define tdep_get_as_arg(c) ((c)->dwarf.as_arg)
|
||||||
#define tdep_get_ip(c) ((c)->dwarf.ip)
|
#define tdep_get_ip(c) ((c)->dwarf.ip)
|
||||||
#define tdep_big_endian(as) 1
|
#define tdep_big_endian(as) ((as)->big_endian)
|
||||||
|
|
||||||
extern int tdep_init_done;
|
extern int tdep_init_done;
|
||||||
|
|
||||||
|
|
|
@ -342,12 +342,12 @@ libunwind_x86_64_la_SOURCES_x86_64 = $(libunwind_la_SOURCES_x86_64_common) \
|
||||||
x86_64/Gstash_frame.c x86_64/Gstep.c x86_64/Gtrace.c
|
x86_64/Gstash_frame.c x86_64/Gstep.c x86_64/Gtrace.c
|
||||||
|
|
||||||
# The list of local files that go to Power 64 and 32:
|
# The list of local files that go to Power 64 and 32:
|
||||||
libunwind_la_SOURCES_ppc = ppc/Lcreate_addr_space.c \
|
libunwind_la_SOURCES_ppc = \
|
||||||
ppc/Lget_proc_info.c ppc/Lget_save_loc.c ppc/Linit_local.c \
|
ppc/Lget_proc_info.c ppc/Lget_save_loc.c ppc/Linit_local.c \
|
||||||
ppc/Linit_remote.c ppc/Lis_signal_frame.c
|
ppc/Linit_remote.c ppc/Lis_signal_frame.c
|
||||||
|
|
||||||
# The list of generic files that go to Power 64 and 32:
|
# The list of generic files that go to Power 64 and 32:
|
||||||
libunwind_ppc_la_SOURCES_ppc_generic = ppc/Gcreate_addr_space.c \
|
libunwind_ppc_la_SOURCES_ppc_generic = \
|
||||||
ppc/Gget_proc_info.c ppc/Gget_save_loc.c ppc/Ginit_local.c \
|
ppc/Gget_proc_info.c ppc/Gget_save_loc.c ppc/Ginit_local.c \
|
||||||
ppc/Ginit_remote.c ppc/Gis_signal_frame.c
|
ppc/Ginit_remote.c ppc/Gis_signal_frame.c
|
||||||
|
|
||||||
|
@ -360,6 +360,7 @@ libunwind_la_SOURCES_ppc32_common = $(libunwind_la_SOURCES_common) \
|
||||||
libunwind_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \
|
libunwind_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \
|
||||||
$(libunwind_la_SOURCES_local) \
|
$(libunwind_la_SOURCES_local) \
|
||||||
$(libunwind_la_SOURCES_ppc) \
|
$(libunwind_la_SOURCES_ppc) \
|
||||||
|
ppc32/Lcreate_addr_space.c \
|
||||||
ppc32/Lglobal.c ppc32/Linit.c \
|
ppc32/Lglobal.c ppc32/Linit.c \
|
||||||
ppc32/Lregs.c ppc32/Lresume.c ppc32/Lstep.c
|
ppc32/Lregs.c ppc32/Lresume.c ppc32/Lstep.c
|
||||||
|
|
||||||
|
@ -367,6 +368,7 @@ libunwind_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \
|
||||||
libunwind_ppc32_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \
|
libunwind_ppc32_la_SOURCES_ppc32 = $(libunwind_la_SOURCES_ppc32_common) \
|
||||||
$(libunwind_la_SOURCES_generic) \
|
$(libunwind_la_SOURCES_generic) \
|
||||||
$(libunwind_ppc_la_SOURCES_ppc_generic) \
|
$(libunwind_ppc_la_SOURCES_ppc_generic) \
|
||||||
|
ppc32/Gcreate_addr_space.c \
|
||||||
ppc32/Gglobal.c ppc32/Ginit.c \
|
ppc32/Gglobal.c ppc32/Ginit.c \
|
||||||
ppc32/Gregs.c ppc32/Gresume.c ppc32/Gstep.c
|
ppc32/Gregs.c ppc32/Gresume.c ppc32/Gstep.c
|
||||||
|
|
||||||
|
@ -379,6 +381,7 @@ libunwind_la_SOURCES_ppc64_common = $(libunwind_la_SOURCES_common) \
|
||||||
libunwind_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \
|
libunwind_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \
|
||||||
$(libunwind_la_SOURCES_local) \
|
$(libunwind_la_SOURCES_local) \
|
||||||
$(libunwind_la_SOURCES_ppc) \
|
$(libunwind_la_SOURCES_ppc) \
|
||||||
|
ppc64/Lcreate_addr_space.c \
|
||||||
ppc64/Lglobal.c ppc64/Linit.c \
|
ppc64/Lglobal.c ppc64/Linit.c \
|
||||||
ppc64/Lregs.c ppc64/Lresume.c ppc64/Lstep.c
|
ppc64/Lregs.c ppc64/Lresume.c ppc64/Lstep.c
|
||||||
|
|
||||||
|
@ -386,6 +389,7 @@ libunwind_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \
|
||||||
libunwind_ppc64_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \
|
libunwind_ppc64_la_SOURCES_ppc64 = $(libunwind_la_SOURCES_ppc64_common) \
|
||||||
$(libunwind_la_SOURCES_generic) \
|
$(libunwind_la_SOURCES_generic) \
|
||||||
$(libunwind_ppc_la_SOURCES_ppc_generic) \
|
$(libunwind_ppc_la_SOURCES_ppc_generic) \
|
||||||
|
ppc64/Gcreate_addr_space.c \
|
||||||
ppc64/Gglobal.c ppc64/Ginit.c \
|
ppc64/Gglobal.c ppc64/Ginit.c \
|
||||||
ppc64/Gregs.c ppc64/Gresume.c ppc64/Gstep.c
|
ppc64/Gregs.c ppc64/Gresume.c ppc64/Gstep.c
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ PROTECTED int
|
||||||
unw_is_signal_frame (unw_cursor_t * cursor)
|
unw_is_signal_frame (unw_cursor_t * cursor)
|
||||||
{
|
{
|
||||||
struct cursor *c = (struct cursor *) cursor;
|
struct cursor *c = (struct cursor *) cursor;
|
||||||
unw_word_t w0, w1, ip;
|
unw_word_t w0, w1, i0, i1, i2, ip;
|
||||||
unw_addr_space_t as;
|
unw_addr_space_t as;
|
||||||
unw_accessors_t *a;
|
unw_accessors_t *a;
|
||||||
void *arg;
|
void *arg;
|
||||||
|
@ -60,7 +60,19 @@ unw_is_signal_frame (unw_cursor_t * cursor)
|
||||||
if ((ret = (*a->access_mem) (as, ip, &w0, 0, arg)) < 0
|
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 + 8, &w1, 0, arg)) < 0)
|
||||||
return 0;
|
return 0;
|
||||||
w1 >>= 32;
|
|
||||||
return (w0 == 0x38210080380000ac && w1 == 0x44000002);
|
|
||||||
|
|
||||||
|
if (tdep_big_endian (as))
|
||||||
|
{
|
||||||
|
i0 = w0 >> 32;
|
||||||
|
i1 = w0 & 0xffffffffUL;
|
||||||
|
i2 = w1 >> 32;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i0 = w0 & 0xffffffffUL;
|
||||||
|
i1 = w0 >> 32;
|
||||||
|
i2 = w1 & 0xffffffffUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (i0 == 0x38210080 && i1 == 0x380000ac && i2 == 0x44000002);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,7 +38,7 @@ unw_create_addr_space (unw_accessors_t *a, int byte_order)
|
||||||
unw_addr_space_t as;
|
unw_addr_space_t as;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Linux ppc64 supports only big-endian.
|
* We support only big-endian on Linux ppc32.
|
||||||
*/
|
*/
|
||||||
if (byte_order != 0 && byte_order != __BIG_ENDIAN)
|
if (byte_order != 0 && byte_order != __BIG_ENDIAN)
|
||||||
return NULL;
|
return NULL;
|
71
src/ppc64/Gcreate_addr_space.c
Normal file
71
src/ppc64/Gcreate_addr_space.c
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
/* libunwind - a platform-independent unwind library
|
||||||
|
Copyright (C) 2006-2007 IBM
|
||||||
|
Contributed by
|
||||||
|
Corey Ashford <cjashfor@us.ibm.com>
|
||||||
|
Jose Flavio Aguilar Paulino <jflavio@br.ibm.com> <joseflavio@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 <stdlib.h>
|
||||||
|
|
||||||
|
#include <libunwind_i.h>
|
||||||
|
|
||||||
|
PROTECTED unw_addr_space_t
|
||||||
|
unw_create_addr_space (unw_accessors_t *a, int byte_order)
|
||||||
|
{
|
||||||
|
#ifdef UNW_LOCAL_ONLY
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
unw_addr_space_t as;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We support both big- and little-endian on Linux ppc64.
|
||||||
|
*/
|
||||||
|
if (byte_order != 0
|
||||||
|
&& byte_order != __LITTLE_ENDIAN
|
||||||
|
&& byte_order != __BIG_ENDIAN)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
as = malloc (sizeof (*as));
|
||||||
|
if (!as)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
memset (as, 0, sizeof (*as));
|
||||||
|
|
||||||
|
as->acc = *a;
|
||||||
|
|
||||||
|
if (byte_order == 0)
|
||||||
|
/* use host default: */
|
||||||
|
as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
|
||||||
|
else
|
||||||
|
as->big_endian = (byte_order == __BIG_ENDIAN);
|
||||||
|
|
||||||
|
/* FIXME! There is no way to specify the ABI.
|
||||||
|
Default to ELFv1 on big-endian and ELFv2 on little-endian. */
|
||||||
|
if (as->big_endian)
|
||||||
|
as->abi = UNW_PPC64_ABI_ELFv1;
|
||||||
|
else
|
||||||
|
as->abi = UNW_PPC64_ABI_ELFv2;
|
||||||
|
|
||||||
|
return as;
|
||||||
|
#endif
|
||||||
|
}
|
|
@ -210,6 +210,12 @@ HIDDEN void
|
||||||
ppc64_local_addr_space_init (void)
|
ppc64_local_addr_space_init (void)
|
||||||
{
|
{
|
||||||
memset (&local_addr_space, 0, sizeof (local_addr_space));
|
memset (&local_addr_space, 0, sizeof (local_addr_space));
|
||||||
|
local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
|
||||||
|
#if _CALL_ELF == 2
|
||||||
|
local_addr_space.abi = UNW_PPC64_ABI_ELFv2;
|
||||||
|
#else
|
||||||
|
local_addr_space.abi = UNW_PPC64_ABI_ELFv1;
|
||||||
|
#endif
|
||||||
local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
|
local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
|
||||||
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
|
local_addr_space.acc.find_proc_info = dwarf_find_proc_info;
|
||||||
local_addr_space.acc.put_unwind_info = put_unwind_info;
|
local_addr_space.acc.put_unwind_info = put_unwind_info;
|
||||||
|
|
5
src/ppc64/Lcreate_addr_space.c
Normal file
5
src/ppc64/Lcreate_addr_space.c
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#define UNW_LOCAL_ONLY
|
||||||
|
#include <libunwind.h>
|
||||||
|
#if defined(UNW_LOCAL_ONLY) && !defined(UNW_REMOTE_ONLY)
|
||||||
|
#include "Gcreate_addr_space.c"
|
||||||
|
#endif
|
|
@ -31,15 +31,21 @@ int
|
||||||
tdep_get_func_addr (unw_addr_space_t as, unw_word_t addr,
|
tdep_get_func_addr (unw_addr_space_t as, unw_word_t addr,
|
||||||
unw_word_t *entry_point)
|
unw_word_t *entry_point)
|
||||||
{
|
{
|
||||||
unw_accessors_t *a;
|
if (as->abi == UNW_PPC64_ABI_ELFv1)
|
||||||
int ret;
|
{
|
||||||
|
unw_accessors_t *a;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
a = unw_get_accessors (as);
|
||||||
|
/* Entry-point is stored in the 1st word of the function descriptor.
|
||||||
|
In case that changes in the future, we'd have to update the line
|
||||||
|
below and read the word at addr + offset: */
|
||||||
|
ret = (*a->access_mem) (as, addr, entry_point, 0, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*entry_point = addr;
|
||||||
|
|
||||||
a = unw_get_accessors (as);
|
|
||||||
/* Entry-point is stored in the 1st word of the function descriptor.
|
|
||||||
In case that changes in the future, we'd have to update the line
|
|
||||||
below and read the word at addr + offset: */
|
|
||||||
ret = (*a->access_mem) (as, addr, entry_point, 0, NULL);
|
|
||||||
if (ret < 0)
|
|
||||||
return ret;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue