binutils-gdb/gdb/nat/amd64-linux-siginfo.c
Walfred Tedeschi 93813b37c8 Merge gdb and gdbserver implementations for siginfo
Extract the compatible siginfo handling from amd64-linux-nat.c and
gdbserver/linux-x86-low to a new file nat/amd64-linux-siginfo.c.

2016-02-02  Walfred Tedeschi  <walfred.tedeschi@intel.com>

gdb/ChangeLog:

	* nat/amd64-linux-siginfo.c: New file.
	* nat/amd64-linux-siginfo.h: New file.
	* Makefile.in (HFILES_NO_SRCDIR): Add nat/amd64-linux-siginfo.h.
	(amd64-linux-siginfo.o): New rule.
	* config/i386/linux64.mh (NATDEPFILES): Add amd64-linux-siginfo.o.
	* amd64-linux-nat.c (nat/amd64-linux-siginfo.h): New include.
	(compat_siginfo_from_siginfo, siginfo_from_compat_siginfo)
	(compat_x32_siginfo_from_siginfo, siginfo_from_compat_x32_siginfo)
	(compat_timeval, compat_sigval, compat_x32_clock, cpt_si_pid)
	(cpt_si_uid, cpt_si_timerid, cpt_si_overrun, cpt_si_status)
	(cpt_si_utime, cpt_si_stime, cpt_si_ptr, cpt_si_addr, cpt_si_band)
	(cpt_si_fd, si_timerid, si_overrun): Move to nat/amd64-linux-siginfo.c.

gdb/gdbserver/ChangeLog:

	* configure.srv (x86_64-*-linux*): Add amd64-linux-siginfo.o
	to srv_tgtobj.
	(i[34567]86-*-linux*): Add amd64-linux-siginfo.o
	to srv_tgtobj.
	* linux-x86-low.c [__x86_64__]: Include
	"nat/amd64-linux-siginfo.h".
	(compat_siginfo_from_siginfo, siginfo_from_compat_siginfo)
	(compat_x32_siginfo_from_siginfo, siginfo_from_compat_x32_siginfo)
	(compat_timeval, compat_sigval, compat_x32_clock, cpt_si_pid)
	(cpt_si_uid, cpt_si_timerid, cpt_si_overrun, cpt_si_status)
	(cpt_si_utime, cpt_si_stime, cpt_si_ptr, cpt_si_addr, cpt_si_band)
	(cpt_si_fd, si_timerid, si_overrun): Move from
	nat/amd64-linux-siginfo.c.
	* Makefile.in (amd64-linux-siginfo.o:): New rule.
2016-02-02 11:42:56 +01:00

462 lines
11 KiB
C

/* Low-level siginfo manipulation for amd64.
Copyright (C) 2002-2016 Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include <signal.h>
#include "common-defs.h"
#include "amd64-linux-siginfo.h"
/* These types below (compat_*) define a siginfo type that is layout
compatible with the siginfo type exported by the 32-bit userspace
support. */
typedef int compat_int_t;
typedef unsigned int compat_uptr_t;
typedef int compat_time_t;
typedef int compat_timer_t;
typedef int compat_clock_t;
struct compat_timeval
{
compat_time_t tv_sec;
int tv_usec;
};
typedef union compat_sigval
{
compat_int_t sival_int;
compat_uptr_t sival_ptr;
} compat_sigval_t;
typedef struct compat_siginfo
{
int si_signo;
int si_errno;
int si_code;
union
{
int _pad[((128 / sizeof (int)) - 3)];
/* kill() */
struct
{
unsigned int _pid;
unsigned int _uid;
} _kill;
/* POSIX.1b timers */
struct
{
compat_timer_t _tid;
int _overrun;
compat_sigval_t _sigval;
} _timer;
/* POSIX.1b signals */
struct
{
unsigned int _pid;
unsigned int _uid;
compat_sigval_t _sigval;
} _rt;
/* SIGCHLD */
struct
{
unsigned int _pid;
unsigned int _uid;
int _status;
compat_clock_t _utime;
compat_clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct
{
unsigned int _addr;
} _sigfault;
/* SIGPOLL */
struct
{
int _band;
int _fd;
} _sigpoll;
} _sifields;
} compat_siginfo_t;
/* For x32, clock_t in _sigchld is 64bit aligned at 4 bytes. */
typedef long __attribute__ ((__aligned__ (4))) compat_x32_clock_t;
typedef struct compat_x32_siginfo
{
int si_signo;
int si_errno;
int si_code;
union
{
int _pad[((128 / sizeof (int)) - 3)];
/* kill() */
struct
{
unsigned int _pid;
unsigned int _uid;
} _kill;
/* POSIX.1b timers */
struct
{
compat_timer_t _tid;
int _overrun;
compat_sigval_t _sigval;
} _timer;
/* POSIX.1b signals */
struct
{
unsigned int _pid;
unsigned int _uid;
compat_sigval_t _sigval;
} _rt;
/* SIGCHLD */
struct
{
unsigned int _pid;
unsigned int _uid;
int _status;
compat_x32_clock_t _utime;
compat_x32_clock_t _stime;
} _sigchld;
/* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
struct
{
unsigned int _addr;
} _sigfault;
/* SIGPOLL */
struct
{
int _band;
int _fd;
} _sigpoll;
} _sifields;
} compat_x32_siginfo_t __attribute__ ((__aligned__ (8)));
/* To simplify usage of siginfo fields. */
#define cpt_si_pid _sifields._kill._pid
#define cpt_si_uid _sifields._kill._uid
#define cpt_si_timerid _sifields._timer._tid
#define cpt_si_overrun _sifields._timer._overrun
#define cpt_si_status _sifields._sigchld._status
#define cpt_si_utime _sifields._sigchld._utime
#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_band _sifields._sigpoll._band
#define cpt_si_fd _sifields._sigpoll._fd
/* glibc at least up to 2.3.2 doesn't have si_timerid, si_overrun.
In their place is si_timer1,si_timer2. */
#ifndef si_timerid
#define si_timerid si_timer1
#endif
#ifndef si_overrun
#define si_overrun si_timer2
#endif
/* Convert the system provided siginfo into compatible siginfo. */
static void
compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from)
{
memset (to, 0, sizeof (*to));
to->si_signo = from->si_signo;
to->si_errno = from->si_errno;
to->si_code = from->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;
}
else if (to->si_code == SI_USER)
{
to->cpt_si_pid = from->si_pid;
to->cpt_si_uid = from->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;
}
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;
break;
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
to->cpt_si_addr = (intptr_t) from->si_addr;
break;
case SIGPOLL:
to->cpt_si_band = from->si_band;
to->cpt_si_fd = from->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;
break;
}
}
}
/* Convert the compatible siginfo into system siginfo. */
static void
siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from)
{
memset (to, 0, sizeof (*to));
to->si_signo = from->si_signo;
to->si_errno = from->si_errno;
to->si_code = from->si_code;
if (to->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;
}
else if (to->si_code == SI_USER)
{
to->si_pid = from->cpt_si_pid;
to->si_uid = from->cpt_si_uid;
}
if (to->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;
}
else
{
switch (to->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;
break;
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
to->si_addr = (void *) (intptr_t) from->cpt_si_addr;
break;
case SIGPOLL:
to->si_band = from->cpt_si_band;
to->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;
break;
}
}
}
/* Convert the system provided siginfo into compatible x32 siginfo. */
static void
compat_x32_siginfo_from_siginfo (compat_x32_siginfo_t *to,
siginfo_t *from)
{
memset (to, 0, sizeof (*to));
to->si_signo = from->si_signo;
to->si_errno = from->si_errno;
to->si_code = from->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;
}
else if (to->si_code == SI_USER)
{
to->cpt_si_pid = from->si_pid;
to->cpt_si_uid = from->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;
}
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,
sizeof (to->cpt_si_utime));
memcpy (&to->cpt_si_stime, &from->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;
break;
case SIGPOLL:
to->cpt_si_band = from->si_band;
to->cpt_si_fd = from->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;
break;
}
}
}
/* Convert the compatible x32 siginfo into system siginfo. */
static void
siginfo_from_compat_x32_siginfo (siginfo_t *to,
compat_x32_siginfo_t *from)
{
memset (to, 0, sizeof (*to));
to->si_signo = from->si_signo;
to->si_errno = from->si_errno;
to->si_code = from->si_code;
if (to->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;
}
else if (to->si_code == SI_USER)
{
to->si_pid = from->cpt_si_pid;
to->si_uid = from->cpt_si_uid;
}
if (to->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;
}
else
{
switch (to->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));
break;
case SIGILL:
case SIGFPE:
case SIGSEGV:
case SIGBUS:
to->si_addr = (void *) (intptr_t) from->cpt_si_addr;
break;
case SIGPOLL:
to->si_band = from->cpt_si_band;
to->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;
break;
}
}
}
/* Convert a native/host 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. */
int
amd64_linux_siginfo_fixup_common (siginfo_t *native, 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);
else
siginfo_from_compat_siginfo (native, (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);
else
siginfo_from_compat_x32_siginfo (native,
(struct compat_x32_siginfo *) inf);
return 1;
}
return 0;
}