Access to siginfo for the signal from debugger
Kostik Belousov
kostikbel at gmail.com
Fri Jul 2 12:46:38 UTC 2010
On Fri, Jul 02, 2010 at 10:13:57AM +0800, David Xu wrote:
> Kostik Belousov wrote:
> >On Thu, Jul 01, 2010 at 05:05:26PM -0400, John Baldwin wrote:
> >>On Thursday 01 July 2010 09:42:17 am Kostik Belousov wrote:
> >>>Hi,
> >>>below is the patch that provides the debugger with access to siginfo
> >>>of the signal that stopped the debuggee. This allows to see a lot more
> >>>details for the cause of the process stop. E.g. you can see a fault
> >>>address if process get SIGSEGV or SIGBUS, you can distinguish between
> >>>breakpoint-generated SIGTRAP and non-breakpoint, whether the signal
> >>>was send due to external event etc.
> >>>
> >>>The change to struct ptrace_lwpinfo is backward-compatible in the sense
> >>>that programs that were compiled with old definition for the struct will
> >>>work on new kernels.
> >>Nice! Does gdb "just work" with these changes or does it need patching
> >>as well?
> >It should "just work", and my testing seems to confirm this. gdb uses
> >PT_LWPINFO to enumerate the thread ids, and I checked it on mt process.
> >
> >As I said, the change is ABI backward-compatible, i.e. you do not need
> >even to recompile the old program for new kernel.
> >
> >Sure, gdb cannot show additional available information without
> >modifications.
>
> Yes, you can add new fields to ptrace_lwpinfo without any problem.
> To print new fields, you should change the function
> fbsd_thread_signal_cmd in file
> src/gnu/usr.bin/gdb/libgdb/fbsd-threads.c
> after change, you just type 'thread signal' command in gdb to
> show thread's signal info. The command is freebsd specific,
> others may or may not have it.
I did what you suggested. The drawback there is that "thread signal"
only works for the threaded processes.
diff --git a/gnu/usr.bin/gdb/libgdb/fbsd-threads.c b/gnu/usr.bin/gdb/libgdb/fbsd-threads.c
index eb83f2e..6b424bc 100644
--- a/gnu/usr.bin/gdb/libgdb/fbsd-threads.c
+++ b/gnu/usr.bin/gdb/libgdb/fbsd-threads.c
@@ -1299,6 +1299,7 @@ fbsd_thread_signal_cmd (char *exp, int from_tty)
td_thrhandle_t th;
td_thrinfo_t ti;
td_err_e err;
+ const char *code;
if (!fbsd_thread_active || !IS_THREAD(inferior_ptid))
return;
@@ -1315,6 +1316,40 @@ fbsd_thread_signal_cmd (char *exp, int from_tty)
fbsd_print_sigset(&ti.ti_sigmask);
printf_filtered("signal pending:\n");
fbsd_print_sigset(&ti.ti_pending);
+ if (ti.ti_siginfo.si_signo != 0) {
+ printf_filtered("si_signo %d\n", ti.ti_siginfo.si_signo);
+ printf_filtered("si_errno %d (%s)\n", ti.ti_siginfo.si_errno,
+ strerror(ti.ti_siginfo.si_errno));
+ switch (ti.ti_siginfo.si_code) {
+ case SI_NOINFO:
+ code = "NOINFO";
+ break;
+ case SI_USER:
+ code = "USER";
+ break;
+ case SI_QUEUE:
+ code = "QUEUE";
+ break;
+ case SI_TIMER:
+ code = "TIMER";
+ break;
+ case SI_ASYNCIO:
+ code = "ASYNCIO";
+ break;
+ case SI_MESGQ:
+ code = "MESGQ";
+ break;
+ case SI_KERNEL:
+ code = "KERNEL";
+ break;
+ default:
+ code = "UNKNOWN";
+ break;
+ }
+ printf_filtered("si_code %s si_pid %d si_uid %d si_status %x si_addr %p\n",
+ code, ti.ti_siginfo.si_pid, ti.ti_siginfo.si_uid, ti.ti_siginfo.si_status,
+ ti.ti_siginfo.si_addr);
+ }
}
static int
diff --git a/lib/libthread_db/Symbol.map b/lib/libthread_db/Symbol.map
index 65e78d4..4e690f9 100644
--- a/lib/libthread_db/Symbol.map
+++ b/lib/libthread_db/Symbol.map
@@ -19,7 +19,6 @@ FBSD_1.0 {
td_thr_dbsuspend;
td_thr_event_enable;
td_thr_event_getmsg;
- td_thr_get_info;
td_thr_getfpregs;
td_thr_getgregs;
#if defined(i386)
@@ -33,3 +32,7 @@ FBSD_1.0 {
td_thr_tls_get_addr;
td_thr_validate;
};
+
+FBSD_1.2 {
+ td_thr_get_info;
+};
diff --git a/lib/libthread_db/libpthread_db.c b/lib/libthread_db/libpthread_db.c
index 65478a7..31ea15d 100644
--- a/lib/libthread_db/libpthread_db.c
+++ b/lib/libthread_db/libpthread_db.c
@@ -570,7 +570,7 @@ pt_thr_validate(const td_thrhandle_t *th)
}
static td_err_e
-pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
+pt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info)
{
const td_thragent_t *ta = th->th_ta;
struct ptrace_lwpinfo linfo;
@@ -659,6 +659,16 @@ pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
return (0);
}
+static td_err_e
+pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
+{
+ td_err_e e;
+
+ e = pt_thr_old_get_info(th, (td_old_thrinfo_t *)info);
+ bzero(&info->ti_siginfo, sizeof(info->ti_siginfo));
+ return (e);
+}
+
#ifdef __i386__
static td_err_e
pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
@@ -1114,6 +1124,7 @@ struct ta_ops libpthread_db_ops = {
.to_thr_dbsuspend = pt_thr_dbsuspend,
.to_thr_event_enable = pt_thr_event_enable,
.to_thr_event_getmsg = pt_thr_event_getmsg,
+ .to_thr_old_get_info = pt_thr_old_get_info,
.to_thr_get_info = pt_thr_get_info,
.to_thr_getfpregs = pt_thr_getfpregs,
.to_thr_getgregs = pt_thr_getgregs,
diff --git a/lib/libthread_db/libthr_db.c b/lib/libthread_db/libthr_db.c
index f79facb..33225f4 100644
--- a/lib/libthread_db/libthr_db.c
+++ b/lib/libthread_db/libthr_db.c
@@ -453,7 +453,7 @@ pt_thr_validate(const td_thrhandle_t *th)
}
static td_err_e
-pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
+pt_thr_get_info_common(const td_thrhandle_t *th, td_thrinfo_t *info, int old)
{
const td_thragent_t *ta = th->th_ta;
struct ptrace_lwpinfo linfo;
@@ -489,6 +489,13 @@ pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
if (ret == PS_OK) {
info->ti_sigmask = linfo.pl_sigmask;
info->ti_pending = linfo.pl_siglist;
+ if (!old) {
+ if ((linfo.pl_flags & PL_FLAG_SI) != 0)
+ info->ti_siginfo = linfo.pl_siginfo;
+ else
+ bzero(&info->ti_siginfo,
+ sizeof(info->ti_siginfo));
+ }
} else
return (ret);
if (state == ta->thread_state_running)
@@ -501,6 +508,20 @@ pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
return (0);
}
+static td_err_e
+pt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info)
+{
+
+ return (pt_thr_get_info_common(th, (td_thrinfo_t *)info, 1));
+}
+
+static td_err_e
+pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
+{
+
+ return (pt_thr_get_info_common(th, info, 0));
+}
+
#ifdef __i386__
static td_err_e
pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
@@ -761,6 +782,7 @@ struct ta_ops libthr_db_ops = {
.to_thr_dbsuspend = pt_thr_dbsuspend,
.to_thr_event_enable = pt_thr_event_enable,
.to_thr_event_getmsg = pt_thr_event_getmsg,
+ .to_thr_old_get_info = pt_thr_old_get_info,
.to_thr_get_info = pt_thr_get_info,
.to_thr_getfpregs = pt_thr_getfpregs,
.to_thr_getgregs = pt_thr_getgregs,
diff --git a/lib/libthread_db/thread_db.c b/lib/libthread_db/thread_db.c
index dc8195d..121855b 100644
--- a/lib/libthread_db/thread_db.c
+++ b/lib/libthread_db/thread_db.c
@@ -176,6 +176,14 @@ td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
}
td_err_e
+td_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info)
+{
+ const td_thragent_t *ta = th->th_ta;
+ return (ta->ta_ops->to_thr_old_get_info(th, info));
+}
+__sym_compat(td_thr_get_info, td_thr_old_get_info, FBSD_1.0);
+
+td_err_e
td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
{
const td_thragent_t *ta = th->th_ta;
diff --git a/lib/libthread_db/thread_db.h b/lib/libthread_db/thread_db.h
index 44ddea4..8c30812 100644
--- a/lib/libthread_db/thread_db.h
+++ b/lib/libthread_db/thread_db.h
@@ -191,6 +191,7 @@ typedef struct {
psaddr_t ti_startfunc;
psaddr_t ti_stkbase;
size_t ti_stksize;
+ siginfo_t ti_siginfo;
} td_thrinfo_t;
/*
diff --git a/lib/libthread_db/thread_db_int.h b/lib/libthread_db/thread_db_int.h
index 3b03062..92ba6e5 100644
--- a/lib/libthread_db/thread_db_int.h
+++ b/lib/libthread_db/thread_db_int.h
@@ -32,6 +32,25 @@
#include <sys/types.h>
#include <sys/queue.h>
+typedef struct {
+ const td_thragent_t *ti_ta_p;
+ thread_t ti_tid;
+ psaddr_t ti_thread;
+ td_thr_state_e ti_state;
+ td_thr_type_e ti_type;
+ td_thr_events_t ti_events;
+ int ti_pri;
+ lwpid_t ti_lid;
+ char ti_db_suspended;
+ char ti_traceme;
+ sigset_t ti_sigmask;
+ sigset_t ti_pending;
+ psaddr_t ti_tls;
+ psaddr_t ti_startfunc;
+ psaddr_t ti_stkbase;
+ size_t ti_stksize;
+} td_old_thrinfo_t;
+
#define TD_THRAGENT_FIELDS \
struct ta_ops *ta_ops; \
TAILQ_ENTRY(td_thragent) ta_next; \
@@ -65,6 +84,8 @@ struct ta_ops {
td_err_e (*to_thr_event_enable)(const td_thrhandle_t *, int);
td_err_e (*to_thr_event_getmsg)(const td_thrhandle_t *,
td_event_msg_t *);
+ td_err_e (*to_thr_old_get_info)(const td_thrhandle_t *,
+ td_old_thrinfo_t *);
td_err_e (*to_thr_get_info)(const td_thrhandle_t *, td_thrinfo_t *);
td_err_e (*to_thr_getfpregs)(const td_thrhandle_t *, prfpregset_t *);
td_err_e (*to_thr_getgregs)(const td_thrhandle_t *, prgregset_t);
@@ -103,4 +124,6 @@ int thr_pwrite_int(const struct td_thragent *, psaddr_t, uint32_t);
int thr_pwrite_long(const struct td_thragent *, psaddr_t, uint64_t);
int thr_pwrite_ptr(const struct td_thragent *, psaddr_t, psaddr_t);
+td_err_e td_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info);
+
#endif /* _THREAD_DB_INT_H_ */
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index f0fde2b..1d60ed4 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -2208,7 +2208,7 @@ freebsd32_thr_suspend(struct thread *td, struct freebsd32_thr_suspend_args *uap)
}
void
-siginfo_to_siginfo32(siginfo_t *src, struct siginfo32 *dst)
+siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst)
{
bzero(dst, sizeof(*dst));
dst->si_signo = src->si_signo;
diff --git a/sys/compat/freebsd32/freebsd32_signal.h b/sys/compat/freebsd32/freebsd32_signal.h
index ba0922a..2669581 100644
--- a/sys/compat/freebsd32/freebsd32_signal.h
+++ b/sys/compat/freebsd32/freebsd32_signal.h
@@ -96,6 +96,6 @@ struct sigevent32 {
} _sigev_un;
};
-void siginfo_to_siginfo32(siginfo_t *src, struct siginfo32 *dst);
+void siginfo_to_siginfo32(const siginfo_t *src, struct siginfo32 *dst);
#endif /* !_COMPAT_FREEBSD32_SIGNAL_H_ */
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 04c2ba7..af3c7da 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2522,7 +2522,6 @@ issignal(struct thread *td, int stop_allowed)
struct sigacts *ps;
struct sigqueue *queue;
sigset_t sigpending;
- ksiginfo_t ksi;
int sig, prop, newsig;
p = td->td_proc;
@@ -2565,10 +2564,10 @@ issignal(struct thread *td, int stop_allowed)
* be thrown away.
*/
queue = &td->td_sigqueue;
- ksi.ksi_signo = 0;
- if (sigqueue_get(queue, sig, &ksi) == 0) {
+ td->td_dbgksi.ksi_signo = 0;
+ if (sigqueue_get(queue, sig, &td->td_dbgksi) == 0) {
queue = &p->p_sigqueue;
- sigqueue_get(queue, sig, &ksi);
+ sigqueue_get(queue, sig, &td->td_dbgksi);
}
mtx_unlock(&ps->ps_mtx);
@@ -2595,13 +2594,13 @@ issignal(struct thread *td, int stop_allowed)
continue;
signotify(td);
} else {
- if (ksi.ksi_signo != 0) {
- ksi.ksi_flags |= KSI_HEAD;
+ if (td->td_dbgksi.ksi_signo != 0) {
+ td->td_dbgksi.ksi_flags |= KSI_HEAD;
if (sigqueue_add(&td->td_sigqueue, sig,
- &ksi) != 0)
- ksi.ksi_signo = 0;
+ &td->td_dbgksi) != 0)
+ td->td_dbgksi.ksi_signo = 0;
}
- if (ksi.ksi_signo == 0)
+ if (td->td_dbgksi.ksi_signo == 0)
sigqueue_add(&td->td_sigqueue, sig,
NULL);
}
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 40c861b..525c0e2 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -64,6 +64,7 @@ __FBSDID("$FreeBSD$");
#ifdef COMPAT_FREEBSD32
#include <sys/procfs.h>
+#include <compat/freebsd32/freebsd32_signal.h>
struct ptrace_io_desc32 {
int piod_op;
@@ -85,6 +86,15 @@ struct ptrace_vm_entry32 {
uint32_t pve_path;
};
+struct ptrace_lwpinfo32 {
+ lwpid_t pl_lwpid; /* LWP described. */
+ int pl_event; /* Event that stopped the LWP. */
+ int pl_flags; /* LWP flags. */
+ sigset_t pl_sigmask; /* LWP signal mask */
+ sigset_t pl_siglist; /* LWP pending signal */
+ struct siginfo32 pl_siginfo; /* siginfo for signal */
+};
+
#endif
/*
@@ -498,6 +508,19 @@ ptrace_vm_entry32(struct thread *td, struct proc *p,
pve32->pve_pathlen = pve.pve_pathlen;
return (error);
}
+
+static void
+ptrace_lwpinfo_to32(const struct ptrace_lwpinfo *pl,
+ struct ptrace_lwpinfo32 *pl32)
+{
+
+ pl32->pl_lwpid = pl->pl_lwpid;
+ pl32->pl_event = pl->pl_event;
+ pl32->pl_flags = pl->pl_flags;
+ pl32->pl_sigmask = pl->pl_sigmask;
+ pl32->pl_siglist = pl->pl_siglist;
+ siginfo_to_siginfo32(&pl->pl_siginfo, &pl32->pl_siginfo);
+}
#endif /* COMPAT_FREEBSD32 */
/*
@@ -552,6 +575,7 @@ ptrace(struct thread *td, struct ptrace_args *uap)
struct fpreg32 fpreg32;
struct reg32 reg32;
struct ptrace_io_desc32 piod32;
+ struct ptrace_lwpinfo32 pl32;
struct ptrace_vm_entry32 pve32;
#endif
} r;
@@ -662,6 +686,8 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
#ifdef COMPAT_FREEBSD32
int wrap32 = 0, safe = 0;
struct ptrace_io_desc32 *piod32 = NULL;
+ struct ptrace_lwpinfo32 *pl32 = NULL;
+ struct ptrace_lwpinfo plr;
#endif
curp = td->td_proc;
@@ -1103,15 +1129,44 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
break;
case PT_LWPINFO:
- if (data <= 0 || data > sizeof(*pl)) {
+ if (data <= 0 ||
+#ifdef COMPAT_FREEBSD32
+ (!wrap32 && data > sizeof(*pl)) ||
+ (wrap32 && data > sizeof(*pl32))) {
+#else
+ data > sizeof(*pl)) {
+#endif
error = EINVAL;
break;
}
+#ifdef COMPAT_FREEBSD32
+ if (wrap32) {
+ pl = &plr;
+ pl32 = addr;
+ } else
+#endif
pl = addr;
pl->pl_lwpid = td2->td_tid;
- if (td2->td_dbgflags & TDB_XSIG)
- pl->pl_event = PL_EVENT_SIGNAL;
pl->pl_flags = 0;
+ if (td2->td_dbgflags & TDB_XSIG) {
+ pl->pl_event = PL_EVENT_SIGNAL;
+ if (td2->td_dbgksi.ksi_signo != 0 &&
+#ifdef COMPAT_FREEBSD32
+ ((!wrap32 && data >= offsetof(struct ptrace_lwpinfo,
+ pl_siginfo) + sizeof(pl->pl_siginfo)) ||
+ (wrap32 && data >= offsetof(struct ptrace_lwpinfo32,
+ pl_siginfo) + sizeof(struct siginfo32)))
+#else
+ data >= offsetof(struct ptrace_lwpinfo, pl_siginfo)
+ + sizeof(pl->pl_siginfo)
+#endif
+ ){
+ pl->pl_flags |= PL_FLAG_SI;
+ pl->pl_siginfo = td2->td_dbgksi.ksi_info;
+ }
+ }
+ if ((pl->pl_flags & PL_FLAG_SI) == 0)
+ bzero(&pl->pl_siginfo, sizeof(pl->pl_siginfo));
if (td2->td_dbgflags & TDB_SCE)
pl->pl_flags |= PL_FLAG_SCE;
else if (td2->td_dbgflags & TDB_SCX)
@@ -1120,6 +1175,10 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
pl->pl_flags |= PL_FLAG_EXEC;
pl->pl_sigmask = td2->td_sigmask;
pl->pl_siglist = td2->td_siglist;
+#ifdef COMPAT_FREEBSD32
+ if (wrap32)
+ ptrace_lwpinfo_to32(pl, pl32);
+#endif
break;
case PT_GETNUMLWPS:
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 3c9a2de..cd00550 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -259,6 +259,7 @@ struct thread {
char td_name[MAXCOMLEN + 1]; /* (*) Thread name. */
struct file *td_fpop; /* (k) file referencing cdev under op */
int td_dbgflags; /* (c) Userland debugger flags */
+ struct ksiginfo td_dbgksi; /* (c) ksi reflected to debugger. */
int td_ng_outbound; /* (k) Thread entered ng from above. */
struct osd td_osd; /* (k) Object specific data. */
#define td_endzero td_base_pri
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index a6dbe2c..f4b25d4 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -33,7 +33,7 @@
#ifndef _SYS_PTRACE_H_
#define _SYS_PTRACE_H_
-#include <sys/_sigset.h>
+#include <sys/signal.h>
#include <machine/reg.h>
#define PT_TRACE_ME 0 /* child declares it's being traced */
@@ -102,8 +102,10 @@ struct ptrace_lwpinfo {
#define PL_FLAG_SCE 0x04 /* syscall enter point */
#define PL_FLAG_SCX 0x08 /* syscall leave point */
#define PL_FLAG_EXEC 0x10 /* exec(2) succeeded */
+#define PL_FLAG_SI 0x20 /* siginfo is valid */
sigset_t pl_sigmask; /* LWP signal mask */
sigset_t pl_siglist; /* LWP pending signal */
+ struct __siginfo pl_siginfo; /* siginfo for signal */
};
/* Argument structure for PT_VM_ENTRY. */
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 196 bytes
Desc: not available
Url : http://lists.freebsd.org/pipermail/freebsd-arch/attachments/20100702/2a1575b7/attachment.pgp
More information about the freebsd-arch
mailing list