2005-06-08 Jeff Johnston <jjohnstn@redhat.com>

David Mosberger <davidm@hpl.hp.com>

        * ia64-tdep.c (KERNEL_START): New macro.
        (ia64_pseudo_register_read): Fix code to use libunwind to properly
        get the rse registers.
        (ia64_frame_this_id): Mark outermost frame with null frame id.
        (ia64_sigtramp_frame_prev_register): Fix up debug output.
        (ia64_access_rse_reg): New accessor function.
        (ia64_access_mem): Add special logic for accessing the
        kernel's unwind table.
        (getunwind_table): Fix for corefiles.
        (get_kernel_table): Fix to handle vDSO.
        (ia64_libunwind_frame_this_id): Check for null frame id and
        don't unwind past pc value of 0.  Fix debugging output.
        (ia64_libunwind_sigtramp_frame_this_id): New function.
        (ia64_libunwind_sigtramp_frame_prev_register): Ditto.
        (ia64_libunwind_sigtramp_frame_sniffer): Ditto.
        (ia64_libunwind_sigtramp_frame_unwind): New unwinder.
        (ia64_unw_rse_accessors): New libunwind accessors.
        (ia64_libunwind_descr): Add ia64_unw_rse_accessors.
        (ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Use
        ia64_libunwind_sigtramp_frame_sniffer instead of
        ia64_sigtramp_frame_sniffer.
        * libunwind-frame.c (libunwind_frame_set_descr): Add
        special register accessors.
        (libunwind_frame_cache): Add special logic to check for
        0 pc value.  Check for a signal trampoline frame.
        (libunwind_frame_this_id): Check if libunwind_frame_cache
        returns NULL.
        (libunwind_frame_prev_register): Check for NULL cache.
        (libunwind_frame_base_address): Ditto.
        (libunwind_sigtramp_frame_sniffer): New function.
        (libunwind_get_reg_special): Ditto.
        (libunwind_load): Add unw_is_signal_frame support.
        * libunwind-frame.h (struct libunwind_descr): Add special_accessors
        field.
        (libunwind_sigtramp_frame_sniffer): New prototype.
        (libunwind_get_reg_special): Ditto.
This commit is contained in:
Jeff Johnston 2005-06-08 21:54:23 +00:00
parent 4dddc1d199
commit c5a27d9ca5
4 changed files with 517 additions and 55 deletions

View File

@ -1,3 +1,43 @@
2005-06-08 Jeff Johnston <jjohnstn@redhat.com>
David Mosberger <davidm@hpl.hp.com>
* ia64-tdep.c (KERNEL_START): New macro.
(ia64_pseudo_register_read): Fix code to use libunwind to properly
get the rse registers.
(ia64_frame_this_id): Mark outermost frame with null frame id.
(ia64_sigtramp_frame_prev_register): Fix up debug output.
(ia64_access_rse_reg): New accessor function.
(ia64_access_mem): Add special logic for accessing the
kernel's unwind table.
(getunwind_table): Fix for corefiles.
(get_kernel_table): Fix to handle vDSO.
(ia64_libunwind_frame_this_id): Check for null frame id and
don't unwind past pc value of 0. Fix debugging output.
(ia64_libunwind_sigtramp_frame_this_id): New function.
(ia64_libunwind_sigtramp_frame_prev_register): Ditto.
(ia64_libunwind_sigtramp_frame_sniffer): Ditto.
(ia64_libunwind_sigtramp_frame_unwind): New unwinder.
(ia64_unw_rse_accessors): New libunwind accessors.
(ia64_libunwind_descr): Add ia64_unw_rse_accessors.
(ia64_gdbarch_init)[HAVE_LIBUNWIND_IA64_H]: Use
ia64_libunwind_sigtramp_frame_sniffer instead of
ia64_sigtramp_frame_sniffer.
* libunwind-frame.c (libunwind_frame_set_descr): Add
special register accessors.
(libunwind_frame_cache): Add special logic to check for
0 pc value. Check for a signal trampoline frame.
(libunwind_frame_this_id): Check if libunwind_frame_cache
returns NULL.
(libunwind_frame_prev_register): Check for NULL cache.
(libunwind_frame_base_address): Ditto.
(libunwind_sigtramp_frame_sniffer): New function.
(libunwind_get_reg_special): Ditto.
(libunwind_load): Add unw_is_signal_frame support.
* libunwind-frame.h (struct libunwind_descr): Add special_accessors
field.
(libunwind_sigtramp_frame_sniffer): New prototype.
(libunwind_get_reg_special): Ditto.
2005-06-08 Wu Zhou <woodzltc@cn.ibm.com>
* expression.h (enum exp_opcode): Fix a comment typo.

View File

@ -45,6 +45,34 @@
#include "elf/ia64.h" /* for PT_IA_64_UNWIND value */
#include "libunwind-frame.h"
#include "libunwind-ia64.h"
/* Note: KERNEL_START is supposed to be an address which is not going
to ever contain any valid unwind info. For ia64 linux, the choice
of 0xc000000000000000 is fairly safe since that's uncached space.
We use KERNEL_START as follows: after obtaining the kernel's
unwind table via getunwind(), we project its unwind data into
address-range KERNEL_START-(KERNEL_START+ktab_size) and then
when ia64_access_mem() sees a memory access to this
address-range, we redirect it to ktab instead.
None of this hackery is needed with a modern kernel/libcs
which uses the kernel virtual DSO to provide access to the
kernel's unwind info. In that case, ktab_size remains 0 and
hence the value of KERNEL_START doesn't matter. */
#define KERNEL_START 0xc000000000000000ULL
static size_t ktab_size = 0;
struct ia64_table_entry
{
uint64_t start_offset;
uint64_t end_offset;
uint64_t info_offset;
};
static struct ia64_table_entry *ktab = NULL;
#endif
/* An enumeration of the different IA-64 instruction types. */
@ -649,24 +677,33 @@ ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
{
if (regnum >= V32_REGNUM && regnum <= V127_REGNUM)
{
ULONGEST bsp;
ULONGEST cfm;
CORE_ADDR reg;
regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
/* The bsp points at the end of the register frame so we
subtract the size of frame from it to get start of register frame. */
bsp = rse_address_add (bsp, -(cfm & 0x7f));
if ((cfm & 0x7f) > regnum - V32_REGNUM)
/* First try and use the libunwind special reg accessor, otherwise fallback to
standard logic. */
if (!libunwind_is_initialized ()
|| libunwind_get_reg_special (gdbarch, regnum, buf) != 0)
{
ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
reg = read_memory_integer ((CORE_ADDR)reg_addr, 8);
store_unsigned_integer (buf, register_size (current_gdbarch, regnum), reg);
/* The fallback position is to assume that r32-r127 are found sequentially
in memory starting at $bof. This isn't always true, but without libunwind,
this is the best we can do. */
ULONGEST cfm;
ULONGEST bsp;
CORE_ADDR reg;
regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
/* The bsp points at the end of the register frame so we
subtract the size of frame from it to get start of register frame. */
bsp = rse_address_add (bsp, -(cfm & 0x7f));
if ((cfm & 0x7f) > regnum - V32_REGNUM)
{
ULONGEST reg_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
reg = read_memory_integer ((CORE_ADDR)reg_addr, 8);
store_unsigned_integer (buf, register_size (current_gdbarch, regnum), reg);
}
else
store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0);
}
else
store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0);
}
else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
{
@ -1522,11 +1559,11 @@ ia64_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct ia64_frame_cache *cache =
ia64_frame_cache (next_frame, this_cache);
/* This marks the outermost frame. */
/* If outermost frame, mark with null frame id. */
if (cache->base == 0)
return;
(*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp);
(*this_id) = null_frame_id;
else
(*this_id) = frame_id_build_special (cache->base, cache->pc, cache->bsp);
if (gdbarch_debug >= 1)
fprintf_unfiltered (gdb_stdlog,
"regular frame id: code 0x%s, stack 0x%s, special 0x%s, next_frame %p\n",
@ -2008,8 +2045,13 @@ ia64_sigtramp_frame_prev_register (struct frame_info *next_frame,
if (gdbarch_debug >= 1)
fprintf_unfiltered (gdb_stdlog,
"sigtramp prev register <%s> is 0x%s\n",
(((unsigned) regnum <= IA64_NAT127_REGNUM)
? ia64_register_names[regnum] : "r??"),
(regnum < IA64_GR32_REGNUM
|| (regnum > IA64_GR127_REGNUM
&& regnum < LAST_PSEUDO_REGNUM))
? ia64_register_names[regnum]
: (regnum < LAST_PSEUDO_REGNUM
? ia64_register_names[regnum-IA64_GR32_REGNUM+V32_REGNUM]
: "OUT_OF_RANGE"),
paddr_nz (extract_unsigned_integer (valuep, 8)));
}
@ -2278,12 +2320,131 @@ ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val
return 0;
}
/* Libunwind callback accessor function for top-level rse registers. */
static int
ia64_access_rse_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
int write, void *arg)
{
int regnum = ia64_uw2gdb_regnum (uw_regnum);
unw_word_t bsp, sof, sol, cfm, psr, ip;
long new_sof, old_sof;
if (write)
{
if (regnum < 0)
/* ignore writes to pseudo-registers such as UNW_IA64_PROC_STARTI. */
return 0;
switch (uw_regnum)
{
case UNW_REG_IP:
ia64_write_pc (*val, inferior_ptid);
break;
case UNW_IA64_AR_BSPSTORE:
write_register (IA64_BSP_REGNUM, *val);
break;
case UNW_IA64_AR_BSP:
case UNW_IA64_BSP:
/* Account for the fact that ptrace() expects bsp to point
after the current register frame. */
cfm = read_register (IA64_CFM_REGNUM);
sof = (cfm & 0x7f);
bsp = ia64_rse_skip_regs (*val, sof);
write_register (IA64_BSP_REGNUM, bsp);
break;
case UNW_IA64_CFM:
/* If we change CFM, we need to adjust ptrace's notion of
bsp accordingly, so that the real bsp remains
unchanged. */
bsp = read_register (IA64_BSP_REGNUM);
cfm = read_register (IA64_CFM_REGNUM);
old_sof = (cfm & 0x7f);
new_sof = (*val & 0x7f);
if (old_sof != new_sof)
{
bsp = ia64_rse_skip_regs (bsp, -old_sof + new_sof);
write_register (IA64_BSP_REGNUM, bsp);
}
write_register (IA64_CFM_REGNUM, *val);
break;
default:
write_register (regnum, *val);
break;
}
if (gdbarch_debug >= 1)
fprintf_unfiltered (gdb_stdlog,
" access_rse_reg: to cache: %4s=0x%s\n",
(((unsigned) regnum <= IA64_NAT127_REGNUM)
? ia64_register_names[regnum] : "r??"),
paddr_nz (*val));
}
else
{
switch (uw_regnum)
{
case UNW_REG_IP:
/* Libunwind expects to see the pc value which means the slot number
from the psr must be merged with the ip word address. */
ip = read_register (IA64_IP_REGNUM);
psr = read_register (IA64_PSR_REGNUM);
*val = ip | ((psr >> 41) & 0x3);
break;
case UNW_IA64_AR_BSP:
/* Libunwind expects to see the beginning of the current register
frame so we must account for the fact that ptrace() will return a value
for bsp that points *after* the current register frame. */
bsp = read_register (IA64_BSP_REGNUM);
cfm = read_register (IA64_CFM_REGNUM);
sof = (cfm & 0x7f);
*val = ia64_rse_skip_regs (bsp, -sof);
break;
case UNW_IA64_AR_BSPSTORE:
/* Libunwind wants bspstore to be after the current register frame.
This is what ptrace() and gdb treats as the regular bsp value. */
*val = read_register (IA64_BSP_REGNUM);
break;
default:
/* For all other registers, just read the value directly. */
*val = read_register (regnum);
break;
}
}
if (gdbarch_debug >= 1)
fprintf_unfiltered (gdb_stdlog,
" access_rse_reg: from cache: %4s=0x%s\n",
(((unsigned) regnum <= IA64_NAT127_REGNUM)
? ia64_register_names[regnum] : "r??"),
paddr_nz (*val));
return 0;
}
/* Libunwind callback accessor function for accessing memory. */
static int
ia64_access_mem (unw_addr_space_t as,
unw_word_t addr, unw_word_t *val,
int write, void *arg)
{
if (addr - KERNEL_START < ktab_size)
{
unw_word_t *laddr = (unw_word_t*) ((char *) ktab
+ (addr - KERNEL_START));
if (write)
*laddr = *val;
else
*val = *laddr;
return 0;
}
/* XXX do we need to normalize byte-order here? */
if (write)
return target_write_memory (addr, (char *) val, sizeof (unw_word_t));
@ -2296,8 +2457,14 @@ static int
getunwind_table (void *buf, size_t len)
{
LONGEST x;
x = target_read_partial (&current_target, TARGET_OBJECT_UNWIND_TABLE, NULL,
buf, 0, len);
/* FIXME: This is a temporary solution to backtracing syscalls in corefiles.
To do this properly, the AUXV section should be used. This
fix will work as long as the kernel used to generate the corefile
is equivalent to the kernel used to debug the corefile. */
x = ia64_linux_xfer_unwind_table (&current_target,
TARGET_OBJECT_UNWIND_TABLE, NULL,
buf, NULL, 0, len);
return (int)x;
}
@ -2306,27 +2473,20 @@ getunwind_table (void *buf, size_t len)
static int
get_kernel_table (unw_word_t ip, unw_dyn_info_t *di)
{
size_t size;
struct ia64_table_entry
{
uint64_t start_offset;
uint64_t end_offset;
uint64_t info_offset;
};
static struct ia64_table_entry *ktab = NULL, *etab;
static struct ia64_table_entry *etab;
if (!ktab)
if (!ktab)
{
size_t size;
size = getunwind_table (NULL, 0);
if ((int)size < 0)
return -UNW_ENOINFO;
ktab = xmalloc (size);
getunwind_table (ktab, size);
/* Determine length of kernel's unwind table and relocate
it's entries. */
return -UNW_ENOINFO;
ktab_size = size;
ktab = xmalloc (ktab_size);
getunwind_table (ktab, ktab_size);
for (etab = ktab; etab->start_offset; ++etab)
etab->info_offset += (uint64_t) ktab;
etab->info_offset += KERNEL_START;
}
if (ip < ktab[0].start_offset || ip >= etab[-1].end_offset)
@ -2389,16 +2549,35 @@ ia64_find_unwind_table (struct objfile *objfile, unw_word_t ip,
}
}
if (!p_text || !p_unwind
/* Verify that the segment that contains the IP also contains
the static unwind table. If not, we are dealing with
runtime-generated code, for which we have no info here. */
|| (p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
if (!p_text || !p_unwind)
return -UNW_ENOINFO;
/* Verify that the segment that contains the IP also contains
the static unwind table. If not, we may be in the Linux kernel's
DSO gate page in which case the unwind table is another segment.
Otherwise, we are dealing with runtime-generated code, for which we
have no info here. */
segbase = p_text->p_vaddr + load_base;
dip->start_ip = segbase;
if ((p_unwind->p_vaddr - p_text->p_vaddr) >= p_text->p_memsz)
{
int ok = 0;
for (i = 0; i < ehdr->e_phnum; ++i)
{
if (phdr[i].p_type == PT_LOAD
&& (p_unwind->p_vaddr - phdr[i].p_vaddr) < phdr[i].p_memsz)
{
ok = 1;
/* Get the segbase from the section containing the
libunwind table. */
segbase = phdr[i].p_vaddr + load_base;
}
}
if (!ok)
return -UNW_ENOINFO;
}
dip->start_ip = p_text->p_vaddr + load_base;
dip->end_ip = dip->start_ip + p_text->p_memsz;
dip->gp = ia64_find_global_pointer (ip);
dip->format = UNW_INFO_FORMAT_REMOTE_TABLE;
@ -2528,14 +2707,33 @@ ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
char buf[8];
CORE_ADDR bsp;
struct frame_id id;
CORE_ADDR prev_ip, addr;
int realnum, optimized;
enum lval_type lval;
libunwind_frame_this_id (next_frame, this_cache, &id);
if (frame_id_eq (id, null_frame_id))
{
(*this_id) = null_frame_id;
return;
}
/* We must add the bsp as the special address for frame comparison purposes. */
/* We must add the bsp as the special address for frame comparison
purposes. */
frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
bsp = extract_unsigned_integer (buf, 8);
(*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
/* If the previous frame pc value is 0, then we are at the end of the stack
and don't want to unwind past this frame. We return a null frame_id to
indicate this. */
libunwind_frame_prev_register (next_frame, this_cache, IA64_IP_REGNUM,
&optimized, &lval, &addr, &realnum, &prev_ip);
if (prev_ip != 0)
(*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
else
(*this_id) = null_frame_id;
if (gdbarch_debug >= 1)
fprintf_unfiltered (gdb_stdlog,
@ -2625,8 +2823,13 @@ ia64_libunwind_frame_prev_register (struct frame_info *next_frame,
if (gdbarch_debug >= 1)
fprintf_unfiltered (gdb_stdlog,
"libunwind prev register <%s> is 0x%s\n",
(((unsigned) regnum <= IA64_NAT127_REGNUM)
? ia64_register_names[regnum] : "r??"),
(regnum < IA64_GR32_REGNUM
|| (regnum > IA64_GR127_REGNUM
&& regnum < LAST_PSEUDO_REGNUM))
? ia64_register_names[regnum]
: (regnum < LAST_PSEUDO_REGNUM
? ia64_register_names[regnum-IA64_GR32_REGNUM+V32_REGNUM]
: "OUT_OF_RANGE"),
paddr_nz (extract_unsigned_integer (valuep, 8)));
}
@ -2646,6 +2849,86 @@ ia64_libunwind_frame_sniffer (struct frame_info *next_frame)
return NULL;
}
static void
ia64_libunwind_sigtramp_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct frame_id *this_id)
{
char buf[8];
CORE_ADDR bsp;
struct frame_id id;
CORE_ADDR prev_ip;
libunwind_frame_this_id (next_frame, this_cache, &id);
if (frame_id_eq (id, null_frame_id))
{
(*this_id) = null_frame_id;
return;
}
/* We must add the bsp as the special address for frame comparison
purposes. */
frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
bsp = extract_unsigned_integer (buf, 8);
/* For a sigtramp frame, we don't make the check for previous ip being 0. */
(*this_id) = frame_id_build_special (id.stack_addr, id.code_addr, bsp);
if (gdbarch_debug >= 1)
fprintf_unfiltered (gdb_stdlog,
"libunwind sigtramp frame id: code 0x%s, stack 0x%s, special 0x%s, next_frame %p\n",
paddr_nz (id.code_addr), paddr_nz (id.stack_addr),
paddr_nz (bsp), next_frame);
}
static void
ia64_libunwind_sigtramp_frame_prev_register (struct frame_info *next_frame,
void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
int *realnump, void *valuep)
{
CORE_ADDR prev_ip, addr;
int realnum, optimized;
enum lval_type lval;
/* If the previous frame pc value is 0, then we want to use the SIGCONTEXT
method of getting previous registers. */
libunwind_frame_prev_register (next_frame, this_cache, IA64_IP_REGNUM,
&optimized, &lval, &addr, &realnum, &prev_ip);
if (prev_ip == 0)
{
void *tmp_cache = NULL;
ia64_sigtramp_frame_prev_register (next_frame, &tmp_cache, regnum, optimizedp, lvalp,
addrp, realnump, valuep);
}
else
ia64_libunwind_frame_prev_register (next_frame, this_cache, regnum, optimizedp, lvalp,
addrp, realnump, valuep);
}
static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
{
SIGTRAMP_FRAME,
ia64_libunwind_sigtramp_frame_this_id,
ia64_libunwind_sigtramp_frame_prev_register
};
static const struct frame_unwind *
ia64_libunwind_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
if (libunwind_is_initialized ())
{
if (libunwind_sigtramp_frame_sniffer (next_frame))
return &ia64_libunwind_sigtramp_frame_unwind;
return NULL;
}
else
return ia64_sigtramp_frame_sniffer (next_frame);
}
/* Set of libunwind callback acccessor functions. */
static unw_accessors_t ia64_unw_accessors =
{
@ -2659,6 +2942,22 @@ static unw_accessors_t ia64_unw_accessors =
/* get_proc_name */
};
/* Set of special libunwind callback acccessor functions specific for accessing
the rse registers. At the top of the stack, we want libunwind to figure out
how to read r32 - r127. Though usually they are found sequentially in memory
starting from $bof, this is not always true. */
static unw_accessors_t ia64_unw_rse_accessors =
{
ia64_find_proc_info_x,
ia64_put_unwind_info,
ia64_get_dyn_info_list,
ia64_access_mem,
ia64_access_rse_reg,
ia64_access_fpreg,
/* resume */
/* get_proc_name */
};
/* Set of ia64 gdb libunwind-frame callbacks and data for generic libunwind-frame code to use. */
static struct libunwind_descr ia64_libunwind_descr =
{
@ -2666,6 +2965,7 @@ static struct libunwind_descr ia64_libunwind_descr =
ia64_uw2gdb_regnum,
ia64_is_fpreg,
&ia64_unw_accessors,
&ia64_unw_rse_accessors,
};
#endif /* HAVE_LIBUNWIND_IA64_H */
@ -3307,10 +3607,12 @@ ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_unwind_dummy_id (gdbarch, ia64_unwind_dummy_id);
set_gdbarch_unwind_pc (gdbarch, ia64_unwind_pc);
frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
#ifdef HAVE_LIBUNWIND_IA64_H
frame_unwind_append_sniffer (gdbarch, ia64_libunwind_sigtramp_frame_sniffer);
frame_unwind_append_sniffer (gdbarch, ia64_libunwind_frame_sniffer);
libunwind_frame_set_descr (gdbarch, &ia64_libunwind_descr);
#else
frame_unwind_append_sniffer (gdbarch, ia64_sigtramp_frame_sniffer);
#endif
frame_unwind_append_sniffer (gdbarch, ia64_frame_sniffer);
frame_base_set_default (gdbarch, &ia64_frame_base);

View File

@ -49,6 +49,7 @@ static struct gdbarch_data *libunwind_descr_handle;
static int (*unw_get_reg_p) (unw_cursor_t *, unw_regnum_t, unw_word_t *);
static int (*unw_get_fpreg_p) (unw_cursor_t *, unw_regnum_t, unw_fpreg_t *);
static int (*unw_get_saveloc_p) (unw_cursor_t *, unw_regnum_t, unw_save_loc_t *);
static int (*unw_is_signal_frame_p) (unw_cursor_t *);
static int (*unw_step_p) (unw_cursor_t *);
static int (*unw_init_remote_p) (unw_cursor_t *, unw_addr_space_t, void *);
static unw_addr_space_t (*unw_create_addr_space_p) (unw_accessors_t *, int);
@ -78,6 +79,7 @@ struct libunwind_frame_cache
static char *get_reg_name = STRINGIFY(UNW_OBJ(get_reg));
static char *get_fpreg_name = STRINGIFY(UNW_OBJ(get_fpreg));
static char *get_saveloc_name = STRINGIFY(UNW_OBJ(get_save_loc));
static char *is_signal_frame_name = STRINGIFY(UNW_OBJ(is_signal_frame));
static char *step_name = STRINGIFY(UNW_OBJ(step));
static char *init_remote_name = STRINGIFY(UNW_OBJ(init_remote));
static char *create_addr_space_name = STRINGIFY(UNW_OBJ(create_addr_space));
@ -119,6 +121,7 @@ libunwind_frame_set_descr (struct gdbarch *gdbarch, struct libunwind_descr *desc
arch_descr->uw2gdb = descr->uw2gdb;
arch_descr->is_fpreg = descr->is_fpreg;
arch_descr->accessors = descr->accessors;
arch_descr->special_accessors = descr->special_accessors;
}
static struct libunwind_frame_cache *
@ -139,6 +142,10 @@ libunwind_frame_cache (struct frame_info *next_frame, void **this_cache)
cache = FRAME_OBSTACK_ZALLOC (struct libunwind_frame_cache);
cache->func_addr = frame_func_unwind (next_frame);
if (cache->func_addr == 0
&& frame_relative_level (next_frame) > 0
&& get_frame_type (next_frame) != SIGTRAMP_FRAME)
return NULL;
/* Get a libunwind cursor to the previous frame. We do this by initializing
a cursor. Libunwind treats a new cursor as the top of stack and will get
@ -156,7 +163,8 @@ libunwind_frame_cache (struct frame_info *next_frame, void **this_cache)
: __LITTLE_ENDIAN);
unw_init_remote_p (&cache->cursor, as, next_frame);
unw_step_p (&cache->cursor);
if (unw_step_p (&cache->cursor) < 0)
return NULL;
/* To get base address, get sp from previous frame. */
uw_sp_regnum = descr->gdb2uw (SP_REGNUM);
@ -208,8 +216,14 @@ libunwind_frame_sniffer (struct frame_info *next_frame)
ret = unw_init_remote_p (&cursor, as, next_frame);
if (ret >= 0)
ret = unw_step_p (&cursor);
if (ret < 0)
return NULL;
/* Check to see if we have libunwind info by checking if we are in a
signal frame. If it doesn't return an error, we have libunwind info
and can use libunwind. */
ret = unw_is_signal_frame_p (&cursor);
if (ret < 0)
return NULL;
@ -224,7 +238,10 @@ libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
struct libunwind_frame_cache *cache =
libunwind_frame_cache (next_frame, this_cache);
(*this_id) = frame_id_build (cache->base, cache->func_addr);
if (cache != NULL)
(*this_id) = frame_id_build (cache->base, cache->func_addr);
else
(*this_id) = null_frame_id;
}
void
@ -245,6 +262,9 @@ libunwind_frame_prev_register (struct frame_info *next_frame, void **this_cache,
unw_regnum_t uw_regnum;
struct libunwind_descr *descr;
if (cache == NULL)
return;
/* Convert from gdb register number to libunwind register number. */
descr = libunwind_descr (get_frame_arch (next_frame));
uw_regnum = descr->gdb2uw (regnum);
@ -312,6 +332,8 @@ libunwind_frame_base_address (struct frame_info *next_frame, void **this_cache)
struct libunwind_frame_cache *cache =
libunwind_frame_cache (next_frame, this_cache);
if (cache == NULL)
return (CORE_ADDR)NULL;
return cache->base;
}
@ -325,6 +347,95 @@ libunwind_search_unwind_table (void *as, long ip, void *di,
di, pi, need_unwind_info, args);
}
/* Verify if we are in a sigtramp frame and we can use libunwind to unwind. */
const struct frame_unwind *
libunwind_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
unw_cursor_t cursor;
unw_accessors_t *acc;
unw_addr_space_t as;
struct libunwind_descr *descr;
int i, ret;
/* To test for libunwind unwind support, initialize a cursor to the
current frame and try to back up. We use this same method when
setting up the frame cache (see libunwind_frame_cache()). If
libunwind returns success for this operation, it means that it
has found sufficient libunwind unwinding information to do
so. */
descr = libunwind_descr (get_frame_arch (next_frame));
acc = descr->accessors;
as = unw_create_addr_space_p (acc,
TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
? __BIG_ENDIAN
: __LITTLE_ENDIAN);
ret = unw_init_remote_p (&cursor, as, next_frame);
if (ret < 0)
return NULL;
/* Check to see if we are in a signal frame. */
ret = unw_is_signal_frame_p (&cursor);
if (ret > 0)
return &libunwind_frame_unwind;
return NULL;
}
/* The following routine is for accessing special registers of the top frame.
A special set of accessors must be given that work without frame info.
This is used by ia64 to access the rse registers r32-r127. While they
are usually located at BOF, this is not always true and only the libunwind
info can decipher where they actually are. */
int
libunwind_get_reg_special (struct gdbarch *gdbarch, int regnum, void *buf)
{
unw_cursor_t cursor;
unw_accessors_t *acc;
unw_addr_space_t as;
struct libunwind_descr *descr;
int ret;
unw_regnum_t uw_regnum;
unw_word_t intval;
unw_fpreg_t fpval;
void *ptr;
descr = libunwind_descr (gdbarch);
acc = descr->special_accessors;
as = unw_create_addr_space_p (acc,
TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
? __BIG_ENDIAN
: __LITTLE_ENDIAN);
ret = unw_init_remote_p (&cursor, as, NULL);
if (ret < 0)
return -1;
uw_regnum = descr->gdb2uw (regnum);
if (descr->is_fpreg (uw_regnum))
{
ret = unw_get_fpreg_p (&cursor, uw_regnum, &fpval);
ptr = &fpval;
}
else
{
ret = unw_get_reg_p (&cursor, uw_regnum, &intval);
ptr = &intval;
}
if (ret < 0)
return -1;
if (buf)
memcpy (buf, ptr, register_size (current_gdbarch, regnum));
return 0;
}
static int
libunwind_load (void)
{
@ -348,6 +459,10 @@ libunwind_load (void)
if (unw_get_saveloc_p == NULL)
return 0;
unw_is_signal_frame_p = dlsym (handle, is_signal_frame_name);
if (unw_is_signal_frame_p == NULL)
return 0;
unw_step_p = dlsym (handle, step_name);
if (unw_step_p == NULL)
return 0;

View File

@ -25,6 +25,7 @@
struct frame_info;
struct frame_id;
struct gdbarch;
#ifndef LIBUNWIND_FRAME_H
#define LIBUNWIND_FRAME_H 1
@ -37,9 +38,11 @@ struct libunwind_descr
int (*uw2gdb) (int);
int (*is_fpreg) (int);
void *accessors;
void *special_accessors;
};
const struct frame_unwind *libunwind_frame_sniffer (struct frame_info *next_frame);
const struct frame_unwind *libunwind_sigtramp_frame_sniffer (struct frame_info *next_frame);
void libunwind_frame_set_descr (struct gdbarch *arch, struct libunwind_descr *descr);
@ -59,6 +62,8 @@ int libunwind_search_unwind_table (void *as, long ip, void *di,
unw_word_t libunwind_find_dyn_list (unw_addr_space_t, unw_dyn_info_t *,
void *);
int libunwind_get_reg_special (struct gdbarch *gdbarch, int regnum, void *buf);
#endif /* libunwind-frame.h */
#endif /* HAVE_LIBUNWIND_H */