/* Low-level siginfo manipulation for amd64.
- Copyright (C) 2002-2016 Free Software Foundation, Inc.
+ Copyright (C) 2002-2020 Free Software Foundation, Inc.
This file is part of GDB.
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <signal.h>
-#include "common-defs.h"
+#include "gdbsupport/common-defs.h"
#include "amd64-linux-siginfo.h"
+#define GDB_SI_SIZE 128
+
+/* The types below define the most complete kernel siginfo types known
+ for the architecture, independent of the system/libc headers. They
+ are named from a 64-bit kernel's perspective:
+
+ | layout | type |
+ |--------+----------------------|
+ | 64-bit | nat_siginfo_t |
+ | 32-bit | compat_siginfo_t |
+ | x32 | compat_x32_siginfo_t |
+*/
+
+#ifndef __ILP32__
+
+typedef int nat_int_t;
+typedef unsigned long nat_uptr_t;
+
+typedef int nat_time_t;
+typedef int nat_timer_t;
+
+/* For native 64-bit, clock_t in _sigchld is 64-bit. */
+typedef long nat_clock_t;
+
+typedef union nat_sigval
+{
+ nat_int_t sival_int;
+ nat_uptr_t sival_ptr;
+} nat_sigval_t;
+
+typedef struct nat_siginfo
+{
+ int si_signo;
+ int si_errno;
+ int si_code;
+
+ union
+ {
+ int _pad[((128 / sizeof (int)) - 4)];
+ /* kill() */
+ struct
+ {
+ unsigned int _pid;
+ unsigned int _uid;
+ } _kill;
+
+ /* POSIX.1b timers */
+ struct
+ {
+ nat_timer_t _tid;
+ int _overrun;
+ nat_sigval_t _sigval;
+ } _timer;
+
+ /* POSIX.1b signals */
+ struct
+ {
+ unsigned int _pid;
+ unsigned int _uid;
+ nat_sigval_t _sigval;
+ } _rt;
+
+ /* SIGCHLD */
+ struct
+ {
+ unsigned int _pid;
+ unsigned int _uid;
+ int _status;
+ nat_clock_t _utime;
+ nat_clock_t _stime;
+ } _sigchld;
+
+ /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+ struct
+ {
+ nat_uptr_t _addr;
+ short int _addr_lsb;
+ struct
+ {
+ nat_uptr_t _lower;
+ nat_uptr_t _upper;
+ } si_addr_bnd;
+ } _sigfault;
+
+ /* SIGPOLL */
+ struct
+ {
+ int _band;
+ int _fd;
+ } _sigpoll;
+ } _sifields;
+} nat_siginfo_t;
+
+#endif /* __ILP32__ */
+
/* These types below (compat_*) define a siginfo type that is layout
compatible with the siginfo type exported by the 32-bit userspace
support. */
struct
{
unsigned int _addr;
+ short int _addr_lsb;
+ struct
+ {
+ unsigned int _lower;
+ unsigned int _upper;
+ } si_addr_bnd;
} _sigfault;
/* SIGPOLL */
struct
{
unsigned int _addr;
+ unsigned int _addr_lsb;
} _sigfault;
/* SIGPOLL */
#define cpt_si_stime _sifields._sigchld._stime
#define cpt_si_ptr _sifields._rt._sigval.sival_ptr
#define cpt_si_addr _sifields._sigfault._addr
+#define cpt_si_addr_lsb _sifields._sigfault._addr_lsb
#define cpt_si_band _sifields._sigpoll._band
#define cpt_si_fd _sifields._sigpoll._fd
#define si_overrun si_timer2
#endif
+/* The type of the siginfo object the kernel returns in
+ PTRACE_GETSIGINFO. If gdb is built as a x32 program, we get a x32
+ siginfo. */
+#ifdef __ILP32__
+typedef compat_x32_siginfo_t ptrace_siginfo_t;
+#else
+typedef nat_siginfo_t ptrace_siginfo_t;
+#endif
+
/* Convert the system provided siginfo into compatible siginfo. */
static void
-compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from)
+compat_siginfo_from_siginfo (compat_siginfo_t *to, const siginfo_t *from)
{
+ ptrace_siginfo_t from_ptrace;
+
+ memcpy (&from_ptrace, from, sizeof (from_ptrace));
memset (to, 0, sizeof (*to));
- to->si_signo = from->si_signo;
- to->si_errno = from->si_errno;
- to->si_code = from->si_code;
+ to->si_signo = from_ptrace.si_signo;
+ to->si_errno = from_ptrace.si_errno;
+ to->si_code = from_ptrace.si_code;
if (to->si_code == SI_TIMER)
{
- to->cpt_si_timerid = from->si_timerid;
- to->cpt_si_overrun = from->si_overrun;
- to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ to->cpt_si_timerid = from_ptrace.cpt_si_timerid;
+ to->cpt_si_overrun = from_ptrace.cpt_si_overrun;
+ to->cpt_si_ptr = from_ptrace.cpt_si_ptr;
}
else if (to->si_code == SI_USER)
{
- to->cpt_si_pid = from->si_pid;
- to->cpt_si_uid = from->si_uid;
+ to->cpt_si_pid = from_ptrace.cpt_si_pid;
+ to->cpt_si_uid = from_ptrace.cpt_si_uid;
}
else if (to->si_code < 0)
{
- to->cpt_si_pid = from->si_pid;
- to->cpt_si_uid = from->si_uid;
- to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ to->cpt_si_pid = from_ptrace.cpt_si_pid;
+ to->cpt_si_uid = from_ptrace.cpt_si_uid;
+ to->cpt_si_ptr = from_ptrace.cpt_si_ptr;
}
else
{
switch (to->si_signo)
{
case SIGCHLD:
- to->cpt_si_pid = from->si_pid;
- to->cpt_si_uid = from->si_uid;
- to->cpt_si_status = from->si_status;
- to->cpt_si_utime = from->si_utime;
- to->cpt_si_stime = from->si_stime;
+ to->cpt_si_pid = from_ptrace.cpt_si_pid;
+ to->cpt_si_uid = from_ptrace.cpt_si_uid;
+ to->cpt_si_status = from_ptrace.cpt_si_status;
+ to->cpt_si_utime = from_ptrace.cpt_si_utime;
+ to->cpt_si_stime = from_ptrace.cpt_si_stime;
break;
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
- to->cpt_si_addr = (intptr_t) from->si_addr;
+ to->cpt_si_addr = from_ptrace.cpt_si_addr;
break;
case SIGPOLL:
- to->cpt_si_band = from->si_band;
- to->cpt_si_fd = from->si_fd;
+ to->cpt_si_band = from_ptrace.cpt_si_band;
+ to->cpt_si_fd = from_ptrace.cpt_si_fd;
break;
default:
- to->cpt_si_pid = from->si_pid;
- to->cpt_si_uid = from->si_uid;
- to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ to->cpt_si_pid = from_ptrace.cpt_si_pid;
+ to->cpt_si_uid = from_ptrace.cpt_si_uid;
+ to->cpt_si_ptr = from_ptrace.cpt_si_ptr;
break;
}
}
/* Convert the compatible siginfo into system siginfo. */
static void
-siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from)
+siginfo_from_compat_siginfo (siginfo_t *to, const compat_siginfo_t *from)
{
- memset (to, 0, sizeof (*to));
+ ptrace_siginfo_t to_ptrace;
- to->si_signo = from->si_signo;
- to->si_errno = from->si_errno;
- to->si_code = from->si_code;
+ memset (&to_ptrace, 0, sizeof (to_ptrace));
- if (to->si_code == SI_TIMER)
+ to_ptrace.si_signo = from->si_signo;
+ to_ptrace.si_errno = from->si_errno;
+ to_ptrace.si_code = from->si_code;
+
+ if (to_ptrace.si_code == SI_TIMER)
{
- to->si_timerid = from->cpt_si_timerid;
- to->si_overrun = from->cpt_si_overrun;
- to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
+ to_ptrace.cpt_si_timerid = from->cpt_si_timerid;
+ to_ptrace.cpt_si_overrun = from->cpt_si_overrun;
+ to_ptrace.cpt_si_ptr = from->cpt_si_ptr;
}
- else if (to->si_code == SI_USER)
+ else if (to_ptrace.si_code == SI_USER)
{
- to->si_pid = from->cpt_si_pid;
- to->si_uid = from->cpt_si_uid;
+ to_ptrace.cpt_si_pid = from->cpt_si_pid;
+ to_ptrace.cpt_si_uid = from->cpt_si_uid;
}
- if (to->si_code < 0)
+ if (to_ptrace.si_code < 0)
{
- to->si_pid = from->cpt_si_pid;
- to->si_uid = from->cpt_si_uid;
- to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
+ to_ptrace.cpt_si_pid = from->cpt_si_pid;
+ to_ptrace.cpt_si_uid = from->cpt_si_uid;
+ to_ptrace.cpt_si_ptr = from->cpt_si_ptr;
}
else
{
- switch (to->si_signo)
+ switch (to_ptrace.si_signo)
{
case SIGCHLD:
- to->si_pid = from->cpt_si_pid;
- to->si_uid = from->cpt_si_uid;
- to->si_status = from->cpt_si_status;
- to->si_utime = from->cpt_si_utime;
- to->si_stime = from->cpt_si_stime;
+ to_ptrace.cpt_si_pid = from->cpt_si_pid;
+ to_ptrace.cpt_si_uid = from->cpt_si_uid;
+ to_ptrace.cpt_si_status = from->cpt_si_status;
+ to_ptrace.cpt_si_utime = from->cpt_si_utime;
+ to_ptrace.cpt_si_stime = from->cpt_si_stime;
break;
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
- to->si_addr = (void *) (intptr_t) from->cpt_si_addr;
+ to_ptrace.cpt_si_addr = from->cpt_si_addr;
+ to_ptrace.cpt_si_addr_lsb = from->cpt_si_addr_lsb;
break;
case SIGPOLL:
- to->si_band = from->cpt_si_band;
- to->si_fd = from->cpt_si_fd;
+ to_ptrace.cpt_si_band = from->cpt_si_band;
+ to_ptrace.cpt_si_fd = from->cpt_si_fd;
break;
default:
- to->si_pid = from->cpt_si_pid;
- to->si_uid = from->cpt_si_uid;
- to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr;
+ to_ptrace.cpt_si_pid = from->cpt_si_pid;
+ to_ptrace.cpt_si_uid = from->cpt_si_uid;
+ to_ptrace.cpt_si_ptr = from->cpt_si_ptr;
break;
}
}
+ memcpy (to, &to_ptrace, sizeof (to_ptrace));
}
/* Convert the system provided siginfo into compatible x32 siginfo. */
static void
compat_x32_siginfo_from_siginfo (compat_x32_siginfo_t *to,
- siginfo_t *from)
+ const siginfo_t *from)
{
+ ptrace_siginfo_t from_ptrace;
+
+ memcpy (&from_ptrace, from, sizeof (from_ptrace));
memset (to, 0, sizeof (*to));
- to->si_signo = from->si_signo;
- to->si_errno = from->si_errno;
- to->si_code = from->si_code;
+ to->si_signo = from_ptrace.si_signo;
+ to->si_errno = from_ptrace.si_errno;
+ to->si_code = from_ptrace.si_code;
if (to->si_code == SI_TIMER)
{
- to->cpt_si_timerid = from->si_timerid;
- to->cpt_si_overrun = from->si_overrun;
- to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ to->cpt_si_timerid = from_ptrace.cpt_si_timerid;
+ to->cpt_si_overrun = from_ptrace.cpt_si_overrun;
+ to->cpt_si_ptr = from_ptrace.cpt_si_ptr;
}
else if (to->si_code == SI_USER)
{
- to->cpt_si_pid = from->si_pid;
- to->cpt_si_uid = from->si_uid;
+ to->cpt_si_pid = from_ptrace.cpt_si_pid;
+ to->cpt_si_uid = from_ptrace.cpt_si_uid;
}
else if (to->si_code < 0)
{
- to->cpt_si_pid = from->si_pid;
- to->cpt_si_uid = from->si_uid;
- to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ to->cpt_si_pid = from_ptrace.cpt_si_pid;
+ to->cpt_si_uid = from_ptrace.cpt_si_uid;
+ to->cpt_si_ptr = from_ptrace.cpt_si_ptr;
}
else
{
switch (to->si_signo)
{
case SIGCHLD:
- to->cpt_si_pid = from->si_pid;
- to->cpt_si_uid = from->si_uid;
- to->cpt_si_status = from->si_status;
- memcpy (&to->cpt_si_utime, &from->si_utime,
+ to->cpt_si_pid = from_ptrace.cpt_si_pid;
+ to->cpt_si_uid = from_ptrace.cpt_si_uid;
+ to->cpt_si_status = from_ptrace.cpt_si_status;
+ memcpy (&to->cpt_si_utime, &from_ptrace.cpt_si_utime,
sizeof (to->cpt_si_utime));
- memcpy (&to->cpt_si_stime, &from->si_stime,
+ memcpy (&to->cpt_si_stime, &from_ptrace.cpt_si_stime,
sizeof (to->cpt_si_stime));
break;
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
- to->cpt_si_addr = (intptr_t) from->si_addr;
+ to->cpt_si_addr = from_ptrace.cpt_si_addr;
break;
case SIGPOLL:
- to->cpt_si_band = from->si_band;
- to->cpt_si_fd = from->si_fd;
+ to->cpt_si_band = from_ptrace.cpt_si_band;
+ to->cpt_si_fd = from_ptrace.cpt_si_fd;
break;
default:
- to->cpt_si_pid = from->si_pid;
- to->cpt_si_uid = from->si_uid;
- to->cpt_si_ptr = (intptr_t) from->si_ptr;
+ to->cpt_si_pid = from_ptrace.cpt_si_pid;
+ to->cpt_si_uid = from_ptrace.cpt_si_uid;
+ to->cpt_si_ptr = from_ptrace.cpt_si_ptr;
break;
}
}
}
+
+
+
/* Convert the compatible x32 siginfo into system siginfo. */
static void
siginfo_from_compat_x32_siginfo (siginfo_t *to,
- compat_x32_siginfo_t *from)
+ const compat_x32_siginfo_t *from)
{
- memset (to, 0, sizeof (*to));
+ ptrace_siginfo_t to_ptrace;
- to->si_signo = from->si_signo;
- to->si_errno = from->si_errno;
- to->si_code = from->si_code;
+ memset (&to_ptrace, 0, sizeof (to_ptrace));
+ to_ptrace.si_signo = from->si_signo;
+ to_ptrace.si_errno = from->si_errno;
+ to_ptrace.si_code = from->si_code;
- if (to->si_code == SI_TIMER)
+ if (to_ptrace.si_code == SI_TIMER)
{
- to->si_timerid = from->cpt_si_timerid;
- to->si_overrun = from->cpt_si_overrun;
- to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
+ to_ptrace.cpt_si_timerid = from->cpt_si_timerid;
+ to_ptrace.cpt_si_overrun = from->cpt_si_overrun;
+ to_ptrace.cpt_si_ptr = from->cpt_si_ptr;
}
- else if (to->si_code == SI_USER)
+ else if (to_ptrace.si_code == SI_USER)
{
- to->si_pid = from->cpt_si_pid;
- to->si_uid = from->cpt_si_uid;
+ to_ptrace.cpt_si_pid = from->cpt_si_pid;
+ to_ptrace.cpt_si_uid = from->cpt_si_uid;
}
- if (to->si_code < 0)
+ if (to_ptrace.si_code < 0)
{
- to->si_pid = from->cpt_si_pid;
- to->si_uid = from->cpt_si_uid;
- to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr;
+ to_ptrace.cpt_si_pid = from->cpt_si_pid;
+ to_ptrace.cpt_si_uid = from->cpt_si_uid;
+ to_ptrace.cpt_si_ptr = from->cpt_si_ptr;
}
else
{
- switch (to->si_signo)
+ switch (to_ptrace.si_signo)
{
case SIGCHLD:
- to->si_pid = from->cpt_si_pid;
- to->si_uid = from->cpt_si_uid;
- to->si_status = from->cpt_si_status;
- memcpy (&to->si_utime, &from->cpt_si_utime,
- sizeof (to->si_utime));
- memcpy (&to->si_stime, &from->cpt_si_stime,
- sizeof (to->si_stime));
+ to_ptrace.cpt_si_pid = from->cpt_si_pid;
+ to_ptrace.cpt_si_uid = from->cpt_si_uid;
+ to_ptrace.cpt_si_status = from->cpt_si_status;
+ memcpy (&to_ptrace.cpt_si_utime, &from->cpt_si_utime,
+ sizeof (to_ptrace.cpt_si_utime));
+ memcpy (&to_ptrace.cpt_si_stime, &from->cpt_si_stime,
+ sizeof (to_ptrace.cpt_si_stime));
break;
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
- to->si_addr = (void *) (intptr_t) from->cpt_si_addr;
+ to_ptrace.cpt_si_addr = from->cpt_si_addr;
break;
case SIGPOLL:
- to->si_band = from->cpt_si_band;
- to->si_fd = from->cpt_si_fd;
+ to_ptrace.cpt_si_band = from->cpt_si_band;
+ to_ptrace.cpt_si_fd = from->cpt_si_fd;
break;
default:
- to->si_pid = from->cpt_si_pid;
- to->si_uid = from->cpt_si_uid;
- to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr;
+ to_ptrace.cpt_si_pid = from->cpt_si_pid;
+ to_ptrace.cpt_si_uid = from->cpt_si_uid;
+ to_ptrace.cpt_si_ptr = from->cpt_si_ptr;
break;
}
}
+ memcpy (to, &to_ptrace, sizeof (to_ptrace));
}
-/* Convert a native/host siginfo object, into/from the siginfo in the
+/* Convert a ptrace siginfo object, into/from the siginfo in the
layout of the inferiors' architecture. Returns true if any
conversion was done; false otherwise. If DIRECTION is 1, then copy
- from INF to NATIVE. If DIRECTION is 0, then copy from NATIVE to INF. */
+ from INF to PTRACE. If DIRECTION is 0, then copy from NATIVE to
+ INF. */
int
-amd64_linux_siginfo_fixup_common (siginfo_t *native, gdb_byte *inf,
+amd64_linux_siginfo_fixup_common (siginfo_t *ptrace, gdb_byte *inf,
int direction,
enum amd64_siginfo_fixup_mode mode)
{
if (mode == FIXUP_32)
{
- gdb_assert (sizeof (siginfo_t) == sizeof (compat_siginfo_t));
-
if (direction == 0)
- compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, native);
+ compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, ptrace);
else
- siginfo_from_compat_siginfo (native, (struct compat_siginfo *) inf);
+ siginfo_from_compat_siginfo (ptrace, (struct compat_siginfo *) inf);
return 1;
}
else if (mode == FIXUP_X32)
{
- gdb_assert (sizeof (siginfo_t) == sizeof (compat_x32_siginfo_t));
-
if (direction == 0)
compat_x32_siginfo_from_siginfo ((struct compat_x32_siginfo *) inf,
- native);
+ ptrace);
else
- siginfo_from_compat_x32_siginfo (native,
+ siginfo_from_compat_x32_siginfo (ptrace,
(struct compat_x32_siginfo *) inf);
return 1;
}
return 0;
}
+
+/* Sanity check for the siginfo structure sizes. */
+
+gdb_static_assert (sizeof (siginfo_t) == GDB_SI_SIZE);
+#ifndef __ILP32__
+gdb_static_assert (sizeof (nat_siginfo_t) == GDB_SI_SIZE);
+#endif
+gdb_static_assert (sizeof (compat_x32_siginfo_t) == GDB_SI_SIZE);
+gdb_static_assert (sizeof (compat_siginfo_t) == GDB_SI_SIZE);
+gdb_static_assert (sizeof (ptrace_siginfo_t) == GDB_SI_SIZE);