Exemple #1
0
td_err_e
td_ta_tsd_iter (const td_thragent_t *ta_arg, td_key_iter_f *callback,
		void *cbdata_p)
{
  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
  td_err_e err;
  void *keys;
  size_t keys_nb, keys_elemsize;
  psaddr_t addr;
  uint32_t idx;

  LOG ("td_ta_tsd_iter");

  /* Test whether the TA parameter is ok.  */
  if (! ta_ok (ta))
    return TD_BADTA;

  /* This makes sure we have the size information on hand.  */
  addr = 0;
  err = _td_locate_field (ta,
			  ta->ta_var___pthread_keys, SYM_DESC___pthread_keys,
			  (psaddr_t) 0 + 1, &addr);
  if (err != TD_OK)
    return err;

  /* Now copy in the entire array of key descriptors.  */
  keys_elemsize = (addr - (psaddr_t) 0) / 8;
  keys_nb = keys_elemsize * DB_DESC_NELEM (ta->ta_var___pthread_keys);
  keys = __alloca (keys_nb);
  err = DB_GET_SYMBOL (addr, ta, __pthread_keys);
  if (err != TD_OK)
    return err;
  if (ps_pdread (ta->ph, addr, keys, keys_nb) != PS_OK)
    return TD_ERR;

  /* Now get all descriptors, one after the other.  */
  for (idx = 0; idx < DB_DESC_NELEM (ta->ta_var___pthread_keys); ++idx)
    {
      psaddr_t seq, destr;
      err = DB_GET_FIELD_LOCAL (seq, ta, keys, pthread_key_struct, seq, 0);
      if (err != TD_OK)
	return err;
      if (((uintptr_t) seq) & 1)
	{
	  err = DB_GET_FIELD_LOCAL (destr, ta, keys, pthread_key_struct,
				    destr, 0);
	  if (err != TD_OK)
	    return err;
	  /* Return with an error if the callback returns a nonzero value.  */
	  if (callback ((thread_key_t) idx, destr, cbdata_p) != 0)
	    return TD_DBERR;
	}
      /* Advance to the next element in the copied array.  */
      keys += keys_elemsize;
    }

  return TD_OK;
}
Exemple #2
0
td_err_e
td_ta_clear_event (const td_thragent_t *ta_arg, td_thr_events_t *event)
{
  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
  td_err_e err;
  psaddr_t eventmask = 0;
  void *copy = NULL;

  LOG ("td_ta_clear_event");

  /* Test whether the TA parameter is ok.  */
  if (! ta_ok (ta))
    return TD_BADTA;

  /* Fetch the old event mask from the inferior and modify it in place.  */
  err = DB_GET_SYMBOL (eventmask, ta, __nptl_threads_events);
  if (err == TD_OK)
    err = DB_GET_STRUCT (copy, ta, eventmask, td_thr_events_t);
  if (err == TD_OK)
    {
      uint32_t idx;
      for (idx = 0; idx < TD_EVENTSIZE; ++idx)
	{
	  psaddr_t word;
	  uint32_t mask;
	  err = DB_GET_FIELD_LOCAL (word, ta, copy,
				    td_thr_events_t, event_bits, idx);
	  if (err != TD_OK)
	    break;
	  mask = (uintptr_t) word;
	  mask &= ~event->event_bits[idx];
	  word = (psaddr_t) (uintptr_t) mask;
	  err = DB_PUT_FIELD_LOCAL (ta, copy,
				    td_thr_events_t, event_bits, idx, word);
	  if (err != TD_OK)
	    break;
	}
      if (err == TD_NOAPLIC)
	{
	  err = TD_OK;
	  while (idx < TD_EVENTSIZE)
	    if (event->event_bits[idx++] != 0)
	      {
		err = TD_NOEVENT;
		break;
	      }
	}
      if (err == TD_OK)
	/* Now write it back to the inferior.  */
	err = DB_PUT_STRUCT (ta, eventmask, td_thr_events_t, copy);
    }

  return err;
}
Exemple #3
0
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;
}
static td_err_e
iterate_thread_list (td_thragent_t *ta, td_thr_iter_f *callback,
		     void *cbdata_p, td_thr_state_e state, int ti_pri,
		     psaddr_t head, bool fake_empty, pid_t match_pid)
{
  td_err_e err;
  psaddr_t next, ofs;
  void *copy;

  /* Test the state.
     XXX This is incomplete.  Normally this test should be in the loop.  */
  if (state != TD_THR_ANY_STATE)
    return TD_OK;

  err = DB_GET_FIELD (next, ta, head, list_t, next, 0);
  if (err != TD_OK)
    return err;

  if (next == 0 && fake_empty)
    {
      /* __pthread_initialize_minimal has not run.  There is just the main
	 thread to return.  We cannot rely on its thread register.  They
	 sometimes contain garbage that would confuse us, left by the
	 kernel at exec.  So if it looks like initialization is incomplete,
	 we only fake a special descriptor for the initial thread.  */
      td_thrhandle_t th = { ta, 0 };
      return callback (&th, cbdata_p) != 0 ? TD_DBERR : TD_OK;
    }

  /* Cache the offset from struct pthread to its list_t member.  */
  err = DB_GET_FIELD_ADDRESS (ofs, ta, 0, pthread, list, 0);
  if (err != TD_OK)
    return err;

  if (ta->ta_sizeof_pthread == 0)
    {
      err = _td_check_sizeof (ta, &ta->ta_sizeof_pthread, SYM_SIZEOF_pthread);
      if (err != TD_OK)
	return err;
    }
  copy = __alloca (ta->ta_sizeof_pthread);

  while (next != head)
    {
      psaddr_t addr, schedpolicy, schedprio;

      addr = next - (ofs - (psaddr_t) 0);
      if (next == 0 || addr == 0) /* Sanity check.  */
	return TD_DBERR;

      /* 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.  */
      if (ps_pdread (ta->ph, addr, copy, ta->ta_sizeof_pthread) != PS_OK)
	return TD_ERR;

      /* Verify that this thread's pid field matches the child PID.
	 If its pid field is negative, it's about to do a fork or it
	 is the sole thread in a fork child.  */
      psaddr_t pid;
      err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, pid, 0);
      if (err == TD_OK && (pid_t) (uintptr_t) pid < 0)
	{
	  if (-(pid_t) (uintptr_t) pid == match_pid)
	    /* It is about to do a fork, but is really still the parent PID.  */
	    pid = (psaddr_t) (uintptr_t) match_pid;
	  else
	    /* It must be a fork child, whose new PID is in the tid field.  */
	    err = DB_GET_FIELD_LOCAL (pid, ta, copy, pthread, tid, 0);
	}
      if (err != TD_OK)
	break;

      if ((pid_t) (uintptr_t) pid == match_pid)
	{
	  err = DB_GET_FIELD_LOCAL (schedpolicy, ta, copy, pthread,
				    schedpolicy, 0);
	  if (err != TD_OK)
	    break;
	  err = DB_GET_FIELD_LOCAL (schedprio, ta, copy, pthread,
				    schedparam_sched_priority, 0);
	  if (err != TD_OK)
	    break;

	  /* Now test whether this thread matches the specified conditions.  */

	  /* Only if the priority level is as high or higher.  */
	  int descr_pri = ((uintptr_t) schedpolicy == SCHED_OTHER
			   ? 0 : (uintptr_t) schedprio);
	  if (descr_pri >= ti_pri)
	    {
	      /* Yep, it matches.  Call the callback function.  */
	      td_thrhandle_t th;
	      th.th_ta_p = (td_thragent_t *) ta;
	      th.th_unique = addr;
	      if (callback (&th, cbdata_p) != 0)
		return TD_DBERR;
	    }
	}

      /* Get the pointer to the next element.  */
      err = DB_GET_FIELD_LOCAL (next, ta, copy + (ofs - (psaddr_t) 0), list_t,
				next, 0);
      if (err != TD_OK)
	break;
    }

  return err;
}