mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-28 04:25:10 +08:00
Fetch signal information for native FreeBSD processes.
Use the `pl_siginfo' field in the `struct ptrace_lwpinfo' object returned by the PT_LWPINFO ptrace() request to supply the current contents of $_siginfo for each thread. Note that FreeBSD does not supply a way to modify the signal information for a thread, so $_siginfo is read-only for FreeBSD. To handle 32-bit processes on a 64-bit host, define types for 32-bit compatible siginfo_t and convert the 64-bit siginfo_t to the 32-bit equivalent when supplying information for a 32-bit process. gdb/ChangeLog: * fbsd-nat.c [PT_LWPINFO && __LP64__] (union sigval32) (struct siginfo32): New. [PT_LWPINFO] (fbsd_siginfo_size, fbsd_convert_siginfo): New. (fbsd_xfer_partial) [PT_LWPINFO]: Handle TARGET_OBJECT_SIGNAL_INFO via ptrace(PT_LWPINFO).
This commit is contained in:
parent
762c974a09
commit
929edea98d
@ -1,3 +1,11 @@
|
||||
2017-07-07 John Baldwin <jhb@FreeBSD.org>
|
||||
|
||||
* fbsd-nat.c [PT_LWPINFO && __LP64__] (union sigval32)
|
||||
(struct siginfo32): New.
|
||||
[PT_LWPINFO] (fbsd_siginfo_size, fbsd_convert_siginfo): New.
|
||||
(fbsd_xfer_partial) [PT_LWPINFO]: Handle TARGET_OBJECT_SIGNAL_INFO
|
||||
via ptrace(PT_LWPINFO).
|
||||
|
||||
2017-07-07 John Baldwin <jhb@FreeBSD.org>
|
||||
|
||||
* fbsd-tdep.c (fbsd_gdbarch_data_handle, struct fbsd_gdbarch_data)
|
||||
|
162
gdb/fbsd-nat.c
162
gdb/fbsd-nat.c
@ -28,6 +28,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/procfs.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/signal.h>
|
||||
#include <sys/sysctl.h>
|
||||
#ifdef HAVE_KINFO_GETVMMAP
|
||||
#include <sys/user.h>
|
||||
@ -216,6 +217,135 @@ static enum target_xfer_status (*super_xfer_partial) (struct target_ops *ops,
|
||||
ULONGEST len,
|
||||
ULONGEST *xfered_len);
|
||||
|
||||
#ifdef PT_LWPINFO
|
||||
/* Return the size of siginfo for the current inferior. */
|
||||
|
||||
#ifdef __LP64__
|
||||
union sigval32 {
|
||||
int sival_int;
|
||||
uint32_t sival_ptr;
|
||||
};
|
||||
|
||||
/* This structure matches the naming and layout of `siginfo_t' in
|
||||
<sys/signal.h>. In particular, the `si_foo' macros defined in that
|
||||
header can be used with both types to copy fields in the `_reason'
|
||||
union. */
|
||||
|
||||
struct siginfo32
|
||||
{
|
||||
int si_signo;
|
||||
int si_errno;
|
||||
int si_code;
|
||||
__pid_t si_pid;
|
||||
__uid_t si_uid;
|
||||
int si_status;
|
||||
uint32_t si_addr;
|
||||
union sigval32 si_value;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
int _trapno;
|
||||
} _fault;
|
||||
struct
|
||||
{
|
||||
int _timerid;
|
||||
int _overrun;
|
||||
} _timer;
|
||||
struct
|
||||
{
|
||||
int _mqd;
|
||||
} _mesgq;
|
||||
struct
|
||||
{
|
||||
int32_t _band;
|
||||
} _poll;
|
||||
struct
|
||||
{
|
||||
int32_t __spare1__;
|
||||
int __spare2__[7];
|
||||
} __spare__;
|
||||
} _reason;
|
||||
};
|
||||
#endif
|
||||
|
||||
static size_t
|
||||
fbsd_siginfo_size ()
|
||||
{
|
||||
#ifdef __LP64__
|
||||
struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
|
||||
|
||||
/* Is the inferior 32-bit? If so, use the 32-bit siginfo size. */
|
||||
if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word == 32)
|
||||
return sizeof (struct siginfo32);
|
||||
#endif
|
||||
return sizeof (siginfo_t);
|
||||
}
|
||||
|
||||
/* Convert a native 64-bit siginfo object to a 32-bit object. Note
|
||||
that FreeBSD doesn't support writing to $_siginfo, so this only
|
||||
needs to convert one way. */
|
||||
|
||||
static void
|
||||
fbsd_convert_siginfo (siginfo_t *si)
|
||||
{
|
||||
#ifdef __LP64__
|
||||
struct gdbarch *gdbarch = get_frame_arch (get_current_frame ());
|
||||
|
||||
/* Is the inferior 32-bit? If not, nothing to do. */
|
||||
if (gdbarch_bfd_arch_info (gdbarch)->bits_per_word != 32)
|
||||
return;
|
||||
|
||||
struct siginfo32 si32;
|
||||
|
||||
si32.si_signo = si->si_signo;
|
||||
si32.si_errno = si->si_errno;
|
||||
si32.si_code = si->si_code;
|
||||
si32.si_pid = si->si_pid;
|
||||
si32.si_uid = si->si_uid;
|
||||
si32.si_status = si->si_status;
|
||||
si32.si_addr = (uintptr_t) si->si_addr;
|
||||
|
||||
/* If sival_ptr is being used instead of sival_int on a big-endian
|
||||
platform, then sival_int will be zero since it holds the upper
|
||||
32-bits of the pointer value. */
|
||||
#if _BYTE_ORDER == _BIG_ENDIAN
|
||||
if (si->si_value.sival_int == 0)
|
||||
si32->si_value.sival_ptr = (uintptr_t) si->si_value.sival_ptr;
|
||||
else
|
||||
si32.si_value.sival_int = si->si_value.sival_int;
|
||||
#else
|
||||
si32.si_value.sival_int = si->si_value.sival_int;
|
||||
#endif
|
||||
|
||||
/* Always copy the spare fields and then possibly overwrite them for
|
||||
signal-specific or code-specific fields. */
|
||||
si32._reason.__spare__.__spare1__ = si->_reason.__spare__.__spare1__;
|
||||
for (int i = 0; i < 7; i++)
|
||||
si32._reason.__spare__.__spare2__[i] = si->_reason.__spare__.__spare2__[i];
|
||||
switch (si->si_signo) {
|
||||
case SIGILL:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
case SIGBUS:
|
||||
si32.si_trapno = si->si_trapno;
|
||||
break;
|
||||
}
|
||||
switch (si->si_code) {
|
||||
case SI_TIMER:
|
||||
si32.si_timerid = si->si_timerid;
|
||||
si32.si_overrun = si->si_overrun;
|
||||
break;
|
||||
case SI_MESGQ:
|
||||
si32.si_mqd = si->si_mqd;
|
||||
break;
|
||||
}
|
||||
|
||||
memcpy(si, &si32, sizeof (si32));
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Implement the "to_xfer_partial target_ops" method. */
|
||||
|
||||
static enum target_xfer_status
|
||||
@ -228,6 +358,38 @@ fbsd_xfer_partial (struct target_ops *ops, enum target_object object,
|
||||
|
||||
switch (object)
|
||||
{
|
||||
#ifdef PT_LWPINFO
|
||||
case TARGET_OBJECT_SIGNAL_INFO:
|
||||
{
|
||||
struct ptrace_lwpinfo pl;
|
||||
size_t siginfo_size;
|
||||
|
||||
/* FreeBSD doesn't support writing to $_siginfo. */
|
||||
if (writebuf != NULL)
|
||||
return TARGET_XFER_E_IO;
|
||||
|
||||
if (inferior_ptid.lwp_p ())
|
||||
pid = inferior_ptid.lwp ();
|
||||
|
||||
siginfo_size = fbsd_siginfo_size ();
|
||||
if (offset > siginfo_size)
|
||||
return TARGET_XFER_E_IO;
|
||||
|
||||
if (ptrace (PT_LWPINFO, pid, (PTRACE_TYPE_ARG3) &pl, sizeof (pl)) == -1)
|
||||
return TARGET_XFER_E_IO;
|
||||
|
||||
if (!(pl.pl_flags & PL_FLAG_SI))
|
||||
return TARGET_XFER_E_IO;
|
||||
|
||||
fbsd_convert_siginfo (&pl.pl_siginfo);
|
||||
if (offset + len > siginfo_size)
|
||||
len = siginfo_size - offset;
|
||||
|
||||
memcpy (readbuf, ((gdb_byte *) &pl.pl_siginfo) + offset, len);
|
||||
*xfered_len = len;
|
||||
return TARGET_XFER_OK;
|
||||
}
|
||||
#endif
|
||||
case TARGET_OBJECT_AUXV:
|
||||
{
|
||||
struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
|
||||
|
Loading…
Reference in New Issue
Block a user