Files
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

2855 lines
98 KiB
C

static char sccsid[] = "@(#)48 1.27 src/bos/usr/ccs/lib/libdbx/k_thread.c, libdbx, bos41J, 9516A_all 4/18/95 02:52:51";
#ifdef K_THREADS
/*
* COMPONENT_NAME: (CMDDBX) - dbx symbolic debugger
*
* FUNCTIONS: k_error, thread_k ,
* insert_pthreads_obj, createType_pthreads,
* search_pthread , update_threads,
* switchThread_k, attribute_k, condition_k,
* thread_info_k, setThreadreg_k,
* getThreadOpt_k, getMutexOpt_k, getConditionOpt_k,
* getAttributeOpt_k, createEnum, create_pthreads_enum,
* isRequested_k, getWaiters_k, display_thread_k,
* create_pthreads_types, update_pthreads_obj,
* thread_k_cont, threadheld, mutex_k, update_running_thread,
* getwaittype, search_object_id, verifArgObject_k,
* isThreadObjectSymbol_k, check_thread_stacks
*
* ORIGINS: 27 83
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
* (C) COPYRIGHT International Business Machines Corp. 1992, 1994
* All Rights Reserved
*
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*
*/
/*
* LEVEL 1, 5 Years Bull Confidential Information
*/
/*
* NOTES: libpthreads objects (threads,mutexes,conditon variables,
* and attributes) are linked together in circular lists headed
* by queue objects such as __dbx_known_pthreads, __dbx_known_mutexes,
* __dbx_known_attributes and __dbx_known_conditions.
* By following the next (forward link) of these
* queue objects, we can get to the portion of the next
* element (thread control block in case of a thread list) in
* an object list. To get the starting address of the object element
* use offsetof(structure,element).
*
* pthread
* ---------------------
* | .... |
* | |
* __dbx_known_pthreads | |
* -------------------- ---------------------
* ---->| queue.next |----------->| DBXlink.next |----->
* |..................| |...................|
* <----| queue.prev |<-----------| DBXlink.prev |<-----
* -------------------- ---------------------
* | ...* | | |
* -------------------- | .... |
*
*/
#ifdef KDBXRT
#include "rtnls.h" /* MUST BE FIRST */
#endif
/* include file for message texts */
#include "dbx_msg.h"
nl_catd scmc_catd; /* Cat descriptor for scmc conversion */
/*
* include files
*/
#include "internal.h" /* libpthreads include files */
#include <sys/ptrace.h>
#undef _THREAD_SAFE /* define global errno */
#undef malloc
#undef free
#ifdef errno /* function) */
#undef errno /* for next errno.h */
extern int errno;
#endif
#include <sys/mstsave.h>
#include <sys/types.h>
#include "defs.h" /* dbx include files */
#include "envdefs.h"
#include "coredump.h"
#include "eval.h"
#include "execute.h"
#include "mappings.h"
#include "names.h"
#include "object.h"
#include "process.h"
#include "runtime.h"
#include "frame.h"
#include "source.h"
#include "symbols.h"
#include <sys/signal.h> /* system include file */
#include <sys/proc.h> /* for getwaittype : p_wtype*/
#include <sys/user.h>
#include <sys/thread.h>
#include "cma_thread.h"
#include <sys/uthread.h>
#include <sys/core.h>
#include <stddef.h>
#include <errno.h>
#include <procinfo.h>
private void threadheld();
typedef struct pthread pthread_st;
typedef struct stk stk_st;
typedef struct vp vp_st;
typedef struct pthread_attr pthread_attr_st;
typedef struct thrdsinfo thrdsinfo_st;
typedef struct mstsave mstsave_st;
typedef struct procsinfo procsinfo_st;
typedef struct uthread uthread_st;
extern boolean traceexec; /* trace execution */
/*
* defines
*/
#define OBJ_THREAD 0 /* object thread */
#define OBJ_MUTEX 1 /* object mutex */
#define OBJ_CONDITION 2 /* object condition */
#define OBJ_ATTRIBUTE 3 /* object attribute */
#define MAX_FIELD 12 /* Max. number of field in object types */
#define MAX_NAME_LEN 25 /* Max. length of object name */
/* "$t" prefix is max. two characters */
/* Number after prefix is max. len of int */
#define QUEUE_NEXT(n) ( (n).next == 0xffffffff ? nil : (n).next )
#define ESIZE(n) sizeof(n)/sizeof(char *)
/* The thread responsible of the stop has in its pthread structure */
/* ti_cursig != 0 (the signal received) */
#define IS_RESPONSIBLE(s) ( (s)!= 0 )
#define IS_RUNNING(t) ( (t)== TSRUN )
#define IS_WAIT(t) ( (t)== TSSLEEP )
#define IS_SUSP(t) ( (t)== TSSTOP )
#define IS_TERM(t) ( (t)== TSZOMB )
#define MODE_K 1 /*the thread is stopped in kernel mode */
#define MODE_U 0 /*the thread is stopped in user mode */
#define MODE_UNDEFINED 2 /*the thread is stopped in undefied mode : core file */
/* define types of attribute object */
#define ATTR_THREAD 0 /* the attribute is a pthread attribute */
#define ATTR_MUTEX 1 /* the attribute is a mutex attribute */
#define ATTR_COND 2 /* the attribute is a condition attribute */
/* define constantes for state of user thread (ss_name) */
#define RUNNING 0 /* the thread is running */
#define TERMINATED 1 /* the thread is terminated */
#define BLOCKED 2 /* the thread is waiting */
#define RUNNABLE 3 /* for M:N only */
#define NO_POLICY 3
#define s_queue (int)(sizeof(pthread_queue))
#define offsetof2(s_name, s_member) offsetof(s_name, s_member) - s_queue
/*
* typedefs, globals, statics, and externs
*/
public Address save_last_bp = 0; /* save le last_pb */
public Symbol running_thread = nil; /* Pointer to running thread */
public Symbol current_thread = nil; /* Pointer to current thread */
/* Not always the running thread, */
/* but the thread dbx displays */
/* registers and traceback on. */
private boolean hold_other = false;/* hold_other : resume or not the other*/
/* threads */
public Address addr_dbsubn = nil; /* if the running thread is held */
int nb_k_threads_sig;
extern tid_running_thread; /* use by ptrace(PTT_CONTINUE) */
extern int lib_type; /* lib type : libcma or libpthreads */
extern thrdsinfo_st *pthrdsinfo;
extern mstsave_st *pmstinfo;
extern int nb_k_threads;
extern struct procsinfo *pprocsinfo;
extern mstsave_st *mstsave_current; /* pointer on current mstsave */
extern boolean coredump; /* Are we debugging a corefile? */
extern struct core_dump corehdr; /* Hold info about the corefile */
typedef struct sigcontext sigcontext; /* hold info for signal switching */
/*
* In order for pthreads objects be treated as regular variables with
* normal dbx subcommands, eg. "print $t1" , "assign $m1.islock = 0"
* Internal "Symbols" (variables) need to be associated with these pthreads
* objects, and types for these variables need to be defined. Following
* typedefs and Symbols are used for defining these Symbol types.
*/
static Symbol e_th_k_state = nil; /* enum symbol for thread state */
static Symbol e_th_k_policy = nil; /* enum symbol for thread policy */
/*
* Structure used for defining fields and info of the pthreads object types.
*/
typedef struct pthreads_field_info {
char *name; /* name of the field */
Symbol *type; /* type of this field */
int offset; /* actual offset in the pthreads object */
} pthreads_field_info;
typedef struct pthreads_type_info {
Symbol sym; /*"Symbol" to be created for the type */
String type_name; /* name of the type (Symbol) */
int num_field; /* number of fields for this type */
pthreads_field_info fields[MAX_FIELD]; /* info for all fields */
} pthreads_type_info;
/*
* Following is actual field information for each pthreads object type.
* This object info is used in procedure create_pthreads_types() where
* the pthreads object type "Symbol" is created.
* Note: Not all fields defined in the actual pthreads object in libpthreads.a
* are used here. Only fields useful and feasible to users are
* defined.
*/
static pthreads_type_info thread_object = {
nil,
"$$threadk",
11,
{
{"thread_id", &t_int, offsetof2(pthread_st,th_id)},
{"state", &e_th_k_state, offsetof2(pthread_st, ti_stat)},
{"state_u", &t_int,offsetof2(pthread_st, state)},
{"tid", &t_int,offsetof2(pthread_st, ti_tid)},
{"mode", &t_int,offsetof2(pthread_st, ti_flags)},
{"held", &t_int, offsetof2(pthread_st, ti_hold)},
{"priority", &t_int, offsetof2(pthread_st, ti_pri)},
{"policy", &e_th_k_policy, offsetof2(pthread_st, ti_policy)},
{"scount", &t_int, offsetof2(pthread_st, ti_scount)},
{"cursig", &t_int, offsetof2(pthread_st, ti_cursig)},
{"attributes", &t_addr, offsetof2(pthread_st, attr)}
}
};
static pthreads_type_info mutex_object = {
nil,
"$$mutexk",
5,
{
{"mutex_id", &t_int, offsetof(pthread_mutex_t, mtx_id)},
{"islock", &t_int, offsetof(pthread_mutex_t, lock)},
{"owner", &t_addr, offsetof(pthread_mutex_t, owner)},
{"flags", &t_int, offsetof(pthread_mutex_t, flags)},
{"attributes", &t_addr,offsetof(pthread_mutex_t, attr)},
}
};
static pthreads_type_info attr_object = {
nil,
"$$attrk",
12,
{
{"attr_id", &t_int, offsetof(pthread_attr_st, attr_id)},
{"type", &t_int, offsetof(pthread_attr_st, type)},
{"state", &t_int, offsetof(pthread_attr_st, flags)},
{"stacksize", &t_int, offsetof(pthread_attr_st, stacksize)},
{"detachedstate", &t_int, offsetof(pthread_attr_st, detachstate)},
{"process_shared", &t_int, offsetof(pthread_attr_st, process_shared)},
{"contentionscope", &t_int, offsetof(pthread_attr_st,
contentionscope)},
{"priority", &t_int, offsetof(pthread_attr_st,
schedule.sched_priority)},
{"sched", &t_int, offsetof(pthread_attr_st, schedule.sched_policy)},
{"inherit", &t_int, offsetof(pthread_attr_st, inherit)},
{"protocol", &t_int, offsetof(pthread_attr_st,protocol)},
{"prio_ceiling", &t_int, offsetof(pthread_attr_st, prio_ceiling)}
}
};
static pthreads_type_info cv_object = {
nil,
"$$cvk",
4,
{
{"cv_id", &t_int, offsetof(pthread_cond_t, cv_id)},
{"lock", &t_int, offsetof(pthread_cond_t, lock)},
{"semaphore_queue", &t_addr, offsetof(pthread_cond_t,waiters)},
{"attributes", &t_addr,offsetof(pthread_cond_t, attr)},
}
};
/* Names for thread state, substate and type */
static char *s_name[] = {"", " ", "run","wait", " ", "susp",
"susp"," susp " ,"????" };
/* state user : state of pthread structure */
static char *ss_name[] = {
"running",
"terminated",
"blocked ",
"runnable "
"????"
};
static char *s_mode[] = { "u", "k", " ", "?" };
static char *t_policy[] = { "other", "fifo", "rr", " ", "??"};
/* subcommand attribute */
#define NO_P_SHARED 2 /* nothing to print */
#define NO_PROTOCOL 3 /* nothing to print */
#define NO_SCOPE 2 /* nothing to print */
#define NO_SCHEDULER 3 /* nothing to print */
/* fields corrupted */
#define ERROR_P_SHARED 3 /* print ??? */
#define ERROR_PROTOCOL 4 /* print ??? */
#define ERROR_SCOPE 3 /* print ??? */
#define ERROR_SCHEDULER 4 /* print ??? */
#define ERROR_KIND 4 /* print ??? */
#define ERROR_TYPE 3 /* print ??? */
#define ERROR_STATE 2 /* print ??? */
#define ERROR_SSNAME 4 /* print ??? */
#define ERROR_SNAME 8 /* print ??? */
#define ERROR_MODE 3 /* print ??? */
#define ERROR_POLICY 4 /* print ??? */
#define control_value(field , er_code) \
if ((field < 0) || (field > er_code)) field = er_code;\
/* thread mutex and condition attribute : type and state */
static char *attr_type[] = { "thr", "mutex","cond", "????" };
static char *attr_state[] = { "", "valid", "????" };
/* thread attribute : contentionscope and sched */
static char *attr_contention[] = { "system", "process", "", "????"};
static char *attr_sched[] = { "other", "fifo", "rr", " ", "????"};
/* mutex and condition attribute : p-shared */
static char *attr_shared[] = { "no", "yes", "", "???"};
/* mutex attribute : protocol */
static char *attr_protocol[] = { "no_prio", "prio", "protect", "", "????"};
static char *attr_kind[] = { "non-rec", "recursi", "fast", "", "????"};
/*
* NAME: k_error
*
* FUNCTION: Make sure error occured while executing thread subcommand is
* not caused by completion or termination of process. If so,
* alert user that program is no longer active.
*
* NOTES: Used by thread subcommand routines only
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
/* VARARGS1 */
private void k_error(s, a, b, c, d, e, f, g, h, i, j, k, l, m)
{
if (notstarted(process) or isfinished(process)) {
error(catgets(scmc_catd, MS_runtime, MSG_265, "program is not active"));
} else {
error(s, a, b, c, d, e, f, g, h, i, j, k, l, m);
}
}
/*
* NAME: getMutexOpt_k
*
* FUNCTION: Scans option used with the "mutex" command
*
* PARAMETERS:
* s - string typed in as option to the command
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: -1 if option string "s" doesn't match any valid option;
* Otherwise the integer value of option matched.
*/
public int getMutexOpt_k(s)
char *s;
{
lowercase(s);
if (!strcmp(s,"lock"))
return (int) mu_lock;
else if (!strcmp(s,"unlock"))
return (int) mu_unlock;
else {
(*rpt_error)(stderr, catgets(scmc_catd, MS_pthread, MSG_760,
"Usage: mutex [ lock | unlock | <mutex#>] \n"));
return -1;
}
}
/*
* NAME: getConditionOpt_k
*
* FUNCTION: Scans option used with the "condition" command
*
* PARAMETERS:
* s - string typed in as option to the command
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: -1 if option string "s" doesn't match any valid option;
* Otherwise the integer value of option matched.
*/
public int getConditionOpt_k(s)
char *s;
{
lowercase(s);
if (!strcmp(s,"wait"))
return (int) cv_wait;
else if (!strcmp(s,"nowait"))
return (int) cv_nowait;
else {
(*rpt_error)(stderr, catgets(scmc_catd, MS_pthread, MSG_761,
"Usage: condition [wait | nowait | <condition#>] \n"));
return -1;
}
}
/*
* NAME: getAttributeOpt_k
*
* FUNCTION: Prints the usage of subcommand attribute.
*
* PARAMETERS:
* s - string typed in as option to the command
*
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: -1 (always)
*
*/
public getAttributeOpt_k(s)
char *s;
{
(*rpt_error)(stderr, catgets(scmc_catd, MS_pthread, MSG_762,
"Usage: attribute [<attribute#>] \n"));
return -1;
}
/*
* NAME: getThreadOpt_k
*
* FUNCTION: Scans option used with the "thread" command
*
* PARAMETERS:
* s - string typed in as option to the command
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: -1 if option string "s" doesn't match any valid option;
* Otherwise the integer value of option matched.
*/
public getThreadOpt_k(s)
char *s;
{
lowercase(s);
if (!strcmp(s,"hold"))
return (int) th_hold;
else if (!strcmp(s,"unhold"))
return (int) th_unhold;
else if (!strcmp(s,"run"))
return (int) th_run;
else if (!strcmp(s,"wait"))
return (int) th_wait;
else if (!strcmp(s,"susp"))
return (int) th_susp;
else if (!strcmp(s,"term"))
return (int) th_term;
else if (!strcmp(s,"current"))
return (int) th_current;
else if (!strcmp(s,"info"))
return (int) th_info;
else {
(*rpt_error)(stderr, catgets(scmc_catd, MS_pthread, MSG_763,
"Usage: thread [ hold | unhold | \n"));
(*rpt_error)(stderr, catgets(scmc_catd, MS_pthread, MSG_764,
" info | current | wait \n"));
(*rpt_error)(stderr, catgets(scmc_catd, MS_pthread, MSG_765,
" run | susp | term ] [thread#]\n"));
return -1;
}
}
/*
* NAME: search_pthread
*
* FUNCTION: Search in the pthread queue the pthread structure with tid .
*
* NOTES: Called by routine update_threads()
*
* PARAMETERS:
* known_thread_addr - begin of pthread queue
* tid - tid searched of the first thread
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: address of the pthread structure
* nil if the thread is not found
*/
private pthread_queue* search_pthread ( known_thread_addr , tid)
Address known_thread_addr;
tid_t tid;
{
pthread_queue *ptr; /* current pointer on pthread structure */
pthread_queue q_buf; /* pthread_queue (link) read */
tid_t thread_id; /* tid read */
vp_st *vp_addr;
unsigned int state;
int badread;
badread = dread(&q_buf, known_thread_addr , sizeof(pthread_queue));
if (badread) return(nil);
ptr=QUEUE_NEXT(q_buf);
while ( ptr != nil && ptr != known_thread_addr) {
badread = dread(&state, (Address) ((int) ptr +
offsetof2(pthread_st, state)), sizeof(unsigned int ));
if (badread) return(nil);
if (!(state & PTHREAD_RETURNED)) { /* pthread not actived */
badread = dread(&vp_addr, (Address) ((int) ptr +
offsetof2(pthread_st, vp)), sizeof(Address ));
if (badread) return(nil);
if ( vp_addr != nil ) {
badread = dread(&thread_id, (Address) ((int) vp_addr +
offsetof(vp_st,id )), sizeof(unsigned long ));
if (badread) return(nil);
if (thread_id == tid) return (ptr);
}
}
badread = dread(&q_buf, ptr ,sizeof(pthread_queue));
if (badread) return(nil);
ptr=QUEUE_NEXT(q_buf);
}
return(nil);
}
/*
* NAME: update_threads
*
* FUNCTION: Update all the pthread structures with kernel informations.
* call after each return kernel (getinfo)
* If coredump : nothing to do (nothing in corefile !)
*
* NOTES: Called by routine thread_k() when option equals th_get_info
* The libpthreads structures pthread are updated.
*
* PARAMETERS:
* known_thread_addr - Address of the pthread_queue
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
private void update_threads ( known_thread_addr)
Address known_thread_addr;
{
thrdsinfo_st *pth;
pthread_queue *ptrcur;
int i, number, n, mode;
int state;
unsigned long hold = 0; /* thread not held */
unsigned long cursig = 0; /* */
boolean found = false;
if (!coredump) {
/* gettid had update pthrdinfo and pmstinfo */
/* it had also updated the registers */
nb_k_threads_sig =0;
for ( i = 0;i < nb_k_threads;i++) {
pth = &pthrdsinfo[i];
/* search in user area a thread with the same tid */
ptrcur = search_pthread(known_thread_addr ,pth->ti_tid);
/* if the tid is not found in the pthread queue it's not an error */
/* the pthread can be in state : PTHREAD_RETURNED */
if (ptrcur != nil) {
/* update pthread structure */
/* pthread with tid found */
dwrite(&pth->ti_tid, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_tid)), sizeof(unsigned long ));
dwrite(&pth->ti_policy, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_policy)), sizeof(unsigned long ));
dwrite(&pth->ti_pri, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_pri)), sizeof(unsigned long ));
dwrite(&pth->ti_wchan, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_wchan)), sizeof(unsigned long));
state = pth->ti_state;
/* all threads are stopped : state = run if waiting for nothing */
/* state = TSSTOP and ti_wtype= TNOWAIT,TWMEM => run */
/* state = TSSTOP and ti_wtype= TWCPU => susp */
if (state == TSSTOP) {
state = TSSLEEP; /* waiting for something */
if ((pth->ti_wtype == TNOWAIT) || (pth->ti_wtype == TWMEM))
state = TSRUN;
else
if (pth->ti_wtype == TWCPU) state = TSSTOP;
}
dwrite(&state, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_stat)), sizeof(unsigned long ));
/* mode user or kernel : depends of t_suspend */
dwrite(&pth->ti_scount, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_flags)), sizeof(unsigned long ));
cursig = 0;
/* only one thread with cursig != 0 in dbx (the running_thread) */
if (pth->ti_flag & TTRCSIG) {
if (!found && (pth->ti_cursig == process->signo)) {
cursig = pth->ti_cursig;
found = true;
}
pth->ti_scount = MODE_U;
nb_k_threads_sig++;
}
dwrite(&pth->ti_scount, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_scount)), sizeof(unsigned long ));
dwrite(&cursig, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_cursig)), sizeof(unsigned long ));
} /* ptrcur */
}/*for */
if (traceexec) {
(*rpt_output)(stdout, "!! number of threads with signal %d\n",
nb_k_threads_sig);
}
} /* if coredump */
}
/*
* NAME: setThreadregs_k
*
* FUNCTION: Sets register values for specified thread.
* The pthread is attached to a kernel thread write the
* registers using ptrace()
* There is not ptrace(0 to write only one register for
* a thread so we are obliged to write all the registers !
*
* NOTES: Called by routine procreturn() if the running_thread had changed
* (the running_thread was held or after a call proc() the running
* can cahnged). We have to restore the registers of the "old"
* running thread.
*
* PARAMETERS:
* tid - thread id of the old running thread
* n - register number to be modified
* addr - addresse of the saved registers
*
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
public void setThreadregs_k(tid ,n, addr)
tid_t tid;
int n;
Address addr;
{
tid_t save_tid;
/* the thread is attached to a kernel thread (libpthreads 1:1) */
/*we can use ptrace */
save_tid = process->tid;
process->tid = tid;
if (n < 0) { /* floating point registers */
/* the thread is attached to a kernel thread we can use ptrace */
writefprs(process,addr);
} else if (n < NGREG) { /* general registers */
writegprs (process,addr);
} else if (n < NGREG+NSYS) { /* system registers */
writesprs (process,addr);
}
process->tid = save_tid;
}
/*
* NAME: isThreadObjectSymbol_k
*
* FUNCTION: Determine whether symbol passed is a thread, attribute,
* condition variable or mutex object.
*
* PARAMETERS:
* ThreadObjectSym - Symbol of object to be checked
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: true - if symbol is a thread, attribute,
* condition variable or mutex object.
* false - otherwise
*/
public boolean isThreadObjectSymbol_k(Symbol ThreadObjectSym)
{
if ((ThreadObjectSym) &&
((ThreadObjectSym->type == thread_object.sym) ||
(ThreadObjectSym->type == mutex_object.sym) ||
(ThreadObjectSym->type == attr_object.sym) ||
(ThreadObjectSym->type == cv_object.sym)))
{
return(true);
}
else
{
return(false);
}
}
/*
* NAME: switchThread_k
*
* FUNCTION: Switch dbx context to a different thread. Context includes
* mainly the stack (frame pointer), the registers, and current
* line, func, and file.
*
* NOTES: Called by routine thread() when the "thread current <#>"
* subcommand is used. If thread <#> is nil, meaning no thread
* number is issued, dbx should display name of the current thread -
* which is handled in routine thread() called from eval().
* If a thread Symbol (argument ThreadSym != nil) is provided,
* just switch to it.
* Called by routine eval(0) to switch on running_thread (cont,step ..)
*
* This routine will be modified for libpthreads M:N.
*
* PARAMETERS:
* ThreadSym - Symbol of thread to switch to.
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
public void switchThread_k(ThreadSym)
Symbol ThreadSym;
{
Address addr; /* thread address for thread */
vp_st *vp_addr;
tid_t thread_id; /* tid : kernel tid */
Address saveaddr; /* address where registers are saved */
int i, regsize;
mstsave_st *ptr; /* pointer on the uthread structure in the */
/* corefile */
int badread;
thrdsinfo_st *ptrinfo;
unsigned long mode; /* mode kernel or user */
Address thread_sp;
Address iar;
/* Make sure the symbol is a thread... */
if (ThreadSym && ThreadSym->type == thread_object.sym) {
/* Update the registers of running thread before */
/* switching in case it was modified. */
/* update in all cases for kernel threads */
/* this procedure is called on call, step,callproc,goto,return */
setregs(process);
current_thread = ThreadSym; /* switch... */
} else {
/* probably should never get here... */
k_error( catgets(scmc_catd, MS_pthread, MSG_767,
"no thread available"));
return;
}
/* get address of thread */
eval(amper(build(O_SYM, ThreadSym)));
addr = pop(Address);
badread = dread(&vp_addr, (Address) ((int) addr +
offsetof2(pthread_st, vp)), sizeof(Address ));
if (badread) return;
if ( vp_addr != nil ) {
badread = dread(&thread_id, (Address) ((int) vp_addr +
offsetof(vp_st,id )), sizeof(unsigned long ));
if (badread) return;
}
process->tid = thread_id;
if ( coredump) {
/* if we are debugging corefile, we cannot use readreg(ptrace) */
/* to get values of regs, they are saved in the corefile. */
/* if kernel threads the thread_info structures follow the core_dump */
/* structure, so we have to find the structure of this thread */
ptr=find_thread(thread_id);
mstsave_current = ptr;
if (ptr)
copyregs(ptr->gpr, process->reg,
ptr->fpr,process->freg);
else
k_error( catgets(scmc_catd, MS_pthread, MSG_768,
"kernel thread id=%d not found"),thread_id);
} else {
/* if the thread is stopped in kernel mode we have to read the stack */
/* pointer in thdsinfo structure (ptrace() doesn't work) */
badread = dread(&mode, (Address) ((int) addr +
offsetof2(pthread_st, ti_scount)), sizeof(unsigned long));
if (badread) return;
if (mode == MODE_K) { /* we can't use ptrace to read registers */
/* getthrds() returns stack pointer */
/* iar not returned by getthrds() */
/* take the next frame in stack : return address in here */
for (i=0; i < NGREG+NSYS; i++) {
process->reg[i] = 0xdeadbeef;
}
for (i = 0; i <= fpregs; i++ ) {
process->freg[i] = 0.0;
}
for (i = 0; i < nb_k_threads; i++) {
ptrinfo=&pthrdsinfo[i];
if (ptrinfo->ti_tid == thread_id) break;
}
if (i != nb_k_threads) {
thread_sp = ptrinfo->ti_ustk; /* stack pointer */
badread = dread(&thread_sp,thread_sp , sizeof(int));
if (badread) return;
process->reg[GPR1] = thread_sp;
thread_sp = thread_sp + 2*sizeof(int); /* iar */
badread = dread(&iar, thread_sp , sizeof(int));
if (badread) return;
pc = process->reg[SYSREGNO(IAR)] = iar;
}
else
k_error( catgets(scmc_catd, MS_pthread, MSG_768,
"kernel thread id=%d not found"),thread_id);
}
else {
regsize = sizeof(Word);
/* read the 32 general purpose registers */
/* read the special purpose registers */
/* read the 32 floating point registers */
readgprs(process,&process->reg[0]);
readsprs(process,&process->reg[NGREG]);
readfprs(process,&process->freg[0]);
/* registers updated */
for (i = 0; i <= NGREG+NSYS+MAXFREG; i++) {
/* set the valid bit so that dbx would not go read it again */
process->dirty[regword(i)] |= regbit(i);
process->dirty[regword(i)] = 0;
}
}
}
pc = process->reg[SYSREGNO(IAR)]; /* set global pc */
cursource = srcfilename(pc); /* set source file */
cursrcline = srcline(pc); /* set source line */
setcurfunc(whatblock(pc)); /* set current func */
action_mask |= EXECUTION;
}
/*
* NAME: insert_pthreads_obj
*
* FUNCTION: Creates and inserts a Symbol associated with a pthreads object
* into the dbx symbol table
*
* NOTES: This routine is called by other thread routines then a new pthreads
* object is found and a dbx Symbols assiocated with this new
* object is needed.
*
* PARAMETERS:
* n - name of the object, eg. ($t1, $m2, $a3,...)
* t - Symbol of type of object
* addr - address of pthreads object this symbol is associated with
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: a Symbol representing the pthreads object
*/
private Symbol insert_pthreads_obj(n, t, addr)
Name n;
Symbol t;
Address addr;
{
Symbol s;
s = insert(n);
s->language = t->language;
s->class = VAR;
s->storage = EXT;
s->level = 3;
s->type = t;
s->symvalue.offset = addr;
return s;
}
/*
* NAME: update_running_thread
*
* FUNCTION: Creates or updates dbx Symbol $running_thread as an int object.
*
* NOTES: call by thread_k with th_get_info option.
* This object allows : stop at 30 if ($running_thread == 7)
*
* PARAMETERS:
* addr - address of pthreads object this symbol is associated with
* address of the thread_id field.
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: Updated Symbol representing the object
*/
private Symbol update_running_thread(addr)
Address addr;
{
char name[MAX_NAME_LEN];
Symbol objectSym;
Name objectName;
String prefix;
prefix = "$running_thread";
sprintf(name, "%s", prefix);
objectName = identname(name, false);
/* Is object symbol already created? */
if ((objectSym = lookup(objectName)) != nil)
objectSym->symvalue.offset = addr;
else
objectSym = insert_pthreads_obj(objectName,t_int,addr);
return objectSym;
}
/*
* NAME: update_pthreads_obj
*
* FUNCTION: Creates and updates dbx Symbol representing a pthreads object.
*
* NOTES:
*
* PARAMETERS:
* prefix - string prefix for names of pthreads objects, eg. "$t",
* "$c"...
* id - ID of the object
* addr - address of pthreads object this symbol is associated with
* object_type - type of pthreads object (thread or mutex or ... )
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: Updated Symbol representing the pthreads object
*/
private Symbol update_pthreads_obj(prefix, id, addr, object_type)
String prefix;
int id;
Address addr;
Symbol object_type;
{
char name[MAX_NAME_LEN];
Symbol objectSym;
Name objectName;
sprintf(name, "%s%d", prefix, id);
objectName = identname(name, false);
/* Is object symbol already created? */
if ((objectSym = lookup(objectName)) != nil)
objectSym->symvalue.offset = addr;
else
objectSym = insert_pthreads_obj(objectName, object_type, addr);
return objectSym;
}
/*
* NAME: createEnum
*
* FUNCTION: Creates a Symbol representing an enum type,
* giving an array of enum element and the number of element.
*
* NOTES: Used in creating Symbols for types of fields in
* pthreads object symbols.
*
* PARAMETERS:
* ename - name of the enum type
* nlist - array of enum element
* nfield - number of element in enum type
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: A Symbol representing the enum type
*/
private Symbol createEnum(ename, nlist, nfields)
char *ename;
char *nlist[];
int nfields;
{
int count;
Symbol s, u;
s = newSymbol(identname(ename, true), 1, SCAL, nil, nil);
s->language = cLang;
s->type = t_int;
s->symvalue.iconval = nfields;
u = s;
for ( count = 0; count < nfields; count++) {
u->chain = insert(identname(nlist[count],true));
u = u->chain;
u->language = cLang;
u->class = CONST;
u->level = 2;
u->type = s;
u->symvalue.constval = cons(O_LCON, (long) count);
u->symvalue.constval->nodetype = s;
}
return s;
}
/*
* NAME: create_pthreads_enum
*
* FUNCTION: Creates Symbols of enum types used by the pthreads object Symbols.
*
* PARAMETERS: NONE
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
private void create_pthreads_enum()
{
e_th_k_state = createEnum("$th_state_k", s_name, ESIZE(s_name));
e_th_k_policy = createEnum("$th_policy_k", t_policy, ESIZE(t_policy));
}
/*
* NAME: createType_pthreads
*
* FUNCTION: Creates Symbols for types of pthreads objects.
*
* NOTE: The fields are based upon the fields in actual pthreads object
* declarations, not all fields are used here.
*
* PARAMETERS:
* t - pthreads_type_info structure containing info about
* the pthreads object
*
* RECOVERY OPERATION: NONE NEEDET
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
private void createType_pthreads(t)
pthreads_type_info *t;
{
Symbol s;
int i;
int typesize;
s = t->sym = newSymbol(identname(t->type_name, true), 1, RECORD, nil, nil);
t->sym->symvalue.offset = 0;
t->sym->language = cLang;
for (i = 0; i < t->num_field; i++) {
s->chain = newSymbol(identname(t->fields[i].name, true), 2,
FIELD, *(t->fields[i].type), nil);
/* we can't assign a $ti variable */
if(!strcmp(t->type_name,"$$threadk"))
s->chain->isConst = 1;
s = s->chain;
/* Fill in the offset from start of struct */
s->symvalue.field.offset = t->fields[i].offset * BITSPERBYTE;
/* Fill in the size of the field */
if (*(t->fields[i].type)) /* make sure it's not null... */
s->symvalue.field.length = size(*(t->fields[i].type))*BITSPERBYTE;
else
s->symvalue.field.length = 0;
s->language = cLang;
/* Update size of pthreads symbol struct... */
if ((typesize =
(s->symvalue.field.offset + s->symvalue.field.length)/BITSPERBYTE)
> t->sym->symvalue.offset)
/* size of structure is largestOffset of any field + it's size;*/
t->sym->symvalue.offset = typesize;
}
}
/*
* NAME: create_pthreads_types
*
* FUNCTION: Created dbx Symbols representing all pthreads object types
*
* NOTES: Called by routine symbols_init() at dbx startup.
*
* PARAMETERS: NONE
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
public void create_pthreads_types()
{
/* Create Symbols for enum types used in pthreads */
create_pthreads_enum();
/* Create Symbol for pthreads objects */
createType_pthreads(&thread_object);
createType_pthreads(&mutex_object);
createType_pthreads(&attr_object);
createType_pthreads(&cv_object);
}
/*
* NAME: isRequested_k
*
* FUNCTION: Checks if an object id is contained in a list of request
*
* NOTES: Used by thread subcommand routines to decided if an action is
* requested for an pthreads object.
*
* PARAMETERS:
* p - Node containing a list of requested id's
* id - the id to look for in the list
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: True if id is in list of requested
* Otherwise return false.
*/
private boolean isRequested_k(p, id)
Node p;
unsigned long id;
{
Node n1 = p;
/* many element in the list */
while (n1 && n1->op == O_COMMA) {
if (n1->value.arg[0]->op == O_LCON &&
n1->value.arg[0]->value.lcon == id) {
return true;
}
n1 = n1->value.arg[1];
}
/* Only one element */
if (n1 && n1->op == O_LCON && n1->value.lcon == id)
return true;
else
return false;
}
/*
* NAME: search_object_id
*
* FUNCTION: Search in the pthread queue the pthread structure with tid .
*
* NOTES: Called by routine verifArgObject_k()
*
* PARAMETERS:
* known_thread_addr - begin of queue
* type - type of object:thread attribute mutex or condition
* tid - number searched
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*
*/
private void search_object_id (known_addr , type , tid)
Address known_addr;
int type;
int tid;
{
pthread_queue *ptr; /* current pointer on pthread structure */
pthread_queue q_buf; /* pthread_queue (link) read */
int object_id; /* tid read */
unsigned int state; /* for thread only */
int badread;
boolean found; /* tid found in queue */
Address p_obj; /* for mutexes and condition var */
found = false;
badread = dread(&q_buf, known_addr , sizeof(pthread_queue));
if (badread) return;
ptr=QUEUE_NEXT(q_buf);
while ( ptr != nil && ptr != known_addr) {
/* case mutex or cond : the list contains the pointer */
if (( type == OBJ_MUTEX) || (type == OBJ_CONDITION)) {
badread = dread(&p_obj, (Address) ((int)ptr +
offsetof(__dbx_cond, pt_cond)), sizeof(int));
if (badread) return;
}
switch(type) {
case OBJ_THREAD:
{
badread = dread(&state, (Address) ((int) ptr +
offsetof2(pthread_st, state)), sizeof(unsigned int ));
if (badread) return;
if (!(state & PTHREAD_RETURNED)) { /* pthread not actived */
badread = dread(&object_id, (Address) ((int) ptr +
offsetof2(pthread_st,th_id)), sizeof(int ));
if (badread) return;
if (object_id == tid) found = true;
}
break;
}
case OBJ_MUTEX:
{
badread = dread(&object_id, (Address) ((int) p_obj +
offsetof(pthread_mutex_t,mtx_id)), sizeof(int ));
if (badread) return;
if (object_id == tid) found = true;
break;
}
case OBJ_ATTRIBUTE:
{
badread = dread(&object_id, (Address) ((int) ptr +
offsetof(pthread_attr_st,attr_id)), sizeof(int ));
if (badread) return;
if (object_id == tid) found = true;
break;
}
case OBJ_CONDITION:
{
badread = dread(&object_id, (Address) ((int) p_obj +
offsetof(pthread_cond_t,cv_id)), sizeof(int ));
if (badread) return;
if (object_id == tid) found = true;
break;
}
default: /* unknown */
return;
} /* switch */
if (found) break;
badread = dread(&q_buf, ptr ,sizeof(pthread_queue));
if (badread) return;
ptr=QUEUE_NEXT(q_buf);
}
if (!found) {
switch(type) {
case OBJ_THREAD:
{
k_error( catgets(scmc_catd, MS_pthread, MSG_766,
"\'$t%d\' is not an existing thread."),tid);
break;
}
case OBJ_MUTEX:
{
k_error( catgets(scmc_catd, MS_pthread, MSG_777,
"\'$m%d\' is not an existing mutex."),tid);
break;
}
case OBJ_ATTRIBUTE:
{
k_error( catgets(scmc_catd, MS_pthread, MSG_776,
"\'$a%d\' is not an existing attribute."),tid);
break;
}
case OBJ_CONDITION:
{
k_error( catgets(scmc_catd, MS_pthread, MSG_778,
"\'$c%d\' is not an existing condition."),tid);
break;
}
} /* switch */
}
return;
}
/*
* NAME: verifArgObject_k
*
* FUNCTION: Verifies the arguments of subcommand
*
* NOTES: Used by subcommand routines(thread_k,attribute_k....)
*
* PARAMETERS:
* known_addr - begin of pthread queue
* type - type of object : thread mutex attribute or condition
* p - Node containing a list of verified id's
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: Nothing
*
*/
private void verifArgObject_k(known_addr,type,p)
Address known_addr;
int type;
Node p;
{
Node n1 = p;
/* many element in the list */
while (n1 && n1->op == O_COMMA) {
if (n1->value.arg[0]->op == O_LCON)
search_object_id(known_addr,type,n1->value.arg[0]->value.lcon);
n1 = n1->value.arg[1];
}
/* Only one element */
if (n1 && n1->op == O_LCON )
search_object_id(known_addr,type,n1->value.lcon );
}
/*
* NAME: getWaiters_k
*
* FUNCTION: Return the numbers of waiters or print names of
* waiters if requested.
*
* NOTES: Used by thread subcommand routines to display the list of
* waiters for a mutex or a condition variable
*
* PARAMETERS:
* semaphore_queue - address of queue containing list of waiters
* doprt - to print names of waiters or not
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: number of waiters in the queue
*/
private int getWaiters_k(semaphore_queue, doprt)
Address semaphore_queue;
Boolean doprt;
{
__ptq_queue th_q_buf; /* buffer for holding one queue section */
__ptq_queue *th_ptr; /* pointer used to advance queue */
int thread_id;
int num_wait = 0;
int badread;
/* read first section of semaphore.queue in pthreads object... */
badread = dread(&th_q_buf, semaphore_queue, sizeof(__ptq_queue));
if (badread) return(0);
th_ptr = QUEUE_NEXT(th_q_buf);
while ( th_ptr != semaphore_queue) {
if (doprt) {
/* If printing is requested, get thread id and print... */
badread = dread(&thread_id, (Address) ( (int)th_ptr +
offsetof(pthread_st, th_id)), sizeof(int));
if (badread) return(0);
(*rpt_output)(stdout, "$t%d ", thread_id);
}
/* Get contents of next thread queue section */
badread = dread(&th_q_buf, th_ptr, sizeof(__ptq_queue));
if (badread) return(0);
th_ptr = QUEUE_NEXT(th_q_buf);
/* advance counter */
num_wait++;
}
return num_wait;
}
/*
* NAME: getwaittype
*
* FUNCTION: convert a waitchannel to some sort of symbolic form.
* These events are hardcoded from proc.h
*
* NOTES: this procedure is the same procedure used by command ps.
* this procudure is not used, wchan is printed (address of
* the wait channel )
*
* RETURNS: pointer to a symbolic name for the event type.
*/
/*
* types of process waits, p_wtype
*/
char *
getwaittype(wtype)
char wtype;
{
switch(wtype) {
case TNOWAIT:
return ("NOWAIT");
case TWEVENT: /* waiting for event(s) signal? */
return ("EVENT");
case TWLOCK: /* waiting for serialization lock */
return ("LOCK");
case TWTIMER: /* waiting for timer */
return ("TIMER");
case TWCPU: /* waiting for CPU (in ready queue) */
return ("CPU");
case TWPGIN: /* waiting for page in */
return ("PGIN");
case TWPGOUT: /* waiting for page out level */
return ("PGOUT");
case TWPLOCK: /* waiting for physical lock */
return ("PLOCK");
case TWFREEF: /* waiting for a free page frame */
return ("FREEF");
case TWMEM: /* waiting for memory */
return ("MEM");
default: /* unknown */
return("");
}
}
/*
* NAME: display_thread_k
*
* FUNCTION: Gathers and displays regular info about a thread
*
* NOTES: Used by rountine thread_k() when the "thread" command with no
* special option is issued
*
* PARAMETERS:
* pthread_addr - address of the thread control block
* thread_id - id of thread we are dealing with
* state - state of thread is in (kernel state)
* print_title - print title info or not
* fullinfo - print full info or not
* thisthread - pointer to symbol of this thread
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
private void display_thread_k(pthread_addr, thread_id, state,
print_title, fullinfo, thisthread)
Address pthread_addr;
int thread_id;
unsigned long state;
Boolean *print_title;
Boolean fullinfo;
Symbol thisthread;
{
uthread_st *ptr;
unsigned state_u; /* state__u of thread list */
tid_t save_tid; /* save the process->tid */
vp_st *vp_addr;
int is_held; /* is thread on held? */
unsigned long mode; /* mode kernel or user */
unsigned long t_id; /* thread id */
unsigned long pri; /* thread priority */
unsigned long policy; /* scheduling policy of thread */
unsigned long scount; /* count of thread preemptions */
pthread_func_t iar; /* iar of thread */
thrdsinfo_st *ptrinfo; /* pointer on thrdinfo struct */
Address thread_sp; /* stack pointer */
int i;
unsigned long wchan; /* event for wchich thread is waiting*/
unsigned long wtype; /* type of thread wait */
int scope = 0; /* local or global */
pthread_attr_t attr_addr; /* attribute address */
Symbol f; /* Symbol of function thread in */
int badread;
Word save_reg[NSYS]; /* save special registers */
badread = dread(&attr_addr, (Address) ((int) pthread_addr +
offsetof2(pthread_st, attr)), sizeof(Address ));
if (badread) return;
if (attr_addr)
badread = dread(&scope, (Address) ((int) attr_addr +
offsetof(pthread_attr_st,contentionscope )), sizeof(int));
if (badread) return;
/* read needed field info from pthread */
if(coredump) {
badread = dread(&vp_addr, (Address) ((int) pthread_addr +
offsetof2(pthread_st, vp)), sizeof(Address ));
if (badread) return;
if ( vp_addr != nil )
badread = dread(&t_id, (Address) ((int) vp_addr +
offsetof(vp_st,id )), sizeof(unsigned long ));
if (badread) return;
} else {
badread = dread(&t_id, (Address) ((int)pthread_addr +
offsetof2(pthread_st, ti_tid)), sizeof(unsigned));
if (badread) return;
}
badread = dread(&state_u, (Address) ((int)pthread_addr +
offsetof2(pthread_st, state)), sizeof(unsigned));
if (badread) return;
/* state of libpthreads is an "OR" of constants */
if (state_u & PTHREAD_RETURNED)
state_u = TERMINATED;
else
if(state_u & PTHREAD_WAITING)
state_u = BLOCKED;
else
state_u = RUNNING;
badread = dread(&is_held, (Address) ((int)pthread_addr +
offsetof2(pthread_st, ti_hold)), sizeof(unsigned long));
if (badread) return;
badread = dread(&mode, (Address) ((int)pthread_addr +
offsetof2(pthread_st, ti_scount)), sizeof(unsigned long));
if (badread) return;
badread = dread(&wchan, (Address) ((int)pthread_addr +
offsetof2(pthread_st, ti_wchan)), sizeof(unsigned long));
if (badread) return;
badread = dread(&wtype, (Address) ((int)pthread_addr +
offsetof2(pthread_st, ti_wtype)), sizeof(unsigned long));
if (badread) return;
/* in case of core file : */
/* state-k = TSNONE : if the kernel thread exists */
/* STERM : term if the kernel thread does not exist */
/* mode = nothing */
/* wchan = nothing */
if(coredump) {
ptr = find_thread(t_id);
wchan = 0;
if( ptr) state = TSNONE;
else state = TSZOMB;
mode = MODE_UNDEFINED;
if (ptr)
iar = (Address) ptr->ut_save.iar;
else iar = nil;
} else {
/* read all special registers of the thread to have iar */
if (mode == MODE_K) { /* we can't use ptrace to read registers */
/* iar not returned by getthrds() */
/* take the next frame in stack : return address is here */
for (i = 0; i < nb_k_threads; i++) {
ptrinfo=&pthrdsinfo[i];
if (ptrinfo->ti_tid == t_id) break;
}
if (i != nb_k_threads) {
thread_sp = ptrinfo->ti_ustk; /* stack pointer */
badread = dread(&thread_sp,thread_sp , sizeof(int));
if (badread) return;
thread_sp = thread_sp + 2*sizeof(int); /* iar */
badread = dread(&iar, thread_sp , sizeof(int));
if (badread) return;
}
else
k_error( catgets(scmc_catd, MS_pthread, MSG_768,
"kernel thread id=%d not found"),t_id);
}
else { /* user mode */
for (i=0; i < NSYS; i++) {
save_reg[i] = process->reg[NGREG+i];
}
save_tid = process->tid;
process->tid = t_id; /* for readsprs iar */
readsprs(process,&process->reg[NGREG]);
iar = (Address) reg(SYSREGNO(PROGCTR));
/* restore special registers of the current thread */
process->tid = save_tid;
for (i=0; i < NSYS; i++) {
process->reg[NGREG+i] = save_reg[i];
}
/* ptrace(PTT_READ_SPRS) breaks floating point registers */
readfprs(process,&process->freg[0]);
}
}
/* Get iar of thread and display function thread is running. */
/* for thread, iar is in register */
if (iar)
f = whatblock((Address)iar);
else f = nil;
/* control fields */
control_value(state_u, ERROR_SSNAME);
control_value(state, ERROR_SNAME);
control_value(mode, ERROR_MODE);
control_value(scope, ERROR_SCOPE);
/* display title if needed... */
if (*print_title || fullinfo) {
(*rpt_output)(stdout,
" thread state-k wchan state-u k-tid mode held scope function\n");
*print_title = false;
}
/* display the arrow pointer to current thread */
/* the current thread : ">" */
/* the running_thread : "*" */
if ( thisthread == current_thread )
(*rpt_output)(stdout, "%c",'>');
else
(*rpt_output)(stdout, "%c", (thisthread == running_thread)?'*':' ');
(*rpt_output)(stdout,
"$t%-4d %-5s ",
(int) thread_id, s_name[state]);
/* display wchan*/
if (wchan)
(*rpt_output)(stdout, "%7lx", wchan);
else
(*rpt_output)(stdout, "%7s", " ");
(*rpt_output)(stdout,
" %-8s%7d %-1s %3s %-3.3s %-20s\n",
ss_name[state_u], t_id , s_mode[mode],
(Boolean)is_held?"yes":"no",attr_contention[scope],
(f ? symname(f) : nil));
}
/*
* NAME: thread_info_k
*
* FUNCTION: Gathers and displays extended info about a thread
*
* NOTES: Used by rountine thread_k() when the "thread info" option is issued
*
* PARAMETERS:
* pthread_addr - address of the thread control block
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
private void thread_info_k(pthread_addr)
Address pthread_addr;
{
int ti_pri_k; /* priority */
int ti_pri_u; /* priority */
int ti_policy_k; /* policy */
int ti_policy_u; /* policy */
int thd_errno; /* per thread errno */
Address start_pc; /* start routine address */
int event; /* event */
int size; /* size of pthread */
int attached = 1; /* kernel thread attached */
Address stack_limit; /* address for top of stack */
Address stack_base; /* address for base of stack */
Address stack_size; /* size of stack */
tid_t ti_tid;
tid_t save_tid;
mstsave_st *ptr; /* pointer on the uthread structure in the */
thrdsinfo_st *ptrinfo;
int i;
unsigned long mode;
Address thread_sp; /* stack pointer for the thread */
Symbol proc = nil;
Name n;
pthread_attr_t attr_addr;
vp_st *vp_addr;
int *errno_addr;
int badread;
badread = dread(&start_pc, (Address) ((int) pthread_addr +
offsetof2(pthread_st, func)), sizeof(Address ));
if (badread) return;
if (start_pc == NILFUNC(void *)) { /* it is the initial thread : main */
n = identname("main",true);
find(proc, n) where isroutine(proc) endfind(proc);
start_pc = codeloc(proc);
}
badread = dread(&ti_pri_k, (Address) ((int) pthread_addr +
offsetof2(pthread_st, ti_pri)), sizeof(unsigned long ));
if (badread) return;
badread = dread(&ti_tid, (Address) ((int) pthread_addr +
offsetof2(pthread_st, ti_tid)), sizeof(int));
if (badread) return;
badread = dread(&event, (Address) ((int) pthread_addr +
offsetof2(pthread_st, event)), sizeof(int));
if (badread) return;
badread = dread(&ti_policy_k,(Address)((int) pthread_addr +
offsetof2(pthread_st, ti_policy)), sizeof(int ));
if (badread) return;
badread = dread(&attr_addr, (Address) ((int) pthread_addr +
offsetof2(pthread_st, attr)), sizeof(Address ));
if (badread) return;
if (attr_addr) {
badread =dread(&ti_pri_u, (Address) ((int) attr_addr +
offsetof(pthread_attr_st,schedule.sched_priority )), sizeof(int));
if (badread) return;
badread = dread(&ti_policy_u, (Address) ((int) attr_addr +
offsetof(pthread_attr_st,schedule.sched_policy)), sizeof(int));
if (badread) return;
}
badread = dread(&vp_addr, (Address) ((int) pthread_addr +
offsetof2(pthread_st, vp)), sizeof(Address ));
if (badread) return;
badread = dread(&errno_addr, (Address) ((int) pthread_addr +
offsetof2(pthread_st, thread_errno)), sizeof(Address ));
if (badread) return;
badread = dread(&thd_errno, (Address) ((int) errno_addr ), sizeof(int ));
if (badread) return;
badread = dread(&stack_limit, (Address) ((int) vp_addr +
offsetof(vp_st, stack.limit)), sizeof(unsigned long ));
if (badread) return;
badread = dread(&stack_base, (Address) ((int) vp_addr +
offsetof(vp_st, stack.base)), sizeof(unsigned long ));
if (badread) return;
badread = dread(&stack_size, (Address) ((int) vp_addr +
offsetof(vp_st, stack.size)), sizeof(unsigned long ));
if (badread) return;
if (coredump) {
/* if coredump : no kernel scheduler information */
ti_policy_u = NO_POLICY;
ti_pri_u = 0;
/* kernel thread id is in vp structure */
badread = dread(&vp_addr, (Address) ((int) pthread_addr +
offsetof2(pthread_st, vp)), sizeof(Address ));
if (badread) return;
if ( vp_addr != nil )
badread = dread(&ti_tid, (Address) ((int) vp_addr +
offsetof(vp_st,id )), sizeof(unsigned long ));
if (badread) return;
/* we can't use ptrace do read stack pointer */
save_tid = process->tid;
ptr=find_thread(ti_tid);
mstsave_current = ptr;
if (ptr)
copyregs(ptr->gpr, process->reg,
ptr->fpr,process->freg);
else
k_error( catgets(scmc_catd, MS_pthread, MSG_768,
"kernel thread id=%d not found"),ti_tid);
thread_sp = reg(GPR1);
process->tid = save_tid;
ptr=find_thread(save_tid);
mstsave_current = ptr;
if (ptr)
copyregs(ptr->gpr, process->reg,
ptr->fpr,process->freg);
else
k_error( catgets(scmc_catd, MS_pthread, MSG_768,
"kernel thread id=%d not found"),save_tid);
}
else {
badread = dread(&mode, (Address) ((int) pthread_addr +
offsetof2(pthread_st, ti_scount)), sizeof(unsigned long));
if (mode == MODE_K) { /* we can't use ptrace to read registers */
/* if the thread is stooped in kernel mode don't use ptrace() */
/* getthrds() provides the stack pointer */
for (i = 0; i < nb_k_threads; i++) {
ptrinfo=&pthrdsinfo[i];
if (ptrinfo->ti_tid == ti_tid) break;
}
if (i != nb_k_threads) {
thread_sp = ptrinfo->ti_ustk; /* stack pointer */
/* take next frame */
badread = dread(&thread_sp,thread_sp , sizeof(int));
if (badread) return;
}
else
k_error( catgets(scmc_catd, MS_pthread, MSG_768,
"kernel thread id=%d not found"),ti_tid);
}
else { /* user mode : user ptrace() */
/* read all general registers of the thread to have stack pointer */
save_tid = process->tid;
process->tid = ti_tid; /* for readgprs sp */
readgprs(process,&process->reg[0]);
thread_sp = reg(GPR1);
/* restore special registers of the current thread */
process->tid = save_tid;
readgprs(process,&process->reg[0]);
}
}
control_value(ti_policy_k, ERROR_POLICY);
control_value(ti_policy_u, ERROR_POLICY);
/* Output the info found... */
(*rpt_output)(stdout, " scheduler:\n");
(*rpt_output)(stdout, " kernel = %d (%s)\n",
ti_pri_k,t_policy[ti_policy_k]);
(*rpt_output)(stdout, " user = %d (%s)\n",
ti_pri_u,t_policy[ti_policy_u]);
(*rpt_output)(stdout, " general:\n");
(*rpt_output)(stdout, " thread errno = %d\n",thd_errno);
(*rpt_output)(stdout, " start pc = 0x%x\n", (Address) start_pc);
(*rpt_output)(stdout, " detached = %s\n",
(Boolean) attached?"no":"yes");
(*rpt_output)(stdout, " event :\n");
(*rpt_output)(stdout, " event = 0x%x\n", event);
/* M:N : thread state instead of thread addr */
/* (*rpt_output)(stdout, " tstate (thread state):\n"); */
(*rpt_output)(stdout, " thread (pthread addr):\n");
(*rpt_output)(stdout, " address = 0x%x", pthread_addr);
(*rpt_output)(stdout, " size = 0x%x\n",
sizeof(pthread_st));
(*rpt_output)(stdout, " stack storage:\n");
(*rpt_output)(stdout, " base = 0x%x",(Address)stack_base);
(*rpt_output)(stdout, " size = 0x%x\n",stack_size);
(*rpt_output)(stdout, " limit = 0x%x\n",(Address)stack_limit);
(*rpt_output)(stdout, " sp = 0x%x\n",
(Address) thread_sp);
}
/*
* NAME: thread_k_cont
*
* FUNCTION: continue all threads not held
*
* NOTE: called by pcont()
* in case of k_thread we have to use ptrace(PTT_CONTINUE) with
* a list of kernel threads to resume
* if the running_thread is held a special subroutine is called
* to hold this thread
*
* PARAMETERS: p = current process
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
public void thread_k_cont(p)
Process p;
{
pthread_queue *ptr; /* current pointer on pthread structure */
pthread_queue q_buf; /* pthread_queue (link) read */
Address known_thread_addr; /* hold address of __dbx_known_threads */
unsigned long hold; /* field of pthread held or unheld */
Symbol known_threads; /* Symbol for thread object list */
thrdsinfo_st *pth;
pthread_queue *ptrcur;
Boolean held_running = 0;
int i,n,i_buf = 0; /* for loop */
struct ptthreads buf_ptthreads; /* buffer for ptrace(PTT_CONTINUE) */
unsigned int state;
int badread;
int nb_thread =0; /* number of threads to resume */
/* Find address for thread queue start - __dbx_known_pthreads */
/* if the process is not linked with libpthreads.a */
known_threads = lookup(identname("__dbx_known_pthreads",true));
if (known_threads) {
eval(amper(build(O_SYM, known_threads)));
known_thread_addr = pop(Address);
badread = dread(&q_buf, known_thread_addr , sizeof(pthread_queue));
if (badread) return;
ptr=QUEUE_NEXT(q_buf);
}
if ((known_threads == nil) or (ptr == nil) or (hold_other)) {
nb_thread = 1;
buf_ptthreads.th[0] = NULL;
} else {
for ( i = 0;i < nb_k_threads;i++) {
pth = &pthrdsinfo[i];
/* search in user area a thread with the same tid */
ptrcur = search_pthread(known_thread_addr ,pth->ti_tid);
state = pth->ti_state;
if (!(state == TSIDL || state == TSZOMB || state == TSSWAP
|| state == TSNONE)) {
if (ptrcur != nil) {
badread = dread(&hold, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_hold)), sizeof(unsigned long ));
}
else hold = 0;
if ( !hold) { /* not held */
if( pth->ti_tid != tid_running_thread )
buf_ptthreads.th[i_buf++] = pth->ti_tid;
nb_thread++;
} else
/* test if the running_thread is held */
/* hold running_thread is looping, so unhold it */
if( pth->ti_tid == tid_running_thread ) {
held_running = 1;
hold = 0;
badread = dwrite(&hold, (Address) ((int) ptrcur +
offsetof2(pthread_st, ti_hold)), sizeof(unsigned long ));
}
} /* kernel state */
buf_ptthreads.th[i_buf] = NULL;
}
}
/* all the threads are held */
/* if we have only one thread : case of child after a fork() */
/* or case of debug the libpthreads -> the pthread structure */
/* is not yet created : do not display an error */
if (( nb_thread == 0 ) && (nb_k_threads > 1)){
if (save_last_bp != 0)
unsetbp(save_last_bp);
else
unsetallbps();
isstopped = true; /* we can continue after unhold threads */
k_error( catgets(scmc_catd, MS_pthread, MSG_769,
"all threads held"));
return;
}
if (held_running) {
if (traceexec) {
(*rpt_output)(stdout, "call threadheld\n");
}
threadheld();
p->signo = 0;
}
if (traceexec) {
(*rpt_output)(stdout, "!! ptrace(%d,%d,%d,%d,%x)\n",
PTT_CONTINUE, tid_running_thread, 1, p->signo, &buf_ptthreads);
(*rpt_output)(stdout, "!! number of threads resumed %d\n",nb_thread);
}
if (ptrace(PTT_CONTINUE, tid_running_thread,1,p->signo,&buf_ptthreads) < 0){
panic( catgets(scmc_catd, MS_process, MSG_285,
"error %d trying to continue process"), errno);
}
return;
}
/*
* NAME: thread_k
*
* FUNCTION: lists all existing pthreads threads
*
* NOTE: See diagram (top of file) for method used in transversing thread queue
* Part of "thread current" (with id) is handled in eval() and routine
* switchThread_k.
*
* PARAMETERS:
* option - option issued with the thread subcommand
* p - Node contain list of thread id's to act on
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
public void thread_k(option, p)
thread_op option;
Node p;
{
Address known_thread_addr; /* hold address of __dbx_known_pthreads*/
pthread_queue q_buf; /* hold queue portion of cur thread */
pthread_queue *ptr; /* pointer to queue buffer */
int thread_id; /* id of thread */
unsigned long t_id; /* thread id of thread */
unsigned long state; /* state of thread */
unsigned long state_u; /* state of thread */
unsigned long cursig; /* cursig of thread */
int is_held; /* Using int here to held holding thread*/
Symbol known_threads; /* Symbol for thread object list */
Symbol thisthread; /* Symbol for this thread */
Boolean print_title = true; /* set if we want the title displayed */
Boolean list_this; /* set if this thread is selected */
Boolean fullinfo = false; /* set if we have "thread info" */
int badread; /* set if we can dread failed */
Boolean thread_found = false; /* set if we find specified thread */
vp_st *vp_addr; /* address of vp */
/* Find address for thread queue start - __dbx_known_pthreads */
known_threads = lookup(identname("__dbx_known_pthreads",true));
if (known_threads == nil) {
/* complain if we are setting non-existing threads... */
if (option == th_hold ||
option == th_unhold ||
(option == th_current && p))
k_error( catgets(scmc_catd, MS_pthread, MSG_767,
"no thread available"));
return;
} else if (!isactive(known_threads->block)) {
/* don't complain if we are just getting thread info... */
if (option != th_get_info)
error(catgets(scmc_catd,MS_runtime, MSG_265,
"program is not active"));
return;
} else {
eval(amper(build(O_SYM, known_threads)));
known_thread_addr = pop(Address);
/* Fill in content of the first queue section */
badread = dread(&q_buf, known_thread_addr, sizeof(pthread_queue));
/* escape out if cannot read known thread queue */
if (badread) {
/* warning message already displayed by dread */
return;
}
ptr = QUEUE_NEXT(q_buf);
/* reset running and current thread if nothing in queue */
if ( ptr == known_thread_addr) {
running_thread = current_thread = nil;
}
/* update the kernel informations */
if ( option == th_get_info && ptr != nil)
update_threads(known_thread_addr);
verifArgObject_k(known_thread_addr,OBJ_THREAD,p);
while ( ptr != nil && ptr != known_thread_addr) {
/* Does it point at active_pthreads */
/* Find out what thread id we are dealing with... */
badread = dread(&thread_id, (Address) ( (int)ptr +
offsetof2(pthread_st, th_id)), sizeof(unsigned));
if (badread) return;
/* check and see if it is requested by number */
/* if no arg (p == nil), list all... */
list_this = (!p || isRequested_k(p,thread_id));
/* find any thread yet? */
thread_found = thread_found || list_this;
/* get state of the thread... */
badread= dread(&state, (Address) ((int)ptr+
offsetof2(pthread_st,ti_stat)),sizeof(unsigned long));
if (badread) return;
badread = dread(&state_u, (Address) ((int)ptr+
offsetof2(pthread_st,state)), sizeof(unsigned long));
if (badread) return;
/* selected thread and state = actived */
/* eliminate the pthread structure with state PTHREAD_RETURNED */
/* this structure is no more attached to a pthread */
if ( state_u & PTHREAD_RETURNED) list_this = false;
if (list_this ) {
badread = dread(&cursig, (Address) ((int)ptr+offsetof2
(pthread_st,ti_cursig)),sizeof(unsigned long));
if (badread) return;
/* find dbx symbol for this thread... */
thisthread = update_pthreads_obj("$t", thread_id, ptr,
thread_object.sym);
/* if coredump select all threads */
if (coredump) state = TSRUN ;
/* handle different options... */
if ((option == th_run && !IS_RUNNING(state)) ||
(option == th_susp && !IS_SUSP(state)) ||
(option == th_term && !IS_TERM(state)) ||
(option == th_wait && !IS_WAIT(state)) ){
/* check and see if it's in the state requested */
list_this = false;
} else if (option == th_get_info) {
/* update running_thread and current thread in case of core */
if(coredump) {
badread = dread(&vp_addr, (Address) ((int) ptr +
offsetof2(pthread_st, vp)), sizeof(Address ));
if (badread) return;
if (vp_addr != nil ){
badread = dread(&t_id, (Address) ((int) vp_addr +
offsetof(vp_st,id )), sizeof(unsigned long ));
if (badread) return;
}
/* the running thread is the thread responsible of
core dump : the mst of this thread is in the header */
if (find_thread(t_id) == &corehdr.c_mst) {
running_thread = thisthread;
process->tid = t_id;
current_thread = running_thread;
}
}
/* updating thread info quickly */
if (IS_RESPONSIBLE(cursig)) {
/* create or update $running_thread symbol */
update_running_thread( (Address) ( (int)ptr +
offsetof2(pthread_st, th_id)));
running_thread = thisthread;
current_thread = running_thread;
}
list_this = false;
} else if (option == th_current) {
if (p) {
/* argument is provided to change current thread */
switchThread_k(thisthread);
list_this = false;
} else if (current_thread != thisthread)
/* no argument, just list the current thread */
list_this = false;
} else if (option == th_info) {
fullinfo = true;
} else if (option == th_hold ||
option == th_unhold) {
/* set the field to hold or unhold threads... */
/* cannot hold or unhold null thread */
is_held = (option == th_hold);
dwrite(&is_held, (Address) ((int)ptr +
offsetof2(pthread_st,ti_hold)),
sizeof(int));
} else if (option == th_hold_other ||
option == th_unhold_other) {
/* If $hold_next is set... */
/* Suspend non-running thread, used when dbx does single- */
/* steps. */
if (option == th_hold_other)
hold_other = true;
else
hold_other = false;
list_this = false;
}
}
/* If we still want it, display it... */
if (list_this) {
display_thread_k(ptr, thread_id, state, &print_title,
fullinfo, thisthread);
if (fullinfo) {
thread_info_k(ptr);
}
} /* display thread */
/* Get contents of next queue section */
badread = dread(&q_buf, ptr, sizeof(pthread_queue));
if (badread) return;
ptr = QUEUE_NEXT(q_buf); /* advances forward link */
}
}
}
/*
* NAME: attribute_k
*
* FUNCTION: Lists all existing pthreads attribute objects
*
* NOTE: See diagram (top of file) for method used in transversing thread queue
*
* PARAMETERS:
* option - option issued with the attribute subcommand
* p - Node contain list of attribute id's to act on
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
public void attribute_k(option, p)
attribute_op option;
Node p;
{
Address acb_addr; /* address of attr control block */
Address known_attr_addr; /*address of __dbx_known_attributes */
pthread_queue q_buf; /* hold queue portion of attribute */
pthread_queue *ptr; /* pointer to queue buffer */
int type; /* attribute type */
int state; /* attribute state */
int attr_id; /* attribute id */
int priority; /* priority of new thread */
int policy; /* sched policy of thread */
int detachstate; /* sched policy of thread */
int processshared; /* sched policy of thread */
int prio_ceil; /* sched policy of thread */
int inherit_sched; /* is scheduling inherited? */
int scheduler; /* schesuling policy */
int scope; /* contentionscope:global or local*/
int protocol; /* for mutex */
unsigned int stack_size; /* size of stack (bytes) */
Symbol known_attr = lookup(identname("__dbx_known_attributes",true));
Boolean print_title = true;
Boolean list_this;
int badread;
if (known_attr == nil) {
return;
} else if (!isactive(known_attr->block)) {
/* don't complain if we are just getting thread info... */
if (option != th_get_info)
error(catgets(scmc_catd,MS_runtime, MSG_265,
"program is not active"));
return;
} else {
eval(amper(build(O_SYM, known_attr)));
known_attr_addr = pop(Address);
badread = dread(&q_buf, known_attr_addr, sizeof(pthread_queue));
/* escape out if cannot read known attribute queue */
if (badread) {
/* warning message already displayed by dread */
return;
}
ptr = QUEUE_NEXT(q_buf);
verifArgObject_k(known_attr_addr,OBJ_ATTRIBUTE,p);
while ( ptr != nil && ptr != known_attr_addr) {
/* get addr of attr object */
acb_addr = (Address) ptr;
/* get id for this attribute object */
badread = dread(&attr_id, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, attr_id)), sizeof(int));
if (badread) return;
/* check and see if we are asked to display this... */
list_this = (!p || isRequested_k(p,attr_id));
if (option == th_get_info) list_this = false;
/* if so, read other info needed for display... */
if (list_this) {
badread = dread(&type, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, type)), sizeof(int));
if (badread) return;
badread = dread(&priority, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, schedule.sched_priority)),
sizeof(int));
if (badread) return;
badread = dread(&state, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, flags)), sizeof(int));
if (badread) return;
badread = dread(&scope, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, contentionscope)), sizeof(int));
if (badread) return;
badread = dread(&protocol, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, protocol)), sizeof(int));
if (badread) return;
badread = dread(&scheduler, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, schedule.sched_policy)),
sizeof(int));
if (badread) return;
badread = dread(&prio_ceil, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, prio_ceiling)), sizeof(int));
if (badread) return;
badread = dread(&stack_size, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, stacksize)), sizeof(int));
if (badread) return;
badread = dread(&detachstate, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, detachstate)), sizeof(int));
if (badread) return;
badread = dread(&processshared, (Address) ((int)acb_addr +
offsetof(pthread_attr_st, process_shared)), sizeof(int));
if (badread) return;
/* prepare the output */
if (type == ATTR_THREAD) { /* thread attribute */
processshared = NO_P_SHARED;
protocol = NO_PROTOCOL;
} else { /* mutex or condition attribute */
scope = NO_SCOPE;
priority = 0;
stack_size = 0;
scheduler = NO_SCHEDULER;
if (type == ATTR_COND) protocol = NO_PROTOCOL;
}
/* control fields */
control_value(type, ERROR_TYPE);
control_value(scope, ERROR_SCOPE);
control_value(scheduler, ERROR_SCHEDULER);
control_value(processshared, ERROR_P_SHARED);
control_value(protocol, ERROR_PROTOCOL);
control_value(state, ERROR_STATE);
/* display title is needed... */
if (print_title) {
(*rpt_output)(stdout,
" attr obj_addr type state stack scope prio sched p-shar protocol \n");
print_title = false;
}
/* Output attr object info... */
(*rpt_output)(stdout,
" $a%-4d 0x%-8x %-5.5s %-5.5s ",
(int)attr_id, acb_addr, attr_type[type],
attr_state[state]);
if (type == 0) {
(*rpt_output)(stdout,"%6d %-3.3s %6d %-5.5s",
(int)stack_size,
attr_contention[scope],
priority,
attr_sched[scheduler]);
}
else {
(*rpt_output)(stdout," ");
(*rpt_output)(stdout," %-3.3s",
attr_shared[processshared]);
if (type == 1) {
(*rpt_output)(stdout," %-8.8s",
attr_protocol[protocol]);
}
}
(*rpt_output)(stdout, "\n");
}
/* create attribute object and insert into dbx symbol table */
update_pthreads_obj("$a", attr_id, acb_addr, attr_object.sym);
/* Get contents of next queue section */
badread = dread(&q_buf, ptr, sizeof(pthread_queue));
if (badread) return;
ptr = QUEUE_NEXT(q_buf); /* advances forward link */
}
}
}
/*
* NAME: condition_k
*
* FUNCTION: Lists all existing pthreads condition variable
*
* NOTE: See diagram (top of file) for method used in transversing thread queue
*
* PARAMETERS:
* option - option issued with the condition subcommand
* p - Node contain list of condition variable id's to act on
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
public void condition_k(option, p)
condition_op option;
Node p;
{
Address ccb_addr; /* address of cv control block */
Address known_attr_addr; /* address of __dbx_known_conditions*/
pthread_queue q_buf; /* hold queue portion of attribute */
pthread_queue *ptr; /* pointer to queue buffer */
int cv_id; /* id of condition variable */
__ptq_queue semaphore_queue; /* semaphore queue for cond. wait */
int num_wait; /* number of waiter cv has */
Symbol known_attr = lookup(identname("__dbx_known_conditions",true));
Boolean print_title = true;
Boolean list_this;
int badread;
Address p_cond; /* pointer on condition */
if (known_attr == nil) {
return;
} else if (!isactive(known_attr->block)) {
/* don't complain if we are just getting thread info... */
if (option != th_get_info)
error(catgets(scmc_catd,MS_runtime, MSG_265,
"program is not active"));
return;
} else {
eval(amper(build(O_SYM, known_attr)));
known_attr_addr = pop(Address);
/* Fill in content of the first queue section */
known_attr_addr = known_attr_addr +
offsetof(pthread_cond_t, link),
badread = dread(&q_buf, known_attr_addr, sizeof(pthread_queue));
/* escape out if cannot read known cvs queue */
if (badread) {
/* warning message already displayed by dread */
return;
}
ptr = QUEUE_NEXT(q_buf);
verifArgObject_k(known_attr_addr,OBJ_CONDITION,p);
while ( ptr != nil && ptr != known_attr_addr) {
num_wait = 0; /* reset number of waiters */
p_cond = (Address) ptr; /* get addr of cv object */
/* the list of condition contains the pointer */
badread = dread(&ccb_addr, (Address) ((int)p_cond +
offsetof(__dbx_cond, pt_cond)), sizeof(int));
if (badread) return;
/* get id and semaphore queue for this condition variable */
badread = dread(&cv_id, (Address) ((int)ccb_addr +
offsetof(pthread_cond_t, cv_id)), sizeof(int));
if (badread) return;
badread = dread(&semaphore_queue, (Address) ((int)ccb_addr +
offsetof(pthread_cond_t, waiters)), sizeof(__ptq_queue));
if (badread) return;
/* check and see if we are asked to display this... */
list_this = (!p || isRequested_k(p,cv_id));
if (option == th_get_info) list_this = false;
/* check if only wait or nowait conditions are requested... */
if (list_this) {
/* find out how many waiters... */
num_wait = getWaiters_k((Address)((int)ccb_addr +
offsetof(pthread_cond_t, waiters)),false);
if ( ((option == cv_wait) && !num_wait) ||
((option == cv_nowait) && num_wait) )
list_this = false;
}
/* if we still want this cv, display it... */
if (list_this) {
if (print_title) {
(*rpt_output)(stdout,
" cv obj_addr num_wait waiters\n");
print_title = false;
}
/* Output cv object info... */
(*rpt_output)(stdout, " $c%-4d 0x%-8x %8d ",
(int)cv_id, ccb_addr, num_wait);
/* call getWaiters_k() to print names of waiters... */
if (num_wait > 0)
getWaiters_k((Address)((int)ccb_addr +
offsetof(pthread_cond_t, waiters)),true);
(*rpt_output)(stdout, "\n");
} /* display cv info */
/* create attribute object and insert into dbx symbol table */
update_pthreads_obj("$c", cv_id, ccb_addr, cv_object.sym);
/* Get contents of next queue section */
badread = dread(&q_buf, ptr, sizeof(pthread_queue));
if (badread) return;
ptr = QUEUE_NEXT(q_buf); /* advances forward link */
}
}
}
/*
* NAME: mutex_k
*
* FUNCTION: Lists all existing mutex objects
*
* NOTE: See diagram (top of file) for method used in transversing thread queue
*
* PARAMETERS:
* option - option issued with the mutex subcommand
* p - Node contain list of mutex id's to act on
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
public void mutex_k(option, p)
mutex_op option;
Node p;
{
Address mcb_addr; /* address of mutex control block */
Address known_mutex_addr; /* address of dbx__known_mutexes */
pthread_queue q_buf; /* hold queue portion of mutex */
pthread_queue *ptr; /* pointer to queue buffer */
int mutex_id; /* id of mutex */
pthread_t owner_thread; /* address of mutex owner thread */
int owner_id; /* id of mutex owner */
int kind; /* kind of attr of mutex */
__ptlock_type islock; /* set if mutex is locked */
Symbol known_mutexes = lookup(identname("__dbx_known_mutexes",true));
Boolean print_title = true;
Boolean list_this;
int badread;
Address p_mutex; /* pointer on __dbx_mutex */
if (known_mutexes == nil) {
return;
} else if (!isactive(known_mutexes->block)) {
/* don't complain if we are just getting thread info... */
if (option != th_get_info)
error(catgets(scmc_catd,MS_runtime, MSG_265,
"program is not active"));
return;
} else {
eval(amper(build(O_SYM, known_mutexes)));
known_mutex_addr = pop(Address);
/* Fill in content of the first queue section */
badread = dread(&q_buf, known_mutex_addr, sizeof(__ptq_queue));
/* escape out if cannot read known mutex queue */
if (badread) {
/* warning message already displayed by dread */
return;
}
ptr = QUEUE_NEXT(q_buf);
verifArgObject_k(known_mutex_addr,OBJ_MUTEX,p);
while ( ptr != nil && ptr != known_mutex_addr) {
owner_id = 0; /* reset mutex owner id */
p_mutex = (Address) ptr; /* get addr of mutex object */
badread = dread(&mcb_addr, (Address) ((int)p_mutex +
offsetof(__dbx_mutex, pt_mutex)), sizeof(int));
if (badread) return;
/* get mutex id for this mutex object */
badread = dread(&mutex_id, (Address) ((int)mcb_addr +
offsetof(pthread_mutex_t, mtx_id)), sizeof(int));
if (badread) return;
/* check and see if we are asked to display this... */
list_this = (!p || isRequested_k(p,mutex_id));
if (option == th_get_info) list_this = false;
/* check if only locked or unlocked mutexes are requested... */
if (list_this) {
/* read mutex info islock, and owner... */
badread = dread(&islock, (Address) ((int)mcb_addr +
offsetof(pthread_mutex_t, lock)), sizeof(int));
if (badread) return;
badread = dread(&kind, (Address) ((int)mcb_addr +
offsetof(pthread_mutex_t, mtx_kind)), sizeof(int));
if (badread) return;
badread = dread(&owner_thread, (Address) ((int)mcb_addr +
offsetof(pthread_mutex_t, owner)), sizeof(pthread_t));
if (badread) return;
badread = dread(&owner_id, (Address) ( (int)owner_thread +
offsetof(pthread_st, th_id)), sizeof(unsigned));
if (badread) return;
if ( ((option == mu_lock) && !islock) ||
((option == mu_unlock) && islock) ) {
list_this = false;
}
}
control_value(kind, ERROR_KIND);
/* if we still want this mutex, display it... */
if (list_this) {
if (print_title) {
(*rpt_output)(stdout,
" mutex obj_addr type lock owner \n");
print_title = false;
}
/* Output mutex object info... */
(*rpt_output)(stdout, " $m%-3d 0x%8x %-7s %4s ",
(int)mutex_id,
mcb_addr,
attr_kind[kind],
(int)islock?"yes":"no");
if (islock && (owner_thread != nil))
(*rpt_output)(stdout, "$t%-3d ", (int)owner_id);
else
(*rpt_output)(stdout, "%7s", "");
(*rpt_output)(stdout, "\n");
} /* display mutex info */
/* create mutex object and insert into dbx symbol table */
update_pthreads_obj("$m", mutex_id, mcb_addr, mutex_object.sym);
/* Get contents of next queue section */
badread = dread(&q_buf, ptr, sizeof(pthread_queue));
if (badread) return;
ptr = QUEUE_NEXT(q_buf); /* advances forward link */
}
}
}
extern tid_t tid_func_thread;
extern Frame callframe;
extern Word caller_reg[NGREG+NSYS+1];
extern double caller_freg[MAXSAVEFREG];
extern Boolean call_command;
extern boolean notderefed;
extern boolean specificptrtomember;
/*
* NAME: threadheld
*
* FUNCTION: Allows the holding of the running_thread
* The running_thread will execute the subroutine __funcbloc_np
*
* Modify the pc register
*
* NOTE: It's the same sequence (approximatly) that callproc()
* Used by thread_k_cont() before calling ptrace
*
* PARAMETERS: NONE
*
* RECOVERY OPERATION: NONE NEEDED
*
* DATA STRUCTURES: NONE
*
* RETURNS: NONE
*/
private void threadheld ()
{
Symbol proc = nil;
integer argc, i;
static struct Frame frame;
Name n;
Address funcAddr;
Address orig_pc;
funcAddr = nil;
orig_pc = reg(SYSREGNO(IAR));
n = identname("__funcblock_np",true);
find(proc, n) where isroutine(proc) endfind(proc);
if (proc == nil) {
error( catgets(scmc_catd, MS_execute, MSG_162,
"Failed establishing calling point (libg.a not linked)"));
}
/* Save off the current frame before we start the call */
callframe = &frame;
getcurframe(callframe);
pushenv();
/* Also save off all registers before the call */
for (i = 0; i < NGREG + NSYS + 1; i++) {
caller_reg[i] = reg(i);
}
for (i = 0; i < fpregs; i++) {
caller_freg[i] = fpregval(i);
}
if (funcAddr) {
pc = funcAddr;
}
else {
pc = codeloc(proc);
}
/*argc = pushargs(proc, arglist, thisptr);*/
orig_pc = reg(SYSREGNO(IAR));
tid_func_thread = tid_running_thread;
call_command = true;
/* to indicate __funcblock_np called */
addr_dbsubn = codeloc(proc);
beginproc(proc, 0, funcAddr);
/* build a special command run after return function : eval calls procreturn */
/* cont - bpact - evalcmdlist - eval - procreturn - flushoutput - beginproc -*/
/* (fflush) stepto .. */
/* fflush is executed */
event_once(
build(O_EQ, build(O_SYM, pcsym), build(O_SYM, retaddrsym)),
buildcmdlist(build(O_PROCRTN, proc))
);
n = identname("__dbsubn",true);
find(proc, n) where isroutine(proc) endfind(proc);
if (proc == nil) {
error( catgets(scmc_catd, MS_execute, MSG_162,
"Failed establishing calling point (libg.a not linked)"));
}
setbp(codeloc(proc));
isstopped = false;
if (not bpact()) {
notderefed = true;
specificptrtomember = false;
isstopped = true;
}
/* indicate to the function bpact() that the running_thread was held */
/* the next break-point will call procreturn() to restore its registers*/
addr_dbsubn = codeloc(proc);
}
/*
* NAME: check_thread_stacks
*
* FUNCTION: Determines whether a passed address is in one of the
* stacks for an active thread.
* If it is, then returns the start and end of the stack.
*
* RECOVERY OPERATION: none
*
* PARAMETERS:
* address - address to be checked (input)
* start - if the passed address is in a stack, then the
* start of the stack is returned in this
* parameter.
* Otherwise, 0 is returned in this parameter.
* (output)
* end - if the passed address is in a stack, then the
* end of the stack is returned in this
* parameter.
* Otherwise, 0 is returned in this parameter.
* (output)
*
* DATA STRUCTURES: none
*
* RETURNS: void
* start and end parameters are returned as defined above.
*
*/
public void check_thread_stacks(uint address,
uint *start,
uint *end)
{
Address known_thread_addr; /* hold address of __dbx_known_pthreads */
pthread_queue q_buf; /* hold queue portion of current thread */
pthread_queue *ptr; /* pointer to queue buffer */
unsigned long t_id; /* thread id of thread */
unsigned long state; /* state of thread */
unsigned long state_u; /* state of thread */
Symbol known_threads; /* Symbol for thread object list */
vp_st *vp_addr; /* address of vp */
int i;
Address stack_limit; /* address for top of stack */
int badread;
tid_t ti_tid;
tid_t save_tid;
Address stack_pointer; /* stack pointer for the thread */
*start = *end = 0;
/* Find address for thread queue start - __dbx_known_pthreads */
known_threads = lookup(identname("__dbx_known_pthreads",true));
if ((known_threads != nil) && (isactive(known_threads->block)))
{
eval(amper(build(O_SYM, known_threads)));
known_thread_addr = pop(Address);
/* Fill in content of the first queue section */
badread = dread(&q_buf, known_thread_addr, sizeof(pthread_queue));
/* escape out if cannot read known thread queue */
if (badread) {
/* warning message already displayed by dread */
return;
}
ptr = QUEUE_NEXT(q_buf);
while ((ptr != nil) &&
(ptr != known_thread_addr) &&
(*start == 0) &&
(*end == 0))
{
badread = dread(&ti_tid, (Address) ((int) ptr +
offsetof2(pthread_st, ti_tid)), sizeof(int));
if (badread) return;
/* get state of the thread... */
badread= dread(&state, (Address) ((int)ptr+
offsetof2(pthread_st,ti_stat)),sizeof(unsigned long));
if (badread) return;
badread = dread(&state_u, (Address) ((int)ptr+
offsetof2(pthread_st,state)), sizeof(unsigned long));
if (badread) return;
/*
skip a thread with state = PTHREAD_RETURNED
since it is longer attached to a pthread
*/
if ( !(state_u & PTHREAD_RETURNED))
{
badread = dread(&vp_addr, (Address) ((int) ptr +
offsetof2(pthread_st, vp)), sizeof(Address ));
if (badread) return;
badread = dread(&stack_limit, (Address) ((int) vp_addr +
offsetof(vp_st, stack.limit)), sizeof(unsigned long ));
if (badread) return;
/*
Read general registers for thread in order
to get value of stack pointer
*/
save_tid = process->tid;
process->tid = ti_tid; /* for readgprs sp */
readgprs(process,&process->reg[0]);
stack_pointer = reg(GPR1);
/* restore registers of the current thread */
process->tid = save_tid;
readgprs(process,&process->reg[0]);
/*
check if address is within the bounds of the
stack for the thread being checked
*/
if ((address <= stack_limit && address >= stack_pointer) )
{
*start = stack_pointer;
*end = stack_limit;
}
}
/* Get contents of next queue section */
badread = dread(&q_buf, ptr, sizeof(pthread_queue));
if (badread) return;
/* move pointer to next element in thread queue */
ptr = QUEUE_NEXT(q_buf);
}
}
}
#else
#include "defs.h"
#include "symbols.h"
getMutexOpt_k(){}
getConditionOpt_k() {}
getAttributeOpt_k() {}
getThreadOpt_k() {}
thread_k() {}
condition_k() {}
mutex_k() {}
attribute_k() {}
switchThread_k() {}
public boolean isThreadObjectSymbol_k(ThreadObjectSym)
Symbol ThreadObjectSym;
{
return(false);
}
#endif /* K_THREADS */