/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
- Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software
- Foundation, Inc.
+ Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "inferior.h"
#include "gdbcore.h"
#include "arch-utils.h"
#include "floatformat.h"
+#include "gdbtypes.h"
#include "regcache.h"
#include "reggroups.h"
#include "frame.h"
#include "infcall.h"
#include "osabi.h"
#include "ia64-tdep.h"
+#include "cp-abi.h"
#ifdef HAVE_LIBUNWIND_IA64_H
#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. */
static gdbarch_register_type_ftype ia64_register_type;
static gdbarch_breakpoint_from_pc_ftype ia64_breakpoint_from_pc;
static gdbarch_skip_prologue_ftype ia64_skip_prologue;
-static gdbarch_extract_return_value_ftype ia64_extract_return_value;
static struct type *is_float_or_hfa_type (struct type *t);
static CORE_ADDR ia64_find_global_pointer (CORE_ADDR faddr);
};
-#define SIGCONTEXT_REGISTER_ADDRESS \
- (gdbarch_tdep (current_gdbarch)->sigcontext_register_address)
-
int
ia64_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
struct reggroup *group)
}
static const char *
-ia64_register_name (int reg)
+ia64_register_name (struct gdbarch *gdbarch, int reg)
{
return ia64_register_names[reg];
}
}
static int
-ia64_dwarf_reg_to_regnum (int reg)
+ia64_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg)
{
if (reg >= IA64_GR32_REGNUM && reg <= IA64_GR127_REGNUM)
return V32_REGNUM + (reg - IA64_GR32_REGNUM);
}
static int
-floatformat_valid (const struct floatformat *fmt, const char *from)
+floatformat_valid (const struct floatformat *fmt, const void *from)
{
return 1;
}
const struct floatformat floatformat_ia64_ext =
{
floatformat_little, 82, 0, 1, 17, 65535, 0x1ffff, 18, 64,
- floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid
+ floatformat_intbit_yes, "floatformat_ia64_ext", floatformat_valid, NULL
+};
+
+const struct floatformat *floatformats_ia64_ext[2] =
+{
+ &floatformat_ia64_ext,
+ &floatformat_ia64_ext
};
at the assembly language level. */
if (slotnum > 2)
{
- warning ("Can't fetch instructions for slot numbers greater than 2.\n"
- "Using slot 0 instead");
+ warning (_("Can't fetch instructions for slot numbers greater than 2.\n"
+ "Using slot 0 instead"));
slotnum = 0;
}
#define IA64_BREAKPOINT 0x00003333300LL
static int
-ia64_memory_insert_breakpoint (CORE_ADDR addr, char *contents_cache)
+ia64_memory_insert_breakpoint (struct bp_target_info *bp_tgt)
{
+ CORE_ADDR addr = bp_tgt->placed_address;
char bundle[BUNDLE_LEN];
int slotnum = (int) (addr & 0x0f) / SLOT_MULTIPLIER;
long long instr;
int template;
if (slotnum > 2)
- error("Can't insert breakpoint for slot numbers greater than 2.");
+ error (_("Can't insert breakpoint for slot numbers greater than 2."));
addr &= ~0x0f;
}
instr = slotN_contents (bundle, slotnum);
- memcpy(contents_cache, &instr, sizeof(instr));
+ memcpy (bp_tgt->shadow_contents, &instr, sizeof (instr));
+ bp_tgt->placed_size = bp_tgt->shadow_len = sizeof (instr);
replace_slotN_contents (bundle, IA64_BREAKPOINT, slotnum);
if (val == 0)
target_write_memory (addr, bundle, BUNDLE_LEN);
}
static int
-ia64_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+ia64_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
{
+ CORE_ADDR addr = bp_tgt->placed_address;
char bundle[BUNDLE_LEN];
int slotnum = (addr & 0x0f) / SLOT_MULTIPLIER;
long long instr;
slotnum = 2;
}
- memcpy (&instr, contents_cache, sizeof instr);
+ memcpy (&instr, bp_tgt->shadow_contents, sizeof instr);
replace_slotN_contents (bundle, instr, slotnum);
if (val == 0)
target_write_memory (addr, bundle, BUNDLE_LEN);
/* We don't really want to use this, but remote.c needs to call it in order
to figure out if Z-packets are supported or not. Oh, well. */
const unsigned char *
-ia64_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+ia64_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
{
static unsigned char breakpoint[] =
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
}
static CORE_ADDR
-ia64_read_pc (ptid_t ptid)
+ia64_read_pc (struct regcache *regcache)
{
- CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
- CORE_ADDR pc_value = read_register_pid (IA64_IP_REGNUM, ptid);
- int slot_num = (psr_value >> 41) & 3;
+ ULONGEST psr_value, pc_value;
+ int slot_num;
+
+ regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr_value);
+ regcache_cooked_read_unsigned (regcache, IA64_IP_REGNUM, &pc_value);
+ slot_num = (psr_value >> 41) & 3;
return pc_value | (slot_num * SLOT_MULTIPLIER);
}
void
-ia64_write_pc (CORE_ADDR new_pc, ptid_t ptid)
+ia64_write_pc (struct regcache *regcache, CORE_ADDR new_pc)
{
int slot_num = (int) (new_pc & 0xf) / SLOT_MULTIPLIER;
- CORE_ADDR psr_value = read_register_pid (IA64_PSR_REGNUM, ptid);
+ ULONGEST psr_value;
+
+ regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr_value);
psr_value &= ~(3LL << 41);
- psr_value |= (CORE_ADDR)(slot_num & 0x3) << 41;
+ psr_value |= (ULONGEST)(slot_num & 0x3) << 41;
new_pc &= ~0xfLL;
- write_register_pid (IA64_PSR_REGNUM, psr_value, ptid);
- write_register_pid (IA64_IP_REGNUM, new_pc, ptid);
+ regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr_value);
+ regcache_cooked_write_unsigned (regcache, IA64_IP_REGNUM, new_pc);
}
#define IS_NaT_COLLECTION_ADDR(addr) ((((addr) >> 3) & 0x3f) == 0x3f)
static void
ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
- int regnum, void *buf)
+ int regnum, gdb_byte *buf)
{
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)
+#ifdef HAVE_LIBUNWIND_IA64_H
+ /* First try and use the libunwind special reg accessor, otherwise fallback to
+ standard logic. */
+ if (!libunwind_is_initialized ()
+ || libunwind_get_reg_special (gdbarch, regcache, regnum, buf) != 0)
+#endif
{
- 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 (gdbarch, regnum), reg);
+ }
+ else
+ store_unsigned_integer (buf, register_size (gdbarch, regnum), 0);
}
- else
- store_unsigned_integer (buf, register_size (current_gdbarch, regnum), 0);
}
else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
{
ULONGEST unat;
regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
unatN_val = (unat & (1LL << (regnum - IA64_NAT0_REGNUM))) != 0;
- store_unsigned_integer (buf, register_size (current_gdbarch, regnum), unatN_val);
+ store_unsigned_integer (buf, register_size (gdbarch, regnum), unatN_val);
}
else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
{
natN_val = (nat_collection >> nat_bit) & 1;
}
- store_unsigned_integer (buf, register_size (current_gdbarch, regnum), natN_val);
+ store_unsigned_integer (buf, register_size (gdbarch, regnum), natN_val);
}
else if (regnum == VBOF_REGNUM)
{
/* The bsp points at the end of the register frame so we
subtract the size of frame from it to get beginning of frame. */
vbsp = rse_address_add (bsp, -(cfm & 0x7f));
- store_unsigned_integer (buf, register_size (current_gdbarch, regnum), vbsp);
+ store_unsigned_integer (buf, register_size (gdbarch, regnum), vbsp);
}
else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
{
+ ((regnum - VP16_REGNUM) + rrb_pr) % 48;
}
prN_val = (pr & (1LL << (regnum - VP0_REGNUM))) != 0;
- store_unsigned_integer (buf, register_size (current_gdbarch, regnum), prN_val);
+ store_unsigned_integer (buf, register_size (gdbarch, regnum), prN_val);
}
else
- memset (buf, 0, register_size (current_gdbarch, regnum));
+ memset (buf, 0, register_size (gdbarch, regnum));
}
static void
ia64_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache,
- int regnum, const void *buf)
+ int regnum, const gdb_byte *buf)
{
if (regnum >= V32_REGNUM && regnum <= V127_REGNUM)
{
{
ULONGEST unatN_val, unat, unatN_mask;
regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
- unatN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum));
+ unatN_val = extract_unsigned_integer (buf, register_size (gdbarch, regnum));
unatN_mask = (1LL << (regnum - IA64_NAT0_REGNUM));
if (unatN_val == 0)
unat &= ~unatN_mask;
if ((cfm & 0x7f) > regnum - V32_REGNUM)
gr_addr = rse_address_add (bsp, (regnum - V32_REGNUM));
- natN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum));
+ natN_val = extract_unsigned_integer (buf, register_size (gdbarch, regnum));
if (gr_addr != 0 && (natN_val == 0 || natN_val == 1))
{
nat_collection |= natN_mask;
else
nat_collection &= ~natN_mask;
- store_unsigned_integer (nat_buf, register_size (current_gdbarch, regnum), nat_collection);
+ store_unsigned_integer (nat_buf, register_size (gdbarch, regnum), nat_collection);
write_memory (nat_addr, nat_buf, 8);
}
}
regnum = VP16_REGNUM
+ ((regnum - VP16_REGNUM) + rrb_pr) % 48;
}
- prN_val = extract_unsigned_integer (buf, register_size (current_gdbarch, regnum));
+ prN_val = extract_unsigned_integer (buf, register_size (gdbarch, regnum));
prN_mask = (1LL << (regnum - VP0_REGNUM));
if (prN_val == 0)
pr &= ~prN_mask;
and the special ia64 floating point register format. */
static int
-ia64_convert_register_p (int regno, struct type *type)
+ia64_convert_register_p (struct gdbarch *gdbarch, int regno, struct type *type)
{
- return (regno >= IA64_FR0_REGNUM && regno <= IA64_FR127_REGNUM);
+ return (regno >= IA64_FR0_REGNUM && regno <= IA64_FR127_REGNUM
+ && type != builtin_type_ia64_ext);
}
static void
ia64_register_to_value (struct frame_info *frame, int regnum,
- struct type *valtype, void *out)
+ struct type *valtype, gdb_byte *out)
{
char in[MAX_REGISTER_SIZE];
frame_register_read (frame, regnum, in);
static void
ia64_value_to_register (struct frame_info *frame, int regnum,
- struct type *valtype, const void *in)
+ struct type *valtype, const gdb_byte *in)
{
char out[MAX_REGISTER_SIZE];
convert_typed_floating (in, valtype, out, builtin_type_ia64_ext);
{
struct symtab_and_line prologue_sal;
CORE_ADDR start_pc = pc;
+ CORE_ADDR end_pc;
+
+ /* The prologue can not possibly go past the function end itself,
+ so we can already adjust LIM_PC accordingly. */
+ if (find_pc_partial_function (pc, NULL, NULL, &end_pc) && end_pc < lim_pc)
+ lim_pc = end_pc;
/* Start off not trusting the limit. */
*trust_limit = 0;
}
CORE_ADDR
-ia64_skip_prologue (CORE_ADDR pc)
+ia64_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
struct ia64_frame_cache cache;
cache.base = 0;
cache->cfm = cfm;
- cache->pc = frame_func_unwind (next_frame);
+ cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
if (cache->pc != 0)
examine_prologue (cache->pc, frame_pc_unwind (next_frame), next_frame, 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",
ia64_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)
+ int *realnump, gdb_byte *valuep)
{
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
struct ia64_frame_cache *cache =
ia64_frame_cache (next_frame, this_cache);
char dummy_valp[MAX_REGISTER_SIZE];
gdb_assert (regnum >= 0);
if (!target_has_registers)
- error ("No registers.");
+ error (_("No registers."));
*optimizedp = 0;
*addrp = 0;
if (!valuep)
valuep = dummy_valp;
- memset (valuep, 0, register_size (current_gdbarch, regnum));
+ memset (valuep, 0, register_size (gdbarch, regnum));
- if (regnum == SP_REGNUM)
+ if (regnum == gdbarch_sp_regnum (gdbarch))
{
/* Handle SP values for all frames but the topmost. */
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum),
cache->base);
}
else if (regnum == IA64_BSP_REGNUM)
bsp = rse_address_add (cache->bsp, -(cache->sof));
prev_bsp = rse_address_add (bsp, (prev_cfm & 0x7f) - ((prev_cfm >> 7) & 0x7f));
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum),
prev_bsp);
}
else if (regnum == IA64_CFM_REGNUM)
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+ read_memory (addr, valuep, register_size (gdbarch, regnum));
}
else if (cache->prev_cfm)
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), cache->prev_cfm);
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum), cache->prev_cfm);
else if (cache->frameless)
{
CORE_ADDR cfm = 0;
above. If the function lacks one of these frame pointers, we can
still provide a value since we know the size of the frame. */
CORE_ADDR vfp = cache->base;
- store_unsigned_integer (valuep, register_size (current_gdbarch, IA64_VFP_REGNUM), vfp);
+ store_unsigned_integer (valuep, register_size (gdbarch, IA64_VFP_REGNUM), vfp);
}
else if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
{
}
prN_val = extract_bit_field ((unsigned char *) pr_valuep,
regnum - VP0_REGNUM, 1);
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum), prN_val);
}
else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT31_REGNUM)
{
&unat_optim, &unat_lval, &unat_addr, &unat_realnum, unat_valuep);
unatN_val = extract_bit_field ((unsigned char *) unat_valuep,
regnum - IA64_NAT0_REGNUM, 1);
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum),
unatN_val);
}
else if (IA64_NAT32_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
natval = (nat_collection >> nat_bit) & 1;
}
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), natval);
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum), natval);
}
else if (regnum == IA64_IP_REGNUM)
{
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
+ read_memory (addr, buf, register_size (gdbarch, IA64_IP_REGNUM));
pc = extract_unsigned_integer (buf, 8);
}
else if (cache->frameless)
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
+ read_memory (addr, buf, register_size (gdbarch, IA64_IP_REGNUM));
pc = extract_unsigned_integer (buf, 8);
}
else if (cache->frameless)
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, buf, register_size (current_gdbarch, IA64_BR0_REGNUM));
+ read_memory (addr, buf, register_size (gdbarch, IA64_BR0_REGNUM));
br0 = extract_unsigned_integer (buf, 8);
}
store_unsigned_integer (valuep, 8, br0);
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+ read_memory (addr, valuep, register_size (gdbarch, regnum));
}
else if (cache->frameless)
{
addr = rse_address_add (prev_bof, (regnum - IA64_GR32_REGNUM));
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+ read_memory (addr, valuep, register_size (gdbarch, regnum));
}
}
else
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+ read_memory (addr, valuep, register_size (gdbarch, regnum));
}
/* Otherwise, punt and get the current value of the register. */
else
/* Signal trampolines. */
static void
-ia64_sigtramp_frame_init_saved_regs (struct ia64_frame_cache *cache)
+ia64_sigtramp_frame_init_saved_regs (struct frame_info *next_frame,
+ struct ia64_frame_cache *cache)
{
- if (SIGCONTEXT_REGISTER_ADDRESS)
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+
+ if (tdep->sigcontext_register_address)
{
int regno;
cache->saved_regs[IA64_VRAP_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_IP_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_IP_REGNUM);
cache->saved_regs[IA64_CFM_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_CFM_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_CFM_REGNUM);
cache->saved_regs[IA64_PSR_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_PSR_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_PSR_REGNUM);
cache->saved_regs[IA64_BSP_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_BSP_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_BSP_REGNUM);
cache->saved_regs[IA64_RNAT_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_RNAT_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_RNAT_REGNUM);
cache->saved_regs[IA64_CCV_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_CCV_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_CCV_REGNUM);
cache->saved_regs[IA64_UNAT_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_UNAT_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_UNAT_REGNUM);
cache->saved_regs[IA64_FPSR_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_FPSR_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_FPSR_REGNUM);
cache->saved_regs[IA64_PFS_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_PFS_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_PFS_REGNUM);
cache->saved_regs[IA64_LC_REGNUM] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, IA64_LC_REGNUM);
+ tdep->sigcontext_register_address (cache->base, IA64_LC_REGNUM);
for (regno = IA64_GR1_REGNUM; regno <= IA64_GR31_REGNUM; regno++)
cache->saved_regs[regno] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
+ tdep->sigcontext_register_address (cache->base, regno);
for (regno = IA64_BR0_REGNUM; regno <= IA64_BR7_REGNUM; regno++)
cache->saved_regs[regno] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
+ tdep->sigcontext_register_address (cache->base, regno);
for (regno = IA64_FR2_REGNUM; regno <= IA64_FR31_REGNUM; regno++)
cache->saved_regs[regno] =
- SIGCONTEXT_REGISTER_ADDRESS (cache->base, regno);
+ tdep->sigcontext_register_address (cache->base, regno);
}
}
cache->cfm = extract_unsigned_integer (buf, 8);
cache->sof = cache->cfm & 0x7f;
- ia64_sigtramp_frame_init_saved_regs (cache);
+ ia64_sigtramp_frame_init_saved_regs (next_frame, cache);
*this_cache = cache;
return cache;
void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
char dummy_valp[MAX_REGISTER_SIZE];
char buf[MAX_REGISTER_SIZE];
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
struct ia64_frame_cache *cache =
ia64_sigtramp_frame_cache (next_frame, this_cache);
gdb_assert (regnum >= 0);
if (!target_has_registers)
- error ("No registers.");
+ error (_("No registers."));
*optimizedp = 0;
*addrp = 0;
if (!valuep)
valuep = dummy_valp;
- memset (valuep, 0, register_size (current_gdbarch, regnum));
+ memset (valuep, 0, register_size (gdbarch, regnum));
if (regnum == IA64_IP_REGNUM)
{
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, buf, register_size (current_gdbarch, IA64_IP_REGNUM));
+ read_memory (addr, buf, register_size (gdbarch, IA64_IP_REGNUM));
pc = extract_unsigned_integer (buf, 8);
}
pc &= ~0xf;
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+ read_memory (addr, valuep, register_size (gdbarch, regnum));
}
}
else
{
*lvalp = lval_memory;
*addrp = addr;
- read_memory (addr, valuep, register_size (current_gdbarch, regnum));
+ read_memory (addr, valuep, register_size (gdbarch, regnum));
}
}
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)));
}
static const struct frame_unwind *
ia64_sigtramp_frame_sniffer (struct frame_info *next_frame)
{
- char *name;
- CORE_ADDR pc = frame_pc_unwind (next_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
+ if (tdep->pc_in_sigtramp)
+ {
+ CORE_ADDR pc = frame_pc_unwind (next_frame);
- find_pc_partial_function (pc, &name, NULL, NULL);
- if (legacy_pc_in_sigtramp (pc, name))
- return &ia64_sigtramp_frame_unwind;
+ if (tdep->pc_in_sigtramp (pc))
+ return &ia64_sigtramp_frame_unwind;
+ }
return NULL;
}
long new_sof, old_sof;
char buf[MAX_REGISTER_SIZE];
- if (write)
+ /* We never call any libunwind routines that need to write registers. */
+ gdb_assert (!write);
+
+ switch (uw_regnum)
{
- 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_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. */
+ frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
+ ip = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+ *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. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+ frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ sof = (cfm & 0x7f);
+ *val = ia64_rse_skip_regs (bsp, -sof);
+ 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_reg: to cache: %4s=0x%s\n",
- (((unsigned) regnum <= IA64_NAT127_REGNUM)
- ? ia64_register_names[regnum] : "r??"),
- paddr_nz (*val));
+ 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. */
+ frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
+
+ default:
+ /* For all other registers, just unwind the value directly. */
+ frame_unwind_register (next_frame, regnum, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
}
- else
+
+ if (gdbarch_debug >= 1)
+ fprintf_unfiltered (gdb_stdlog,
+ " access_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 floating-point registers. */
+static int
+ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val,
+ int write, void *arg)
+{
+ int regnum = ia64_uw2gdb_regnum (uw_regnum);
+ struct frame_info *next_frame = arg;
+
+ /* We never call any libunwind routines that need to write registers. */
+ gdb_assert (!write);
+
+ frame_unwind_register (next_frame, regnum, (char *) 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;
+ struct regcache *regcache = arg;
+ long new_sof, old_sof;
+ char buf[MAX_REGISTER_SIZE];
+
+ /* We never call any libunwind routines that need to write registers. */
+ gdb_assert (!write);
+
+ switch (uw_regnum)
{
- 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. */
- frame_unwind_register (next_frame, IA64_IP_REGNUM, buf);
- ip = extract_unsigned_integer (buf, 8);
- frame_unwind_register (next_frame, IA64_PSR_REGNUM, buf);
- psr = extract_unsigned_integer (buf, 8);
- *val = ip | ((psr >> 41) & 0x3);
- break;
+ 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. */
+ regcache_cooked_read (regcache, IA64_IP_REGNUM, buf);
+ ip = extract_unsigned_integer (buf, 8);
+ regcache_cooked_read (regcache, IA64_PSR_REGNUM, buf);
+ psr = extract_unsigned_integer (buf, 8);
+ *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. */
- frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
- bsp = extract_unsigned_integer (buf, 8);
- frame_unwind_register (next_frame, IA64_CFM_REGNUM, buf);
- cfm = extract_unsigned_integer (buf, 8);
- sof = (cfm & 0x7f);
- *val = ia64_rse_skip_regs (bsp, -sof);
- 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. */
+ regcache_cooked_read (regcache, IA64_BSP_REGNUM, buf);
+ bsp = extract_unsigned_integer (buf, 8);
+ regcache_cooked_read (regcache, IA64_CFM_REGNUM, buf);
+ cfm = extract_unsigned_integer (buf, 8);
+ 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. */
- frame_unwind_register (next_frame, IA64_BSP_REGNUM, buf);
- *val = extract_unsigned_integer (buf, 8);
- 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. */
+ regcache_cooked_read (regcache, IA64_BSP_REGNUM, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ break;
- default:
- /* For all other registers, just unwind the value directly. */
- frame_unwind_register (next_frame, regnum, buf);
- *val = extract_unsigned_integer (buf, 8);
- break;
- }
-
- if (gdbarch_debug >= 1)
- fprintf_unfiltered (gdb_stdlog,
- " access_reg: from cache: %4s=0x%s\n",
- (((unsigned) regnum <= IA64_NAT127_REGNUM)
- ? ia64_register_names[regnum] : "r??"),
- paddr_nz (*val));
+ default:
+ /* For all other registers, just unwind the value directly. */
+ regcache_cooked_read (regcache, regnum, buf);
+ *val = extract_unsigned_integer (buf, 8);
+ 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 floating-point registers. */
+/* Libunwind callback accessor function for top-level fp registers. */
static int
-ia64_access_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_fpreg_t *val,
- int write, void *arg)
+ia64_access_rse_fpreg (unw_addr_space_t as, unw_regnum_t uw_regnum,
+ unw_fpreg_t *val, int write, void *arg)
{
int regnum = ia64_uw2gdb_regnum (uw_regnum);
+ struct regcache *regcache = arg;
- if (write)
- regcache_cooked_write (current_regcache, regnum, (char *) val);
- else
- regcache_cooked_read (current_regcache, regnum, (char *) val);
+ /* We never call any libunwind routines that need to write registers. */
+ gdb_assert (!write);
+
+ regcache_cooked_read (regcache, regnum, (char *) val);
+
return 0;
}
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));
}
/* Call low-level function to access the kernel unwind table. */
-static int
-getunwind_table (void *buf, size_t len)
+static LONGEST
+getunwind_table (gdb_byte **buf_p)
{
LONGEST x;
- x = target_read_partial (¤t_target, TARGET_OBJECT_UNWIND_TABLE, NULL,
- buf, 0, len);
- return (int)x;
+ /* FIXME drow/2005-09-10: This code used to call
+ ia64_linux_xfer_unwind_table directly to fetch the unwind table
+ for the currently running ia64-linux kernel. That data should
+ come from the core file and be accessed via the auxv vector; if
+ we want to preserve fall back to the running kernel's table, then
+ we should find a way to override the corefile layer's
+ xfer_partial method. */
+
+ x = target_read_alloc (¤t_target, TARGET_OBJECT_UNWIND_TABLE,
+ NULL, buf_p);
+
+ return x;
}
-
+
/* Get the kernel unwind table. */
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 = getunwind_table (NULL, 0);
- if ((int)size < 0)
+ gdb_byte *ktab_buf;
+ LONGEST size;
+
+ size = getunwind_table (&ktab_buf);
+ if (size <= 0)
return -UNW_ENOINFO;
- ktab = xmalloc (size);
- getunwind_table (ktab, size);
-
- /* Determine length of kernel's unwind table and relocate
- it's entries. */
+
+ ktab = (struct ia64_table_entry *) ktab_buf;
+ ktab_size = 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)
}
}
- 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;
static void
ia64_libunwind_frame_this_id (struct frame_info *next_frame, void **this_cache,
- struct frame_id *this_id)
+ struct frame_id *this_id)
{
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, buf);
+ prev_ip = extract_unsigned_integer (buf, 8);
+
+ 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,
void **this_cache,
int regnum, int *optimizedp,
enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
+ int *realnump, gdb_byte *valuep)
{
int reg = regnum;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
if (VP0_REGNUM <= regnum && regnum <= VP63_REGNUM)
reg = IA64_PR_REGNUM;
else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
}
prN_val = extract_bit_field ((unsigned char *) valuep,
regnum - VP0_REGNUM, 1);
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum), prN_val);
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum), prN_val);
}
else if (IA64_NAT0_REGNUM <= regnum && regnum <= IA64_NAT127_REGNUM)
{
unatN_val = extract_bit_field ((unsigned char *) valuep,
regnum - IA64_NAT0_REGNUM, 1);
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum),
unatN_val);
}
else if (regnum == IA64_BSP_REGNUM)
prev_cfm = extract_unsigned_integer (cfm_valuep, 8);
prev_bsp = rse_address_add (prev_bsp, (prev_cfm & 0x7f));
- store_unsigned_integer (valuep, register_size (current_gdbarch, regnum),
+ store_unsigned_integer (valuep, register_size (gdbarch, regnum),
prev_bsp);
}
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)));
}
{
NORMAL_FRAME,
ia64_libunwind_frame_this_id,
- ia64_libunwind_frame_prev_register
+ ia64_libunwind_frame_prev_register,
+ NULL,
+ NULL,
+ NULL,
+ libunwind_frame_dealloc_cache
};
static const struct frame_unwind *
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, gdb_byte *valuep)
+
+{
+ gdb_byte buf[8];
+ 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, buf);
+ prev_ip = extract_unsigned_integer (buf, 8);
+
+ 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 =
{
/* 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_rse_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 =
{
ia64_uw2gdb_regnum,
ia64_is_fpreg,
&ia64_unw_accessors,
+ &ia64_unw_rse_accessors,
};
#endif /* HAVE_LIBUNWIND_IA64_H */
-/* Should we use DEPRECATED_EXTRACT_STRUCT_VALUE_ADDRESS instead of
- EXTRACT_RETURN_VALUE? GCC_P is true if compiled with gcc and TYPE
- is the type (which is known to be struct, union or array). */
-int
-ia64_use_struct_convention (int gcc_p, struct type *type)
+static int
+ia64_use_struct_convention (struct type *type)
{
struct type *float_elt_type;
+ /* Don't use the struct convention for anything but structure,
+ union, or array types. */
+ if (!(TYPE_CODE (type) == TYPE_CODE_STRUCT
+ || TYPE_CODE (type) == TYPE_CODE_UNION
+ || TYPE_CODE (type) == TYPE_CODE_ARRAY))
+ return 0;
+
/* HFAs are structures (or arrays) consisting entirely of floating
point values of the same length. Up to 8 of these are returned
in registers. Don't use the struct convention when this is the
return TYPE_LENGTH (type) > 32;
}
-void
-ia64_extract_return_value (struct type *type, struct regcache *regcache, void *valbuf)
+static void
+ia64_extract_return_value (struct type *type, struct regcache *regcache,
+ gdb_byte *valbuf)
{
struct type *float_elt_type;
ULONGEST val;
int offset = 0;
int regnum = IA64_GR8_REGNUM;
- int reglen = TYPE_LENGTH (ia64_register_type (NULL, IA64_GR8_REGNUM));
+ int reglen = TYPE_LENGTH (register_type (get_regcache_arch (regcache),
+ IA64_GR8_REGNUM));
int n = TYPE_LENGTH (type) / reglen;
int m = TYPE_LENGTH (type) % reglen;
}
}
-CORE_ADDR
-ia64_extract_struct_value_address (struct regcache *regcache)
+static void
+ia64_store_return_value (struct type *type, struct regcache *regcache,
+ const gdb_byte *valbuf)
{
- error ("ia64_extract_struct_value_address called and cannot get struct value address");
- return 0;
+ struct type *float_elt_type;
+
+ float_elt_type = is_float_or_hfa_type (type);
+ if (float_elt_type != NULL)
+ {
+ char to[MAX_REGISTER_SIZE];
+ int offset = 0;
+ int regnum = IA64_FR8_REGNUM;
+ int n = TYPE_LENGTH (type) / TYPE_LENGTH (float_elt_type);
+
+ while (n-- > 0)
+ {
+ convert_typed_floating ((char *)valbuf + offset, float_elt_type,
+ to, builtin_type_ia64_ext);
+ regcache_cooked_write (regcache, regnum, to);
+ offset += TYPE_LENGTH (float_elt_type);
+ regnum++;
+ }
+ }
+ else
+ {
+ ULONGEST val;
+ int offset = 0;
+ int regnum = IA64_GR8_REGNUM;
+ int reglen = TYPE_LENGTH (register_type (get_regcache_arch (regcache),
+ IA64_GR8_REGNUM));
+ int n = TYPE_LENGTH (type) / reglen;
+ int m = TYPE_LENGTH (type) % reglen;
+
+ while (n-- > 0)
+ {
+ ULONGEST val;
+ memcpy (&val, (char *)valbuf + offset, reglen);
+ regcache_cooked_write_unsigned (regcache, regnum, val);
+ offset += reglen;
+ regnum++;
+ }
+
+ if (m)
+ {
+ memcpy (&val, (char *)valbuf + offset, m);
+ regcache_cooked_write_unsigned (regcache, regnum, val);
+ }
+ }
}
+
+static enum return_value_convention
+ia64_return_value (struct gdbarch *gdbarch, struct type *valtype,
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf)
+{
+ int struct_return = ia64_use_struct_convention (valtype);
+
+ if (writebuf != NULL)
+ {
+ gdb_assert (!struct_return);
+ ia64_store_return_value (valtype, regcache, writebuf);
+ }
+
+ if (readbuf != NULL)
+ {
+ gdb_assert (!struct_return);
+ ia64_extract_return_value (valtype, regcache, readbuf);
+ }
+ if (struct_return)
+ return RETURN_VALUE_STRUCT_CONVENTION;
+ else
+ return RETURN_VALUE_REGISTER_CONVENTION;
+}
static int
is_float_or_hfa_type_recurse (struct type *t, struct type **etp)
stack using the address at fdaptr. */
static CORE_ADDR
-find_func_descr (CORE_ADDR faddr, CORE_ADDR *fdaptr)
+find_func_descr (struct regcache *regcache, CORE_ADDR faddr, CORE_ADDR *fdaptr)
{
CORE_ADDR fdesc;
if (fdesc == 0)
{
- CORE_ADDR global_pointer;
+ ULONGEST global_pointer;
char buf[16];
fdesc = *fdaptr;
global_pointer = ia64_find_global_pointer (faddr);
if (global_pointer == 0)
- global_pointer = read_register (IA64_GR1_REGNUM);
+ regcache_cooked_read_unsigned (regcache,
+ IA64_GR1_REGNUM, &global_pointer);
store_unsigned_integer (buf, 8, faddr);
store_unsigned_integer (buf + 8, 8, global_pointer);
if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
return read_memory_unsigned_integer (addr, 8);
+ /* There are also descriptors embedded in vtables. */
+ if (s)
+ {
+ struct minimal_symbol *minsym;
+
+ minsym = lookup_minimal_symbol_by_pc (addr);
+
+ if (minsym && is_vtable_name (SYMBOL_LINKAGE_NAME (minsym)))
+ return read_memory_unsigned_integer (addr, 8);
+ }
+
return addr;
}
int len, argoffset;
int nslots, rseslots, memslots, slotnum, nfuncargs;
int floatreg;
- CORE_ADDR bsp, cfm, pfs, new_bsp, funcdescaddr, pc, global_pointer;
+ ULONGEST bsp, cfm, pfs, new_bsp;
+ CORE_ADDR funcdescaddr, pc, global_pointer;
CORE_ADDR func_addr = find_function_addr (function, NULL);
nslots = 0;
memslots = nslots - rseslots;
/* Allocate a new RSE frame. */
- cfm = read_register (IA64_CFM_REGNUM);
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
- bsp = read_register (IA64_BSP_REGNUM);
+ regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
new_bsp = rse_address_add (bsp, rseslots);
- write_register (IA64_BSP_REGNUM, new_bsp);
+ regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
- pfs = read_register (IA64_PFS_REGNUM);
+ regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
pfs &= 0xc000000000000000LL;
pfs |= (cfm & 0xffffffffffffLL);
- write_register (IA64_PFS_REGNUM, pfs);
+ regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
cfm &= 0xc000000000000000LL;
cfm |= rseslots;
- write_register (IA64_CFM_REGNUM, cfm);
+ regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
/* We will attempt to find function descriptors in the .opd segment,
but if we can't we'll construct them ourselves. That being the
&& TYPE_CODE (TYPE_TARGET_TYPE (type)) == TYPE_CODE_FUNC)
{
char val_buf[8];
-
+ ULONGEST faddr = extract_unsigned_integer (value_contents (arg), 8);
store_unsigned_integer (val_buf, 8,
- find_func_descr (extract_unsigned_integer (value_contents (arg), 8),
+ find_func_descr (regcache, faddr,
&funcdescaddr));
if (slotnum < rseslots)
write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
global_pointer = ia64_find_global_pointer (func_addr);
if (global_pointer != 0)
- write_register (IA64_GR1_REGNUM, global_pointer);
+ regcache_cooked_write_unsigned (regcache, IA64_GR1_REGNUM, global_pointer);
- write_register (IA64_BR0_REGNUM, bp_addr);
+ regcache_cooked_write_unsigned (regcache, IA64_BR0_REGNUM, bp_addr);
- write_register (sp_regnum, sp);
+ regcache_cooked_write_unsigned (regcache, sp_regnum, sp);
return sp;
}
return pc;
}
-static void
-ia64_store_return_value (struct type *type, struct regcache *regcache, const void *valbuf)
-{
- if (TYPE_CODE (type) == TYPE_CODE_FLT)
- {
- char to[MAX_REGISTER_SIZE];
- convert_typed_floating (valbuf, type, to, builtin_type_ia64_ext);
- regcache_cooked_write (regcache, IA64_FR8_REGNUM, (void *)to);
- target_store_registers (IA64_FR8_REGNUM);
- }
- else
- regcache_cooked_write (regcache, IA64_GR8_REGNUM, valbuf);
-}
-
-static void
-ia64_remote_translate_xfer_address (struct gdbarch *gdbarch,
- struct regcache *regcache,
- CORE_ADDR memaddr, int nr_bytes,
- CORE_ADDR *targ_addr, int *targ_len)
-{
- *targ_addr = memaddr;
- *targ_len = nr_bytes;
-}
-
static int
ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info)
{
gdbarch = gdbarch_alloc (&info, tdep);
tdep->sigcontext_register_address = 0;
-
- /* Define the ia64 floating-point format to gdb. */
- builtin_type_ia64_ext =
- init_type (TYPE_CODE_FLT, 128 / 8,
- 0, "builtin_type_ia64_ext", NULL);
- TYPE_FLOATFORMAT (builtin_type_ia64_ext) = &floatformat_ia64_ext;
+ tdep->pc_in_sigtramp = 0;
/* According to the ia64 specs, instructions that store long double
floats in memory use a long-double format different than that
format for storing long doubles (e.g. HPUX). In the latter case,
the setting of the format may be moved/overridden in an
OS-specific tdep file. */
- set_gdbarch_long_double_format (gdbarch, &floatformat_i387_ext);
+ set_gdbarch_long_double_format (gdbarch, floatformats_i387_ext);
set_gdbarch_short_bit (gdbarch, 16);
set_gdbarch_int_bit (gdbarch, 32);
set_gdbarch_fp0_regnum (gdbarch, IA64_FR0_REGNUM);
set_gdbarch_register_name (gdbarch, ia64_register_name);
- /* FIXME: Following interface should not be needed, however, without it recurse.exp
- gets a number of extra failures. */
- set_gdbarch_deprecated_register_size (gdbarch, 8);
set_gdbarch_register_type (gdbarch, ia64_register_type);
set_gdbarch_pseudo_register_read (gdbarch, ia64_pseudo_register_read);
set_gdbarch_skip_prologue (gdbarch, ia64_skip_prologue);
- set_gdbarch_deprecated_use_struct_convention (gdbarch, ia64_use_struct_convention);
- set_gdbarch_extract_return_value (gdbarch, ia64_extract_return_value);
-
- set_gdbarch_store_return_value (gdbarch, ia64_store_return_value);
- set_gdbarch_deprecated_extract_struct_value_address (gdbarch, ia64_extract_struct_value_address);
+ set_gdbarch_return_value (gdbarch, ia64_return_value);
set_gdbarch_memory_insert_breakpoint (gdbarch, ia64_memory_insert_breakpoint);
set_gdbarch_memory_remove_breakpoint (gdbarch, ia64_memory_remove_breakpoint);
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);
/* Settings that should be unnecessary. */
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
- set_gdbarch_remote_translate_xfer_address (
- gdbarch, ia64_remote_translate_xfer_address);
-
set_gdbarch_print_insn (gdbarch, ia64_print_insn);
set_gdbarch_convert_from_func_ptr_addr (gdbarch, ia64_convert_from_func_ptr_addr);
+ /* The virtual table contains 16-byte descriptors, not pointers to
+ descriptors. */
+ set_gdbarch_vtable_function_descriptors (gdbarch, 1);
+
/* Hook in ABI-specific overrides, if they have been registered. */
gdbarch_init_osabi (info, gdbarch);
void
_initialize_ia64_tdep (void)
{
+ /* Define the ia64 floating-point format to gdb. */
+ builtin_type_ia64_ext =
+ init_type (TYPE_CODE_FLT, 128 / 8,
+ 0, "builtin_type_ia64_ext", NULL);
+ TYPE_FLOATFORMAT (builtin_type_ia64_ext) = floatformats_ia64_ext;
+
gdbarch_register (bfd_arch_ia64, ia64_gdbarch_init, NULL);
}