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:
parent
86f8635442
commit
793c8a3005
49 changed files with 0 additions and 3968 deletions
|
@ -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);
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gfind_dynamic_proc_info.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gput_dynamic_unwind_info.c"
|
||||
#endif
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
259
src/dyn-remote.c
259
src/dyn-remote.c
|
@ -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, ®ion->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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
}
|
0
src/ia64/Gdestroy_addr_space.c
Normal file
0
src/ia64/Gdestroy_addr_space.c
Normal file
0
src/ia64/Gflush_cache.c
Normal file
0
src/ia64/Gflush_cache.c
Normal 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
0
src/ia64/Gget_fpreg.c
Normal 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;
|
||||
}
|
|
@ -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
0
src/ia64/Gget_reg.c
Normal file
0
src/ia64/Gget_save_loc.c
Normal file
0
src/ia64/Gget_save_loc.c
Normal file
357
src/ia64/Ginit.c
357
src/ia64/Ginit.c
|
@ -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
0
src/ia64/Ginit_local.c
Normal file
0
src/ia64/Ginit_remote.c
Normal file
0
src/ia64/Ginit_remote.c
Normal 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;
|
||||
}
|
1057
src/ia64/Gparser.c
1057
src/ia64/Gparser.c
File diff suppressed because it is too large
Load diff
494
src/ia64/Gregs.c
494
src/ia64/Gregs.c
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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;
|
||||
}
|
0
src/ia64/Gset_caching_policy.c
Normal file
0
src/ia64/Gset_caching_policy.c
Normal file
0
src/ia64/Gset_fpreg.c
Normal file
0
src/ia64/Gset_fpreg.c
Normal file
0
src/ia64/Gset_reg.c
Normal file
0
src/ia64/Gset_reg.c
Normal file
132
src/ia64/Gstep.c
132
src/ia64/Gstep.c
|
@ -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;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gcreate_addr_space.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gdestroy_addr_space.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gflush_cache.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gget_accessors.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gget_fpreg.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gget_proc_info.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gget_proc_name.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gget_reg.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gget_save_loc.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Ginit_local.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Ginit_remote.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gis_signal_frame.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gresume.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gset_caching_policy.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gset_fpreg.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gset_reg.c"
|
||||
#endif
|
|
@ -1,4 +0,0 @@
|
|||
#ifndef UNW_REMOTE_ONLY
|
||||
#define UNW_LOCAL_ONLY
|
||||
#include "Gstep.c"
|
||||
#endif
|
Loading…
Reference in a new issue