Files
Arquivotheca.Solaris-2.5/lib/libthread_db/common/td_to.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

3158 lines
65 KiB
C
Executable File

/*
*
*ident "@(#)td_to.c 1.73 95/05/25 SMI"
*
* Copyright 1993, 1994 by Sun Microsystems, Inc.
*
*/
/*
* Description:
* This module contains functions for interacting with
* the threads within the program.
*/
#ifdef __STDC__
#pragma weak td_thr_validate = __td_thr_validate /* i386 work around */
#pragma weak td_thr_tsd = __td_thr_tsd /* i386 work around */
#pragma weak td_thr_get_info = __td_thr_get_info
#pragma weak td_thr_sigsetmask = __td_thr_sigsetmask /* i386 work around */
#pragma weak td_thr_setprio = __td_thr_setprio /* i386 work around */
#pragma weak td_thr_setsigpending = __td_thr_setsigpending /* i386work around */
#ifdef PHASE2
#pragma weak td_thr_lockowner
#pragma weak td_thr_sleepinfo
#pragma weak td_thr_dbsuspend
#pragma weak td_thr_dbresume
#endif /* END PHASE2 */
#pragma weak td_ta_map_id2thr = __td_ta_map_id2thr
#pragma weak td_thr_getfpregs = __td_thr_getfpregs /* i386 work around */
#pragma weak td_thr_setfpregs = __td_thr_setfpregs /* i386 work around */
#define V8PLUS_SUPPORT
#pragma weak td_thr_getxregsize = __td_thr_getxregsize /* i386 work around */
#pragma weak td_thr_setxregs = __td_thr_setxregs /* i386 work around */
#pragma weak td_thr_getxregs = __td_thr_getxregs /* i386 work around */
#endif /* __STDC__ */
#include <thread_db.h>
#include "thread_db2.h"
#include "td.h"
#include "td_to_impl.h"
#include "xtd_to.h"
#include "td.extdcl.h"
#include "xtd.extdcl.h"
/*
* This structure is used to create a single parameter to pass to
* a function that writes signal information to a thread struct.
*/
struct td_thr_sigsetinfo_param {
uchar_t sigflag;
td_thr_siginfo_t *siginfo_p;
};
typedef struct td_thr_sigsetinfo_param td_thr_sigsetinfo_param_t;
struct td_mapper_param {
thread_t tid;
int found;
td_thrhandle_t th;
};
typedef struct td_mapper_param td_mapper_param_t;
static td_err_e
td_read_thread_tsd(const td_thrhandle_t *th_p, tsd_t *thr_tsd_p,
struct tsd_common * tsd_common_p, void **tsd_array_ptr);
static td_terr_e
td_thr2to_const(td_thragent_t *ta_p, paddr_t ts_addr,
uthread_t * thr_struct_p, td_thrinfo_t *ti_p);
static td_terr_e
td_thr2to_var(uthread_t * thr_struct_p, td_thrinfo_t *ti_p);
static td_terr_e
td_thr2to(td_thragent_t *ta_p, paddr_t ts_addr, uthread_t * thr_struct_p,
td_thrinfo_t *ti_p);
static td_err_e
td_thr_get_const_info(const td_thrhandle_t *th_p, td_thrinfo_t *ti_p);
static td_err_e
td_thr_get_var_info(const td_thrhandle_t *th_p, td_thrinfo_t *ti_p);
static td_terr_e
__td_thr_struct_set(const td_thrhandle_t *th_p, td_set_func_t set_func,
void *set_func_data);
static td_terr_e
td_thr_struct_sigsetmask(uthread_t * thr_struct_p, void *ti_sigmask_p);
static td_terr_e
td_thr_struct_setprio(uthread_t * thr_struct_p, void *prio_p);
static int
td_searcher(const td_thrhandle_t *th_p, void *data);
static int
td_mapper_id2thr(const td_thrhandle_t *th_p, td_mapper_param_t *data);
static void
td_ucontext_dump(const ucontext_t * uc_p);
static void
td_siginfo_dump(const siginfo_t * sig_p);
/* Macros used in calls that would otherwise be > 80 characters. */
#define TDT_M1 "malloc() failed - td_read_thread_tsd"
#define TDT_M2 "Writing FP information: td_thr_getfpregs"
static td_err_e
/*
* Description: Read thread specific data information.
*
* Input:
* *th_p - thread handle
*
* Output:
* *thr_tsd_p - tsd count and address of array of tsd keys
* *tsd_common - common tsd information
* **tsd_array_ptr - array of tsd values(pointers)
* td_read_thread_tsd - return value
*
* Side effects:
* Space is allocated for *tsd_array_ptr and should
* be released by caller.
*
* Notes:
* Though "thr_tsd_p" seemingly contains "tsd_array_ptr"
* both are provided separately because "thr_tsd_p" only
* contains a pointer to an address in the target process.
* "tsd_array_ptr" contains the actual array.
* In libthread, tsd_thread may be #define'ed to
* a reference to "t_tls" in the current threads thread struct.
*/
td_read_thread_tsd(const td_thrhandle_t *th_p, tsd_t *thr_tsd_p,
struct tsd_common * tsd_common_p, void **tsd_array_ptr)
{
td_err_e return_val = TD_OK;
ps_err_e db_return;
td_terr_e td_return;
paddr_t key_array_addr;
int tsd_size;
uthread_t thr_struct;
struct ps_prochandle *ph_p;
td_thragent_t *ta_p;
ta_p = th_p->th_ta_p;
ph_p = ta_p->ph_p;
/*
* Extract the thread struct address from the thread handle and read
* the thread struct.
*/
#ifdef TLS
/*
* I have not covered this option because I don't know that it really
* is an option. But if it is, this will not compile.
*/
? ? ? ? ? ? ? ? ? ?
#endif
td_return =
__td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique, &thr_struct);
if (td_return == TD_TOK) {
/*
* tsd_thread holds the TSD count and a pointer array to TSD
* data for a thread. tsd_common holds information about
* number of keys used.
*/
*tsd_array_ptr = NULL;
*tsd_common_p = NULL_TSD_COMMON;
*thr_tsd_p = NULL_TSD_T;
/*
* The pointer to thread tsd is in t_tls field of a thread
* struct. If t_tls is NIL, there is no thread specific data
* for this thread.
*/
if (thr_struct.t_tls) {
db_return = ps_pdread(ph_p,
(paddr_t) thr_struct.t_tls,
(char *) thr_tsd_p, sizeof (*thr_tsd_p));
if (db_return == PS_OK) {
key_array_addr = (paddr_t)
thr_tsd_p->array;
/*
* If "key_array_addr" is NULL, then nothing
* has been allocated for this thread.
*/
if (key_array_addr) {
/*
* Allocate storage to hold TSD array
* for this this thread only and read
* TSD array.
*/
tsd_size = sizeof (void *)
* thr_tsd_p->count;
*tsd_array_ptr =
(void *) malloc(tsd_size);
if (*tsd_array_ptr) {
/*
* Calculate the address of
* the array of values for
* this thread.
*/
db_return =
ps_pdread(ph_p,
key_array_addr,
*tsd_array_ptr,
tsd_size);
if (db_return == PS_OK) {
/*
* Get tsd_common to
* check number of
* keys used.
*/
return_val =
__td_dread_process(
th_p->th_ta_p,
TD_TSD_COMMON_NAME,
tsd_common_p,
sizeof (tsd_common))
;
} else {
free(*tsd_array_ptr);
return_val = TD_ERR;
}
} else {
return_val = TD_ERR;
__td_report_to_err(TD_TERR,
TDT_M1);
}
} else {
return_val = TD_NOTSD;
}
} else {
return_val = TD_DBERR;
}
} else {
return_val = TD_NOTSD;
}
} else {
return_val = TD_ERR;
}
return (return_val);
}
/*
* Description:
* Check the struct thread address in *th_p again first
* value in "data". If value in data is found, set second value
* in "data" to TRUE and return 1 to terminate iterations.
* This function is used by td_thr_validate() to verify that
* a thread handle is valid.
*
* Input:
* *th_p - thread handle
* data[0] - struct thread address being sought
* flag indicating struct thread address found
*
* Output:
* td_searcher - returns 1 if thread struct address found
* data[1] - flag indicating struct thread address found
*
* Side effects:
*/
static int
td_searcher(const td_thrhandle_t *th_p, void *data)
{
int return_val = 0;
if (((int *) data)[0] == th_p->th_unique) {
((int *) data)[1] = TRUE;
return_val = 1;
}
return (return_val);
}
/*
* Description:
* Validate the thread handle. Check that
* a thread exists in the thread agent/process that
* corresponds to thread with handle *th_p.
*
* Input:
* *th_p - thread handle
*
* Output:
* td_thr_validate - return value
* return value == TD_OK implies thread handle is valid
* return value == TD_NOTHR implies thread handle not valid
* return value == other implies error
*
* Side effects:
* none
* Imported functions called:
* ps_pdread, ps_pstop, ps_pcontinue.
*
*/
td_err_e
__td_thr_validate(const td_thrhandle_t *th_p)
{
td_err_e return_val;
int searcher_data[] = {0, FALSE};
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pdread(0, 0, 0, 0);
(void) ps_pcontinue(0);
return (TD_OK);
}
#endif
/*
* check for valid thread handle pointer
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
/*
* Check for valid thread handle - check for NULLs
*/
if ((th_p->th_unique == NULL) || (th_p->th_ta_p == NULL)) {
return_val = TD_BADTH;
return (return_val);
}
/*
* LOCKING EXCEPTION - Locking is not required
* here because no use of the thread agent is made (other
* than the sanity check) and checking of the thread
* agent will be
* done in __td_ta_thr_iter. If __td_ta_thr_iter
* is not used or if some use of the thread agent
* is made other than the sanity checks, ADD
* locking.
*/
/*
* Use thread iterator.
*/
searcher_data[0] = th_p->th_unique;
return_val = __td_ta_thr_iter(th_p->th_ta_p,
td_searcher, &searcher_data,
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
if (return_val != TD_OK) {
__td_report_po_err(return_val,
"Iterator failed in td_thr_validate()");
} else {
if (searcher_data[1] == TRUE) {
return_val = TD_OK;
} else {
return_val = TD_NOTHR;
}
}
return (return_val);
}
/*
* Description:
* Get a thread's private binding to a given thread specific
* data(TSD) key(see thr_getspecific(3T). If the thread doesn't
* have a binding for a particular key, then NULL is returned.
*
* Input:
* *th_p - thread handle
* key - TSD key
*
* Output:
* data_pp - key value for given thread. This value
* is typically a pointer. It is NIL if
* there is no TSD data for this thread.
* td_thr_tsd - return value
*
* Side effects:
* none
* Imported functions called: ps_pglobal_lookup,
* ps_pdread, ps_pstop, ps_pcontinue.
*/
td_err_e
__td_thr_tsd(const td_thrhandle_t *th_p, const thread_key_t key,
void **data_pp)
{
tsd_t tsd_thread = NULL_TSD_T;
struct tsd_common tsd_common = NULL_TSD_COMMON;
td_err_e return_val = TD_OK;
void *tsd_array_ptr = 0;
/*
* I followed the code for libthread thr_getspecific().
*/
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pglobal_lookup(0, 0, 0, 0);
(void) ps_pdread(0, 0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
return (return_val);
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* tsd_thread holds the TSD count and an array of pointers to TSD
* data. tsd_common holds information about number of keys used.
*/
if (key == 0) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return (TD_BADKEY);
} else {
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Read struct containing TSD count and pointer to
* storage.
*/
return_val = td_read_thread_tsd(th_p,
&tsd_thread, &tsd_common, &tsd_array_ptr);
if (return_val == TD_OK) {
/*
* If key is greater than TSD count but less
* than TSD nkeys, then request is valid but
* there is no data. If key is greater than
* TSD nkeys, then the request is invalid.
*/
if (key > tsd_thread.count) {
if (key > tsd_common.nkeys) {
return_val = TD_BADKEY;
__td_report_po_err(return_val,
"TSD common - td_thr_tsd");
} else {
/*
* There is no TSD for this
* thread.
*/
*data_pp = 0;
}
} else {
/*
* Extract the TSD for this thread
* from the array of TSD(.i.e.,
* data[key-1])
*/
*data_pp = (void *) ((paddr_t *)
tsd_array_ptr)[key - 1];
}
} else if (return_val == TD_NOTSD) {
*data_pp = 0;
} else {
*data_pp = 0;
return_val = TD_ERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
} /* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
} /* key valid */
if (tsd_array_ptr) {
(void) free(tsd_array_ptr);
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
/*
* Description:
* Write the value of a variable.
*
* Input:
* *ta_p - thread agent
* *symbol_name - name of symbol to be read
* buffer - location to holding contents of symbol
* size - size of symbol
*
* Output:
* __td_dwrite_process - return value
*
* Side effects:
*/
td_err_e
__td_dwrite_process(const td_thragent_t *ta_p, char *symbol_name, void *buffer,
int size)
{
char error_msg[TD_MAX_BUFFER_SIZE];
paddr_t symbol_addr;
td_err_e return_val;
ps_err_e db_return;
struct ps_prochandle *ph_p;
/*
* Get address of symbol out of libthread.so
*/
ph_p = ta_p->ph_p;
db_return = ps_pglobal_lookup(ph_p, TD_LIBTHREAD_NAME,
symbol_name, (paddr_t *) & symbol_addr);
if (db_return == PS_OK) {
/*
* Write process
*/
db_return = ps_pdwrite(ph_p, symbol_addr,
(char *) buffer, size);
if (db_return != PS_OK) {
strcpy(error_msg, "__td_dwrite_process - ");
strcpy(&error_msg[strlen(error_msg)], symbol_name);
__td_report_db_err(db_return, error_msg);
return_val = TD_DBERR;
} else {
return_val = (TD_OK);
}
} else {
return_val = TD_DBERR;
__td_report_po_err(return_val,
"Symbol lookup failed - __td_dwrite_process");
}
return (return_val);
}
/*
* Description:
* Read the value of a variable.
*
* Input:
* *ta_p - thread agent
* *symbol_name - name of symbol to be read
* buffer - location to hold contents of symbol
* size - size of symbol
*
* Output:
* buffer - value of symbol
* __td_dread_process - return value
*
* Side effects:
*/
td_err_e
__td_dread_process(const td_thragent_t *ta_p, char *symbol_name, void *buffer,
int size)
{
char error_msg[TD_MAX_BUFFER_SIZE];
paddr_t symbol_addr;
td_err_e return_val;
ps_err_e db_return;
struct ps_prochandle *ph_p;
ph_p = ta_p->ph_p;
/*
* Get address of symbol out of libthread.so
*/
db_return = ps_pglobal_lookup(ph_p, TD_LIBTHREAD_NAME,
symbol_name, (paddr_t *) & symbol_addr);
if (db_return == PS_OK) {
/*
* Read process
*/
db_return = ps_pdread(ph_p, symbol_addr, (char *) buffer, size);
if (db_return != PS_OK) {
strcpy(error_msg, "__td_dread_process - ");
strcpy(&error_msg[strlen(error_msg)], symbol_name);
__td_report_db_err(db_return, error_msg);
return_val = TD_DBERR;
} else {
return_val = TD_OK;
}
} else {
return_val = TD_DBERR;
__td_report_po_err(return_val,
"Symbol lookup failed - __td_dread_process");
}
return (return_val);
}
/*
* Description:
* Write a thread structure.
*
* Input:
* *ta_p - thread agent
* thr_addr - address of thread structure in *td_thragent_t
* *thr_struct_p - thread struct
*
* Output:
* __td_write_thr_struct - return value
*
* Side effects:
* Process is written
*/
td_terr_e
__td_write_thr_struct(td_thragent_t *ta_p,
paddr_t thr_addr, uthread_t * thr_struct_p)
{
td_terr_e return_val = TD_TOK;
struct ps_prochandle *ph_p;
ph_p = ta_p->ph_p;
if (return_val == TD_TOK) {
if (ps_pdwrite(ph_p, thr_addr, (char *) thr_struct_p,
sizeof (*thr_struct_p)) != PS_OK) {
return_val = TD_TDBERR;
__td_report_to_err(TD_TDBERR,
"Writing thread struct: __td_write_thr_struct");
}
}
return (return_val);
}
/*
* Description:
* Read a thread structure.
*
* Input:
* *ta_p - thread agent
* thr_addr - address of thread structure in *ta_p
*
* Output:
* *thr_struct_p - thread struct
*
* Side effects:
* Process is read
*/
td_terr_e
__td_read_thr_struct(const td_thragent_t *ta_p, paddr_t thr_addr,
uthread_t * thr_struct_p)
{
td_terr_e return_val = TD_TOK;
struct ps_prochandle *ph_p;
/*
* Extract the process handle and read the process.
*/
ph_p = ta_p->ph_p;
if (ps_pdread(ph_p, thr_addr, (char *) thr_struct_p,
sizeof (*thr_struct_p)) != PS_OK) {
return_val = TD_TDBERR;
__td_report_to_err(TD_TDBERR,
"Reading thread struct: __td_read_thr_struct");
}
return (return_val);
}
/*
* Description:
* Map state from threads struct to thread information states
*
* Input:
* ts_state - thread struct state
*
* Output:
* *to_state - thread information state
*
* Side effects:
* none
*/
td_terr_e
__td_thr_map_state(thstate_t ts_state, td_thr_state_e *to_state)
{
td_terr_e return_val = TD_TOK;
switch (ts_state) {
case TS_SLEEP:
*to_state = TD_THR_SLEEP;
break;
case TS_RUN:
*to_state = TD_THR_RUN;
break;
case TS_DISP:
*to_state = TD_THR_ACTIVE;
break;
case TS_ONPROC:
*to_state = TD_THR_ACTIVE;
break;
case TS_STOPPED:
*to_state = TD_THR_STOPPED;
break;
case TS_ZOMB:
*to_state = TD_THR_ZOMBIE;
break;
#ifdef NEW_LIBTHREAD_SUPPORT
case TS_STOPPED_ASLEEP:
*to_state = TD_THR_STOPPED_ASLEEP;
break;
#endif
default:
__td_report_to_err(TD_TSTATE,
"Unknown state from thread struct: td_thr_map_state");
return_val = TD_TSTATE;
}
return (return_val);
}
/*
* Description:
* Transfer constant information from thread struct to
* thread information struct.
*
* Input:
* *ta_p - thread agent
* ts_addr - address of thread struct
* *thr_struct_p - libthread thread struct
*
* Output:
* *ti_p - thread information struct
*
* Side effects:
* none
*/
static td_terr_e
td_thr2to_const(td_thragent_t *ta_p, paddr_t ts_addr,
uthread_t * thr_struct_p, td_thrinfo_t *ti_p)
{
td_terr_e return_val = TD_TOK;
/*
* Set td_to_ph_p_(*ti_p)
*/
ti_p->ti_ta_p = ta_p;
ti_p->ti_user_flags = thr_struct_p->t_usropts;
ti_p->ti_tid = thr_struct_p->t_tid;
ti_p->ti_tls = thr_struct_p->t_tls;
ti_p->ti_startfunc = thr_struct_p->t_startpc;
ti_p->ti_stkbase = (paddr_t) thr_struct_p->t_stk;
ti_p->ti_stksize = thr_struct_p->t_stksize;
ti_p->ti_flags = thr_struct_p->t_flag;
ti_p->ti_ro_area = ts_addr;
ti_p->ti_ro_size = sizeof (uthread_t);
return (return_val);
}
/*
* Description:
* Transfer variable information from thread struct to
* thread information struct.
*
* Input:
* *thr_struct_p - libthread thread struct
*
* Output:
* *ti_p - thread information struct variable part
*
* Side effects:
* none
*
* Assumptions:
* Fields not set:
* to_db_suspended, to_events, to_traceme
*/
static td_terr_e
td_thr2to_var(uthread_t * thr_struct_p, td_thrinfo_t *ti_p)
{
td_terr_e return_val = TD_TOK;
td_thr_state_e state;
return_val = __td_thr_map_state(thr_struct_p->t_state, &state);
ti_p->ti_state = state;
/*
* td_to_db_suspended_( *ti_p ) always set to NULL.
*/
ti_p->ti_db_suspended = 0;
ti_p->ti_type = TD_CONVERT_TYPE(*thr_struct_p);
ti_p->ti_pc = thr_struct_p->t_pc;
ti_p->ti_sp = thr_struct_p->t_sp;
ti_p->ti_pri = thr_struct_p->t_pri;
/*
* Non-Null lwp id is not always provided. See notes in
* td_thr_get_var_info() header.
*/
if (ISVALIDLWP(thr_struct_p)) {
ti_p->ti_lid = thr_struct_p->t_lwpid;
} else {
ti_p->ti_lid = 0;
}
ti_p->ti_sigmask = thr_struct_p->t_hold;
/*
* td_to_events_( *ti_p ) always set to NULL.
* td_to_traceme_( *ti_p ) always set to NULL
*/
ti_p->ti_traceme = 0;
eventemptyset(&(ti_p->ti_events));
ti_p->ti_preemptflag = thr_struct_p->t_preempt;
#ifdef PHASE2
/*
* Set the priority inversion flag in the thread information struct
* from the thread struct.
*/
#else
memset(&(ti_p->ti_pirecflag), 0,
sizeof (ti_p->ti_pirecflag));
#endif
/*
* Set pending signal bits only if t_pending is set.
*/
if (thr_struct_p->t_pending) {
ti_p->ti_pending = thr_struct_p->t_psig;
} else {
sigemptyset(&(ti_p->ti_pending));
}
return (return_val);
}
/*
* Description:
* Transfer information from thread struct to thread information struct.
*
* Input:
* *ta_p - thread agent
* ts_addr - address of thread struct
* *thr_struct_p - libthread thread struct
*
* Output:
* *ti_p - thread information struct
*
* Side effects:
* none
*/
static td_terr_e
td_thr2to(td_thragent_t *ta_p, paddr_t ts_addr,
uthread_t * thr_struct_p, td_thrinfo_t *ti_p)
{
td_terr_e return_val = TD_TOK;
return_val = td_thr2to_const(ta_p, ts_addr,
thr_struct_p, ti_p);
if (return_val == TD_TOK) {
return_val = td_thr2to_var(thr_struct_p, ti_p);
}
return (return_val);
}
/*
* Description:
* Read the threads hash table for the debug process.
*
* Input:
* *ta_p - thread agent
*
* Output:
* *tab_p[] - hash table
*
* Side effects:
* Debug process is read.
*/
td_err_e
__td_read_thread_hash_tbl(const td_thragent_t *ta_p, thrtab_t * tab_p,
int tab_size)
{
td_err_e return_val;
ps_err_e db_return;
char error_msg[TD_MAX_BUFFER_SIZE];
paddr_t symbol_addr;
symbol_addr = ta_p->hash_tab_addr;
db_return = ps_pdread(ta_p->ph_p, symbol_addr,
(char *) tab_p, tab_size);
if (db_return != PS_OK) {
strcpy(error_msg, "__td_read_thread_hash_tbl - ");
strcpy(&error_msg[strlen(error_msg)], TD_HASH_TAB_NAME);
__td_report_db_err(db_return, error_msg);
return_val = TD_DBERR;
} else {
return_val = TD_OK;
}
return (return_val);
}
/*
* Description:
* Update the constant part of
* thread information struct. Constant fields in
* a thread information struct will be updated to be
* consistent with properties of its respective
* thread.
*
* Input:
* *th_p - thread handle with valid ti_tid and ti_ta_p fields
*
* Output: *ti_p - updated thread information struct
* td_thr_get_const_info - return value
*
* Side effects:
* none
*/
static td_err_e
td_thr_get_const_info(const td_thrhandle_t *th_p,
td_thrinfo_t *ti_p)
{
uthread_t thr_struct;
td_err_e return_val = TD_ERR;
td_terr_e td_return = TD_TERR;
/*
* Extract the thread struct address from the thread handle and read
* the thread struct. Transfer the thread struct to
* the thread information
* struct. Check that the thread id is correct.
*/
td_return = __td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique, &thr_struct);
if (td_return == TD_TOK) {
td_return = td_thr2to_const(th_p->th_ta_p,
th_p->th_unique, &thr_struct, ti_p);
if (td_return == TD_TOK) {
return_val = TD_OK;
} else {
return_val = TD_ERR;
}
}
return (return_val);
}
/*
* Description:
* Update the variable part of
* thread information struct. Variable fields in
* a thread information struct will be updated to be
* consistent with properties of its respective
* thread.
*
* Input:
* *th_p - thread handle with valid ti_tid and ti_ta_p fields
*
* Output:
* *ti_p - updated thread information struct
* td_thr_get_var_info - return value
*
* Side effects:
* none
*
* Notes:
* The lwp id field of a thread information struct is update to
* an non-Null value only if the thread is active on an lwp,
* bound to an lwp, or parked on an lwp.
*/
static td_err_e
td_thr_get_var_info(const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
{
uthread_t thr_struct;
td_err_e return_val = TD_ERR;
td_terr_e td_return = TD_TERR;
/*
* Extract the thread struct address from the thread handle and read
* the thread struct. Transfer the thread struct to
* the thread information
* struct. Check that the thread id is correct.
*/
td_return = __td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique, &thr_struct);
if (td_return == TD_TOK) {
td_return = td_thr2to_var(&thr_struct, ti_p);
if (td_return == TD_TOK) {
return_val = TD_OK;
} else {
return_val = TD_ERR;
}
}
return (return_val);
}
/*
* Description:
* Update the thread information struct. All fields in a thread
* information structure(td_thrinfo_t) will be updated to be
* consistent with properties of its respective thread.
*
* Input:
* *th_p - thread handle
*
* Output:
* *ti_p - updated thread information structure
* td_thr_get_info - return value
*
* Side effects:
* none
* Imported functions called: ps_pdread, ps_pstop,
* ps_pcontinue.
*
*/
td_err_e
__td_thr_get_info(const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
{
uthread_t thr_struct;
td_err_e return_val = TD_ERR;
td_terr_e td_return = TD_TERR;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdread(0, 0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
if (ti_p == NULL) {
return_val = TD_ERR;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
return (return_val);
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* Null out the thread information struct.
*/
memset(ti_p, NULL, sizeof (*ti_p));
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Extract the thread struct address from the
* thread handle and read the thread struct.
* Transfer the thread struct to
* the thread information struct. Check that
* the thread id is correct.
*/
td_return = __td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique,
&thr_struct);
if (td_return == TD_TOK) {
td_return = td_thr2to(th_p->th_ta_p,
th_p->th_unique, &thr_struct, ti_p);
if (td_return == TD_TOK) {
return_val = TD_OK;
} else {
return_val = TD_ERR;
}
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
/* ps_pstop succeeded */
} else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
/*
* Description:
* Get the floating point registers for the given thread.
* The floating registers are only available for a thread executing
* on and LWP. If the thread is not running on an LWP, this
* function will return TD_NOFPREGS.
*
* Input:
* *th_p - thread handle for which fp registers are
* being requested
*
* Output:
* *fpregset - floating point register values(see sys/procfs.h)
* td_thr_getfpregs - return value
*
* Side effects:
* none
* Imported functions called:
*/
td_err_e
__td_thr_getfpregs(const td_thrhandle_t *th_p, prfpregset_t * fpregset)
{
td_err_e return_val = TD_OK;
td_terr_e td_return;
uthread_t thr_struct;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdread(0, 0, 0, 0);
ps_lgetfpregs(0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
if (fpregset == NULL) {
return_val = TD_DBERR;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Extract the thread struct address from
* the thread handle and read
* the thread struct.
*/
td_return = __td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique, &thr_struct);
if (td_return == TD_TOK) {
if (ISVALIDLWP(&thr_struct) &&
HASVALIDFP(&thr_struct)) {
/*
* Read the floating point registers
* using the imported interface.
*/
if (ps_lgetfpregs(th_p->th_ta_p->ph_p,
thr_struct.t_lwpid, fpregset) ==
PS_ERR) {
return_val = TD_DBERR;
}
} else {
/*
* fp registers not available in thread struct.
*/
return_val = TD_NOFPREGS;
}
} else {
return_val = TD_ERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
/*
* Description:
* Get the size of the extra register set for the given thread.
* The extra registers are only available for a thread executing
* on and LWP. If the thread is not running on an LWP, this
* function will return TD_NOXREGS.
*
* Input:
* *th_p - thread handle for which the extra register set size
* is being requested.
*
* Output:
* *xregsize - size of the extra register set.
* td_thr_getxregsize - return value.
*
* Side Effect:
* none
* Imported functions called:
*/
td_err_e
__td_thr_getxregsize(const td_thrhandle_t *th_p, int *xregsize)
{
td_err_e return_val = TD_OK;
td_terr_e td_return;
uthread_t thr_struct;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdread(0, 0, 0, 0);
(void) ps_pdwrite(0, 0, 0, 0);
(void) ps_lgetxregsize(0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
if (xregsize == NULL) {
return_val = TD_ERR;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Extract the thread struct address
* from the thread handle and read
* the thread struct.
*/
td_return = __td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique, &thr_struct);
if (td_return == TD_TOK) {
/*
* Read the extra registers using the imported
* interface.
*/
if (ISVALIDLWP(&thr_struct)) {
if (ps_lgetxregsize(th_p->th_ta_p->ph_p,
thr_struct.t_lwpid, xregsize) ==
PS_ERR) {
return_val = TD_DBERR;
}
if (!HASVALIDFP(&thr_struct)) {
return_val = TD_NOFPREGS;
}
} else {
return_val = TD_NOFPREGS;
}
} else {
return_val = TD_ERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
/*
* Description:
* Get the extra registers for the given thread. Extra register can
* only be gotten for a thread executing on an LWP. This
* operation will return TD_NOFPREGS
* for thread not on an LWP.
*
* Input:
* *th_p - thread handle for thread on which extra registers
* are being requested.
*
* Output:
* *xregset - extra register set, see sys/procfs.h.
* td_thr_getxregs - return value
*
* Side Effect:
* None
* Imported function called: ps_pstop, ps_pcontinue, ps_pdread,
* ps_pdwrite, ps_lgetxregs.
*/
td_err_e
__td_thr_getxregs(const td_thrhandle_t *th_p, const caddr_t xregset)
{
td_err_e return_val = TD_OK;
td_terr_e td_return;
uthread_t thr_struct;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdread(0, 0, 0, 0);
(void) ps_pdwrite(0, 0, 0, 0);
(void) ps_lgetxregs(0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
if (xregset == NULL) {
return (TD_ERR);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Extract the thread struct address
* from the thread handle and read
* the thread struct.
*/
td_return = __td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique, &thr_struct);
if (td_return == TD_TOK) {
/*
* Read the x registers using the imported
* interface.
*/
if (ISVALIDLWP(&thr_struct)) {
if (ps_lgetxregs(th_p->th_ta_p->ph_p,
thr_struct.t_lwpid, xregset)
== PS_ERR) {
return_val = TD_DBERR;
}
if (!HASVALIDFP(&thr_struct)) {
/*
* Let user know floating pointer
* registers are not available.
*/
return_val = TD_NOFPREGS;
}
} else {
return_val = TD_NOXREGS;
}
} else {
return_val = TD_ERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
#ifdef PHASE2
/*
* Description:
* If a thread is in the SLEEP state, its ti_p->ti_state ==
* TD_THR_SLEEP, then get the synchronization handle of the
* synchronization variable that this thread is asleep on.
*
* Input:
* *th_p - thread handle
*
* Output:
* *sh_p - synchronization handle on which thread is asleep
* if thread in SLEEP state, NULL otherwise.
* td_thr_sleepinfo - return value
*
* Side effects:
* none
* Imported functions called: ps_pdread, ps_pstop,
* ps_pcontinue, ps_pglobal_lookup, ps_pdwrite.
*
*
*/
td_err_e
td_thr_sleepinfo(const td_thrhandle_t *th_p, td_synchandle_t *sh_p)
{
td_err_e return_val = TD_NOT_DONE;
/*
* not currently supported by libthread
*/
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
if (return_val != TD_NOT_DONE) {
(void) ps_pglobal_lookup(0, 0, 0, 0);
(void) ps_pdread(0, 0, 0, 0);
(void) ps_pdwrite(0, 0, 0, 0);
}
return (TD_OK);
}
#endif
if (__td_pub_debug)
diag_print(
"libthread_db: td_thr_sleepinfo() not fully implemented\n");
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Set to avoid lint warning.
*/
sh_p->sh_ta_p = 0;
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (TD_NOT_DONE);
}
/*
* Description:
* Iterate over the set of locks owned by a specified thread.
* If cb returns a non-zero value, terminate iterations.
*
* Input:
* *th_p - thread handle
* *cb - function to be called on each lock owned by thread.
* cb_data_p - pointer passed to td_sync_iter_f()
*
* Output:
* td_thr_lockowner - return value
*
* Side effects:
* *cb is called on each lock owned by thread.
* Imported functions called: ps_pdread, ps_pstop,
* ps_pcontinue, ps_pglobal_lookup, ps_pdwrite.
*/
td_err_e
td_thr_lockowner(const td_thrhandle_t *th_p,
td_sync_iter_f * cb, void *cb_data_p)
{
td_err_e return_val = TD_NOT_DONE;
/*
* not currently supported by libthread
*/
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
if (return_val != TD_NOT_DONE) {
(void) ps_pglobal_lookup(0, 0, 0, 0);
(void) ps_pdread(0, 0, 0, 0);
}
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (TD_NOT_DONE);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (TD_NOT_DONE);
}
if (__td_pub_debug) diag_print(
"libthread_db: td_thr_lockowner() not fully implemented\n");
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* This is just to fix lint warning.
*/
{
const td_synchandle_t *sh_p = 0;
if (((int) sh_p) != 0) {
cb(sh_p, cb_data_p);
}
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (TD_NOT_DONE);
}
#endif /* END PHASE2 */
/*
*
* Description:
* Read a thead structure, change a field in the
* thread structure by calling a provided function, and
* write back the thread structure.
*
* Input:
* *th_p - thread handle
* set_func - function to call to set field in thread struct
* set_func_data - data for set_func
*
* Output:
* __td_thr_struct_set - return value
*
* Side effects:
* Thread structure corresponding to *th_p is changed
*/
static td_terr_e
__td_thr_struct_set(const td_thrhandle_t *th_p,
td_set_func_t set_func, void *set_func_data)
{
paddr_t ts_addr;
uthread_t thread_struct;
struct ps_prochandle *ph_p;
td_terr_e return_val = TD_TOK;
/*
* Read the thread struct, reset the signal mask, and write back the
* thread struct.
*/
ts_addr = th_p->th_unique;
ph_p = th_p->th_ta_p->ph_p;
if (ps_pdread(ph_p, ts_addr, (char *) &thread_struct,
sizeof (thread_struct)) != PS_OK) {
return_val = TD_TDBERR;
__td_report_to_err(return_val,
"Thread struct read - td_thr_sigsetmask");
} else {
return_val = (set_func) (&thread_struct, set_func_data);
if (return_val == TD_TOK) {
if (ps_pdwrite(ph_p, ts_addr, (char *) &thread_struct,
sizeof (thread_struct)) != PS_OK) {
return_val = TD_TDBERR;
__td_report_to_err(return_val,
"Thread struct write - td_thr_sigsetmask");
}
}
}
return (return_val);
}
/*
* Description:
* Set the signal mask in the thread struct.
*
* Input:
* *thr_struct_p - thread struct
* sigmask - signal mask
*
* Output:
* td_thr_struct_sigsetmask - return value
*
* Side effects:
* none
*/
static td_terr_e
td_thr_struct_sigsetmask(uthread_t * thr_struct_p, void *ti_sigmask_p)
{
thr_struct_p->t_hold = *((sigset_t *) ti_sigmask_p);
return (TD_TOK);
}
/*
* Description:
* Change a thread's signal mask to the value specified by
* ti_sigmask.
*
* Input:
* *th_p - thread handle
* ti_sigmask - new value of signal mask
*
* Output:
* td_thr_sigsetmask - return value
*
* Side effects:
* Thread corresponding to *th_p is assigned new signal mask.
* Imported functions called: ps_pstop,
* ps_pcontinue, ps_pdwrite.
*/
td_err_e
__td_thr_sigsetmask(const td_thrhandle_t *th_p, const sigset_t ti_sigmask)
{
td_err_e return_val = TD_OK;
uthread_t *ts_p;
paddr_t sigmask_addr;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdwrite(0, 0, 0, 0);
return (return_val);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is being written. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Write the sigmask into the thread struct.
*/
ts_p = (uthread_t *) th_p->th_unique;
sigmask_addr = (paddr_t) & (ts_p->t_hold);
if (ps_pdwrite(th_p->th_ta_p->ph_p, sigmask_addr,
(char *) &ti_sigmask, sizeof (ti_sigmask)) != PS_OK) {
return_val = TD_DBERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
/*
* Description:
* Set the thread priority in the thread struct.
*
* Input:
* *thr_struct_p - thread struct
* *prio_p - new thread priority
*
* Output:
* td_thr_struct_setprio - return value
*
* Side effects:
* none
*/
static td_terr_e
td_thr_struct_setprio(uthread_t * thr_struct_p, void *prio_p)
{
thr_struct_p->t_pri = *((int *) prio_p);
return (TD_TOK);
}
/*
* Description:
* Change a thread's priority to the value specified by ti_pri.
*
* Input:
* *th_p - thread handle
* ti_pri - new value of thread priority >= 0(see thr_setprio(3T))
*
* Output:
* td_thr_setprio - return value
*
* Side effects:
* Thread corresponding to *th_p is assigned new priority.
* Imported functions called: ps_pdwrite.
*
*/
td_err_e
__td_thr_setprio(const td_thrhandle_t *th_p, const int ti_pri)
{
uthread_t *ts_p;
paddr_t pri_addr;
td_err_e return_val = TD_OK;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pdwrite(0, 0, 0, 0);
return (return_val);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* Set the priority in the thread struct.
*/
/*
* Only setting 1 byte. Don't stop process.
*/
if ((ti_pri >= THREAD_MIN_PRIORITY) &&
(ti_pri <= THREAD_MAX_PRIORITY)) {
ts_p = (uthread_t *) th_p->th_unique;
pri_addr = (paddr_t) & ts_p->t_pri;
if (ps_pdwrite(th_p->th_ta_p->ph_p, pri_addr,
(char *) &ti_pri, sizeof (ti_pri)) != PS_OK) {
return_val = TD_DBERR;
}
} else {
return_val = TD_ERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
/*
* Description:
* Change the pending signal flag and pending signals
*
* Input:
* *th_p - thread handle
* ti_pending_flag - flag that indicates that there are
* pending signals in the thread. If this value is not
* set, the pending signal mask is ignored.
* ti_pending - new pending signal information.
*
* Output:
* td_thr_setsigpending - return value
*
* Side effects:
* Thread corresponding to *th_p has pending signal
* information changed.
* Imported functions called: ps_pstop,
* ps_pcontinue, ps_pdwrite.
*/
td_err_e
__td_thr_setsigpending(const td_thrhandle_t *th_p,
const uchar_t ti_pending_flag, const sigset_t ti_pending)
{
/*
* Only the pending signal flag and pending signal mask are set in
* the thread struct.
*/
td_err_e return_val = TD_OK;
td_terr_e td_return = TD_TOK;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdwrite(0, 0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is being written. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
uthread_t *thr_struct_p;
/*
* Point a thread struct pointer at the address
* of the thread struct in the debuggee. The
* address of the pending signal information will
* be offset from this thread struct address.
*/
thr_struct_p = (uthread_t *)th_p->th_unique;
/*
* Write t_psig.
*/
if (ps_pdwrite(th_p->th_ta_p->ph_p, (paddr_t)
&(thr_struct_p->t_psig), (char *)&ti_pending,
sizeof (thr_struct_p->t_psig)) != PS_OK) {
return_val = TD_DBERR;
}
/*
* Write t_pending.
*/
if (ps_pdwrite(th_p->th_ta_p->ph_p, (paddr_t)
&(thr_struct_p->t_pending), (char *)&ti_pending_flag,
sizeof (thr_struct_p->t_pending)) != PS_OK) {
return_val = TD_DBERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
/*
* Description:
* Set the floating pointing registers for a given thread.
* The floating registers are only available for a thread executing
* on and LWP. If the thread is not running on an LWP, this
* function will return TD_NOFPREGS.
*
* Input:
* *th_p - thread handle for thread on which fp registers are
* being set.
* *fpregset - floating point register values(see sys/procfs.h)
*
* Output:
* none
*
* Side effects:
* Floating point registers in thread corresponding to *th_p
* are set.
* Imported functions called: ps_pdread,
* ps_pstop, ps_pcontinue, ps_lsetfpregs.
*/
td_err_e
__td_thr_setfpregs(const td_thrhandle_t *th_p, const prfpregset_t * fpregset)
{
td_err_e return_val = TD_OK;
td_terr_e td_return;
uthread_t thr_struct;
fpregset_t ts_fpregset;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdread(0, 0, 0, 0);
(void) ps_lsetfpregs(0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
if (fpregset == NULL) {
return (TD_ERR);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Extract the thread struct address from the
* thread handle and read
* the thread struct.
*/
td_return = __td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique, &thr_struct);
if (td_return == TD_TOK) {
/*
* Read the floating point registers using the imported
* interface.
*/
if (ISVALIDLWP(&thr_struct) &&
HASVALIDFP(&thr_struct)) {
if (ps_lsetfpregs(th_p->th_ta_p->ph_p,
thr_struct.t_lwpid,
fpregset) == PS_ERR) {
return_val = TD_DBERR;
}
} else {
return_val = TD_NOFPREGS;
}
} else {
return_val = TD_ERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
/*
* Description:
* Set the extra registers for the given thread. Extra register can
* only be set on a thread in on an LWP. This operation will return
* TD_NOFPREGS for thread not on and LWP.
*
* Input:
* *th_p - thread handle for thread on which extra registers
* are being set.
* *xregset - extra register set values, see sys / procfs.h.
*
* Output:
* td_thr_setxregs - return value. TD_NOCAPAB will be
* returned if x registers are not available from the
* thread.
*
* Side Effect:
* Extra registers in the thread corresponding to
* *th_p are set.
* Imported functions called: ps_pdread, ps_pdwrite, ps_lsetxregs.
* ps_pstop, ps_pcontinue.
*/
td_err_e
__td_thr_setxregs(const td_thrhandle_t *th_p, const caddr_t xregset)
{
td_err_e return_val = TD_OK;
td_terr_e td_return;
uthread_t thr_struct;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdread(0, 0, 0, 0);
(void) ps_pdwrite(0, 0, 0, 0);
(void) ps_lsetxregs(0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
if (xregset == NULL) {
return (TD_ERR);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* More than 1 byte is geing read. Stop the process.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Extract the thread struct address from
* the thread handle and read
* the thread struct.
*/
td_return =
__td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique,
&thr_struct);
if (td_return == TD_TOK) {
if (ISVALIDLWP(&thr_struct)) {
/*
* Write the x registers
* using the imported interface.
*/
if (ps_lsetxregs(th_p->th_ta_p->ph_p,
thr_struct.t_lwpid,
xregset) == PS_ERR) {
return_val = TD_DBERR;
}
if (!HASVALIDFP(&thr_struct)) {
/*
* Let user now that floating
* point registeres are not
* available.
*/
return_val = TD_NOFPREGS;
}
} else {
return_val = TD_NOXREGS;
}
} else {
return_val = TD_ERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
#if 0
/* This function does the same thing as td_thr_setsiginfo(). */
/*
* Description:
* Send a signal to a thread corresponding to thread handle
* *th_p.
*
* Input:
* *th_p - thread handle
* sig - signal to be sent to thread. (see signal(5) for
* valid sig values.)
*
* Output:
* td_thr_kill - return value
*
* Side effects:
* Threads corresponding to *th_p is sent signal sig
* Imported functions called: ps_pdread, ps_pstop,
* ps_pcontinue, ps_pdwrite.
*/
td_err_e
td_thr_kill(const td_thrhandle_t *th_p, int sig)
{
int kill_return = 0;
td_err_e return_val = TD_OK;
td_terr_e td_return = TD_TERR;
uthread_t thr_struct;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdread(0, 0, 0, 0);
(void) ps_pdwrite(0, 0, 0, 0);
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
/*
* Check range of signal value.
*/
if (sig == NULL) {
return_val = TD_ERR;
return (return_val);
}
if (sig > SIGRTMAX) {
return_val = TD_ERR;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* Have to read pending signals and add signal. Stop to prevent
* change of pending signals before write back.
*/
if (ps_pstop(th_p->th_ta_p->ph_p) == PS_OK) {
/*
* Extract the thread struct address from the thread handle
* and read the thread struct.
*/
td_return = __td_read_thr_struct(th_p->th_ta_p,
th_p->th_unique,
&thr_struct);
if (td_return == TD_TOK) {
/*
* Set the signal as a pending signal in the target
* thread. Set the bit for the signal in the thread
* struct pending signal mask. Note that if there is
* no pending signal, the bits for pending signals
* are cleared.
*/
if (!(thr_struct.t_pending)) {
sigemptyset(&(thr_struct.t_psig));
thr_struct.t_pending = TRUE;
}
sigaddset(&(thr_struct.t_psig), sig);
/*
* Write thread struct back.
*/
td_return = __td_write_thr_struct(th_p->th_ta_p,
th_p->th_unique,
&thr_struct);
if (td_return != TD_TOK) {
return_val = TD_ERR;
}
}
/* read of thread struct succeeded */
else {
return_val = TD_ERR;
}
/*
* Continue process.
*/
if (ps_pcontinue(th_p->th_ta_p->ph_p) != PS_OK) {
return_val = TD_DBERR;
}
}
/* ps_pstop succeeded */
else {
return_val = TD_DBERR;
}
rw_unlock(&(th_p->th_ta_p->rwlock));
return (return_val);
}
#endif
#ifdef TD_INTERNAL_TESTS
/*
* Description:
* Validate the thread information in the
* thread information struct by comparison with original
* threads information.
*
* Input:
* *ti_p - thread information struct
*
* Output:
* __td_ti_validate - return value
*
* Side effects:
* none
*
*/
td_terr_e
__td_ti_validate(const td_thrinfo_t *ti_p)
{
/*
* Compare the contents of the thread information struct to that of the
* threads in this process.
*/
td_terr_e return_val = TD_TOK;
uthread_t *ts_p;
td_thr_state_e mapped_state;
ts_p = (uthread_t *) ti_p->ti_ro_area;
if (ts_p->t_usropts != ti_p->ti_user_flags) {
if (__td_debug)
diag_print("Compare failed: user flags %x %x\n",
ts_p->t_usropts, ti_p->ti_user_flags);
return_val = TD_TBADTH;
}
if (ts_p->t_tid != ti_p->ti_tid) {
if (__td_debug)
diag_print("Compare failed: tid %x %x\n",
ts_p->t_tid, ti_p->ti_tid);
return_val = TD_TBADTH;
}
if (ts_p->t_startpc != ti_p->ti_startfunc) {
if (__td_debug)
diag_print("Compare failed: start func %x %x\n",
ts_p->t_startpc, ti_p->ti_startfunc);
return_val = TD_TBADTH;
}
if (ts_p->t_stk != ti_p->ti_stkbase) {
if (__td_debug)
diag_print("Compare failed: stkbase %x %x\n",
ts_p->t_stk, ti_p->ti_stkbase);
return_val = TD_TBADTH;
}
if (ts_p->t_stksize != ti_p->ti_stksize) {
if (__td_debug)
diag_print("Compare failed: stksize %x %x\n",
ts_p->t_stksize, ti_p->ti_stksize);
return_val = TD_TBADTH;
}
if (ts_p->t_flag != ti_p->ti_flags) {
if (__td_debug)
diag_print("Compare failed: flags %x %x\n",
ts_p->t_flag, ti_p->ti_flags);
return_val = TD_TBADTH;
}
if (__td_thr_map_state(ts_p->t_state, &mapped_state) != TD_TOK) {
if (__td_debug)
diag_print("State mapping failed\n");
}
if (mapped_state != ti_p.ti_state) {
if (__td_debug)
diag_print("Compare failed: state %x %x\n",
mapped_state, ti_p->ti_state);
return_val = TD_TBADTH;
}
if (TD_CONVERT_TYPE(*ts_p) != ti_p->ti_type) {
if (__td_debug)
diag_print("Compare failed: type %x %x\n",
TD_CONVERT_TYPE(*ts_p), ti_p->ti_type);
return_val = TD_TBADTH;
}
if (ts_p->t_pc != ti_p->ti_pc) {
if (__td_debug)
diag_print("Compare failed: pc %x %x\n",
ts_p.t_pc, ti_p->ti_pc);
return_val = TD_TBADTH;
}
if (ts_p->t_sp != ti_p->ti_sp) {
if (__td_debug)
diag_print("Compare failed: sp %x %x\n",
ts_p->t_sp, ti_p->ti_sp);
return_val = TD_TBADTH;
}
if (ts_p->t_pri != ti_p->ti_pri) {
if (__td_debug)
diag_print("Compare failed: priority %x %x\n",
ts_p->t_pri, ti_p->ti_pri);
return_val = TD_TBADTH;
}
/*
* lwp id is only correct if thread is on an lwp.
*/
if (ISVALIDLWP(ts_p)) {
if (ts_p->t_lwpid != ti_p->ti_lid) {
if (__td_debug)
diag_print("Compare failed: lid %x %x\n",
ts_p->t_lwpid, ti_p->ti_lid);
return_val = TD_TBADTH;
}
}
if (ts_p->__sigbits[0] !=
ti_p->ti_sigmask.__sigbits[0]) {
if (__td_debug)
diag_print("Compare failed: sigmask %x %x\n",
ts_p->t_hold, ti_p->ti_sigmask);
return_val = TD_TBADTH;
}
if (ts_p->t_preempt != ti_p->ti_preemptflag) {
if (__td_debug)
diag_print("Compare failed: preemptflag %x %x\n",
ts_p->t_preempt,
ti_p->ti_preemptflag);
return_val = TD_TBADTH;
}
if (ts_p->__sigbits[0] !=
ti_p->ti_pending.__sigbits[0]) {
if (__td_debug)
diag_print("Compare failed: pending %x %x\n",
ts_p->t_psig, ti_p->ti_pending);
return_val = TD_TBADTH;
}
#ifdef PHASE2
/*
* Check priority inversion flag when it is present in thread
* struct.
*/
#endif
#if TD_DEBUG
if (!return_val) {
if (__td_debug)
diag_print("Compare passed\n");
}
#endif
return (return_val);
}
#endif /* TD_INTERNAL_TESTS */
#ifdef PHASE2
/*
* Description:
* Suspend the execution of a specified thread. It remains
* suspended until it is resumed by td_thr_dbresume(). A thread
* that is suspended via td_thr_dbsuspend() is completely different
* from a thread being suspended * via thr_suspend(). The
* application cannot cause a suspended thread to become runnable.
*
* Input:
* *th_p - thread handle
*
* Output:
* td_thr_dbsuspend - return value
*
* Side effects:
* Thread is suspended.
* Imported functions called:
*/
td_err_e
td_thr_dbsuspend(const td_thrhandle_t *th_p)
{
td_err_e return_val;
#ifdef TEST_PS_CALLS
if (td_noop) {
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
/*
* This will be implemented with libthread help. Will
* only have to set a bit.
*/
if (__td_pub_debug) diag_print(
"libthread_db: td_thr_dbsuspend() not fully implemented\n");
rw_unlock(&(th_p->th_ta_p->rwlock));
return (TD_NOT_DONE);
}
/*
* Description:
* Resume the execution of a thread suspended via
* td_thr_dbsuspend().
*
* Input:
* *th_p - thread handle
*
* Output:
* td_thr_dbresume - return value
*
* Side effects:
* Thread is continued.
* Imported functions called:
*/
td_err_e
td_thr_dbresume(const td_thrhandle_t *th_p)
{
td_err_e return_val;
#ifdef TEST_PS_CALLS
if (td_noop) {
return (TD_OK);
}
#endif
/*
* Sanity checks.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if ((th_p->th_ta_p == NULL) || (th_p->th_unique == NULL)) {
return_val = TD_BADTA;
return (return_val);
}
/*
* Get a reader lock.
*/
if (rw_rdlock(&(th_p->th_ta_p->rwlock))) {
return_val = TD_ERR;
}
if (th_p->th_ta_p->ph_p == NULL) {
rw_unlock(&(th_p->th_ta_p->rwlock));
return_val = TD_BADTA;
return (return_val);
}
if (__td_pub_debug) diag_print(
"libthread_db: td_thr_dbresume() not fully implemented\n");
rw_unlock(&(th_p->th_ta_p->rwlock));
return (TD_NOT_DONE);
}
#endif /* END PHASE2 */
/*
* Description:
* Check the value in data against the thread id. If
* it matches, return 1 to terminate interations.
* This function is used by td_ta_map_id2thr() to map id to
* a thread handle.
*
* Input:
* *th_p - thread handle
* *data - thread id being sought
*
* Output:
* td_mapper_id2thr - returns 1 if thread id is found.
*
* Side effects:
*/
static int
td_mapper_id2thr(const td_thrhandle_t *th_p, td_mapper_param_t *data)
{
int return_val = 0;
td_thrinfo_t ti;
td_err_e td_return;
td_return = __td_thr_get_info(th_p, &ti);
if (td_return == TD_OK) {
if (data->tid == ti.ti_tid) {
data->found = TRUE;
data->th = *th_p;
return_val = 1;
}
}
return (return_val);
}
/*
* Description:
* Given a thread identifier, return the corresponding thread
* handle.
*
* Input:
* *ta_p - thread agent
* tid - Value of thread identifier(e.g., as
* returned by call to thr_self()).
*
* Output:
* *th_p - Thread handle
* td_ta_map_id2thr - return value
*
* Side effects:
* none
* Imported functions called: ps_pdread, ps_pstop,
* ps_pcontinue.
*/
td_err_e
__td_ta_map_id2thr(const td_thragent_t *ta_p, thread_t tid,
td_thrhandle_t *th_p)
{
td_err_e return_val;
td_mapper_param_t data;
#ifdef TEST_PS_CALLS
if (td_noop) {
(void) ps_pstop(0);
(void) ps_pcontinue(0);
(void) ps_pdread(0, 0, 0, 0);
return (TD_OK);
}
#endif
/*
* Check for bad thread agent pointer.
*/
if (ta_p == NULL) {
return_val = TD_BADTA;
return (return_val);
}
/*
* LOCKING EXCEPTION - Locking is not required
* here because the locking and checking will be
* done in __td_ta_thr_iter. If __td_ta_thr_iter
* is not used or if some use of the thread agent
* is made other than the sanity checks, ADD
* locking.
*/
/*
* Check for bad thread handle pointer.
*/
if (th_p == NULL) {
return_val = TD_BADTH;
return (return_val);
}
if (tid != 0) {
data.tid = tid;
data.found = NULL;
return_val = __td_ta_thr_iter(ta_p,
(td_thr_iter_f *) td_mapper_id2thr, (void *)&data,
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
if (return_val == TD_OK) {
if (data.found != NULL) {
*th_p = (data.th);
} else {
return_val = TD_NOTHR;
__td_report_po_err(return_val,
"Thread not found - td_ta_map_id2thr");
}
}
} else {
return_val = TD_NOTHR;
__td_report_po_err(return_val,
"Invalid thread id - td_ta_map_id2thr");
}
return (return_val);
}
#ifdef TD_INTERNAL_TESTS
/*
* Description:
* Dump out selected fields of a thread information struct
*
* Input:
* *ti_p - thread information struct
*
* Output:
* none
*
* Side effects:
* none
*/
void
__td_tsd_dump(const td_thrinfo_t *ti_p, const thread_key_t key)
{
void *data;
td_thrhandle_t th;
th.th_unique = ti_p->ti_ro_area;
th.th_ta_p = ti_p->ti_ta_p;
td_thr_tsd(&th, key, &data);
diag_print("Thread Object:\n");
diag_print(" Id: %d\n", ti_p->ti_tid);
diag_print(" TSD key: %i\n", key);
diag_print(" Key binding: %x\n", data);
}
/*
* Description:
* Dump out a thread information struct
*
* Input:
* *ti_p - thread information struct
* full - flag for full dump
*
* Output:
* none
*
* Side effects:
* none
*/
void
__td_ti_dump(const td_thrinfo_t *ti_p, int full)
{
int i;
diag_print("Thread Object:\n");
if (full) {
diag_print(" Thread agent pointer: %x\n",
ti_p->ti_ta_p);
diag_print(" Thread creation information:\n");
diag_print(" User flags: %x\n",
ti_p->ti_user_flags);
}
diag_print(" Id: %d\n", ti_p->ti_tid);
diag_print(" Start function address: %x\n",
ti_p->ti_startfunc);
diag_print(" Stack base: %x\n",
ti_p->ti_stkbase);
diag_print(" Stack size: %d\n", ti_p->stksize);
if (full) {
diag_print(" Thread flags: %x\n",
ti_p->ti_flags);
diag_print(" Thread struct address: %x\n",
ti_p_ti_ro_area);
diag_print(" Thread struct size: %d\n",
ti_p->ti_ro_size);
}
diag_print(" Thread variable information:\n");
diag_print(" PC: %x\n", ti_p->ti_pc);
diag_print(" SP: %x\n", ti_p->ti_sp);
diag_print(" State: %s\n",
td_thr_state_names[ti_p->ti_state];
if (full) {
diag_print(" Debugger suspended: %d\n",
ti_p->ti_db_suspended);
diag_print(" Priority: %d\n",
ti_p->ti_pri);
diag_print(" Associated LWP Id: %d\n",
ti_p->ti_lid);
diag_print(" Signal mask: %x\n",
ti_p->ti_sigmask);
diag_print(" Enabled events: %x\n",
ti_p->ti_events.event_bits[1]);
diag_print(" Trace enabled: %d\n",
ti_p->ti_traceme);
diag_print(" Has been preempted: %d\n",
ti_p->ti_preemptflag);
diag_print(" Priority inheritance done %d\n",
ti_p->ti_pirecflag);
diag_print(" Pending signal information:\n");
diag_print(" Pending signals: ");
for (i = 1; i < 4; i++) {
diag_print("%x ",
ti_p->ti_pending.__sigbits[i]);
}
diag_print("\n");
}
}
/*
* Description:
* Dump ucontext struct
*
* Input:
* *uc_p - ucontext struct
*
* Output:
* none
*
* Side effects:
* ucontext_t is dumped
*/
static void
td_ucontext_dump(const ucontext_t * uc_p)
{
diag_print(" Signal ucontext:\n");
diag_print(" Flags: %x\n",
uc_p->uc_flags);
diag_print(" Link: %x\n",
uc_p->uc_link);
diag_print(" Signal mask %x\n",
uc_p->uc_sigmask);
diag_print(" Stack: %x\n",
uc_p->uc_stack);
diag_print(" mcontext: (Not shown)\n");
}
/*
* Description:
* Dump siginfo_t struct
*
* Input:
* *sig - siginfo_t struct
*
* Output:
* none
*
* Side effects:
* none
*/
static void
td_siginfo_dump(const siginfo_t * sig_p)
{
siginfo_t sig;
sig = *sig_p;
diag_print("si_signo - signal from signal.h: %d\n", sig.si_signo);
diag_print("si_code - code from above: %d\n", sig.si_code);
diag_print("si_errno - error from errno.h: %d\n", sig.si_errno);
diag_print("union _data:\n");
diag_print(" struct _proc:\n");
diag_print(" _pid: %d\n", sig._data._proc._pid);
diag_print(" union _data:\n");
diag_print(" struct _kill:\n");
diag_print(" _uid: %d\n",
sig._data._proc._pid);
diag_print(" struct _cld:\n");
diag_print(" _utime: %d\n",
sig._data._proc._pdata._cld._utime);
diag_print(" _status: %d\n",
sig._data._proc._pdata._cld._status);
diag_print(" _stime: %d\n",
sig._data._proc._pdata._cld._stime);
diag_print(" struct _fault - SIGSEGV, SIGBUS, SIGILL and SIGFPE :\n");
diag_print(" _addr - faulting address: %x\n",
sig._data._fault._addr);
diag_print(" _trapno - Illegal trap number:%d\n",
sig._data._fault._trapno);
diag_print(" struct _file - SIGPOLL, SIGXFSZ\n");
diag_print(" _fd - file descriptor: %d\n",
sig._data._file._fd);
diag_print(" _band: %d\n", sig._data._file._band);
diag_print(" struct _prof - SIGPROF\n");
diag_print(" _faddr - last fault address %x\n",
sig._data._prof._faddr);
diag_print(" _tstamp - real time stamp: %d\n",
sig._data._prof._tstamp);
diag_print(" _syscall - current syscall: %d\n",
sig._data._prof._syscall);
diag_print(" _nsysarg - no. of arguments:%d\n",
sig._data._prof._nsysarg);
diag_print(" _fault - last fault type: %d\n",
sig._data._prof._fault);
diag_print(" _sysarg - syscall arguments:(not shown)\n");
diag_print(" _mstate (not shown)\n");
}
#endif
/*
* Description:
* Compare mask1 and mask2. If equal, return 0,
* Otherwise, return non-zero.
*
* Input:
* mask1_p - signal mask
* mask2_p - signal mask
*
* Output:
* td_sigmak_are_equal - return value
*
* Side effects:
* none
*/
int
__td_sigmask_are_equal(sigset_t * mask1_p, sigset_t * mask2_p)
{
int return_val = 1;
int i, mask_word_cnt;
if ((mask1_p != NULL) && (mask2_p != NULL)) {
mask_word_cnt = sizeof (sigset_t) /
sizeof ((*mask1_p).__sigbits[0]);
for (i = 0; i < mask_word_cnt; i++) {
if ((*mask1_p).__sigbits[i] !=
(*mask2_p).__sigbits[i]) {
return_val = 0;
break;
}
}
} else {
return_val = 0;
}
return (return_val);
}