1
0
Fork 0
mirror of https://github.com/tobast/libunwind-eh_elf.git synced 2025-01-10 19:23:41 +01:00

Initial revision

This commit is contained in:
mostang.com!davidm 2002-12-12 09:17:41 +00:00
parent 86f8635442
commit 793c8a3005
49 changed files with 0 additions and 3968 deletions

View file

@ -1,116 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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. */
#define IA64_LOG_UNW_CACHE_SIZE 7
#define IA64_UNW_CACHE_SIZE (1 << IA64_LOG_UNW_CACHE_SIZE)
#define IA64_LOG_UNW_HASH_SIZE (IA64_LOG_UNW_CACHE_SIZE + 1)
#define IA64_UNW_HASH_SIZE (1 << IA64_LOG_UNW_HASH_SIZE)
typedef unsigned char unw_hash_index_t;
enum ia64_script_insn_opcode
{
IA64_INSN_SET, /* s[dst] = val */
IA64_INSN_ADD, /* s[dst] += val */
IA64_INSN_ADD_PSP, /* s[dst] = (s.psp + val) */
IA64_INSN_ADD_SP, /* s[dst] = (s.sp + val) */
IA64_INSN_MOVE, /* s[dst] = s[val] */
IA64_INSN_MOVE_STACKED, /* s[dst] = ia64_rse_skip(*s.bsp_loc, val) */
IA64_INSN_MOVE_SCRATCH, /* s[dst] = scratch reg "val" */
IA64_INSN_SETNAT_MEMSTK, /* s[dst].nat.type = s.pri_unat_loc | MEMSTK */
IA64_INSN_LOAD /* s[dst] = *s[val] */
};
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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. */
struct ia64_script_insn
{
unsigned int opc;
unsigned int dst;
unw_word_t val;
};
/* Preserved general static registers (r4-r7) give rise to two script
instructions; everything else yields at most one instruction; at
the end of the script, the psp gets popped, accounting for one more
instruction. */
#define IA64_MAX_SCRIPT_LEN (IA64_NUM_PREGS + 5)
struct ia64_script
{
unw_word_t ip; /* ip this script is for */
unw_word_t pr_mask; /* mask of predicates script depends on */
unw_word_t pr_val; /* predicate values this script is for */
unw_proc_info_t pi; /* info about underlying procedure */
unsigned short lru_chain; /* used for least-recently-used chain */
unsigned short coll_chain; /* used for hash collisions */
unsigned short hint; /* hint for next script to try (or -1) */
unsigned short count; /* number of instructions in script */
struct ia64_script_insn insn[IA64_MAX_SCRIPT_LEN];
};
struct ia64_script_cache
{
unsigned short lru_head; /* index of lead-recently used script */
unsigned short lru_tail; /* index of most-recently used script */
/* hash table that maps instruction pointer to script index: */
unsigned short hash[IA64_UNW_HASH_SIZE];
uint32_t generation; /* generation number */
/* script cache: */
struct ia64_script buckets[IA64_UNW_CACHE_SIZE];
};
#define ia64_script_lookup UNW_OBJ(ia64_script_lookup)
struct ia64_cursor; /* forward declaration */
extern struct ia64_script *ia64_script_lookup (struct ia64_cursor *c);

View file

@ -1,182 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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. */
#ifndef internal_h
#define internal_h
/* Platform-independent libunwind-internal declarations. */
#include <assert.h>
#include <pthread.h>
#include <libunwind.h>
#include <tdep.h>
#ifdef __GNUC__
# define HIDDEN __attribute__((visibility ("hidden")))
#else
# define HIDDEN
#endif
/* Make it easy to write thread-safe code which may or may not be
linked against libpthread. The macros below can be used
unconditionally and if -lpthread is around, they'll call the
corresponding routines otherwise, they do nothing. */
#pragma weak pthread_mutex_lock
#pragma weak pthread_mutex_unlock
#define mutex_lock(l) (pthread_mutex_lock ? pthread_mutex_lock (l) : 0)
#define mutex_unlock(l) (pthread_mutex_unlock ? pthread_mutex_unlock (l) : 0)
#define UNWI_OBJ(fn) UNW_PASTE(UNW_PREFIX,UNW_PASTE(I,fn))
#define UNWI_ARCH_OBJ(fn) UNW_PASTE(UNW_PASTE(UNW_PASTE(_UI,UNW_TARGET),_), fn)
extern int UNWI_OBJ(find_dynamic_proc_info) (unw_addr_space_t as,
unw_word_t ip,
unw_proc_info_t *pi,
int need_unwind_info, void *arg);
extern int UNWI_ARCH_OBJ(extract_dynamic_proc_info) (unw_addr_space_t as,
unw_word_t ip,
unw_proc_info_t *pi,
unw_dyn_info_t *di,
int need_unwind_info,
void *arg);
extern void UNWI_OBJ(put_dynamic_unwind_info) (unw_addr_space_t as,
unw_proc_info_t *pi, void *arg);
extern int UNWI_ARCH_OBJ(dyn_remote_find_proc_info) (unw_addr_space_t as,
unw_word_t ip,
unw_proc_info_t *pi,
unw_word_t *generation,
int need_unwind_info,
void *arg);
extern void UNWI_ARCH_OBJ(dyn_remote_put_unwind_info) (unw_addr_space_t as,
unw_proc_info_t *pi,
void *arg);
extern int UNWI_ARCH_OBJ(get_proc_name) (unw_addr_space_t as,
unw_word_t ip, int is_local,
char *buf, size_t buf_len, void *arg);
#define unwi_find_dynamic_proc_info(as,ip,pi,n,arg) \
UNWI_OBJ(find_dynamic_proc_info)(as, ip, pi, n, arg)
#define unwi_extract_dynamic_proc_info(as,ip,pi,di,n,arg) \
UNWI_ARCH_OBJ(extract_dynamic_proc_info)(as, ip, pi, di, n, arg)
#define unwi_put_dynamic_unwind_info(as,pi,arg) \
UNWI_OBJ(put_dynamic_unwind_info)(as, pi, arg)
/* These handle the remote (cross-address-space) case of accessing
dynamic unwind info. */
#define unwi_dyn_remote_find_proc_info(as,i,p,g,n,arg) \
UNWI_ARCH_OBJ(dyn_remote_find_proc_info)(as, i, p, g, n, arg)
#define unwi_dyn_remote_put_unwind_info(as,p,arg) \
UNWI_ARCH_OBJ(dyn_remote_put_unwind_info)(as, p, arg)
#define unwi_get_proc_name(as,ip,l,b,s,arg) \
UNWI_ARCH_OBJ(get_proc_name)(as, ip, l, b, s, arg)
extern unw_dyn_info_list_t _U_dyn_info_list;
extern pthread_mutex_t _U_dyn_info_list_lock;
#define WSIZE (sizeof (unw_word_t))
static inline int
fetch8 (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, int8_t *valp, void *arg)
{
unw_word_t val, aligned_addr = *addr & -WSIZE, off = *addr - aligned_addr;
int ret;
*addr += 1;
ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg);
#if __BYTE_ORDER == __LITTLE_ENDIAN
val >>= 8*off;
#else
val >>= 8*(WSIZE - 1 - off);
#endif
*valp = val & 0xff;
return ret;
}
static inline int
fetch16 (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, int16_t *valp, void *arg)
{
unw_word_t val, aligned_addr = *addr & -WSIZE, off = *addr - aligned_addr;
int ret;
assert ((off & 0x1) == 0);
*addr += 2;
ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg);
#if __BYTE_ORDER == __LITTLE_ENDIAN
val >>= 8*off;
#else
val >>= 8*(WSIZE - 2 - off);
#endif
*valp = val & 0xffff;
return ret;
}
static inline int
fetch32 (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, int32_t *valp, void *arg)
{
unw_word_t val, aligned_addr = *addr & -WSIZE, off = *addr - aligned_addr;
int ret;
assert ((off & 0x3) == 0);
*addr += 4;
ret = (*a->access_mem) (as, aligned_addr, &val, 0, arg);
#if __BYTE_ORDER == __LITTLE_ENDIAN
val >>= 8*off;
#else
val >>= 8*(WSIZE - 4 - off);
#endif
*valp = val & 0xffffffff;
return ret;
}
static inline int
fetchw (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_word_t *valp, void *arg)
{
int ret;
ret = (*a->access_mem) (as, *addr, valp, 0, arg);
*addr += WSIZE;
return ret;
}
#endif /* internal_h */

View file

@ -1,93 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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. */
#ifndef TDEP_IA64_H
#define TDEP_IA64_H
/* Target-dependent definitions that are internal to libunwind but need
to be shared with target-independent code. */
#include <endian.h>
#include <libunwind.h>
enum ia64_pregnum
{
/* primary unat: */
IA64_REG_PRI_UNAT_GR,
IA64_REG_PRI_UNAT_MEM,
/* register stack */
IA64_REG_BSP, /* register stack pointer */
IA64_REG_BSPSTORE,
IA64_REG_PFS, /* previous function state */
IA64_REG_RNAT,
/* memory stack */
IA64_REG_PSP, /* previous memory stack pointer */
/* return pointer: */
IA64_REG_RP,
/* preserved registers: */
IA64_REG_R4, IA64_REG_R5, IA64_REG_R6, IA64_REG_R7,
IA64_REG_NAT4, IA64_REG_NAT5, IA64_REG_NAT6, IA64_REG_NAT7,
IA64_REG_UNAT, IA64_REG_PR, IA64_REG_LC, IA64_REG_FPSR,
IA64_REG_B1, IA64_REG_B2, IA64_REG_B3, IA64_REG_B4, IA64_REG_B5,
IA64_REG_F2, IA64_REG_F3, IA64_REG_F4, IA64_REG_F5,
IA64_REG_F16, IA64_REG_F17, IA64_REG_F18, IA64_REG_F19,
IA64_REG_F20, IA64_REG_F21, IA64_REG_F22, IA64_REG_F23,
IA64_REG_F24, IA64_REG_F25, IA64_REG_F26, IA64_REG_F27,
IA64_REG_F28, IA64_REG_F29, IA64_REG_F30, IA64_REG_F31,
IA64_NUM_PREGS
};
#include "ia64/script.h"
struct unw_addr_space
{
struct unw_accessors acc;
int big_endian;
unw_caching_policy_t caching_policy;
uint32_t cache_generation;
unw_word_t dyn_generation; /* see dyn-common.h */
struct ia64_script_cache global_cache;
};
extern int UNW_ARCH_OBJ (search_unwind_table) (unw_addr_space_t as,
unw_word_t ip,
unw_dyn_info_t *di,
unw_proc_info_t *pi,
int need_unwind_info,
void *arg);
extern void UNW_ARCH_OBJ (put_unwind_info) (unw_addr_space_t as,
unw_proc_info_t *pi, void *arg);
/* Platforms that support UNW_INFO_FORMAT_TABLE need to define
tdep_search_unwind_table. */
#define tdep_search_unwind_table(a,b,c,d,e,f) \
UNW_ARCH_OBJ(search_unwind_table) (a,b,c,d,e,f)
#define tdep_put_unwind_info(a,b,c) \
UNW_ARCH_OBJ(put_unwind_info)(a,b,c)
#endif /* TDEP_IA64_H */

View file

@ -1,60 +0,0 @@
#include <stdio.h>
#include "internal.h"
static inline int
local_find_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi,
int need_unwind_info, void *arg)
{
unw_dyn_info_t *di;
for (di = _U_dyn_info_list.first; di; di = di->next)
if (ip >= di->start_ip && ip < di->end_ip)
return unwi_extract_dynamic_proc_info (as, ip, pi, di, need_unwind_info,
arg);
return -UNW_ENOINFO;
}
static inline int
remote_find_proc_info (unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi,
int need_unwind_info, void *arg)
{
unw_word_t generation;
int ret;
ret = unwi_dyn_remote_find_proc_info (as, ip, pi, &generation,
need_unwind_info, arg);
if (ret < 0)
return ret;
/* Note: this can't go into dyn-remote.c because that file get's
compiled exactly once (there are no separate local/general
versions) and the call to unw_flush_cache() must evaluate to
either the local or generic version. */
if (as->dyn_generation != generation)
{
unw_flush_cache (as, 0, 0);
as->dyn_generation = generation;
}
return 0;
}
HIDDEN int
unwi_find_dynamic_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi, int need_unwind_info,
void *arg)
{
#ifdef UNW_LOCAL_ONLY
return local_find_proc_info (as, ip, pi, need_unwind_info, arg);
#else
# ifdef UNW_REMOTE_ONLY
return remote_find_proc_info (as, ip, pi, need_unwind_info, arg);
# else
if (as == unw_local_addr_space)
return local_find_proc_info (as, ip, pi, need_unwind_info, arg);
else
return remote_find_proc_info (as, ip, pi, need_unwind_info, arg);
# endif
#endif
}

View file

@ -1,47 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 "internal.h"
HIDDEN void
unwi_put_dynamic_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi,
void *arg)
{
switch (pi->format)
{
case UNW_INFO_FORMAT_DYNAMIC:
unwi_dyn_remote_put_unwind_info (as, pi, arg);
break;
case UNW_INFO_FORMAT_TABLE:
#ifdef tdep_put_unwind_info
tdep_put_unwind_info (as, pi, arg);
break;
#endif
/* fall through */
default:
break;
}
}

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gfind_dynamic_proc_info.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gput_dynamic_unwind_info.c"
#endif

View file

@ -1,46 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 "internal.h"
void
_U_dyn_cancel (unw_dyn_info_t *di)
{
mutex_lock (&_U_dyn_info_list_lock);
{
++_U_dyn_info_list.generation;
if (di->prev)
di->prev->next = di->next;
else
_U_dyn_info_list.first = di->next;
if (di->next)
di->next->prev = di->prev;
}
mutex_unlock (&_U_dyn_info_list_lock);
di->next = di->prev = NULL;
}

View file

@ -1,60 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 "internal.h"
#include "tdep.h"
HIDDEN int
unwi_extract_dynamic_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi, unw_dyn_info_t *di,
int need_unwind_info, void *arg)
{
pi->start_ip = di->start_ip;
pi->end_ip = di->end_ip;
pi->gp = di->gp;
pi->format = di->format;
switch (di->format)
{
case UNW_INFO_FORMAT_DYNAMIC:
pi->handler = di->u.pi.handler;
pi->flags = di->u.pi.flags;
if (need_unwind_info)
pi->unwind_info = di;
else
pi->unwind_info = NULL;
return 0;
case UNW_INFO_FORMAT_TABLE:
#ifdef tdep_search_unwind_table
/* call platform-specific search routine: */
return tdep_search_unwind_table (as, ip, di, pi, need_unwind_info, arg);
#else
/* fall through */
#endif
default:
break;
}
return -UNW_EINVAL;
}

View file

@ -1,259 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 <endian.h>
#include <stdlib.h>
#include "internal.h"
static void
free_regions (unw_dyn_region_info_t *region)
{
if (region->next)
free_regions (region->next);
free (region);
}
static int
intern_op (unw_addr_space_t as, unw_accessors_t *a, unw_word_t *addr,
unw_dyn_op_t *op, void *arg)
{
int ret;
if ((ret = fetch8 (as, a, addr, &op->tag, arg)) < 0
|| (ret = fetch8 (as, a, addr, &op->qp, arg)) < 0
|| (ret = fetch16 (as, a, addr, &op->reg, arg)) < 0
|| (ret = fetch32 (as, a, addr, &op->when, arg)) < 0
|| (ret = fetchw (as, a, addr, &op->val, arg)) < 0)
return ret;
return 0;
}
static int
intern_regions (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_dyn_region_info_t **regionp, void *arg)
{
uint32_t insn_count, op_count;
unw_dyn_region_info_t *region;
unw_word_t next_addr;
int i, ret;
*regionp = NULL;
if ((ret = fetchw (as, a, addr, &next_addr, arg)) < 0
|| (ret = fetch32 (as, a, addr, &insn_count, arg)) < 0
|| (ret = fetch32 (as, a, addr, &op_count, arg)) < 0)
return ret;
region = calloc (1, _U_dyn_region_info_size (op_count));
if (!region)
{
ret = -UNW_ENOMEM;
goto out;
}
region->insn_count = insn_count;
region->op_count = op_count;
for (i = 0; i < op_count; ++i)
if ((ret = intern_op (as, a, addr, region->op + i, arg)) < 0)
goto out;
if (next_addr)
if ((ret = intern_regions (as, a, &next_addr, &region->next, arg)) < 0)
goto out;
*regionp = region;
return 0;
out:
if (region)
free_regions (region);
return ret;
}
static int
intern_array (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_word_t table_len, unw_word_t **table_data,
void *arg)
{
unw_word_t *data = calloc (table_len, WSIZE);
int ret = 0, i;
if (!data)
{
ret = -UNW_ENOMEM;
goto out;
}
for (i = 0; i < table_len; ++i)
if (fetchw (as, a, addr, data + i, arg) < 0)
goto out;
*table_data = data;
return 0;
out:
if (data)
free (data);
return ret;
}
static void
free_dyn_info (unw_dyn_info_t *di)
{
switch (di->format)
{
case UNW_INFO_FORMAT_DYNAMIC:
if (di->u.pi.regions)
{
free_regions (di->u.pi.regions);
di->u.pi.regions = NULL;
}
break;
case UNW_INFO_FORMAT_TABLE:
if (di->u.ti.table_data)
{
free (di->u.ti.table_data);
di->u.ti.table_data = NULL;
}
break;
default:
break;
}
}
static int
intern_dyn_info (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t *addr, unw_dyn_info_t *di, void *arg)
{
int ret;
switch (di->format)
{
case UNW_INFO_FORMAT_DYNAMIC:
if ((ret = fetchw (as, a, addr, &di->u.pi.name_ptr, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.pi.handler, arg)) < 0
|| (ret = fetch32 (as, a, addr, &di->u.pi.flags, arg)) < 0
|| (ret = fetch32 (as, a, addr, &di->u.pi.pad0, arg)) < 0
|| (ret = intern_regions (as, a, addr, &di->u.pi.regions, arg)) < 0)
goto out;
break;
case UNW_INFO_FORMAT_TABLE:
if ((ret = fetchw (as, a, addr, &di->u.ti.name_ptr, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.ti.segbase, arg)) < 0
|| (ret = fetchw (as, a, addr, &di->u.ti.table_len, arg)) < 0
|| (ret = intern_array (as, a, addr, di->u.ti.table_len,
&di->u.ti.table_data, arg)) < 0)
goto out;
break;
default:
ret = -UNW_ENOINFO;
goto out;
}
return 0;
out:
free_dyn_info (di);
return ret;
}
HIDDEN int
unwi_dyn_remote_find_proc_info (unw_addr_space_t as, unw_word_t ip,
unw_proc_info_t *pi, unw_word_t *genp,
int need_unwind_info, void *arg)
{
unw_accessors_t *a = unw_get_accessors (as);
unw_word_t dyn_list_addr, addr, next_addr, gen1, gen2;
unw_word_t start_ip, end_ip;
unw_dyn_info_t di;
int32_t pad;
int ret;
ret = (*a->get_dyn_info_list_addr) (as, &dyn_list_addr, arg);
if (ret < 0)
return ret;
do
{
addr = dyn_list_addr;
if ((ret = fetchw (as, a, &addr, &gen1, arg)) < 0
|| (ret = fetchw (as, a, &addr, &next_addr, arg)) < 0)
return ret;
for (addr = next_addr; addr != 0; addr = next_addr)
{
if ((ret = fetchw (as, a, &addr, &next_addr, arg)) < 0
|| (ret = fetchw (as, a, &addr, &start_ip, arg)) < 0
|| (ret = fetchw (as, a, &addr, &end_ip, arg)) < 0)
return ret;
if (ip >= di.start_ip && ip < di.end_ip)
{
if ((ret = fetchw (as, a, &addr, &di.gp, arg)) < 0
|| (ret = fetch32 (as, a, &addr, &di.format, arg)) < 0
|| (ret = fetch32 (as, a, &addr, &pad, arg)) < 0)
return ret;
if (need_unwind_info)
if ((ret = intern_dyn_info (as, a, &addr, &di, arg)) < 0)
return ret;
ret = unwi_extract_dynamic_proc_info (as, ip, pi, &di,
need_unwind_info, arg);
if (ret < 0)
{
free_dyn_info (&di);
return ret;
}
return 0;
}
}
/* Recheck generation number to ensure things didn't change
underneath us: */
addr = dyn_list_addr;
if ((ret = fetchw (as, a, &addr, &gen2, arg)) < 0)
return ret;
}
while (gen1 != gen2);
*genp = gen1;
return 0;
}
HIDDEN void
unwi_dyn_remote_put_unwind_info (unw_addr_space_t as, unw_proc_info_t *pi,
void *arg)
{
if (!pi->unwind_info)
return;
free_dyn_info(pi->unwind_info);
pi->unwind_info = NULL;
}

View file

@ -1,98 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 <endian.h>
#include "internal.h"
static int
intern_string (unw_addr_space_t as, unw_accessors_t *a,
unw_word_t addr, char *buf, size_t buf_len, void *arg)
{
int ret, i;
for (i = 0; i < buf_len; ++i)
{
if ((ret = fetch8 (as, a, &addr, buf + i, arg)) < 0)
return ret;
if (buf[i] == '\0')
return 0; /* copied full string; return success */
}
buf[buf_len - 1] = '\0'; /* ensure string is NUL terminated */
return -UNW_ENOMEM;
}
HIDDEN int
unwi_get_proc_name (unw_addr_space_t as, unw_word_t ip, int is_local,
char *buf, size_t buf_len, void *arg)
{
unw_accessors_t *a = unw_get_accessors (as);
unw_proc_info_t pi;
int ret;
buf[0] = '\0'; /* always return a valid string, even if it's empty */
ret = unwi_find_dynamic_proc_info (as, ip, &pi, 1, arg);
if (ret == 0)
{
unw_dyn_info_t *di = pi.unwind_info;
switch (di->format)
{
case UNW_INFO_FORMAT_DYNAMIC:
ret = intern_string (as, a, di->u.pi.name_ptr, buf, buf_len, arg);
break;
case UNW_INFO_FORMAT_TABLE:
/* XXX should we create a fake name, e.g.: "tablenameN",
where N is the index of the function in the table??? */
ret = -UNW_ENOINFO;
break;
default:
ret = -UNW_EINVAL;
break;
}
unwi_put_dynamic_unwind_info (as, &pi, arg);
return ret;
}
if (ret != -UNW_ENOINFO)
return ret;
/* not a dynamic procedure */
if (!is_local)
/* It makes no sense to implement get_proc_name() for remote
address spaces because that would require a callback and in
that case, the application using libunwind needs to know how to
look up a procedure name anyhow. */
return -UNW_ENOINFO;
/* XXX implement me: look up ELF executable covering IP, then check
dynamic and regular symbol tables for a good name. */
return -UNW_ENOINFO;
}

View file

@ -1,61 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002 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 <stdlib.h>
#include "unwind_i.h"
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 = malloc (sizeof (*as));
if (!as)
return NULL;
memset (as, 0, sizeof (*as));
as->acc = *a;
/*
* IA-64 supports only big or little-endian, not weird stuff like
* PDP_ENDIAN.
*/
if (byte_order != 0
&& byte_order != __LITTLE_ENDIAN
&& byte_order != __BIG_ENDIAN)
return NULL;
if (byte_order == 0)
/* use host default: */
as->big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
else
as->big_endian = (byte_order == __BIG_ENDIAN);
return as;
#endif
}

View file

0
src/ia64/Gflush_cache.c Normal file
View file

View file

@ -1,37 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002 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"
unw_accessors_t *
unw_get_accessors (unw_addr_space_t as)
{
if (unw.first_time)
{
unw.first_time = 0;
ia64_init ();
}
return &as->acc;
}

0
src/ia64/Gget_fpreg.c Normal file
View file

View file

@ -1,38 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2002 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"
int
unw_get_proc_info (unw_cursor_t *cursor, unw_proc_info_t *pi)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
int ret;
if ((ret = ia64_make_proc_info (c)) < 0)
return ret;
*pi = c->pi;
return 0;
}

View file

@ -1,35 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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"
int
unw_get_proc_name (unw_cursor_t *cursor, char *buf, size_t buf_len)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
return unwi_get_proc_name (c->as, c->ip, c->as == unw_local_addr_space,
buf, buf_len, c->as_arg);
}

0
src/ia64/Gget_reg.c Normal file
View file

0
src/ia64/Gget_save_loc.c Normal file
View file

View file

@ -1,357 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 <endian.h>
#include <stdlib.h>
#include "rse.h"
#include "unwind_i.h"
struct ia64_global_unwind_state unw =
{
first_time: 1,
save_order: {
IA64_REG_RP, IA64_REG_PFS, IA64_REG_PSP, IA64_REG_PR,
IA64_REG_UNAT, IA64_REG_LC, IA64_REG_FPSR, IA64_REG_PRI_UNAT_GR
},
preg_index: {
struct_offset (struct ia64_cursor, pri_unat_loc)/8, /* PRI_UNAT_GR */
struct_offset (struct ia64_cursor, pri_unat_loc)/8, /* PRI_UNAT_MEM */
struct_offset (struct ia64_cursor, bsp_loc)/8,
struct_offset (struct ia64_cursor, bspstore_loc)/8,
struct_offset (struct ia64_cursor, pfs_loc)/8,
struct_offset (struct ia64_cursor, rnat_loc)/8,
struct_offset (struct ia64_cursor, psp)/8,
struct_offset (struct ia64_cursor, ip_loc)/8,
struct_offset (struct ia64_cursor, r4_loc)/8,
struct_offset (struct ia64_cursor, r5_loc)/8,
struct_offset (struct ia64_cursor, r6_loc)/8,
struct_offset (struct ia64_cursor, r7_loc)/8,
struct_offset (struct ia64_cursor, nat4_loc)/8,
struct_offset (struct ia64_cursor, nat5_loc)/8,
struct_offset (struct ia64_cursor, nat6_loc)/8,
struct_offset (struct ia64_cursor, nat7_loc)/8,
struct_offset (struct ia64_cursor, unat_loc)/8,
struct_offset (struct ia64_cursor, pr_loc)/8,
struct_offset (struct ia64_cursor, lc_loc)/8,
struct_offset (struct ia64_cursor, fpsr_loc)/8,
struct_offset (struct ia64_cursor, b1_loc)/8,
struct_offset (struct ia64_cursor, b2_loc)/8,
struct_offset (struct ia64_cursor, b3_loc)/8,
struct_offset (struct ia64_cursor, b4_loc)/8,
struct_offset (struct ia64_cursor, b5_loc)/8,
struct_offset (struct ia64_cursor, f2_loc)/8,
struct_offset (struct ia64_cursor, f3_loc)/8,
struct_offset (struct ia64_cursor, f4_loc)/8,
struct_offset (struct ia64_cursor, f5_loc)/8,
struct_offset (struct ia64_cursor, fr_loc[16 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[17 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[18 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[19 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[20 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[21 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[22 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[23 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[24 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[25 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[26 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[27 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[28 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[29 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[30 - 16])/8,
struct_offset (struct ia64_cursor, fr_loc[31 - 16])/8,
},
#if IA64_UNW_DEBUG
debug_level: 0,
preg_name: {
"pri_unat_gr", "pri_unat_mem", "bsp", "bspstore", "ar.pfs", "ar.rnat",
"psp", "rp",
"r4", "r5", "r6", "r7",
"ar.unat", "pr", "ar.lc", "ar.fpsr",
"b1", "b2", "b3", "b4", "b5",
"f2", "f3", "f4", "f5",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"
}
#endif
};
#ifdef UNW_REMOTE_ONLY
/* unw_local_addr_space is a NULL pointer in this case. */
unw_addr_space_t unw_local_addr_space;
#else
static struct unw_addr_space local_addr_space;
unw_addr_space_t unw_local_addr_space = &local_addr_space;
static inline void *
uc_addr (ucontext_t *uc, int reg)
{
void *addr;
switch (reg)
{
case UNW_IA64_IP: addr = &uc->uc_mcontext.sc_br[0]; break;
case UNW_IA64_CFM: addr = &uc->uc_mcontext.sc_ar_pfs; break;
case UNW_IA64_AR_RNAT: addr = &uc->uc_mcontext.sc_ar_rnat; break;
case UNW_IA64_AR_UNAT: addr = &uc->uc_mcontext.sc_ar_unat; break;
case UNW_IA64_AR_LC: addr = &uc->uc_mcontext.sc_ar_lc; break;
case UNW_IA64_AR_FPSR: addr = &uc->uc_mcontext.sc_ar_fpsr; break;
case UNW_IA64_PR: addr = &uc->uc_mcontext.sc_pr; break;
case UNW_IA64_AR_BSP: addr = &uc->uc_mcontext.sc_rbs_base; break;
case UNW_IA64_AR_BSPSTORE: addr = &uc->uc_mcontext.sc_rbs_base; break;
case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7:
case UNW_IA64_GR + 12:
addr = &uc->uc_mcontext.sc_gr[reg - UNW_IA64_GR];
break;
case UNW_IA64_BR + 1 ... UNW_IA64_BR + 5:
addr = &uc->uc_mcontext.sc_br[reg - UNW_IA64_BR];
break;
case UNW_IA64_FR+ 2 ... UNW_IA64_FR+ 5:
case UNW_IA64_FR+16 ... UNW_IA64_FR+31:
addr = &uc->uc_mcontext.sc_fr[reg - UNW_IA64_FR];
break;
default:
addr = NULL;
}
return addr;
}
# ifdef UNW_LOCAL_ONLY
void *
_Uia64_uc_addr (ucontext_t *uc, int reg)
{
return uc_addr (uc, reg);
}
# endif /* UNW_LOCAL_ONLY */
static void
put_unwind_info (unw_addr_space_t as, unw_proc_info_t *proc_info, void *arg)
{
/* it's a no-op */
}
static int
get_dyn_info_list_addr (unw_addr_space_t as, unw_word_t *dyn_info_list_addr,
void *arg)
{
*dyn_info_list_addr = (unw_word_t) &_U_dyn_info_list;
return 0;
}
static int
access_mem (unw_addr_space_t as, unw_word_t addr, unw_word_t *val, int write,
void *arg)
{
if (write)
{
debug (100, "%s: mem[%lx] <- %lx\n", __FUNCTION__, addr, *val);
*(unw_word_t *) addr = *val;
}
else
{
*val = *(unw_word_t *) addr;
debug (100, "%s: mem[%lx] -> %lx\n", __FUNCTION__, addr, *val);
}
return 0;
}
static int
access_reg (unw_addr_space_t as, unw_regnum_t reg, unw_word_t *val, int write,
void *arg)
{
unw_word_t *addr, mask;
ucontext_t *uc = arg;
if (reg >= UNW_IA64_FR && reg < UNW_IA64_FR + 128)
goto badreg;
if (reg >= UNW_IA64_NAT + 4 && reg <= UNW_IA64_NAT + 7)
{
mask = ((unw_word_t) 1) << (reg - UNW_IA64_NAT);
if (write)
{
if (*val)
uc->uc_mcontext.sc_nat |= mask;
else
uc->uc_mcontext.sc_nat &= ~mask;
}
else
*val = (uc->uc_mcontext.sc_nat & mask) != 0;
if (write)
debug (100, "%s: %s <- %lx\n", __FUNCTION__, unw_regname (reg), *val);
else
debug (100, "%s: %s -> %lx\n", __FUNCTION__, unw_regname (reg), *val);
return 0;
}
addr = uc_addr (uc, reg);
if (!addr)
goto badreg;
if (write)
{
*(unw_word_t *) addr = *val;
debug (100, "%s: %s <- %lx\n", __FUNCTION__, unw_regname (reg), *val);
}
else
{
*val = *(unw_word_t *) addr;
debug (100, "%s: %s -> %lx\n", __FUNCTION__, unw_regname (reg), *val);
}
return 0;
badreg:
debug (1, "%s: bad register number %u\n", __FUNCTION__, reg);
return -UNW_EBADREG;
}
static int
access_fpreg (unw_addr_space_t as, unw_regnum_t reg, unw_fpreg_t *val,
int write, void *arg)
{
ucontext_t *uc = arg;
unw_fpreg_t *addr;
if (reg < UNW_IA64_FR || reg >= UNW_IA64_FR + 128)
goto badreg;
addr = uc_addr (uc, reg);
if (!addr)
goto badreg;
if (write)
{
debug (100, "%s: %s <- %016lx.%016lx\n", __FUNCTION__,
unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
*(unw_fpreg_t *) addr = *val;
}
else
{
*val = *(unw_fpreg_t *) addr;
debug (100, "%s: %s -> %016lx.%016lx\n", __FUNCTION__,
unw_regname (reg), val->raw.bits[1], val->raw.bits[0]);
}
return 0;
badreg:
debug (1, "%s: bad register number %u\n", __FUNCTION__, reg);
/* attempt to access a non-preserved register */
return -UNW_EBADREG;
}
#endif /* !UNW_REMOTE_ONLY */
void
ia64_init (void)
{
extern void unw_hash_index_t_is_too_narrow (void);
extern void unw_cursor_t_is_too_small (void);
uint8_t f1_bytes[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t nat_val_bytes[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t int_val_bytes[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xff, 0xfe,
0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
uint8_t *lep, *bep;
long i;
#if IA64_UNW_DEBUG
{
const char *str = getenv ("UNW_DEBUG_LEVEL");
if (str)
unw.debug_level = atoi (str);
}
#endif
mempool_init (&unw.state_record_pool, sizeof (struct ia64_state_record), 0);
mempool_init (&unw.labeled_state_pool,
sizeof (struct ia64_labeled_state), 0);
unw.f0.raw.bits[0] = 0;
unw.f0.raw.bits[1] = 0;
lep = (uint8_t *) &unw.f1_le + 16;
bep = (uint8_t *) &unw.f1_be;
for (i = 0; i < 16; ++i)
{
*--lep = f1_bytes[i];
*bep++ = f1_bytes[i];
}
lep = (uint8_t *) &unw.nat_val_le + 16;
bep = (uint8_t *) &unw.nat_val_be;
for (i = 0; i < 16; ++i)
{
*--lep = nat_val_bytes[i];
*bep++ = nat_val_bytes[i];
}
lep = (uint8_t *) &unw.int_val_le + 16;
bep = (uint8_t *) &unw.int_val_be;
for (i = 0; i < 16; ++i)
{
*--lep = int_val_bytes[i];
*bep++ = int_val_bytes[i];
}
if (sizeof (struct ia64_cursor) > sizeof (unw_cursor_t))
unw_cursor_t_is_too_small();
if (8*sizeof(unw_hash_index_t) < IA64_LOG_UNW_HASH_SIZE)
unw_hash_index_t_is_too_narrow();
#ifndef UNW_REMOTE_ONLY
memset (&local_addr_space, 0, sizeof (local_addr_space));
ia64_script_cache_init (&local_addr_space.global_cache);
local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN);
local_addr_space.caching_policy = UNW_CACHE_GLOBAL;
local_addr_space.acc.find_proc_info = _Uia64_find_proc_info;
local_addr_space.acc.put_unwind_info = put_unwind_info;
local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr;
local_addr_space.acc.access_mem = access_mem;
local_addr_space.acc.access_reg = access_reg;
local_addr_space.acc.access_fpreg = access_fpreg;
local_addr_space.acc.resume = ia64_local_resume;
#endif
}

0
src/ia64/Ginit_local.c Normal file
View file

0
src/ia64/Ginit_remote.c Normal file
View file

View file

@ -1,43 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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"
int
unw_is_signal_frame (unw_cursor_t *cursor)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
struct ia64_state_record sr;
int ret;
/* Crude and slow, but we need to peek ahead into the unwind
descriptors to find out if the current IP is inside the signal
trampoline. */
ret = ia64_create_state_record (c, &sr);
if (ret < 0)
return ret;
return sr.is_signal_frame;
}

File diff suppressed because it is too large Load diff

View file

@ -1,494 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 <assert.h>
#include "offsets.h"
#include "regs.h"
#include "rse.h"
#include "unwind_i.h"
unw_word_t
ia64_scratch_loc (struct ia64_cursor *c, unw_regnum_t reg)
{
unw_word_t loc = c->sigcontext_loc;
if (loc)
{
switch (reg)
{
case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3:
case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31:
loc += SIGCONTEXT_NAT_OFF;
break;
case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3:
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 31:
loc += SIGCONTEXT_GR_OFF + 8*reg;
break;
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15:
loc += SIGCONTEXT_FR_OFF + 16*(reg - UNW_IA64_FR);
break;
case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127:
loc += SIGCONTEXT_FR_OFF + 16*(reg - UNW_IA64_FR);
break;
case UNW_IA64_BR + 0: loc += SIGCONTEXT_BR_OFF + 0; break;
case UNW_IA64_BR + 6: loc += SIGCONTEXT_BR_OFF + 6*8; break;
case UNW_IA64_BR + 7: loc += SIGCONTEXT_BR_OFF + 7*8; break;
case UNW_IA64_AR_RSC: loc += SIGCONTEXT_AR_RSC_OFF; break;
case UNW_IA64_AR_25: loc += SIGCONTEXT_AR_25_OFF; break;
case UNW_IA64_AR_26: loc += SIGCONTEXT_AR_26_OFF; break;
case UNW_IA64_AR_CCV: loc += SIGCONTEXT_AR_CCV; break;
}
return loc;
}
else
return IA64_REG_LOC (c, reg);
}
static inline int
update_nat (struct ia64_cursor *c, unw_word_t nat_loc, unw_word_t mask,
unw_word_t *valp, int write)
{
unw_word_t nat_word;
int ret;
ret = ia64_get (c, nat_loc, &nat_word);
if (ret < 0)
return ret;
if (write)
{
if (*valp)
nat_word |= mask;
else
nat_word &= ~mask;
ret = ia64_put (c, nat_loc, nat_word);
}
else
*valp = (nat_word & mask) != 0;
return ret;
}
static int
access_nat (struct ia64_cursor *c, unw_word_t loc, unw_word_t reg_loc,
unw_word_t *valp, int write)
{
unw_word_t nat_loc = -8, mask = 0, sc_addr;
unw_fpreg_t tmp;
int ret, reg;
if (IA64_IS_FP_LOC (reg_loc))
{
/* NaT bit is saved as a NaTVal. This happens when a general
register is saved to a floating-point register. */
if (write)
{
if (*valp)
{
if (c->as->big_endian)
ret = ia64_putfp (c, reg_loc, unw.nat_val_be);
else
ret = ia64_putfp (c, reg_loc, unw.nat_val_le);
}
else
{
unw_fpreg_t tmp;
ret = ia64_getfp (c, reg_loc, &tmp);
if (ret < 0)
return ret;
/* Reset the exponent to 0x1003e so that the significand
will be interpreted as an integer value. */
if (c->as->big_endian)
tmp.raw.bits[0] = unw.int_val_be.raw.bits[0];
else
tmp.raw.bits[1] = unw.int_val_le.raw.bits[1];
ret = ia64_putfp (c, reg_loc, tmp);
}
}
else
{
ret = ia64_getfp (c, reg_loc, &tmp);
if (ret < 0)
return ret;
if (c->as->big_endian)
*valp = (memcmp (&tmp, &unw.nat_val_be, sizeof (tmp)) == 0);
else
*valp = (memcmp (&tmp, &unw.nat_val_le, sizeof (tmp)) == 0);
}
return ret;
}
if (IA64_IS_MEMSTK_NAT (loc))
{
nat_loc = IA64_GET_LOC (loc) << 3;
mask = (unw_word_t) 1 << ia64_rse_slot_num (reg_loc);
}
else
{
reg = IA64_GET_LOC (loc);
assert (reg >= 0 && reg < 128);
if (!reg)
{
/* NaT bit is not saved. This happens if a general register
is saved to a branch register. Since the NaT bit gets
lost, we need to drop it here, too. Note that if the NaT
bit had been set when the save occurred, it would have
caused a NaT consumption fault. */
if (write)
{
if (*valp)
return -UNW_EBADREG; /* can't set NaT bit */
}
else
*valp = 0;
return 0;
}
if (reg >= 4 && reg <= 7)
{
/* NaT bit is saved in a NaT register. This happens when a
general register is saved to another general
register. */
#ifdef UNW_LOCAL_ONLY
ucontext_t *uc = c->as_arg;
mask = ((unw_word_t) 1) << reg;
nat_loc = (unw_word_t) &uc->uc_mcontext.sc_nat;
#else
if (write)
ret = ia64_put (c, IA64_REG_LOC (c, UNW_IA64_NAT + reg), *valp);
else
ret = ia64_get (c, IA64_REG_LOC (c, UNW_IA64_NAT + reg), valp);
return ret;
#endif
}
else if (reg >= 32)
{
/* NaT bit is saved in a stacked register. */
nat_loc = ia64_rse_rnat_addr (reg_loc); /* XXX looks wrong */
if (nat_loc > c->rbs_top)
nat_loc = c->top_rnat_loc;
mask = (unw_word_t) 1 << ia64_rse_slot_num (reg_loc);
}
else
{
/* NaT bit is saved in a scratch register. */
sc_addr = c->sigcontext_loc;
if (sc_addr)
{
nat_loc = sc_addr + SIGCONTEXT_NAT_OFF;
mask = (unw_word_t) 1 << reg;
}
else
{
if (write)
return ia64_put (c, loc, *valp);
else
return ia64_get (c, loc, valp);
}
}
}
return update_nat (c, nat_loc, mask, valp, write);
}
int
ia64_access_reg (struct ia64_cursor *c, unw_regnum_t reg, unw_word_t *valp,
int write)
{
unw_word_t loc = -8, reg_loc, nat, nat_loc, cfm, mask, pr;
int ret, readonly = 0;
switch (reg)
{
/* frame registers: */
case UNW_IA64_BSP:
if (write)
return -UNW_EREADONLYREG;
*valp = c->bsp;
return 0;
case UNW_REG_SP:
if (write)
return -UNW_EREADONLYREG;
*valp = c->sp;
return 0;
case UNW_REG_IP:
if (write)
c->ip = *valp; /* also update the IP cache */
loc = c->ip_loc;
break;
/* preserved registers: */
case UNW_IA64_GR + 4 ... UNW_IA64_GR + 7:
loc = (&c->r4_loc)[reg - (UNW_IA64_GR + 4)];
break;
case UNW_IA64_NAT + 4 ... UNW_IA64_NAT + 7:
loc = (&c->nat4_loc)[reg - (UNW_IA64_NAT + 4)];
reg_loc = (&c->r4_loc)[reg - (UNW_IA64_NAT + 4)];
return access_nat (c, loc, reg_loc, valp, write);
case UNW_IA64_AR_BSP: loc = c->bsp_loc; break;
case UNW_IA64_AR_BSPSTORE: loc = c->bspstore_loc; break;
case UNW_IA64_AR_PFS: loc = c->pfs_loc; break;
case UNW_IA64_AR_RNAT: loc = c->rnat_loc; break;
case UNW_IA64_AR_UNAT: loc = c->unat_loc; break;
case UNW_IA64_AR_LC: loc = c->lc_loc; break;
case UNW_IA64_AR_FPSR: loc = c->fpsr_loc; break;
case UNW_IA64_BR + 1: loc = c->b1_loc; break;
case UNW_IA64_BR + 2: loc = c->b2_loc; break;
case UNW_IA64_BR + 3: loc = c->b3_loc; break;
case UNW_IA64_BR + 4: loc = c->b4_loc; break;
case UNW_IA64_BR + 5: loc = c->b5_loc; break;
case UNW_IA64_CFM: loc = c->cfm_loc; break;
case UNW_IA64_PR:
if (write)
{
c->pr = *valp; /* update the predicate cache */
pr = pr_ltop (c, *valp);
return ia64_put (c, c->pr_loc, pr);
}
else
{
ret = ia64_get (c, c->pr_loc, &pr);
if (ret < 0)
return ret;
*valp = pr_ptol (c, pr);
}
return 0;
case UNW_IA64_GR + 32 ... UNW_IA64_GR + 127: /* stacked reg */
reg = rotate_gr (c, reg - UNW_IA64_GR) + UNW_IA64_GR;
if (reg < 0)
return -UNW_EBADREG;
loc = ia64_rse_skip_regs (c->bsp, reg - (UNW_IA64_GR + 32));
break;
case UNW_IA64_NAT + 32 ... UNW_IA64_NAT + 127: /* stacked reg */
reg = rotate_gr (c, reg - UNW_IA64_NAT) + UNW_IA64_NAT;
if (reg < 0)
return -UNW_EBADREG;
loc = ia64_rse_skip_regs (c->bsp, reg - (UNW_IA64_NAT + 32));
nat_loc = ia64_rse_rnat_addr (loc);
if (nat_loc > c->rbs_top)
nat_loc = c->top_rnat_loc;
mask = (unw_word_t) 1 << ia64_rse_slot_num (loc);
return update_nat (c, nat_loc, mask, valp, write);
case UNW_IA64_AR_EC:
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
if (write)
ret = ia64_put (c, c->cfm_loc, ((cfm & ~((unw_word_t) 0x3f << 52))
| (*valp & 0x3f) << 52));
else
*valp = (cfm >> 52) & 0x3f;
return ret;
/* scratch & special registers: */
case UNW_IA64_GR + 0:
if (write)
return -UNW_EREADONLYREG;
*valp = 0;
return 0;
case UNW_IA64_GR + 1: /* global pointer */
if (write)
return -UNW_EREADONLYREG;
/* ensure c->pi is up-to-date: */
if ((ret = ia64_make_proc_info (c)) < 0)
return ret;
*valp = c->pi.gp;
return 0;
case UNW_IA64_NAT + 0:
case UNW_IA64_NAT + 1: /* global pointer */
if (write)
return -UNW_EREADONLYREG;
*valp = 0;
return 0;
case UNW_IA64_NAT + 2 ... UNW_IA64_NAT + 3:
case UNW_IA64_NAT + 8 ... UNW_IA64_NAT + 31:
loc = ia64_scratch_loc (c, reg);
if (c->sigcontext_loc)
{
mask = (unw_word_t) 1 << (reg - UNW_IA64_NAT);
ret = ia64_get (c, loc, &nat);
if (ret < 0)
return ret;
if (write)
{
if (*valp)
nat |= mask;
else
nat &= ~mask;
ret = ia64_put (c, loc, nat);
}
else
*valp = (nat & mask) != 0;
return ret;
}
break;
case UNW_IA64_GR + 15 ... UNW_IA64_GR + 18:
if (c->is_signal_frame)
loc = ia64_scratch_loc (c, reg);
else
{
if (write)
c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp;
else
*valp = c->eh_args[reg - (UNW_IA64_GR + 15)] = *valp;
return 0;
}
break;
case UNW_IA64_GR + 2 ... UNW_IA64_GR + 3:
case UNW_IA64_GR + 8 ... UNW_IA64_GR + 14:
case UNW_IA64_GR + 19 ... UNW_IA64_GR + 31:
case UNW_IA64_BR + 0:
case UNW_IA64_BR + 6:
case UNW_IA64_BR + 7:
case UNW_IA64_AR_RSC:
case UNW_IA64_AR_25:
case UNW_IA64_AR_26:
case UNW_IA64_AR_CCV:
loc = ia64_scratch_loc (c, reg);
break;
default:
dprintf ("%s: bad register number %d\n", __FUNCTION__, reg);
return -UNW_EBADREG;
}
if (write)
{
if (readonly)
return -UNW_EREADONLYREG;
return ia64_put (c, loc, *valp);
}
else
return ia64_get (c, loc, valp);
}
int
ia64_access_fpreg (struct ia64_cursor *c, int reg, unw_fpreg_t *valp,
int write)
{
unw_word_t loc = -8, flags, tmp_loc;
int ret, i;
switch (reg)
{
case UNW_IA64_FR + 0:
if (write)
return -UNW_EREADONLYREG;
*valp = unw.f0;
return 0;
case UNW_IA64_FR + 1:
if (write)
return -UNW_EREADONLYREG;
if (c->as->big_endian)
*valp = unw.f1_be;
else
*valp = unw.f1_le;
return 0;
case UNW_IA64_FR + 2: loc = c->f2_loc; break;
case UNW_IA64_FR + 3: loc = c->f3_loc; break;
case UNW_IA64_FR + 4: loc = c->f4_loc; break;
case UNW_IA64_FR + 5: loc = c->f5_loc; break;
case UNW_IA64_FR + 16 ... UNW_IA64_FR + 31:
loc = c->fr_loc[reg - (UNW_IA64_FR + 16)];
break;
case UNW_IA64_FR + 6 ... UNW_IA64_FR + 15:
loc = ia64_scratch_loc (c, reg);
break;
case UNW_IA64_FR + 32 ... UNW_IA64_FR + 127:
loc = c->sigcontext_loc;
if (loc)
{
ret = ia64_get (c, loc + SIGCONTEXT_FLAGS_OFF, &flags);
if (ret < 0)
return ret;
if (!(flags & IA64_SC_FLAG_FPH_VALID))
{
if (write)
{
/* initialize fph partition: */
tmp_loc = loc + SIGCONTEXT_FR_OFF + 32*16;
for (i = 32; i < 128; ++i, tmp_loc += 16)
{
ret = ia64_putfp (c, tmp_loc, unw.f0);
if (ret < 0)
return ret;
}
/* mark fph partition as valid: */
ret = ia64_put (c, loc + SIGCONTEXT_FLAGS_OFF,
flags | IA64_SC_FLAG_FPH_VALID);
if (ret < 0)
return ret;
}
else
{
*valp = unw.f0;
return 0;
}
}
}
reg = rotate_fr (c, reg - UNW_IA64_FR) + UNW_IA64_FR;
loc = ia64_scratch_loc (c, reg);
break;
}
if (write)
return ia64_putfp (c, loc, *valp);
else
return ia64_getfp (c, loc, valp);
}

View file

@ -1,124 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 <stdlib.h>
#include "rse.h"
#include "unwind_i.h"
inline int
ia64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
unw_fpreg_t fpval;
ucontext_t *uc = arg;
unw_word_t val, sol;
int i, ret;
# define SET_NAT(n) \
do \
{ \
ret = ia64_access_reg (c, UNW_IA64_NAT + (n), &val, 0); \
if (ret < 0) \
return ret; \
if (val) \
uc->uc_mcontext.sc_nat |= (unw_word_t) 1 << n; \
} \
while (0)
# define SET_REG(f, r) \
do \
{ \
ret = ia64_get (c, c->r, &val); \
if (ret < 0) \
return ret; \
uc->uc_mcontext.f = val; \
} \
while (0)
# define SET_FPREG(f, r) \
do \
{ \
ret = ia64_getfp (c, c->r, &fpval); \
if (ret < 0) \
return ret; \
uc->uc_mcontext.f.u.bits[0] = fpval.raw.bits[0]; \
uc->uc_mcontext.f.u.bits[1] = fpval.raw.bits[1]; \
} \
while (0)
/* ensure c->pi is up-to-date: */
if ((ret = ia64_make_proc_info (c)) < 0)
return ret;
SET_REG (sc_ar_pfs, pfs_loc);
SET_REG (sc_br[0], ip_loc);
SET_REG (sc_pr, pr_loc);
SET_REG (sc_ar_rnat, rnat_loc);
SET_REG (sc_ar_lc, lc_loc);
SET_REG (sc_ar_fpsr, fpsr_loc);
SET_REG (sc_gr[4], r4_loc); SET_REG(sc_gr[5], r5_loc);
SET_REG (sc_gr[6], r6_loc); SET_REG(sc_gr[7], r7_loc);
uc->uc_mcontext.sc_nat = 0;
SET_NAT (4); SET_NAT(5);
SET_NAT (6); SET_NAT(7);
SET_REG (sc_br[1], b1_loc);
SET_REG (sc_br[2], b2_loc);
SET_REG (sc_br[3], b3_loc);
SET_REG (sc_br[4], b4_loc);
SET_REG (sc_br[5], b5_loc);
SET_FPREG (sc_fr[2], f2_loc);
SET_FPREG (sc_fr[3], f3_loc);
SET_FPREG (sc_fr[4], f4_loc);
SET_FPREG (sc_fr[5], f5_loc);
for (i = 16; i < 32; ++i)
SET_FPREG (sc_fr[i], fr_loc[i - 16]);
if (c->is_signal_frame)
abort (); /* XXX this needs to be fixed... */
/* Account for the fact that __ia64_install_context() returns via
br.ret, which will decrement bsp by size-of-locals. */
sol = (uc->uc_mcontext.sc_ar_pfs >> 7) & 0x7f;
uc->uc_mcontext.sc_ar_bsp = ia64_rse_skip_regs (c->bsp, sol);
uc->uc_mcontext.sc_flags = 0;
uc->uc_mcontext.sc_gr[1] = c->pi.gp;
uc->uc_mcontext.sc_gr[12] = c->psp;
__ia64_install_context (uc, c->eh_args[0], c->eh_args[1], c->eh_args[2],
c->eh_args[3]);
}
int
unw_resume (unw_cursor_t *cursor)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
#ifdef UNW_LOCAL_ONLY
return ia64_local_resume (c->as, cursor, c->as_arg);
#else
return (*c->as->acc.resume) (c->as, cursor, c->as_arg);
#endif
}

View file

@ -1,553 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 "offsets.h"
#include "rse.h"
#include "unwind_i.h"
#ifdef HAVE___THREAD
static __thread struct ia64_script_cache ia64_per_thread_cache;
#endif
static inline unw_hash_index_t
hash (unw_word_t ip)
{
# define magic 0x9e3779b97f4a7c16 /* based on (sqrt(5)/2-1)*2^64 */
return (ip >> 4) * magic >> (64 - IA64_LOG_UNW_HASH_SIZE);
}
static inline long
cache_match (struct ia64_script *script, unw_word_t ip, unw_word_t pr)
{
/* XXX lock script cache */
if (ip == script->ip && ((pr ^ script->pr_val) & script->pr_mask) == 0)
/* keep the lock... */
return 1;
/* XXX unlock script cache */
return 0;
}
static inline void
flush_script_cache (unw_addr_space_t as, struct ia64_script_cache *cache)
{
int i;
for (i = 0; i < IA64_UNW_CACHE_SIZE; ++i)
cache->buckets[i].ip = 0;
cache->generation = as->cache_generation;
}
static inline struct ia64_script_cache *
get_script_cache (unw_addr_space_t as)
{
struct ia64_script_cache *cache = &as->global_cache;
#ifdef HAVE___THREAD
if (as->caching_policy == UNW_CACHE_PER_THREAD)
cache = &ia64_per_thread_cache;
#endif
if (as->cache_generation != cache->generation)
flush_script_cache (as, cache);
return cache;
}
static struct ia64_script *
script_lookup (struct ia64_script_cache *cache, struct ia64_cursor *c)
{
struct ia64_script *script = cache->buckets + c->hint;
unsigned short index;
unw_word_t ip, pr;
STAT(++unw.stat.cache.lookups);
ip = c->ip;
pr = c->pr;
if (cache_match (script, ip, pr))
{
STAT(++unw.stat.cache.hinted_hits);
return script;
}
index = cache->hash[hash (ip)];
if (index >= IA64_UNW_CACHE_SIZE)
return 0;
script = cache->buckets + index;
while (1)
{
if (cache_match (script, ip, pr))
{
/* update hint; no locking needed: single-word writes are atomic */
STAT(++unw.stat.cache.normal_hits);
c->hint = cache->buckets[c->prev_script].hint =
(script - cache->buckets);
return script;
}
if (script->coll_chain >= IA64_UNW_HASH_SIZE)
return 0;
script = cache->buckets + script->coll_chain;
STAT(++unw.stat.cache.collision_chain_traversals);
}
}
struct ia64_script *
ia64_script_lookup (struct ia64_cursor *c)
{
return script_lookup (get_script_cache (c->as), c);
}
/* On returning, the lock for the SCRIPT is still being held. */
static inline struct ia64_script *
script_new (struct ia64_script_cache *cache, unw_word_t ip)
{
struct ia64_script *script, *prev, *tmp;
unw_hash_index_t index;
unsigned short head;
STAT(++unw.stat.script.news);
/* XXX lock hash table */
{
head = cache->lru_head;
script = cache->buckets + head;
cache->lru_head = script->lru_chain;
}
/* XXX unlock hash table */
/* XXX We'll deadlock here if we interrupt a thread that is holding
the script->lock. */
/* XXX lock script */
/* XXX lock unwind data lock */
{
/* re-insert script at the tail of the LRU chain: */
cache->buckets[cache->lru_tail].lru_chain = head;
cache->lru_tail = head;
/* remove the old script from the hash table (if it's there): */
if (script->ip)
{
index = hash (script->ip);
tmp = cache->buckets + cache->hash[index];
prev = 0;
while (1)
{
if (tmp == script)
{
if (prev)
prev->coll_chain = tmp->coll_chain;
else
cache->hash[index] = tmp->coll_chain;
break;
}
else
prev = tmp;
if (tmp->coll_chain >= IA64_UNW_CACHE_SIZE)
/* old script wasn't in the hash-table */
break;
tmp = cache->buckets + tmp->coll_chain;
}
}
/* enter new script in the hash table */
index = hash (ip);
script->coll_chain = cache->hash[index];
cache->hash[index] = script - cache->buckets;
script->ip = ip; /* set new IP while we're holding the locks */
STAT(if (script->coll_chain < IA64_UNW_CACHE_SIZE)
++unw.stat.script.collisions);
}
/* XXX unlock unwind data lock */
script->hint = 0;
script->count = 0;
return script;
}
static inline void
script_finalize (struct ia64_script *script, struct ia64_cursor *c,
struct ia64_state_record *sr)
{
script->pr_mask = sr->pr_mask;
script->pr_val = sr->pr_val;
script->pi = c->pi;
}
static inline void
script_emit (struct ia64_script *script, struct ia64_script_insn insn)
{
if (script->count >= IA64_MAX_SCRIPT_LEN)
{
dprintf ("%s: script exceeds maximum size of %u instructions!\n",
__FUNCTION__, IA64_MAX_SCRIPT_LEN);
return;
}
script->insn[script->count++] = insn;
}
static inline void
emit_nat_info (struct ia64_state_record *sr, int i, struct ia64_script *script)
{
struct ia64_reg_info *r = sr->curr.reg + i;
struct ia64_script_insn insn;
enum ia64_script_insn_opcode opc = IA64_INSN_SET;
unsigned long val = 0;
switch (r->where)
{
case IA64_WHERE_GR:
val = IA64_LOC (r->val, 0);
break;
case IA64_WHERE_FR:
val = 0; /* value doesn't matter... */
break;
case IA64_WHERE_BR:
val = IA64_LOC (0, 0); /* no NaT bit */
break;
case IA64_WHERE_PSPREL:
case IA64_WHERE_SPREL:
opc = IA64_INSN_SETNAT_MEMSTK;
break;
default:
dprintf ("%s: don't know how to emit nat info for where = %u\n",
__FUNCTION__, r->where);
return;
}
insn.opc = opc;
insn.dst = unw.preg_index[i];
insn.val = val;
script_emit (script, insn);
}
static void
compile_reg (struct ia64_state_record *sr, int i, struct ia64_script *script)
{
struct ia64_reg_info *r = sr->curr.reg + i;
enum ia64_script_insn_opcode opc;
unsigned long val, rval;
struct ia64_script_insn insn;
long is_preserved_gr;
if (r->where == IA64_WHERE_NONE || r->when >= sr->when_target)
return;
opc = IA64_INSN_MOVE;
val = rval = r->val;
is_preserved_gr = (i >= IA64_REG_R4 && i <= IA64_REG_R7);
switch (r->where)
{
case IA64_WHERE_GR:
if (rval >= 32)
{
/* register got spilled to a stacked register */
opc = IA64_INSN_MOVE_STACKED;
val = rval - 32;
}
else if (rval >= 4 && rval <= 7)
/* register got spilled to a preserved register */
val = unw.preg_index[IA64_REG_R4 + (rval - 4)];
else
{
/* register got spilled to a scratch register */
opc = IA64_INSN_MOVE_SCRATCH;
val = UNW_IA64_GR + rval;
}
break;
case IA64_WHERE_FR:
if (rval <= 5)
val = unw.preg_index[IA64_REG_F2 + (rval - 1)];
else if (rval >= 16 && rval <= 31)
val = unw.preg_index[IA64_REG_F16 + (rval - 16)];
else
{
opc = IA64_INSN_MOVE_SCRATCH;
val = UNW_IA64_FR + rval;
}
break;
case IA64_WHERE_BR:
if (rval >= 1 && rval <= 5)
val = unw.preg_index[IA64_REG_B1 + (rval - 1)];
else
{
opc = IA64_INSN_MOVE_SCRATCH;
val = UNW_IA64_BR + rval;
}
break;
case IA64_WHERE_SPREL:
opc = IA64_INSN_ADD_SP;
if (i >= IA64_REG_F2 && i <= IA64_REG_F31)
val |= IA64_LOC_TYPE_FP;
break;
case IA64_WHERE_PSPREL:
opc = IA64_INSN_ADD_PSP;
if (i >= IA64_REG_F2 && i <= IA64_REG_F31)
val |= IA64_LOC_TYPE_FP;
break;
default:
dprintf ("%s: register %u has unexpected `where' value of %u\n",
__FUNCTION__, i, r->where);
break;
}
insn.opc = opc;
insn.dst = unw.preg_index[i];
insn.val = val;
script_emit (script, insn);
if (is_preserved_gr)
emit_nat_info (sr, i, script);
if (i == IA64_REG_PSP)
{
/* info->psp must contain the _value_ of the previous sp, not
it's save location. We get this by dereferencing the value
we just stored in info->psp: */
insn.opc = IA64_INSN_LOAD;
insn.dst = insn.val = unw.preg_index[IA64_REG_PSP];
script_emit (script, insn);
}
}
/* Build an unwind script that unwinds from state OLD_STATE to the
entrypoint of the function that called OLD_STATE. */
static inline int
build_script (struct ia64_cursor *c, struct ia64_script *script)
{
struct ia64_state_record sr;
struct ia64_script_insn insn;
int i, ret;
STAT(unsigned long start, parse_start;)
STAT(++unw.stat.script.builds; start = ia64_get_itc ());
STAT(unw.stat.script.parse_time += ia64_get_itc () - parse_start);
ret = ia64_create_state_record (c, &sr);
if (ret < 0)
return ret;
/* First, set psp if we're dealing with a fixed-size frame;
subsequent instructions may depend on this value. */
if (sr.when_target > sr.curr.reg[IA64_REG_PSP].when
&& (sr.curr.reg[IA64_REG_PSP].where == IA64_WHERE_NONE)
&& sr.curr.reg[IA64_REG_PSP].val != 0)
{
/* new psp is psp plus frame size */
insn.opc = IA64_INSN_ADD;
insn.dst = struct_offset (struct ia64_cursor, psp) / 8;
insn.val = sr.curr.reg[IA64_REG_PSP].val; /* frame size */
script_emit (script, insn);
}
/* determine where the primary UNaT is: */
if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_GR].when)
i = IA64_REG_PRI_UNAT_MEM;
else if (sr.when_target < sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when)
i = IA64_REG_PRI_UNAT_GR;
else if (sr.curr.reg[IA64_REG_PRI_UNAT_MEM].when >
sr.curr.reg[IA64_REG_PRI_UNAT_GR].when)
i = IA64_REG_PRI_UNAT_MEM;
else
i = IA64_REG_PRI_UNAT_GR;
compile_reg (&sr, i, script);
for (i = IA64_REG_BSP; i < IA64_NUM_PREGS; ++i)
compile_reg (&sr, i, script);
if (sr.is_signal_frame)
{
insn.opc = IA64_INSN_SET;
insn.dst = struct_offset (struct ia64_cursor, is_signal_frame) / 8;
insn.val = 1;
script_emit (script, insn);
}
script_finalize (script, c, &sr);
ia64_free_state_record (&sr);
STAT(unw.stat.script.build_time += ia64_get_itc () - start);
return 0;
}
/* Apply the unwinding actions represented by OPS and update SR to
reflect the state that existed upon entry to the function that this
unwinder represents. */
static inline int
run_script (struct ia64_script *script, struct ia64_cursor *c)
{
struct ia64_script_insn *ip, *limit, next_insn;
unw_word_t val, unat_addr, *s = (unw_word_t *) c;
unsigned long opc, dst;
int ret;
STAT(unsigned long start;)
STAT(++unw.stat.script.runs; start = ia64_get_itc ());
c->pi = script->pi;
ip = script->insn;
limit = script->insn + script->count;
next_insn = *ip;
while (ip++ < limit)
{
opc = next_insn.opc;
dst = next_insn.dst;
val = next_insn.val;
next_insn = *ip;
switch (opc)
{
case IA64_INSN_SET:
s[dst] = val;
break;
case IA64_INSN_ADD:
s[dst] += val;
break;
case IA64_INSN_ADD_PSP:
s[dst] = c->psp + val;
break;
case IA64_INSN_ADD_SP:
s[dst] = c->sp + val;
break;
case IA64_INSN_MOVE:
s[dst] = s[val];
break;
case IA64_INSN_MOVE_SCRATCH:
s[dst] = ia64_scratch_loc (c, val);
break;
case IA64_INSN_MOVE_STACKED:
s[dst] = ia64_rse_skip_regs (c->bsp, val);
break;
case IA64_INSN_SETNAT_MEMSTK:
ret = ia64_get (c, c->pri_unat_loc, &unat_addr);
if (ret < 0)
return ret;
s[dst] = IA64_LOC (unat_addr >> 3, IA64_LOC_TYPE_MEMSTK_NAT);
break;
case IA64_INSN_LOAD:
ret = ia64_get (c, s[val], &s[dst]);
if (ret < 0)
return ret;
break;
}
}
STAT(unw.stat.script.run_time += ia64_get_itc () - start);
return 0;
}
int
ia64_find_save_locs (struct ia64_cursor *c)
{
struct ia64_script *script = NULL;
int ret = 0;
if (c->as->caching_policy == UNW_CACHE_NONE)
{
struct ia64_script tmp_script;
script = &tmp_script;
script->ip = c->ip;
script->hint = 0;
script->count = 0;
ret = build_script (c, script);
}
else
{
struct ia64_script_cache *cache = get_script_cache (c->as);
script = script_lookup (cache, c);
if (!script)
{
script = script_new (cache, c->ip);
if (!script)
{
dprintf ("%s: failed to create unwind script\n", __FUNCTION__);
STAT(unw.stat.script.build_time += ia64_get_itc() - start);
return -UNW_EUNSPEC;
}
cache->buckets[c->prev_script].hint = script - cache->buckets;
ret = build_script (c, script);
}
c->hint = script->hint;
c->prev_script = script - cache->buckets;
}
if (ret < 0)
{
if (ret != UNW_ESTOPUNWIND)
dprintf ("%s: failed to locate/build unwind script for ip %lx\n",
__FUNCTION__, (long) c->ip);
return ret;
}
run_script (script, c);
return 0;
}
void
ia64_script_cache_init (struct ia64_script_cache *cache)
{
int i;
cache->lru_head = IA64_UNW_CACHE_SIZE - 1;
cache->lru_tail = 0;
for (i = 0; i < IA64_UNW_CACHE_SIZE; ++i)
{
if (i > 0)
cache->buckets[i].lru_chain = (i - 1);
cache->buckets[i].coll_chain = -1;
#if 0
/* must be lock-free! */
unw.cache[i].lock = RW_LOCK_UNLOCKED;
#endif
}
for (i = 0; i<IA64_UNW_HASH_SIZE; ++i)
cache->hash[i] = -1;
}

View file

0
src/ia64/Gset_fpreg.c Normal file
View file

0
src/ia64/Gset_reg.c Normal file
View file

View file

@ -1,132 +0,0 @@
/* libunwind - a platform-independent unwind library
Copyright (C) 2001-2002 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 "offsets.h"
#include "rse.h"
#include "unwind_i.h"
static inline int
update_frame_state (struct ia64_cursor *c)
{
unw_word_t prev_ip, prev_sp, prev_bsp, ip, pr, num_regs, cfm;
int ret;
prev_ip = c->ip;
prev_sp = c->sp;
prev_bsp = c->bsp;
c->cfm_loc = c->pfs_loc;
num_regs = 0;
if (c->is_signal_frame)
{
ret = ia64_get (c, c->sp + 0x10 + SIGFRAME_ARG2_OFF, &c->sigcontext_loc);
debug (100, "%s: sigcontext_loc=%lx (ret=%d)\n",
__FUNCTION__, c->sigcontext_loc, ret);
if (ret < 0)
return ret;
if (c->ip_loc == c->sigcontext_loc + SIGCONTEXT_BR_OFF + 0*8)
{
/* Earlier kernels (before 2.4.19 and 2.5.10) had buggy
unwind info for sigtramp. Fix it up here. */
c->ip_loc = (c->sigcontext_loc + SIGCONTEXT_IP_OFF);
c->cfm_loc = (c->sigcontext_loc + SIGCONTEXT_CFM_OFF);
}
/* do what can't be described by unwind directives: */
c->pfs_loc = (c->sigcontext_loc + SIGCONTEXT_AR_PFS_OFF);
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
num_regs = cfm & 0x7f; /* size of frame */
}
else
{
ret = ia64_get (c, c->cfm_loc, &cfm);
if (ret < 0)
return ret;
num_regs = (cfm >> 7) & 0x7f; /* size of locals */
}
c->bsp = ia64_rse_skip_regs (c->bsp, -num_regs);
/* update the IP cache: */
ret = ia64_get (c, c->ip_loc, &ip);
if (ret < 0)
return ret;
c->ip = ip;
if ((ip & 0xc) != 0)
{
/* don't let obviously bad addresses pollute the cache */
debug (1, "%s: rejecting bad ip=0x%lx\n", __FUNCTION__, (long) c->ip);
return -UNW_EINVALIDIP;
}
if (ip == 0)
/* end of frame-chain reached */
return 0;
pr = c->pr;
c->sp = c->psp;
c->is_signal_frame = 0;
if (c->ip == prev_ip && c->sp == prev_sp && c->bsp == prev_bsp)
{
dprintf ("%s: ip, sp, and bsp unchanged; stopping here (ip=0x%lx)\n",
__FUNCTION__, (long) ip);
return -UNW_EBADFRAME;
}
/* as we unwind, the saved ar.unat becomes the primary unat: */
c->pri_unat_loc = c->unat_loc;
/* restore the predicates: */
ret = ia64_get (c, c->pr_loc, &c->pr);
if (ret < 0)
return ret;
c->pi_valid = 0;
return 0;
}
int
unw_step (unw_cursor_t *cursor)
{
struct ia64_cursor *c = (struct ia64_cursor *) cursor;
int ret;
ret = ia64_find_save_locs (c);
if (ret < 0)
return ret;
ret = update_frame_state (c);
if (ret < 0)
return ret;
return (c->ip == 0) ? 0 : 1;
}

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gcreate_addr_space.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gdestroy_addr_space.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gflush_cache.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gget_accessors.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gget_fpreg.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gget_proc_info.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gget_proc_name.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gget_reg.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gget_save_loc.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Ginit_local.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Ginit_remote.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gis_signal_frame.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gresume.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gset_caching_policy.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gset_fpreg.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gset_reg.c"
#endif

View file

@ -1,4 +0,0 @@
#ifndef UNW_REMOTE_ONLY
#define UNW_LOCAL_ONLY
#include "Gstep.c"
#endif