/* Target-dependent code for the IA-64 for GDB, the GNU debugger.
- Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
- 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1999-2012 Free Software Foundation, Inc.
This file is part of GDB.
#ifdef HAVE_LIBUNWIND_IA64_H
#include "elf/ia64.h" /* for PT_IA_64_UNWIND value */
-#include "libunwind-frame.h"
-#include "libunwind-ia64.h"
+#include "ia64-libunwind-tdep.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
/* In BUNDLE_MEM, be careful to modify only the bits belonging to SLOTNUM
and not any of the other ones that are stored in SHADOW_CONTENTS. */
replace_slotN_contents (bundle_mem, instr_saved, slotnum);
- val = target_write_memory (addr, bundle_mem, BUNDLE_LEN);
+ val = target_write_raw_memory (addr, bundle_mem, BUNDLE_LEN);
do_cleanups (cleanup);
return val;
return new_addr;
}
-static void
+static enum register_status
ia64_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int regnum, gdb_byte *buf)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ enum register_status status;
if (regnum >= V32_REGNUM && regnum <= V127_REGNUM)
{
found sequentially in memory starting at $bof. This
isn't always true, but without libunwind, this is the
best we can do. */
+ enum register_status status;
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);
-
+
+ status = regcache_cooked_read_unsigned (regcache,
+ IA64_BSP_REGNUM, &bsp);
+ if (status != REG_VALID)
+ return status;
+
+ status = regcache_cooked_read_unsigned (regcache,
+ IA64_CFM_REGNUM, &cfm);
+ if (status != REG_VALID)
+ return status;
+
/* 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. */
{
ULONGEST unatN_val;
ULONGEST unat;
- regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
+ status = regcache_cooked_read_unsigned (regcache, IA64_UNAT_REGNUM, &unat);
+ if (status != REG_VALID)
+ return status;
unatN_val = (unat & (1LL << (regnum - IA64_NAT0_REGNUM))) != 0;
store_unsigned_integer (buf, register_size (gdbarch, regnum),
byte_order, unatN_val);
ULONGEST bsp;
ULONGEST cfm;
CORE_ADDR gr_addr = 0;
- regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
- regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+ status = regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ if (status != REG_VALID)
+ return status;
+ status = regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+ if (status != REG_VALID)
+ return status;
/* 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. */
It can be calculated as the bsp - sof (sizeof frame). */
ULONGEST bsp, vbsp;
ULONGEST cfm;
- CORE_ADDR reg;
- regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
- regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+ status = regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
+ if (status != REG_VALID)
+ return status;
+ status = regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+ if (status != REG_VALID)
+ return status;
/* The bsp points at the end of the register frame so we
subtract the size of frame from it to get beginning of frame. */
ULONGEST pr;
ULONGEST cfm;
ULONGEST prN_val;
- CORE_ADDR reg;
- regcache_cooked_read_unsigned (regcache, IA64_PR_REGNUM, &pr);
- regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+ status = regcache_cooked_read_unsigned (regcache, IA64_PR_REGNUM, &pr);
+ if (status != REG_VALID)
+ return status;
+ status = regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+ if (status != REG_VALID)
+ return status;
if (VP16_REGNUM <= regnum && regnum <= VP63_REGNUM)
{
}
else
memset (buf, 0, register_size (gdbarch, regnum));
+
+ return REG_VALID;
}
static void
{
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);
collection from the computed address. */
if (nat_addr >= bsp)
{
- regcache_cooked_read_unsigned (regcache, IA64_RNAT_REGNUM,
+ regcache_cooked_read_unsigned (regcache,
+ IA64_RNAT_REGNUM,
&nat_collection);
if (natN_val)
nat_collection |= natN_mask;
&& type != ia64_ext_type (gdbarch));
}
-static void
+static int
ia64_register_to_value (struct frame_info *frame, int regnum,
- struct type *valtype, gdb_byte *out)
+ struct type *valtype, gdb_byte *out,
+ int *optimizedp, int *unavailablep)
{
struct gdbarch *gdbarch = get_frame_arch (frame);
char in[MAX_REGISTER_SIZE];
- frame_register_read (frame, regnum, in);
+
+ /* Convert to TYPE. */
+ if (!get_frame_register_bytes (frame, regnum, 0,
+ register_size (gdbarch, regnum),
+ in, optimizedp, unavailablep))
+ return 0;
+
convert_typed_floating (in, ia64_ext_type (gdbarch), out, valtype);
+ *optimizedp = *unavailablep = 0;
+ return 1;
}
static void
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct ia64_frame_cache *cache;
char buf[8];
- CORE_ADDR cfm, sof, sol, bsp, psr;
- int i;
+ CORE_ADDR cfm, psr;
if (*this_cache)
return *this_cache;
static const struct frame_unwind ia64_frame_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
&ia64_frame_this_id,
&ia64_frame_prev_register,
NULL,
struct gdbarch *gdbarch = get_frame_arch (this_frame);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct ia64_frame_cache *cache;
- CORE_ADDR addr;
char buf[8];
- int i;
if (*this_cache)
return *this_cache;
static const struct frame_unwind ia64_sigtramp_frame_unwind =
{
SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
ia64_sigtramp_frame_this_id,
ia64_sigtramp_frame_prev_register,
NULL,
return addr + ((num_regs + delta/0x3f) << 3);
}
-/* Gdb libunwind-frame callback function to convert from an ia64 gdb register
- number to a libunwind register number. */
+/* Gdb ia64-libunwind-tdep callback function to convert from an ia64 gdb
+ register number to a libunwind register number. */
static int
ia64_gdb2uw_regnum (int regnum)
{
return -1;
}
-/* Gdb libunwind-frame callback function to convert from a libunwind register
- number to a ia64 gdb register number. */
+/* Gdb ia64-libunwind-tdep callback function to convert from a libunwind
+ register number to a ia64 gdb register number. */
static int
ia64_uw2gdb_regnum (int uw_regnum)
{
return -1;
}
-/* Gdb libunwind-frame callback function to reveal if register is a float
- register or not. */
+/* Gdb ia64-libunwind-tdep callback function to reveal if register is
+ a float register or not. */
static int
ia64_is_fpreg (int uw_regnum)
{
return unw_is_fpreg (uw_regnum);
}
-
+
/* Libunwind callback accessor function for general registers. */
static int
ia64_access_reg (unw_addr_space_t as, unw_regnum_t uw_regnum, unw_word_t *val,
bsp = extract_unsigned_integer (buf, 8, byte_order);
get_frame_register (this_frame, IA64_CFM_REGNUM, buf);
cfm = extract_unsigned_integer (buf, 8, byte_order);
- sof = (cfm & 0x7f);
+ sof = gdbarch_tdep (gdbarch)->size_of_register_frame (this_frame, cfm);
*val = ia64_rse_skip_regs (bsp, -sof);
break;
static const struct frame_unwind ia64_libunwind_frame_unwind =
{
NORMAL_FRAME,
+ default_frame_unwind_stop_reason,
ia64_libunwind_frame_this_id,
ia64_libunwind_frame_prev_register,
NULL,
static const struct frame_unwind ia64_libunwind_sigtramp_frame_unwind =
{
SIGTRAMP_FRAME,
+ default_frame_unwind_stop_reason,
ia64_libunwind_sigtramp_frame_this_id,
ia64_libunwind_sigtramp_frame_prev_register,
NULL,
};
/* Set of libunwind callback acccessor functions. */
-static unw_accessors_t ia64_unw_accessors =
+unw_accessors_t ia64_unw_accessors =
{
ia64_find_proc_info_x,
ia64_put_unwind_info,
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 =
+unw_accessors_t ia64_unw_rse_accessors =
{
ia64_find_proc_info_x,
ia64_put_unwind_info,
/* 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 =
+/* Set of ia64-libunwind-tdep gdb callbacks and data for generic
+ ia64-libunwind-tdep code to use. */
+struct libunwind_descr ia64_libunwind_descr =
{
ia64_gdb2uw_regnum,
ia64_uw2gdb_regnum,
}
static enum return_value_convention
-ia64_return_value (struct gdbarch *gdbarch, struct type *func_type,
+ia64_return_value (struct gdbarch *gdbarch, struct value *function,
struct type *valtype, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf)
{
d_un.d_ptr value is the global pointer. */
static CORE_ADDR
-ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
+ia64_find_global_pointer_from_dynamic_section (struct gdbarch *gdbarch,
+ CORE_ADDR faddr)
{
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
struct obj_section *faddr_sect;
return 0;
}
+/* Attempt to find (and return) the global pointer for the given
+ function. We first try the find_global_pointer_from_solib routine
+ from the gdbarch tdep vector, if provided. And if that does not
+ work, then we try ia64_find_global_pointer_from_dynamic_section. */
+
+static CORE_ADDR
+ia64_find_global_pointer (struct gdbarch *gdbarch, CORE_ADDR faddr)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ CORE_ADDR addr = 0;
+
+ if (tdep->find_global_pointer_from_solib)
+ addr = tdep->find_global_pointer_from_solib (gdbarch, faddr);
+ if (addr == 0)
+ addr = ia64_find_global_pointer_from_dynamic_section (gdbarch, faddr);
+ return addr;
+}
+
/* Given a function's address, attempt to find (and return) the
corresponding (canonical) function descriptor. Return 0 if
not found. */
return sp & ~0xfLL;
}
+/* The default "allocate_new_rse_frame" ia64_infcall_ops routine for ia64. */
+
+static void
+ia64_allocate_new_rse_frame (struct regcache *regcache, ULONGEST bsp, int sof)
+{
+ ULONGEST cfm, pfs, new_bsp;
+
+ regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
+
+ new_bsp = rse_address_add (bsp, sof);
+ regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
+
+ regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
+ pfs &= 0xc000000000000000LL;
+ pfs |= (cfm & 0xffffffffffffLL);
+ regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
+
+ cfm &= 0xc000000000000000LL;
+ cfm |= sof;
+ regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
+}
+
+/* The default "store_argument_in_slot" ia64_infcall_ops routine for
+ ia64. */
+
+static void
+ia64_store_argument_in_slot (struct regcache *regcache, CORE_ADDR bsp,
+ int slotnum, gdb_byte *buf)
+{
+ write_memory (rse_address_add (bsp, slotnum), buf, 8);
+}
+
+/* The default "set_function_addr" ia64_infcall_ops routine for ia64. */
+
+static void
+ia64_set_function_addr (struct regcache *regcache, CORE_ADDR func_addr)
+{
+ /* Nothing needed. */
+}
+
static CORE_ADDR
ia64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
struct regcache *regcache, CORE_ADDR bp_addr,
int nargs, struct value **args, CORE_ADDR sp,
int struct_return, CORE_ADDR struct_addr)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
int argno;
struct value *arg;
int len, argoffset;
int nslots, rseslots, memslots, slotnum, nfuncargs;
int floatreg;
- ULONGEST bsp, cfm, pfs, new_bsp;
+ ULONGEST bsp;
CORE_ADDR funcdescaddr, pc, global_pointer;
CORE_ADDR func_addr = find_function_addr (function, NULL);
memslots = nslots - rseslots;
/* Allocate a new RSE frame. */
- regcache_cooked_read_unsigned (regcache, IA64_CFM_REGNUM, &cfm);
-
regcache_cooked_read_unsigned (regcache, IA64_BSP_REGNUM, &bsp);
- new_bsp = rse_address_add (bsp, rseslots);
- regcache_cooked_write_unsigned (regcache, IA64_BSP_REGNUM, new_bsp);
-
- regcache_cooked_read_unsigned (regcache, IA64_PFS_REGNUM, &pfs);
- pfs &= 0xc000000000000000LL;
- pfs |= (cfm & 0xffffffffffffLL);
- regcache_cooked_write_unsigned (regcache, IA64_PFS_REGNUM, pfs);
-
- cfm &= 0xc000000000000000LL;
- cfm |= rseslots;
- regcache_cooked_write_unsigned (regcache, IA64_CFM_REGNUM, cfm);
+ tdep->infcall_ops.allocate_new_rse_frame (regcache, bsp, rseslots);
/* We will attempt to find function descriptors in the .opd segment,
but if we can't we'll construct them ourselves. That being the
find_func_descr (regcache, faddr,
&funcdescaddr));
if (slotnum < rseslots)
- write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+ tdep->infcall_ops.store_argument_in_slot (regcache, bsp,
+ slotnum, val_buf);
else
write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
slotnum++;
}
if (slotnum < rseslots)
- write_memory (rse_address_add (bsp, slotnum), val_buf, 8);
+ tdep->infcall_ops.store_argument_in_slot (regcache, bsp,
+ slotnum, val_buf);
else
write_memory (sp + 16 + 8 * (slotnum - rseslots), val_buf, 8);
if (global_pointer != 0)
regcache_cooked_write_unsigned (regcache, IA64_GR1_REGNUM, global_pointer);
+ /* The following is not necessary on HP-UX, because we're using
+ a dummy code sequence pushed on the stack to make the call, and
+ this sequence doesn't need b0 to be set in order for our dummy
+ breakpoint to be hit. Nonetheless, this doesn't interfere, and
+ it's needed for other OSes, so we do this unconditionaly. */
regcache_cooked_write_unsigned (regcache, IA64_BR0_REGNUM, bp_addr);
regcache_cooked_write_unsigned (regcache, sp_regnum, sp);
+ tdep->infcall_ops.set_function_addr (regcache, func_addr);
+
return sp;
}
+static const struct ia64_infcall_ops ia64_infcall_ops =
+{
+ ia64_allocate_new_rse_frame,
+ ia64_store_argument_in_slot,
+ ia64_set_function_addr
+};
+
static struct frame_id
ia64_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame)
{
return print_insn_ia64 (memaddr, info);
}
+/* The default "size_of_register_frame" gdbarch_tdep routine for ia64. */
+
+static int
+ia64_size_of_register_frame (struct frame_info *this_frame, ULONGEST cfm)
+{
+ return (cfm & 0x7f);
+}
+
static struct gdbarch *
ia64_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
{
tdep = xzalloc (sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
+ tdep->size_of_register_frame = ia64_size_of_register_frame;
+
/* According to the ia64 specs, instructions that store long double
floats in memory use a long-double format different than that
used in the floating registers. The memory format matches the
/* Settings for calling functions in the inferior. */
set_gdbarch_push_dummy_call (gdbarch, ia64_push_dummy_call);
+ tdep->infcall_ops = ia64_infcall_ops;
set_gdbarch_frame_align (gdbarch, ia64_frame_align);
set_gdbarch_dummy_id (gdbarch, ia64_dummy_id);