aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Brobecker <brobecker@gnat.com>2011-01-13 16:24:27 +0000
committerJoel Brobecker <brobecker@gnat.com>2011-01-13 16:24:27 +0000
commit77ca787b12516ebb1b0d23710021b26b9c81b018 (patch)
treec566d4c91a59e95671e251887b36d704ec6e8d1a
parent92c9a4639bb3294d74a36b6d0c0cb07771bbe906 (diff)
downloadfsf-binutils-gdb-77ca787b12516ebb1b0d23710021b26b9c81b018.zip
fsf-binutils-gdb-77ca787b12516ebb1b0d23710021b26b9c81b018.tar.gz
fsf-binutils-gdb-77ca787b12516ebb1b0d23710021b26b9c81b018.tar.bz2
[ia64-hpux] unwinding bsp value from system call
This fixes unwinding from a thread that is stopped inside a system call. This can be seen when switching to a thread that is stopped doing a pthread_cond_wait, for instance... The comments inside the code should explain what is happening in our case (the HP-UX exception in the case of system calls): Under certain circumstances (program stopped inside syscall), the offset to apply to the current BSP in order to compute the previous BSP is not the usual CFM & 0x7f. We parts in this patch: 1. Figuring out that we are stopped inside a syscal: This requires a TT_LWP_RUREGS ttrace call, which is not directly possible from ia64-tdep.c. So use defined a new TARGET_OBJECT_HPUX_UREGS object to request it from the -nat side. 2. Add a gdbarch_tdep method that allows us to change the default behavior on ia64-hpux, permitting us to have a different "size of register frame" in that one particular case. gdb/ChangeLog: * target.h (enum target_object): Add TARGET_OBJECT_HPUX_UREGS. * ia64-tdep.h (struct frame_info): forward declaration. (struct gdbarch_tdep): Add field size_of_register_frame. * ia64-tdep.c (ia64_access_reg): Use tdep->size_of_register_frame to determine the size of the register frame. (ia64_size_of_register_frame): New function. (ia64_gdbarch_init): Set tdep->size_of_register_frame. * ia64-hpux-tdep.c: Include "target.h" and "frame.h". (IA64_HPUX_UREG_REASON): New macro. (ia64_hpux_stopped_in_syscall, ia64_hpux_size_of_register_frame): New functions. (ia64_hpux_init_abi): Set tdep->size_of_register_frame. * ia64-hpux-nat.c (ia64_hpux_xfer_uregs): New function. (ia64_hpux_xfer_partial): Add handling of TARGET_OBJECT_HPUX_UREGS objects.
-rw-r--r--gdb/ChangeLog18
-rw-r--r--gdb/ia64-hpux-nat.c24
-rw-r--r--gdb/ia64-hpux-tdep.c56
-rw-r--r--gdb/ia64-tdep.c14
-rw-r--r--gdb/ia64-tdep.h9
-rw-r--r--gdb/target.h3
6 files changed, 122 insertions, 2 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 814b0dc..54a8d05 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,23 @@
2011-01-13 Joel Brobecker <brobecker@adacore.com>
+ * target.h (enum target_object): Add TARGET_OBJECT_HPUX_UREGS.
+ * ia64-tdep.h (struct frame_info): forward declaration.
+ (struct gdbarch_tdep): Add field size_of_register_frame.
+ * ia64-tdep.c (ia64_access_reg): Use tdep->size_of_register_frame
+ to determine the size of the register frame.
+ (ia64_size_of_register_frame): New function.
+ (ia64_gdbarch_init): Set tdep->size_of_register_frame.
+ * ia64-hpux-tdep.c: Include "target.h" and "frame.h".
+ (IA64_HPUX_UREG_REASON): New macro.
+ (ia64_hpux_stopped_in_syscall, ia64_hpux_size_of_register_frame):
+ New functions.
+ (ia64_hpux_init_abi): Set tdep->size_of_register_frame.
+ * ia64-hpux-nat.c (ia64_hpux_xfer_uregs): New function.
+ (ia64_hpux_xfer_partial): Add handling of TARGET_OBJECT_HPUX_UREGS
+ objects.
+
+2011-01-13 Joel Brobecker <brobecker@adacore.com>
+
Add support for ia64-hpux.
* config/ia64/hpux.mh, ia64-hpux-nat.c, ia64-hpux-tdep.c,
ia64-hpux-tdep.h, solib-ia64-hpux.c, solib-ia64-hpux.h: New files.
diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
index ca1c278..fd58bba 100644
--- a/gdb/ia64-hpux-nat.c
+++ b/gdb/ia64-hpux-nat.c
@@ -568,6 +568,28 @@ ia64_hpux_xfer_memory (struct target_ops *ops, const char *annex,
return len;
}
+/* Handle the transfer of TARGET_OBJECT_HPUX_UREGS objects on ia64-hpux.
+ ANNEX is currently ignored.
+
+ The current implementation does not support write transfers (because
+ we do not currently do not need these transfers), and will raise
+ a failed assertion if WRITEBUF is not NULL. */
+
+static LONGEST
+ia64_hpux_xfer_uregs (struct target_ops *ops, const char *annex,
+ gdb_byte *readbuf, const gdb_byte *writebuf,
+ ULONGEST offset, LONGEST len)
+{
+ int status;
+
+ gdb_assert (writebuf == NULL);
+
+ status = ia64_hpux_read_register_from_save_state_t (offset, readbuf, len);
+ if (status < 0)
+ return -1;
+ return len;
+}
+
/* The "to_xfer_partial" target_ops routine for ia64-hpux. */
static LONGEST
@@ -579,6 +601,8 @@ ia64_hpux_xfer_partial (struct target_ops *ops, enum target_object object,
if (object == TARGET_OBJECT_MEMORY)
val = ia64_hpux_xfer_memory (ops, annex, readbuf, writebuf, offset, len);
+ else if (object == TARGET_OBJECT_HPUX_UREGS)
+ val = ia64_hpux_xfer_uregs (ops, annex, readbuf, writebuf, offset, len);
else
val = super_xfer_partial (ops, object, annex, readbuf, writebuf, offset,
len);
diff --git a/gdb/ia64-hpux-tdep.c b/gdb/ia64-hpux-tdep.c
index 139ff83..a4d2fa7 100644
--- a/gdb/ia64-hpux-tdep.c
+++ b/gdb/ia64-hpux-tdep.c
@@ -23,6 +23,17 @@
#include "osabi.h"
#include "gdbtypes.h"
#include "solib.h"
+#include "target.h"
+#include "frame.h"
+
+/* The offset to be used in order to get the __reason pseudo-register
+ when using one of the *UREGS ttrace requests (see system header file
+ /usr/include/ia64/sys/uregs.h for more details).
+
+ The documentation for this pseudo-register says that a nonzero value
+ indicates that the thread stopped due to a fault, trap, or interrupt.
+ A null value indicates a stop inside a syscall. */
+#define IA64_HPUX_UREG_REASON 0x00070000
/* Return nonzero if the value of the register identified by REGNUM
can be modified. */
@@ -74,6 +85,47 @@ ia64_hpux_cannot_store_register (struct gdbarch *gdbarch, int regnum)
return 0;
}
+/* Return nonzero if the inferior is stopped inside a system call. */
+
+static int
+ia64_hpux_stopped_in_syscall (struct gdbarch *gdbarch)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+ struct target_ops *ops = &current_target;
+ gdb_byte buf[8];
+ int len;
+
+ len = target_read (ops, TARGET_OBJECT_HPUX_UREGS, NULL,
+ buf, IA64_HPUX_UREG_REASON, sizeof (buf));
+ if (len == -1)
+ /* The target wasn't able to tell us. Assume we are not stopped
+ in a system call, which is the normal situation. */
+ return 0;
+ gdb_assert (len == 8);
+
+ return (extract_unsigned_integer (buf, len, byte_order) == 0);
+}
+
+/* The "size_of_register_frame" gdbarch_tdep routine for ia64-hpux. */
+
+static int
+ia64_hpux_size_of_register_frame (struct frame_info *this_frame,
+ ULONGEST cfm)
+{
+ int sof;
+
+ if (frame_relative_level (this_frame) == 0
+ && ia64_hpux_stopped_in_syscall (get_frame_arch (this_frame)))
+ /* If the inferior stopped in a system call, the base address
+ of the register frame is at BSP - SOL instead of BSP - SOF.
+ This is an HP-UX exception. */
+ sof = (cfm & 0x3f80) >> 7;
+ else
+ sof = (cfm & 0x7f);
+
+ return sof;
+}
+
/* Should be set to non-NULL if the ia64-hpux solib module is linked in.
This may not be the case because the shared library support code can
only be compiled on ia64-hpux. */
@@ -83,6 +135,10 @@ struct target_so_ops *ia64_hpux_so_ops = NULL;
static void
ia64_hpux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ tdep->size_of_register_frame = ia64_hpux_size_of_register_frame;
+
set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad);
set_gdbarch_cannot_store_register (gdbarch, ia64_hpux_cannot_store_register);
diff --git a/gdb/ia64-tdep.c b/gdb/ia64-tdep.c
index 05ca3a1..2529897 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -2452,7 +2452,7 @@ 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,
@@ -2490,7 +2490,7 @@ 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;
@@ -3848,6 +3848,14 @@ ia64_print_insn (bfd_vma memaddr, struct disassemble_info *info)
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)
{
@@ -3862,6 +3870,8 @@ 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
diff --git a/gdb/ia64-tdep.h b/gdb/ia64-tdep.h
index 7e53cb6..384cb14 100644
--- a/gdb/ia64-tdep.h
+++ b/gdb/ia64-tdep.h
@@ -195,11 +195,20 @@
#define IA64_NAT32_REGNUM (IA64_NAT0_REGNUM + 32)
#define IA64_NAT127_REGNUM (IA64_NAT0_REGNUM + 127)
+struct frame_info;
+
struct gdbarch_tdep
{
CORE_ADDR (*sigcontext_register_address) (struct gdbarch *, CORE_ADDR, int);
int (*pc_in_sigtramp) (CORE_ADDR);
+ /* Return the total size of THIS_FRAME's register frame.
+ CFM is THIS_FRAME's cfm register value.
+
+ Normally, the size of the register frame is always obtained by
+ extracting the lowest 7 bits ("cfm & 0x7f"). */
+ int (*size_of_register_frame) (struct frame_info *this_frame, ULONGEST cfm);
+
/* ISA-specific data types. */
struct type *ia64_ext_type;
};
diff --git a/gdb/target.h b/gdb/target.h
index a1288d0..4b2e6a8 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -266,6 +266,9 @@ enum target_object
TARGET_OBJECT_THREADS,
/* Collected static trace data. */
TARGET_OBJECT_STATIC_TRACE_DATA,
+ /* The HP-UX registers (those that can be obtained or modified by using
+ the TT_LWP_RUREGS/TT_LWP_WUREGS ttrace requests). */
+ TARGET_OBJECT_HPUX_UREGS,
/* Possible future objects: TARGET_OBJECT_FILE, ... */
};