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:
parent
8916adb1c9
commit
a31a256002
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=132172
5
lib/libthread_db/Makefile
Normal file
5
lib/libthread_db/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
SUBDIR=pthread src
|
||||
|
||||
.include <bsd.subdir.mk>
|
287
lib/libthread_db/include/thread_db.h
Normal file
287
lib/libthread_db/include/thread_db.h
Normal 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
|
93
lib/libthread_db/include/thread_db_int.h
Normal file
93
lib/libthread_db/include/thread_db_int.h
Normal 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
|
19
lib/libthread_db/pthread/Makefile
Normal file
19
lib/libthread_db/pthread/Makefile
Normal 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>
|
1087
lib/libthread_db/pthread/pthread_db.c
Normal file
1087
lib/libthread_db/pthread/pthread_db.c
Normal file
File diff suppressed because it is too large
Load Diff
60
lib/libthread_db/pthread/pthread_db.h
Normal file
60
lib/libthread_db/pthread/pthread_db.h
Normal 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
|
105
lib/libthread_db/pthread/pthread_db_i386.c
Normal file
105
lib/libthread_db/pthread/pthread_db_i386.c
Normal 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 ? */
|
||||
}
|
||||
|
15
lib/libthread_db/src/Makefile
Normal file
15
lib/libthread_db/src/Makefile
Normal 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>
|
359
lib/libthread_db/src/thread_db.c
Normal file
359
lib/libthread_db/src/thread_db.c
Normal 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);
|
||||
}
|
Loading…
Reference in New Issue
Block a user