td_err_e td_ta_get_nthreads (const td_thragent_t *ta_arg, int *np) { td_thragent_t *const ta = (td_thragent_t *) ta_arg; td_err_e err; psaddr_t n; LOG ("td_ta_get_nthreads"); /* Test whether the TA parameter is ok. */ if (! ta_ok (ta)) return TD_BADTA; /* Access the variable in the inferior that tells us. */ err = DB_GET_VALUE (n, ta, __nptl_nthreads, 0); if (err == TD_OK) *np = (uintptr_t) n; return err; }
td_err_e td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data) { td_err_e err; psaddr_t tk_seq, level1, level2, seq, value; void *copy; uint32_t pthread_key_2ndlevel_size, idx1st, idx2nd; LOG ("td_thr_tsd"); /* Get the key entry. */ err = DB_GET_VALUE (tk_seq, th->th_ta_p, __pthread_keys, tk); if (err == TD_NOAPLIC) return TD_BADKEY; if (err != TD_OK) return err; /* Fail if this key is not at all used. */ if (((uintptr_t) tk_seq & 1) == 0) return TD_BADKEY; /* This makes sure we have the size information on hand. */ err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, 0, pthread_key_data_level2, data, 1); if (err != TD_OK) return err; /* Compute the indeces. */ pthread_key_2ndlevel_size = DB_DESC_NELEM (th->th_ta_p->ta_field_pthread_key_data_level2_data); idx1st = tk / pthread_key_2ndlevel_size; idx2nd = tk % pthread_key_2ndlevel_size; /* Now fetch the first level pointer. */ err = DB_GET_FIELD (level1, th->th_ta_p, th->th_unique, pthread, specific, idx1st); if (err == TD_NOAPLIC) return TD_DBERR; if (err != TD_OK) return err; /* Check the pointer to the second level array. */ if (level1 == 0) return TD_NOTSD; /* Locate the element within the second level array. */ err = DB_GET_FIELD_ADDRESS (level2, th->th_ta_p, level1, pthread_key_data_level2, data, idx2nd); if (err == TD_NOAPLIC) return TD_DBERR; if (err != TD_OK) return err; /* Now copy in that whole structure. */ err = DB_GET_STRUCT (copy, th->th_ta_p, level2, pthread_key_data); if (err != TD_OK) return err; /* Check whether the data is valid. */ err = DB_GET_FIELD_LOCAL (seq, th->th_ta_p, copy, pthread_key_data, seq, 0); if (err != TD_OK) return err; if (seq != tk_seq) return TD_NOTSD; /* Finally, fetch the value. */ err = DB_GET_FIELD_LOCAL (value, th->th_ta_p, copy, pthread_key_data, data, 0); if (err == TD_OK) *data = value; return err; }
td_err_e td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop) { td_err_e err; void *copy; psaddr_t tls, schedpolicy, schedprio, cancelhandling, tid, report_events; LOG ("td_thr_get_info"); if (th->th_unique == 0) { /* Special case for the main thread before initialization. */ copy = NULL; tls = 0; cancelhandling = 0; schedprio = 0; tid = 0; err = DB_GET_VALUE (report_events, th->th_ta_p, __nptl_initial_report_events, 0); } else { /* Copy the whole descriptor in once so we can access the several fields locally. Excess copying in one go is much better than multiple ps_pdread calls. */ err = DB_GET_STRUCT (copy, th->th_ta_p, th->th_unique, pthread); if (err != TD_OK) return err; err = DB_GET_FIELD_ADDRESS (tls, th->th_ta_p, th->th_unique, pthread, specific, 0); if (err != TD_OK) return err; err = DB_GET_FIELD_LOCAL (schedpolicy, th->th_ta_p, copy, pthread, schedpolicy, 0); if (err != TD_OK) return err; err = DB_GET_FIELD_LOCAL (schedprio, th->th_ta_p, copy, pthread, schedparam_sched_priority, 0); if (err != TD_OK) return err; err = DB_GET_FIELD_LOCAL (tid, th->th_ta_p, copy, pthread, tid, 0); if (err != TD_OK) return err; err = DB_GET_FIELD_LOCAL (cancelhandling, th->th_ta_p, copy, pthread, cancelhandling, 0); if (err != TD_OK) return err; err = DB_GET_FIELD_LOCAL (report_events, th->th_ta_p, copy, pthread, report_events, 0); } if (err != TD_OK) return err; /* Fill in information. Clear first to provide reproducable results for the fields we do not fill in. */ memset (infop, '\0', sizeof (td_thrinfo_t)); infop->ti_tid = (thread_t) th->th_unique; infop->ti_tls = (char *) tls; infop->ti_pri = ((uintptr_t) schedpolicy == SCHED_OTHER ? 0 : (uintptr_t) schedprio); infop->ti_type = TD_THR_USER; if ((((int) (uintptr_t) cancelhandling) & EXITING_BITMASK) == 0) /* XXX For now there is no way to get more information. */ infop->ti_state = TD_THR_ACTIVE; else if ((((int) (uintptr_t) cancelhandling) & TERMINATED_BITMASK) == 0) infop->ti_state = TD_THR_ZOMBIE; else infop->ti_state = TD_THR_UNKNOWN; /* Initialization which are the same in both cases. */ infop->ti_ta_p = th->th_ta_p; infop->ti_lid = tid == 0 ? ps_getpid (th->th_ta_p->ph) : (uintptr_t) tid; infop->ti_traceme = report_events != 0; if (copy != NULL) err = DB_GET_FIELD_LOCAL (infop->ti_startfunc, th->th_ta_p, copy, pthread, start_routine, 0); if (copy != NULL && err == TD_OK) { uint32_t idx; for (idx = 0; idx < TD_EVENTSIZE; ++idx) { psaddr_t word; err = DB_GET_FIELD_LOCAL (word, th->th_ta_p, copy, pthread, eventbuf_eventmask_event_bits, idx); if (err != TD_OK) break; infop->ti_events.event_bits[idx] = (uintptr_t) word; } if (err == TD_NOAPLIC) memset (&infop->ti_events.event_bits[idx], 0, (TD_EVENTSIZE - idx) * sizeof infop->ti_events.event_bits[0]); } return err; }