mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-25 21:19:54 +00:00
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:
parent
4dddc1d199
commit
c5a27d9ca5
@ -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.
|
||||
|
404
gdb/ia64-tdep.c
404
gdb/ia64-tdep.c
@ -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 (¤t_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 (¤t_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);
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
Loading…
Reference in New Issue
Block a user