Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
From: Joel Brobecker <brobecker@adacore.com>
To: gdb-patches@sourceware.org
Cc: Joel Brobecker <brobecker@adacore.com>
Subject: [PATCH 7/8] ia64-hpux: unwinding bsp value from system call
Date: Tue, 28 Dec 2010 04:54:00 -0000	[thread overview]
Message-ID: <1293511386-7384-8-git-send-email-brobecker@adacore.com> (raw)
In-Reply-To: <1293511386-7384-1-git-send-email-brobecker@adacore.com>

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 ttrace call, which is not directly possible from ia64-tdep.c.
     So we get the info using a target-read of a TARGET_OBJECT_OSDATA
     object (with the annex set to "ia64.hpux.in_syscall").

  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:

        * 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".
        (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_in_syscall): New function.
        (ia64_hpux_xfer_os_data): New function.
        (ia64_hpux_xfer_partial): Add handling of TARGET_OBJECT_OSDATA objects.

---
 gdb/ia64-hpux-nat.c  |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/ia64-hpux-tdep.c |   47 +++++++++++++++++++++++++++++++++++++++++
 gdb/ia64-tdep.c      |   14 ++++++++++-
 gdb/ia64-tdep.h      |    9 ++++++++
 4 files changed, 124 insertions(+), 2 deletions(-)

diff --git a/gdb/ia64-hpux-nat.c b/gdb/ia64-hpux-nat.c
index 53941a7..dfa6b7f 100644
--- a/gdb/ia64-hpux-nat.c
+++ b/gdb/ia64-hpux-nat.c
@@ -567,6 +567,60 @@ ia64_hpux_xfer_memory (struct target_ops *ops, const char *annex,
   return len;
 }
 
+/* Handle the transfer of the "ia64.hpux.in_syscall" TARGET_OBJECT_OSDATA
+   object.  */
+
+static LONGEST
+ia64_hpux_xfer_in_syscall (struct target_ops *ops, gdb_byte *readbuf,
+			   LONGEST len)
+{
+  struct gdbarch *gdbarch = target_gdbarch;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  gdb_byte buf[8];
+  int status;
+
+  gdb_assert (len > 0); /* We need 1 byte to write the return value.  */
+
+  status = ia64_hpux_read_register_from_save_state_t (__reason, buf, 8);
+  if (status < 0)
+    {
+      /* This should never happen, but if it does, just warn the user
+	 and return -1 (we don't know).  The caller should be able to
+	 handle this condition.  */
+      warning (_("failed to read reason pseudo-register"));
+      return -1;
+    }
+
+  readbuf[0] = (extract_unsigned_integer (buf, 8, byte_order) == 0);
+  return 1;
+}
+
+/* Handle the transfer of TARGET_OBJECT_OSDATA objects on ia64-hpux.
+
+   The type of data being requested depends on the value of ANNEX:
+
+     * "ia64.hpux.in_syscall":
+       Store a 1-byte integer in READBUF.  The value of that integer
+       is nonzero iff the inferior is stopped inside a system call.
+       OFFSET is ignored.
+
+   Any other request is deferred to super_xfer_partial.
+   ANNEX is assumed to never be NULL.  */
+
+static LONGEST
+ia64_hpux_xfer_os_data (struct target_ops *ops, const char *annex,
+			gdb_byte *readbuf, ULONGEST offset, LONGEST len)
+{
+  gdb_assert (annex != NULL);
+
+  if (strcmp (annex, "ia64.hpux.in_syscall") == 0)
+    return ia64_hpux_xfer_in_syscall (ops, readbuf, len);
+  else
+    /* Unknown OSDATA request, delegate to super_xfer_partial.  */
+    return super_xfer_partial (ops, TARGET_OBJECT_OSDATA, annex, readbuf,
+                               NULL, offset, len);
+}
+
 /* The "to_xfer_partial" target_ops routine for ia64-hpux.  */
 
 static LONGEST
@@ -578,6 +632,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 (readbuf && object == TARGET_OBJECT_OSDATA && annex)
+    val = ia64_hpux_xfer_os_data (ops, annex, readbuf, 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..5dd0a4e 100644
--- a/gdb/ia64-hpux-tdep.c
+++ b/gdb/ia64-hpux-tdep.c
@@ -23,6 +23,8 @@
 #include "osabi.h"
 #include "gdbtypes.h"
 #include "solib.h"
+#include "target.h"
+#include "frame.h"
 
 /* Return nonzero if the value of the register identified by REGNUM
    can be modified.  */
@@ -74,6 +76,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[1];
+  int len;
+
+  len = target_read (ops, TARGET_OBJECT_OSDATA, "ia64.hpux.in_syscall",
+		     buf, 0, 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 == 1);
+
+  return extract_unsigned_integer (buf, len, byte_order);
+}
+
+/* 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 +126,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 1cd6a38..1cfffc7 100644
--- a/gdb/ia64-tdep.c
+++ b/gdb/ia64-tdep.c
@@ -2423,7 +2423,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, 
@@ -2460,7 +2460,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;
 
@@ -3812,6 +3812,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)
 {
@@ -3826,6 +3834,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 b7a8eaf..b88031e 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;
 };
-- 
1.7.1


  parent reply	other threads:[~2010-12-28  4:44 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-12-28  4:43 Porting GDB to ia64-hpux Joel Brobecker
2010-12-28  4:43 ` [PATCH 2/8] small integral parameters and return values Joel Brobecker
2010-12-28  4:43 ` [PATCH 4/8] libunwind-frame.c: handle functions with no minimal symbol/debug info Joel Brobecker
2010-12-28  4:43 ` [PATCH 1/8] Add a big-endian version of the ia64-ext floatformat Joel Brobecker
2010-12-28  4:44 ` [PATCH 6/8] port GDB to ia64-hpux (native) Joel Brobecker
2011-01-11 23:26   ` Steve Ellcey
2011-01-12  1:26     ` Joel Brobecker
2011-01-12 16:57       ` Steve Ellcey
2011-01-12 20:11         ` Joel Brobecker
2011-01-13  1:01     ` Joel Brobecker
2011-01-13  5:13       ` Steve Ellcey
     [not found]       ` <1299014508.30497.20.camel@hpsje.cup.hp.com>
     [not found]         ` <20110302044549.GU2513@adacore.com>
     [not found]           ` <1299171098.30497.88.camel@hpsje.cup.hp.com>
     [not found]             ` <20110303172717.GJ2513@adacore.com>
     [not found]               ` <1299173882.30497.114.camel@hpsje.cup.hp.com>
2011-06-17 16:30                 ` Joel Brobecker
2011-01-13 18:07   ` Joel Brobecker
2010-12-28  4:44 ` [PATCH 3/8] Make sure __LITTLE_ENDIAN/__BIG_ENDIAN are defined in libunwind-frame.c Joel Brobecker
2010-12-28  4:44 ` [PATCH 5/8] inf-ttrace: Determine attached process LWP immediately after attaching Joel Brobecker
2010-12-28 11:04   ` Pedro Alves
2010-12-28 11:26     ` Joel Brobecker
2010-12-28  4:54 ` Joel Brobecker [this message]
2010-12-28 11:35   ` [PATCH 7/8] ia64-hpux: unwinding bsp value from system call Pedro Alves
2010-12-28 12:01     ` Joel Brobecker
2010-12-28 16:17       ` Pedro Alves
2010-12-29  5:49         ` Joel Brobecker
2010-12-29 12:05           ` Pedro Alves
2010-12-29 13:16             ` Joel Brobecker
2010-12-31 18:15             ` Joel Brobecker
2010-12-28 15:29     ` [RFA/commit] Add documentation for TARGET_OBJECT_OSDATA Joel Brobecker
2010-12-28 15:46       ` Pedro Alves
2010-12-29  3:29       ` Joel Brobecker
2010-12-28  5:00 ` [PATCH 8/8] [ia64-hpux] inferior function call support Joel Brobecker
2010-12-31 19:18   ` Joel Brobecker
2011-01-13 16:53 ` Porting GDB to ia64-hpux Joel Brobecker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1293511386-7384-8-git-send-email-brobecker@adacore.com \
    --to=brobecker@adacore.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox