diff options
Diffstat (limited to 'gdb/linux-nat.c')
-rw-r--r-- | gdb/linux-nat.c | 59 |
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) |