Add my initial work of libthread_db. The library is used by gdb to debug

threaded process. Current, only libpthread is supported, but macrel will
work on it to support libthr and libc_r.
This commit is contained in:
David Xu 2004-07-15 03:36:35 +00:00
parent 8916adb1c9
commit a31a256002
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=132172
9 changed files with 2030 additions and 0 deletions

View File

@ -0,0 +1,5 @@
# $FreeBSD$
SUBDIR=pthread src
.include <bsd.subdir.mk>

View File

@ -0,0 +1,287 @@
/*
* Copyright (c) 2004 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _THREAD_DB_H_
#define _THREAD_DB_H_
#include <sys/types.h>
#include <pthread.h>
typedef enum
{
TD_OK,
TD_ERR,
TD_NOTHR,
TD_NOSV,
TD_NOLWP,
TD_BADPH,
TD_BADTH,
TD_BADSH,
TD_BADTA,
TD_BADKEY,
TD_NOMSG,
TD_NOFPREGS,
TD_NOLIBTHREAD,
TD_NOEVENT,
TD_NOCAPAB,
TD_DBERR,
TD_NOAPLIC,
TD_NOTSD,
TD_MALLOC,
TD_PARTIALREG,
TD_NOXREGS
} td_err_e;
typedef enum
{
TD_THR_ANY_STATE,
TD_THR_UNKNOWN,
TD_THR_STOPPED,
TD_THR_RUN,
TD_THR_ACTIVE,
TD_THR_ZOMBIE,
TD_THR_SLEEP,
TD_THR_STOPPED_ASLEEP
} td_thr_state_e;
typedef enum
{
TD_THR_ANY_TYPE,
TD_THR_USER,
TD_THR_SYSTEM
} td_thr_type_e;
typedef long thread_t;
typedef pthread_key_t thread_key_t;
typedef struct td_thragent td_thragent_t;
typedef struct td_thrhandle
{
td_thragent_t *th_ta_p;
thread_t th_unique;
int th_ta_data;
} td_thrhandle_t;
/* Flags for `td_ta_thr_iter'. */
#define TD_THR_ANY_USER_FLAGS 0xffffffff
#define TD_THR_LOWEST_PRIORITY 0
#define TD_SIGNO_MASK NULL
typedef uint32_t td_thr_events_t;
typedef enum
{
TD_ALL_EVENTS,
TD_EVENT_NONE = TD_ALL_EVENTS,
TD_CREATE,
TD_DEATH,
TD_REAP,
TD_READY,
TD_SLEEP,
TD_SWITCHTO,
TD_SWITCHFROM,
TD_LOCK_TRY,
TD_CATCHSIG,
TD_IDLE,
TD_PREEMPT,
TD_PRI_INHERIT,
TD_CONCURRENCY,
TD_TIMEOUT,
TD_MIN_EVENT_NUM = TD_READY,
TD_MAX_EVENT_NUM = TD_TIMEOUT,
TD_EVENTS_ENABLE = 31
} td_event_e;
typedef enum
{
NOTIFY_BPT,
NOTIFY_AUTOBPT,
NOTIFY_SYSCALL
} td_notify_e;
typedef struct td_notify
{
td_notify_e type;
union {
psaddr_t bptaddr;
int syscallno;
} u;
} td_notify_t;
typedef struct td_event_msg
{
td_event_e event;
const td_thrhandle_t *th_p;
union {
#if 0
td_synchandle_t *sh;
#endif
uintptr_t data;
} msg;
} td_event_msg_t;
/* Structure containing event data available in each thread structure. */
typedef struct
{
td_thr_events_t eventmask; /* Mask of enabled events. */
td_event_e eventnum; /* Number of last event. */
void *eventdata; /* Data associated with event. */
} td_eventbuf_t;
/* Gathered statistics about the process. */
typedef struct td_ta_stats
{
int nthreads; /* Total number of threads in use. */
int r_concurrency; /* Concurrency level requested by user. */
int nrunnable_num; /* Average runnable threads, numerator. */
int nrunnable_den; /* Average runnable threads, denominator. */
int a_concurrency_num; /* Achieved concurrency level, numerator. */
int a_concurrency_den; /* Achieved concurrency level, denominator. */
int nlwps_num; /* Average number of processes in use,
numerator. */
int nlwps_den; /* Average number of processes in use,
denominator. */
int nidle_num; /* Average number of idling processes,
numerator. */
int nidle_den; /* Average number of idling processes,
denominator. */
} td_ta_stats_t;
static inline void
td_event_emptyset(td_thr_events_t *setp)
{
*setp = 0;
}
static inline void
td_event_fillset(td_thr_events_t *setp)
{
*setp = 0xFFFFFFFF;
}
static inline void
td_event_addset(td_thr_events_t *setp, int n)
{
*setp |= (1 << (n-1));
}
static inline void
td_event_delset(td_thr_events_t *setp, int n)
{
*setp &= ~(1 << (n-1));
}
static inline int
td_eventismember(td_thr_events_t *setp, int n)
{
return (*setp & (1 << (n-1)) ? 1 : 0);
}
static inline int
td_eventisempty(td_thr_events_t *setp)
{
return (*setp == 0);
}
typedef int td_thr_iter_f(const td_thrhandle_t *, void *);
typedef int td_key_iter_f(thread_key_t, void (*) (void *), void *);
struct ps_prochandle;
typedef struct td_thrinfo
{
td_thragent_t *ti_ta_p;
unsigned int ti_user_flags;
thread_t ti_tid;
char *ti_tls;
psaddr_t ti_startfunc;
psaddr_t ti_stkbase;
long int ti_stksize;
psaddr_t ti_ro_area;
int ti_ro_size;
td_thr_state_e ti_state;
unsigned char ti_db_suspended;
td_thr_type_e ti_type;
intptr_t ti_pc;
intptr_t ti_sp;
short int ti_flags;
int ti_pri;
lwpid_t ti_lid;
sigset_t ti_sigmask;
unsigned char ti_traceme;
unsigned char ti_preemptflag;
unsigned char ti_pirecflag;
sigset_t ti_pending;
td_thr_events_t ti_events;
} td_thrinfo_t;
td_err_e td_init(void);
td_err_e td_log(void);
td_err_e td_ta_new(struct ps_prochandle *, td_thragent_t **);
td_err_e td_ta_delete(td_thragent_t *);
td_err_e td_ta_get_nthreads(const td_thragent_t *, int *);
td_err_e td_ta_get_ph(const td_thragent_t *, struct ps_prochandle **);
td_err_e td_ta_map_id2thr(const td_thragent_t *, thread_t, td_thrhandle_t *);
td_err_e td_ta_map_lwp2thr(const td_thragent_t *, lwpid_t lwpid,
td_thrhandle_t *);
td_err_e td_ta_thr_iter(const td_thragent_t *, td_thr_iter_f *, void *,
td_thr_state_e, int, sigset_t *, unsigned int);
td_err_e td_ta_tsd_iter(const td_thragent_t *, td_key_iter_f *, void *);
td_err_e td_ta_event_addr(const td_thragent_t *, td_event_e , td_notify_t *);
td_err_e td_ta_set_event(const td_thragent_t *, td_thr_events_t *);
td_err_e td_ta_clear_event(const td_thragent_t *, td_thr_events_t *);
td_err_e td_ta_event_getmsg(const td_thragent_t *, td_event_msg_t *);
td_err_e td_ta_setconcurrency(const td_thragent_t *, int);
td_err_e td_ta_enable_stats(const td_thragent_t *, int);
td_err_e td_ta_reset_stats(const td_thragent_t *);
td_err_e td_ta_get_stats(const td_thragent_t *, td_ta_stats_t *);
td_err_e td_thr_validate(const td_thrhandle_t *);
td_err_e td_thr_get_info(const td_thrhandle_t *, td_thrinfo_t *);
td_err_e td_thr_getfpregs(const td_thrhandle_t *, prfpregset_t *);
td_err_e td_thr_getgregs(const td_thrhandle_t *, prgregset_t);
td_err_e td_thr_getxregs(const td_thrhandle_t *, void *);
td_err_e td_thr_getxregsize(const td_thrhandle_t *, int *);
td_err_e td_thr_setfpregs(const td_thrhandle_t *, const prfpregset_t *);
td_err_e td_thr_setgregs(const td_thrhandle_t *, prgregset_t);
td_err_e td_thr_setxregs(const td_thrhandle_t *, const void *);
td_err_e td_thr_event_enable(const td_thrhandle_t *, int);
td_err_e td_thr_set_event(const td_thrhandle_t *, td_thr_events_t *);
td_err_e td_thr_clear_event(const td_thrhandle_t *, td_thr_events_t *);
td_err_e td_thr_event_getmsg(const td_thrhandle_t *, td_event_msg_t *);
td_err_e td_thr_setprio(const td_thrhandle_t *, int);
td_err_e td_thr_setsigpending(const td_thrhandle_t *, unsigned char,
const sigset_t *);
td_err_e td_thr_sigsetmask(const td_thrhandle_t *, const sigset_t *);
td_err_e td_thr_tsd(const td_thrhandle_t *, const thread_key_t, void **);
td_err_e td_thr_dbsuspend(const td_thrhandle_t *);
td_err_e td_thr_dbresume(const td_thrhandle_t *);
td_err_e td_get_ta(int pid, td_thragent_t **);
td_err_e td_ta_activated(td_thragent_t *, int *);
td_err_e td_thr_sstep(td_thrhandle_t *, int);
#endif

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2004 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _THREAD_DB_INT_H
#define _THREAD_DB_INT_H
#include <sys/types.h>
#include <sys/queue.h>
struct td_thragent {
struct ta_ops *ta_ops;
TAILQ_ENTRY(td_thragent) ta_next;
};
struct ta_ops {
td_err_e (*to_init)(void);
td_err_e (*to_ta_new)(struct ps_prochandle *, td_thragent_t **);
td_err_e (*to_ta_delete)(td_thragent_t *);
td_err_e (*to_ta_get_nthreads)(const td_thragent_t *, int *);
td_err_e (*to_ta_get_ph)(const td_thragent_t *, struct ps_prochandle **);
td_err_e (*to_ta_map_id2thr)(const td_thragent_t *, thread_t, td_thrhandle_t *);
td_err_e (*to_ta_map_lwp2thr)(const td_thragent_t *, lwpid_t lwpid,
td_thrhandle_t *);
td_err_e (*to_ta_thr_iter)(const td_thragent_t *, td_thr_iter_f *, void *,
td_thr_state_e, int, sigset_t *, unsigned int);
td_err_e (*to_ta_tsd_iter)(const td_thragent_t *, td_key_iter_f *, void *);
td_err_e (*to_ta_event_addr)(const td_thragent_t *, td_event_e , td_notify_t *);
td_err_e (*to_ta_set_event)(const td_thragent_t *, td_thr_events_t *);
td_err_e (*to_ta_clear_event)(const td_thragent_t *, td_thr_events_t *);
td_err_e (*to_ta_event_getmsg)(const td_thragent_t *, td_event_msg_t *);
td_err_e (*to_ta_setconcurrency)(const td_thragent_t *, int);
td_err_e (*to_ta_enable_stats)(const td_thragent_t *, int);
td_err_e (*to_ta_reset_stats)(const td_thragent_t *);
td_err_e (*to_ta_get_stats)(const td_thragent_t *, td_ta_stats_t *);
td_err_e (*to_thr_validate)(const td_thrhandle_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);
td_err_e (*to_thr_getxregs)(const td_thrhandle_t *, void *);
td_err_e (*to_thr_getxregsize)(const td_thrhandle_t *, int *);
td_err_e (*to_thr_setfpregs)(const td_thrhandle_t *, const prfpregset_t *);
td_err_e (*to_thr_setgregs)(const td_thrhandle_t *, prgregset_t);
td_err_e (*to_thr_setxregs)(const td_thrhandle_t *, const void *);
td_err_e (*to_thr_event_enable)(const td_thrhandle_t *, int);
td_err_e (*to_thr_set_event)(const td_thrhandle_t *, td_thr_events_t *);
td_err_e (*to_thr_clear_event)(const td_thrhandle_t *, td_thr_events_t *);
td_err_e (*to_thr_event_getmsg)(const td_thrhandle_t *, td_event_msg_t *);
td_err_e (*to_thr_setprio)(const td_thrhandle_t *, int);
td_err_e (*to_thr_setsigpending)(const td_thrhandle_t *, unsigned char,
const sigset_t *);
td_err_e (*to_thr_sigsetmask)(const td_thrhandle_t *, const sigset_t *);
td_err_e (*to_thr_tsd)(const td_thrhandle_t *, const thread_key_t, void **);
td_err_e (*to_thr_dbsuspend)(const td_thrhandle_t *);
td_err_e (*to_thr_dbresume)(const td_thrhandle_t *);
td_err_e (*to_get_ta)(int pid, td_thragent_t **);
td_err_e (*to_ta_activated)(td_thragent_t *, int *);
td_err_e (*to_thr_sstep)(td_thrhandle_t *, int step);
};
#ifdef TD_DEBUG
#define TDBG(...) ps_plog(__VA_ARGS__)
#define TDBG_FUNC() ps_plog(__func__); ps_plog("\n")
#else
#define TDBG(...)
#define TDBG_FUNC()
#endif
#endif

View File

@ -0,0 +1,19 @@
# $FreeBSD$
LIB=pthread_db
INTERNALLIB=yes
NOPROFILE=yes
NOPIC=yes
CFLAGS+=-DPTHREAD_KERNEL -fpic -DPIC
CFLAGS+=-I${.CURDIR}/../include \
-I${.CURDIR}/../../libc/include -I${.CURDIR}/../../libpthread/thread \
-I${.CURDIR}/../../../include
CFLAGS+=-I${.CURDIR}/../../libpthread/arch/${MACHINE_ARCH}/include
CFLAGS+=-I${.CURDIR}/../../libpthread/sys
CFLAGS+=-Wall
.PATH: ${.CURDIR}
SRCS+=pthread_db.c pthread_db_${MACHINE_ARCH}.c
.include <bsd.lib.mk>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
/*
* Copyright (c) 2004 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#ifndef _PTHREAD_DB_H
#define _PTHREAD_DB_H
#include <sys/ucontext.h>
#include <machine/reg.h>
#include "thread_db_int.h"
struct pt_thragent {
struct td_thragent base;
struct ps_prochandle *ph;
psaddr_t libkse_debug_addr;
psaddr_t thread_list_addr;
psaddr_t thread_listgen_addr;
psaddr_t thread_activated_addr;
psaddr_t thread_active_threads_addr;
psaddr_t thread_keytable_addr;
int thread_activated;
struct pt_map *map;
int map_len;
};
typedef struct pt_thragent pt_thragent_t;
void pt_md_init(void);
void pt_reg_to_ucontext(const struct reg *, ucontext_t *);
void pt_ucontext_to_reg(const ucontext_t *, struct reg *);
void pt_fpreg_to_ucontext(const struct fpreg *, ucontext_t *);
void pt_ucontext_to_fpreg(const ucontext_t *, struct fpreg *);
int pt_reg_sstep(struct reg *reg, int step);
#endif

View File

@ -0,0 +1,105 @@
/*
* Copyright (c) 2004 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <string.h>
#include <sys/types.h>
#include <proc_service.h>
#include <thread_db.h>
#include <machine/npx.h>
#include "pthread_db.h"
static int has_xmm_regs;
void
pt_reg_to_ucontext(const struct reg *r, ucontext_t *uc)
{
memcpy(&uc->uc_mcontext.mc_fs, &r->r_fs, 18*4);
uc->uc_mcontext.mc_gs = r->r_gs;
}
void
pt_ucontext_to_reg(const ucontext_t *uc, struct reg *r)
{
memcpy(&r->r_fs, &uc->uc_mcontext.mc_fs, 18*4);
r->r_gs = uc->uc_mcontext.mc_gs;
}
void
pt_fpreg_to_ucontext(const struct fpreg* r, ucontext_t *uc)
{
if (!has_xmm_regs)
memcpy(&uc->uc_mcontext.mc_fpstate, r,
sizeof(struct save87));
else {
int i;
struct savexmm *sx = (struct savexmm *)&uc->uc_mcontext.mc_fpstate;
memcpy(&sx->sv_env, &r->fpr_env, sizeof(r->fpr_env));
for (i = 0; i < 8; ++i)
memcpy(&sx->sv_fp[i].fp_acc, &r->fpr_acc[i], 10);
}
}
void
pt_ucontext_to_fpreg(const ucontext_t *uc, struct fpreg *r)
{
if (!has_xmm_regs)
memcpy(r, &uc->uc_mcontext.mc_fpstate, sizeof(struct save87));
else {
int i;
struct savexmm *sx = (struct savexmm *)&uc->uc_mcontext.mc_fpstate;
memcpy(&r->fpr_env, &sx->sv_env, sizeof(r->fpr_env));
for (i = 0; i < 8; ++i)
memcpy(&r->fpr_acc[i], &sx->sv_fp[i].fp_acc, 10);
}
}
void
pt_md_init(void)
{
ucontext_t uc;
getcontext(&uc);
if (uc.uc_mcontext.mc_fpformat == _MC_FPFMT_XMM)
has_xmm_regs = 1;
}
int
pt_reg_sstep(struct reg *reg, int step)
{
unsigned int old;
old = reg->r_eflags;
if (step)
reg->r_eflags |= 0x0100;
else
reg->r_eflags &= ~0x0100;
return (old != reg->r_eflags); /* changed ? */
}

View File

@ -0,0 +1,15 @@
# $FreeBSD$
SHLIB_NAME=libthread_db.so.1
NOPROFILE=yes
CFLAGS+=-Wall -I${.CURDIR}/../../../include -I${.CURDIR}/../include
LDADD=../pthread/libpthread_db.a
PRECIOUSLIB=yes
.PATH: ${.CURDIR}
SRCS+=thread_db.c
INCS=../include/thread_db.h
.include <bsd.lib.mk>

View File

@ -0,0 +1,359 @@
/*
* Copyright (c) 2004 David Xu <davidxu@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <stddef.h>
#include <unistd.h>
#include <proc_service.h>
#include <thread_db.h>
#include "thread_db_int.h"
static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist);
extern struct ta_ops pthread_ops;
#if 0
extern struct ta_ops thr_ops;
extern struct ta_ops c_r_ops;
#endif
static struct ta_ops *ops[] = {
&pthread_ops,
#if 0
&thr_ops,
&c_r_ops
#endif
};
td_err_e
td_init(void)
{
int i, ret = 0;
for (i = 0; i < sizeof(ops)/sizeof(ops[0]); ++i) {
int tmp;
if ((tmp = ops[i]->to_init()) != 0)
ret = tmp;
}
return (ret);
}
td_err_e
td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
{
int i;
for (i = 0; i < sizeof(ops)/sizeof(ops[0]); ++i) {
if (ops[i]->to_ta_new(ph, pta) == 0) {
(*pta)->ta_ops = ops[i];
TAILQ_INSERT_HEAD(&proclist, *pta, ta_next);
return (0);
}
}
return (TD_NOLIBTHREAD);
}
td_err_e
td_ta_delete(td_thragent_t *ta)
{
TAILQ_REMOVE(&proclist, ta, ta_next);
return ta->ta_ops->to_ta_delete(ta);
}
td_err_e
td_ta_get_nthreads(const td_thragent_t *ta, int *np)
{
return ta->ta_ops->to_ta_get_nthreads(ta, np);
}
td_err_e
td_ta_get_ph(const td_thragent_t *ta, struct ps_prochandle **ph)
{
return ta->ta_ops->to_ta_get_ph(ta, ph);
}
td_err_e
td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
{
return ta->ta_ops->to_ta_map_id2thr(ta, id, th);
}
td_err_e
td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
{
return ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th);
}
td_err_e
td_ta_thr_iter(const td_thragent_t *ta,
td_thr_iter_f *callback, void *cbdata_p,
td_thr_state_e state, int ti_pri,
sigset_t *ti_sigmask_p,
unsigned int ti_user_flags)
{
return ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state,
ti_pri, ti_sigmask_p, ti_user_flags);
}
td_err_e
td_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
{
return ta->ta_ops->to_ta_tsd_iter(ta, ki, arg);
}
td_err_e
td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
{
return ta->ta_ops->to_ta_event_addr(ta, event, ptr);
}
td_err_e
td_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
{
return ta->ta_ops->to_ta_set_event(ta, events);
}
td_err_e
td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
{
return ta->ta_ops->to_ta_clear_event(ta, events);
}
td_err_e
td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
{
return ta->ta_ops->to_ta_event_getmsg(ta, msg);
}
td_err_e
td_ta_setconcurrency(const td_thragent_t *ta, int level)
{
return ta->ta_ops->to_ta_setconcurrency(ta, level);
}
td_err_e
td_ta_enable_stats(const td_thragent_t *ta, int enable)
{
return ta->ta_ops->to_ta_enable_stats(ta, enable);
}
td_err_e
td_ta_reset_stats(const td_thragent_t *ta)
{
return ta->ta_ops->to_ta_reset_stats(ta);
}
td_err_e
td_ta_get_stats(const td_thragent_t *ta, td_ta_stats_t *statsp)
{
return ta->ta_ops->to_ta_get_stats(ta, statsp);
}
td_err_e
td_thr_validate(const td_thrhandle_t *th)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_validate(th);
}
td_err_e
td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_get_info(th, info);
}
td_err_e
td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_getfpregs(th, fpregset);
}
td_err_e
td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_getgregs(th, gregs);
}
td_err_e
td_thr_getxregs(const td_thrhandle_t *th, void *xregs)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_getxregs(th, xregs);
}
td_err_e
td_thr_getxregsize(const td_thrhandle_t *th, int *sizep)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_getxregsize(th, sizep);
}
td_err_e
td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_setfpregs(th, fpregs);
}
td_err_e
td_thr_setgregs(const td_thrhandle_t *th, prgregset_t gregs)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_setgregs(th, gregs);
}
td_err_e
td_thr_setxregs(const td_thrhandle_t *th, const void *addr)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_setxregs(th, addr);
}
td_err_e
td_thr_event_enable(const td_thrhandle_t *th, int en)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_event_enable(th, en);
}
td_err_e
td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_set_event(th, setp);
}
td_err_e
td_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_clear_event(th, setp);
}
td_err_e
td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_event_getmsg(th, msg);
}
td_err_e
td_thr_setprio(const td_thrhandle_t *th, int pri)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_setprio(th, pri);
}
td_err_e
td_thr_setsigpending(const td_thrhandle_t *th, unsigned char n,
const sigset_t *set)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_setsigpending(th, n, set);
}
td_err_e
td_thr_sigsetmask(const td_thrhandle_t *th, const sigset_t *set)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_sigsetmask(th, set);
}
td_err_e
td_thr_tsd(const td_thrhandle_t *th, const thread_key_t key, void **data)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_tsd(th, key, data);
}
td_err_e
td_thr_dbsuspend(const td_thrhandle_t *th)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_dbsuspend(th);
}
td_err_e
td_thr_dbresume(const td_thrhandle_t *th)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_dbresume(th);
}
td_err_e
td_get_ta(int pid, td_thragent_t **ta_p)
{
td_thragent_t *ta;
struct ps_prochandle *ph;
TAILQ_FOREACH(ta, &proclist, ta_next) {
td_ta_get_ph(ta, &ph);
if (ps_getpid(ph) == pid) {
*ta_p = ta;
return (TD_OK);
}
}
return (TD_ERR);
}
td_err_e
td_ta_activated(td_thragent_t *ta, int *a)
{
return ta->ta_ops->to_ta_activated(ta, a);
}
td_err_e
td_thr_sstep(td_thrhandle_t *th, int step)
{
td_thragent_t *ta = th->th_ta_p;
return ta->ta_ops->to_thr_sstep(th, step);
}