aboutsummaryrefslogtreecommitdiff
path: root/gdb/linux-nat.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r--gdb/linux-nat.c59
1 files changed, 57 insertions, 2 deletions
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 0b098a0..a54ebb4 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -205,6 +205,13 @@ static struct target_ops linux_ops_saved;
/* The method to call, if any, when a new thread is attached. */
static void (*linux_nat_new_thread) (ptid_t);
+/* The method to call, if any, when the siginfo object needs to be
+ converted between the layout returned by ptrace, and the layout in
+ the architecture of the inferior. */
+static int (*linux_nat_siginfo_fixup) (struct siginfo *,
+ gdb_byte *,
+ int);
+
/* The saved to_xfer_partial method, inherited from inf-ptrace.c.
Called by our to_xfer_partial. */
static LONGEST (*super_xfer_partial) (struct target_ops *,
@@ -3223,6 +3230,28 @@ linux_nat_mourn_inferior (struct target_ops *ops)
linux_fork_mourn_inferior ();
}
+/* Convert a native/host siginfo object, into/from the siginfo in the
+ layout of the inferiors' architecture. */
+
+static void
+siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction)
+{
+ int done = 0;
+
+ if (linux_nat_siginfo_fixup != NULL)
+ done = linux_nat_siginfo_fixup (siginfo, inf_siginfo, direction);
+
+ /* If there was no callback, or the callback didn't do anything,
+ then just do a straight memcpy. */
+ if (!done)
+ {
+ if (direction == 1)
+ memcpy (siginfo, inf_siginfo, sizeof (struct siginfo));
+ else
+ memcpy (inf_siginfo, siginfo, sizeof (struct siginfo));
+ }
+}
+
static LONGEST
linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
@@ -3232,6 +3261,7 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
LONGEST n;
int pid;
struct siginfo siginfo;
+ gdb_byte inf_siginfo[sizeof (struct siginfo)];
gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO);
gdb_assert (readbuf || writebuf);
@@ -3248,14 +3278,26 @@ linux_xfer_siginfo (struct target_ops *ops, enum target_object object,
if (errno != 0)
return -1;
+ /* When GDB is built as a 64-bit application, ptrace writes into
+ SIGINFO an object with 64-bit layout. Since debugging a 32-bit
+ inferior with a 64-bit GDB should look the same as debugging it
+ with a 32-bit GDB, we need to convert it. GDB core always sees
+ the converted layout, so any read/write will have to be done
+ post-conversion. */
+ siginfo_fixup (&siginfo, inf_siginfo, 0);
+
if (offset + len > sizeof (siginfo))
len = sizeof (siginfo) - offset;
if (readbuf != NULL)
- memcpy (readbuf, (char *)&siginfo + offset, len);
+ memcpy (readbuf, inf_siginfo + offset, len);
else
{
- memcpy ((char *)&siginfo + offset, writebuf, len);
+ memcpy (inf_siginfo + offset, writebuf, len);
+
+ /* Convert back to ptrace layout before flushing it out. */
+ siginfo_fixup (&siginfo, inf_siginfo, 1);
+
errno = 0;
ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo);
if (errno != 0)
@@ -4720,6 +4762,19 @@ linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
linux_nat_new_thread = new_thread;
}
+/* Register a method that converts a siginfo object between the layout
+ that ptrace returns, and the layout in the architecture of the
+ inferior. */
+void
+linux_nat_set_siginfo_fixup (struct target_ops *t,
+ int (*siginfo_fixup) (struct siginfo *,
+ gdb_byte *,
+ int))
+{
+ /* Save the pointer. */
+ linux_nat_siginfo_fixup = siginfo_fixup;
+}
+
/* Return the saved siginfo associated with PTID. */
struct siginfo *
linux_nat_get_siginfo (ptid_t ptid)