Пример #1
0
td_err_e
td_thr_validate (const td_thrhandle_t *th)
{
  struct pthread_handle_struct *handles = th->th_ta_p->handles;
  int pthread_threads_max = th->th_ta_p->pthread_threads_max;
  int cnt;

  LOG (__FUNCTION__);

  /* Now get all descriptors, one after the other.  */
  for (cnt = 0; cnt < pthread_threads_max; ++cnt, ++handles)
    {
      struct pthread_handle_struct phc;

      if (ps_pdread (th->th_ta_p->ph, handles, &phc,
		     sizeof (struct pthread_handle_struct)) != PS_OK)
	return TD_ERR;	/* XXX Other error value?  */

      if (phc.h_descr != NULL && phc.h_descr == th->th_unique)
	{
	  struct _pthread_descr_struct pds;

	  if (ps_pdread (th->th_ta_p->ph, phc.h_descr, &pds,
			 th->th_ta_p->sizeof_descr) != PS_OK)
	    return TD_ERR;	/* XXX Other error value?  */

	  /* XXX There should be another test using the TID but this is
	     currently not available.  */
	  return pds.p_terminated != 0 ? TD_NOTHR : TD_OK;
	}
    }

  return TD_ERR;
}
Пример #2
0
td_err_e
td_ta_map_id2thr (const td_thragent_t *ta, pthread_t pt, td_thrhandle_t *th)
{
  struct pthread_handle_struct phc;
  struct _pthread_descr_struct pds;
  int pthread_threads_max;

  LOG ("td_ta_map_id2thr");

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

  /* Make the following expression a bit smaller.  */
  pthread_threads_max = ta->pthread_threads_max;

  /* We can compute the entry in the handle array we want.  */
  if (ps_pdread (ta->ph, ta->handles + pt % pthread_threads_max, &phc,
		 sizeof (struct pthread_handle_struct)) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

  /* Test whether this entry is in use.  */
  if (phc.h_descr == NULL)
    {
      if (pt % pthread_threads_max == 0)
	{
	  /* The initial thread always exists but the thread library
	     might not yet be initialized.  */
	  th->th_ta_p = (td_thragent_t *) ta;
	  th->th_unique = NULL;

	  return TD_OK;
	}

      return TD_BADTH;
    }

  /* Next test: get the descriptor to see whether this is not an old
     thread handle.  */
  if (ps_pdread (ta->ph, phc.h_descr, &pds,
		 sizeof (struct _pthread_descr_struct)) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

  if (pds.p_tid != pt)
    return TD_BADTH;

  if (pds.p_terminated != 0)
    return TD_NOTHR;

  /* Create the `td_thrhandle_t' object.  */
  th->th_ta_p = (td_thragent_t *) ta;
  th->th_unique = phc.h_descr;

  return TD_OK;
}
Пример #3
0
td_err_e
td_thr_tsd (const td_thrhandle_t *th, const thread_key_t tk, void **data)
{
  struct _pthread_descr_struct pds;
  struct pthread_key_struct *keys = th->th_ta_p->keys;
  struct pthread_key_struct key;
  int pthread_keys_max = th->th_ta_p->pthread_keys_max;
  int pthread_key_2ndlevel_size = th->th_ta_p->pthread_key_2ndlevel_size;
  unsigned int idx1st;
  unsigned int idx2nd;
  void *p;

  LOG (__FUNCTION__);

  /* Get the thread descriptor.  */
  if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds,
		 sizeof (struct _pthread_descr_struct)) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

  /* Check correct value of key.  */
  if (tk >= pthread_keys_max)
    return TD_BADKEY;

  /* Get the key entry.  */
  if (ps_pdread (th->th_ta_p->ph, keys, &key,
		 sizeof (struct pthread_key_struct)) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

  /* Fail if this key is not at all used.  */
  if (! key.in_use)
    return TD_BADKEY;

  /* Compute the indeces.  */
  idx1st = tk / pthread_key_2ndlevel_size;
  idx2nd = tk % pthread_key_2ndlevel_size;

  /* Check the pointer to the second level array.  */
  if (pds.p_specific[idx1st] == NULL)
    return TD_NOTSD;

  /* Now get the real key.
     XXX I don't know whether it's correct but there is currently no
     easy way to determine whether a key was never set or the value
     is NULL.  We return an error whenever the value is NULL.  */
  if (ps_pdread (th->th_ta_p->ph, &pds.p_specific[idx1st][idx2nd], &p,
		 sizeof (void *)) != PS_OK)
    return TD_ERR;

  if (p != NULL)
    *data = p;

  return p != NULL ? TD_OK : TD_NOTSD;
}
Пример #4
0
td_err_e
_td_fetch_value (td_thragent_t *ta,
		 db_desc_t desc, int descriptor_name,
		 psaddr_t idx, psaddr_t address,
		 psaddr_t *result)
{
  ps_err_e err;
  td_err_e terr = _td_locate_field (ta, desc, descriptor_name, idx, &address);
  if (terr != TD_OK)
    return terr;

  if (DB_DESC_SIZE (desc) == 8 || DB_DESC_SIZE (desc) == bswap_32 (8))
    {
      uint8_t value;
      err = ps_pdread (ta->ph, address, &value, sizeof value);
      *result = (psaddr_t) 0 + value;
    }
  else if (DB_DESC_SIZE (desc) == 32)
    {
      uint32_t value;
      err = ps_pdread (ta->ph, address, &value, sizeof value);
      *result = (psaddr_t) 0 + value;
    }
  else if (DB_DESC_SIZE (desc) == 64)
    {
      uint64_t value;
      if (sizeof (psaddr_t) < 8)
	return TD_NOCAPAB;
      err = ps_pdread (ta->ph, address, &value, sizeof value);
      *result = (psaddr_t) 0 + value;
    }
  else if (DB_DESC_SIZE (desc) == bswap_32 (32))
    {
      uint32_t value;
      err = ps_pdread (ta->ph, address, &value, sizeof value);
      value = bswap_32 (value);
      *result = (psaddr_t) 0 + value;
    }
  else if (DB_DESC_SIZE (desc) == bswap_32 (64))
    {
      uint64_t value;
      if (sizeof (psaddr_t) < 8)
	return TD_NOCAPAB;
      err = ps_pdread (ta->ph, address, &value, sizeof value);
      value = bswap_64 (value);
      *result = (psaddr_t) 0 + value;
    }
  else
    return TD_DBERR;

  return err == PS_OK ? TD_OK : TD_ERR;
}
Пример #5
0
td_err_e
td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
{
  psaddr_t versaddr;
  char versbuf[sizeof (VERSION)];

  LOG ("td_ta_new");

  /* Check whether the versions match.  */
  if (td_lookup (ps, SYM_nptl_version, &versaddr) != PS_OK)
    return TD_NOLIBTHREAD;
  if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
    return TD_ERR;

  if (memcmp (versbuf, VERSION, sizeof VERSION) != 0)
    /* Not the right version.  */
    return TD_VERSION;

  /* Fill in the appropriate information.  */
  *ta = (td_thragent_t *) calloc (1, sizeof (td_thragent_t));
  if (*ta == NULL)
    return TD_MALLOC;

  /* Store the proc handle which we will pass to the callback functions
     back into the debugger.  */
  (*ta)->ph = ps;

  /* Now add the new agent descriptor to the list.  */
  list_add (&(*ta)->list, &__td_agent_list);

  return TD_OK;
}
Пример #6
0
td_err_e
td_ta_tsd_iter (const td_thragent_t *ta, td_key_iter_f *callback,
		void *cbdata_p)
{
  struct pthread_key_struct *keys;
  int pthread_keys_max;
  int cnt;

  LOG ("td_ta_tsd_iter");

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

  pthread_keys_max = ta->pthread_keys_max;
  keys = (struct pthread_key_struct *) alloca (sizeof (keys[0])
					       * pthread_keys_max);

  /* Read all the information about the keys.  */
  if (ps_pdread (ta->ph, ta->keys, keys,
		 sizeof (keys[0]) * pthread_keys_max) != PS_OK)
	return TD_ERR;	/* XXX Other error value?  */

  /* Now get all descriptors, one after the other.  */
  for (cnt = 0; cnt < pthread_keys_max; ++cnt)
    if (keys[cnt].in_use
	/* Return with an error if the callback returns a nonzero value.  */
	&& callback (cnt, keys[cnt].destr, cbdata_p) != 0)
      return TD_DBERR;

  return TD_OK;
}
Пример #7
0
td_err_e
td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *event)
{
  td_thr_events_t old_event;
  int i;

  LOG ("td_ta_clear_event");

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

  /* Write the new value into the thread data structure.  */
  if (ps_pdread (ta->ph, ta->pthread_threads_eventsp,
		 &old_event, sizeof (td_thr_events_t)) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

  /* Remove the set bits in.  */
  for (i = 0; i < TD_EVENTSIZE; ++i)
    old_event.event_bits[i] &= ~event->event_bits[i];

  /* Write the new value into the thread data structure.  */
  if (ps_pdwrite (ta->ph, ta->pthread_threads_eventsp,
		  &old_event, sizeof (td_thr_events_t)) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

  return TD_OK;
}
Пример #8
0
td_err_e
td_thr_getgregs (const td_thrhandle_t *th, prgregset_t gregs)
{
  struct _pthread_descr_struct pds;

  LOG ("td_thr_getgregs");

  /* We have to get the state and the PID for this thread.  */
  if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds,
		 sizeof (struct _pthread_descr_struct)) != PS_OK)
    return TD_ERR;

  /* If the thread already terminated we return all zeroes.  */
  if (pds.p_terminated)
    memset (gregs, '\0', sizeof (prgregset_t));
  /* Otherwise get the register content through the callback.  */
  else
    {
      pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph);

      if (ps_lgetregs (th->th_ta_p->ph, pid, gregs) != PS_OK)
	return TD_ERR;
    }

  return TD_OK;
}
Пример #9
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;
}
Пример #10
0
static bool read_jboolean(struct ps_prochandle* ph, uintptr_t addr, jboolean* pvalue) {
   jboolean i;
   if (ps_pdread(ph, (psaddr_t) addr, &i, sizeof(i)) == PS_OK) {
      *pvalue = i;
      return true;
   } else {
      return false;
   }
}
Пример #11
0
static bool read_pointer(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* pvalue) {
   uintptr_t uip;
   if (ps_pdread(ph, (psaddr_t) addr, &uip, sizeof(uip)) == PS_OK) {
      *pvalue = uip;
      return true;
   } else {
      return false;
   }
}
Пример #12
0
td_err_e
td_thr_get_info (const td_thrhandle_t *th, td_thrinfo_t *infop)
{
  struct _pthread_descr_struct pds;

  LOG ("td_thr_get_info");

  /* Handle the case when the thread library is not yet initialized.  */
  if (th->th_unique == NULL)
    {
      memset (&pds, '\0', sizeof (pds));
      pds.p_tid = PTHREAD_THREADS_MAX;
    }
  else
    /* Get the thread descriptor.  */
    if (ps_pdread (th->th_ta_p->ph, th->th_unique, &pds,
		   th->th_ta_p->sizeof_descr) != PS_OK)
      return TD_ERR;	/* XXX Other error value?  */

  /* Fill in information.  Clear first to provide reproducable
     results for the fields we do not fill in.  */
  memset (infop, '\0', sizeof (td_thrinfo_t));

  /* We have to handle the manager thread special since the thread
     descriptor in older versions is not fully initialized.  */
  if (pds.p_nr == 1)
    {
      infop->ti_tid = th->th_ta_p->pthread_threads_max * 2 + 1;
      infop->ti_type = TD_THR_SYSTEM;
      infop->ti_state = TD_THR_ACTIVE;
    }
  else
    {
      infop->ti_tid = pds.p_tid;
      infop->ti_tls = (char *) pds.p_specific;
      infop->ti_pri = pds.p_priority;
      infop->ti_type = TD_THR_USER;

      if (! pds.p_terminated)
	/* XXX For now there is no way to get more information.  */
	infop->ti_state = TD_THR_ACTIVE;
      else if (! pds.p_detached)
	infop->ti_state = TD_THR_ZOMBIE;
      else
	infop->ti_state = TD_THR_UNKNOWN;
    }

  /* Initialization which are the same in both cases.  */
  infop->ti_lid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph);
  infop->ti_ta_p = th->th_ta_p;
  infop->ti_startfunc = pds.p_start_args.start_routine;
  memcpy (&infop->ti_events, &pds.p_eventbuf.eventmask,
	  sizeof (td_thr_events_t));
  infop->ti_traceme = pds.p_report_events != 0;

  return TD_OK;
}
Пример #13
0
/*
 * Class:     sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal
 * Method:    readBytesFromProcess0
 * Signature: (JJ)Lsun/jvm/hotspot/debugger/ReadResult;
 */
JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_linux_LinuxDebuggerLocal_readBytesFromProcess0
  (JNIEnv *env, jobject this_obj, jlong addr, jlong numBytes) {

  jboolean isCopy;
  jbyteArray array;
  jbyte *bufPtr;
  ps_err_e err;

  array = (*env)->NewByteArray(env, numBytes);
  CHECK_EXCEPTION_(0);
  bufPtr = (*env)->GetByteArrayElements(env, array, &isCopy);
  CHECK_EXCEPTION_(0);

  err = ps_pdread(get_proc_handle(env, this_obj), (psaddr_t) (uintptr_t)addr, bufPtr, numBytes);
  (*env)->ReleaseByteArrayElements(env, array, bufPtr, 0);
  return (err == PS_OK)? array : 0;
}
Пример #14
0
// used to read strings from debuggee
static bool read_string(struct ps_prochandle* ph, uintptr_t addr, char* buf, size_t size) {
   size_t i = 0;
   char  c = ' ';

   while (c != '\0') {
     if (ps_pdread(ph, (psaddr_t) addr, &c, sizeof(char)) != PS_OK)
         return false;
      if (i < size - 1)
         buf[i] = c;
      else // smaller buffer
         return false;
      i++; addr++;
   }

   buf[i] = '\0';
   return true;
}
Пример #15
0
td_err_e
_td_check_sizeof (td_thragent_t *ta, uint32_t *sizep, int sizep_name)
{
  if (*sizep == 0)
    {
      psaddr_t descptr;
      ps_err_e err = td_lookup (ta->ph, sizep_name, &descptr);
      if (err == PS_NOSYM)
	return TD_NOCAPAB;
      if (err == PS_OK)
	err = ps_pdread (ta->ph, descptr, sizep, sizeof *sizep);
      if (err != PS_OK)
	return TD_ERR;
      if (*sizep & 0xff000000U)
	*sizep = bswap_32 (*sizep);
    }
  return TD_OK;
}
Пример #16
0
td_err_e
_td_locate_field (td_thragent_t *ta,
		  db_desc_t desc, int descriptor_name,
		  psaddr_t idx, psaddr_t *address)
{
  uint32_t elemsize;

  if (DB_DESC_SIZE (desc) == 0)
    {
      /* Read the information about this field from the inferior.  */
      psaddr_t descptr;
      ps_err_e err = td_lookup (ta->ph, descriptor_name, &descptr);
      if (err == PS_NOSYM)
	return TD_NOCAPAB;
      if (err == PS_OK)
	err = ps_pdread (ta->ph, descptr, desc, DB_SIZEOF_DESC);
      if (err != PS_OK)
	return TD_ERR;
      if (DB_DESC_SIZE (desc) == 0)
	return TD_DBERR;
      if (DB_DESC_SIZE (desc) & 0xff000000U)
	{
	  /* Byte-swap these words, though we leave the size word
	     in native order as the handy way to distinguish.  */
	  DB_DESC_OFFSET (desc) = bswap_32 (DB_DESC_OFFSET (desc));
	  DB_DESC_NELEM (desc) = bswap_32 (DB_DESC_NELEM (desc));
	}
    }

  if (idx != 0 && DB_DESC_NELEM (desc) != 0
      && idx - (psaddr_t) 0 > DB_DESC_NELEM (desc))
    /* This is an internal indicator to callers with nonzero IDX
       that the IDX value is too big.  */
    return TD_NOAPLIC;

  elemsize = DB_DESC_SIZE (desc);
  if (elemsize & 0xff000000U)
    elemsize = bswap_32 (elemsize);

  *address += (int32_t) DB_DESC_OFFSET (desc);
  *address += (elemsize / 8 * (idx - (psaddr_t) 0));
  return TD_OK;
}
td_err_e
td_ta_get_nthreads (const td_thragent_t *ta, int *np)
{
  psaddr_t addr;

  LOG ("td_ta_get_nthreads");

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

  /* Access the variable `__pthread_handles_num'.  */
  if (td_lookup (ta->ph, PTHREAD_HANDLES_NUM, &addr) != PS_OK)
     return TD_ERR;	/* XXX Other error value?  */

  if (ps_pdread (ta->ph, addr, np, sizeof (int)) != PS_OK)
     return TD_ERR;	/* XXX Other error value?  */

  return TD_OK;
}
Пример #18
0
td_err_e
td_thr_setgregs (const td_thrhandle_t *th, prgregset_t gregs)
{
    struct _pthread_descr_struct pds = { .p_terminated = 0, .p_pid = 0 };

    LOG ("td_thr_setgregs");

    /* We have to get the state and the PID for this thread.  */
    if (th->th_unique != NULL
            && ps_pdread (th->th_ta_p->ph, th->th_unique, &pds,
                          sizeof (struct _pthread_descr_struct)) != PS_OK)
        return TD_ERR;

    /* Only set the registers if the thread hasn't yet terminated.  */
    if (pds.p_terminated == 0)
    {
        pid_t pid = pds.p_pid ?: ps_getpid (th->th_ta_p->ph);

        if (ps_lsetregs (th->th_ta_p->ph, pid, gregs) != PS_OK)
            return TD_ERR;
    }

    return TD_OK;
}
Пример #19
0
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;
}
Пример #20
0
td_err_e
td_ta_thr_iter (const td_thragent_t *ta, td_thr_iter_f *callback,
		void *cbdata_p, td_thr_state_e state, int ti_pri,
		sigset_t *ti_sigmask_p, unsigned int ti_user_flags)
{
  int pthread_threads_max;
  struct pthread_handle_struct *phc;
  td_err_e result = TD_OK;
  int cnt;
#ifdef ALL_THREADS_STOPPED
  int num;
#else
# define num 1
#endif

  LOG ("td_ta_thr_iter");

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

  pthread_threads_max = ta->pthread_threads_max;
  phc = (struct pthread_handle_struct *) alloca (sizeof (phc[0])
						 * pthread_threads_max);

  /* First read only the main thread and manager thread information.  */
  if (ps_pdread (ta->ph, ta->handles, phc,
		 sizeof (struct pthread_handle_struct) * 2) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

  /* Now handle these descriptors.  */
  result = handle_descr (ta, callback, cbdata_p, state, ti_pri, 0,
			 phc[0].h_descr);
  if (result != TD_OK)
    return result;
  result = handle_descr (ta, callback, cbdata_p, state, ti_pri, 1,
			 phc[1].h_descr);
  if (result != TD_OK)
    return result;

  /* Read all the descriptors.  */
  if (ps_pdread (ta->ph, ta->handles + 2, &phc[2],
		 (sizeof (struct pthread_handle_struct)
		  * (pthread_threads_max - 2))) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

#ifdef ALL_THREADS_STOPPED
  /* Read the number of currently active threads.  */
  if (ps_pdread (ta->ph, ta->pthread_handles_num, &num, sizeof (int)) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */
#endif

  /* Now get all descriptors, one after the other.  */
  for (cnt = 2; cnt < pthread_threads_max && num > 0; ++cnt)
    if (phc[cnt].h_descr != NULL)
      {
#ifdef ALL_THREADS_STOPPED
	/* First count this active thread.  */
	--num;
#endif

	result = handle_descr (ta, callback, cbdata_p, state, ti_pri, cnt,
			       phc[cnt].h_descr);
	if (result != TD_OK)
	  break;
      }

  return result;
}
Пример #21
0
// read shared library info from runtime linker's data structures.
// This work is done by librtlb_db in Solaris
static bool read_shared_lib_info(struct ps_prochandle* ph) {
   uintptr_t addr = ph->core->dynamic_addr;
   uintptr_t debug_base;
   uintptr_t first_link_map_addr;
   uintptr_t ld_base_addr;
   uintptr_t link_map_addr;
   uintptr_t lib_base_diff;
   uintptr_t lib_base;
   uintptr_t lib_name_addr;
   char lib_name[BUF_SIZE];
   ELF_DYN dyn;
   ELF_EHDR elf_ehdr;
   int lib_fd;

   // _DYNAMIC has information of the form
   //         [tag] [data] [tag] [data] .....
   // Both tag and data are pointer sized.
   // We look for dynamic info with DT_DEBUG. This has shared object info.
   // refer to struct r_debug in link.h

   dyn.d_tag = DT_NULL;
   while (dyn.d_tag != DT_DEBUG) {
      if (ps_pdread(ph, (psaddr_t) addr, &dyn, sizeof(ELF_DYN)) != PS_OK) {
         print_debug("can't read debug info from _DYNAMIC\n");
         return false;
      }
      addr += sizeof(ELF_DYN);
   }

   // we have got Dyn entry with DT_DEBUG
   debug_base = dyn.d_un.d_ptr;
   // at debug_base we have struct r_debug. This has first link map in r_map field
   if (ps_pdread(ph, (psaddr_t) debug_base + FIRST_LINK_MAP_OFFSET,
                 &first_link_map_addr, sizeof(uintptr_t)) != PS_OK) {
      print_debug("can't read first link map address\n");
      return false;
   }

   // read ld_base address from struct r_debug
   if (ps_pdread(ph, (psaddr_t) debug_base + LD_BASE_OFFSET, &ld_base_addr,
                 sizeof(uintptr_t)) != PS_OK) {
      print_debug("can't read ld base address\n");
      return false;
   }
   ph->core->ld_base_addr = ld_base_addr;

   print_debug("interpreter base address is 0x%lx\n", ld_base_addr);

   // now read segments from interp (i.e ld.so or ld-linux.so)
   if (read_interp_segments(ph) != true)
      return false;

   // after adding interpreter (ld.so) mappings sort again
   if (sort_map_array(ph) != true)
      return false;

   print_debug("first link map is at 0x%lx\n", first_link_map_addr);

   link_map_addr = first_link_map_addr;
   while (link_map_addr != 0) {
      // read library base address of the .so. Note that even though <sys/link.h> calls
      // link_map->l_addr as "base address",  this is * not * really base virtual
      // address of the shared object. This is actually the difference b/w the virtual
      // address mentioned in shared object and the actual virtual base where runtime
      // linker loaded it. We use "base diff" in read_lib_segments call below.

      if (ps_pdread(ph, (psaddr_t) link_map_addr + LINK_MAP_ADDR_OFFSET,
                   &lib_base_diff, sizeof(uintptr_t)) != PS_OK) {
         print_debug("can't read shared object base address diff\n");
         return false;
      }

      // read address of the name
      if (ps_pdread(ph, (psaddr_t) link_map_addr + LINK_MAP_NAME_OFFSET,
                    &lib_name_addr, sizeof(uintptr_t)) != PS_OK) {
         print_debug("can't read address of shared object name\n");
         return false;
      }

      // read name of the shared object
      lib_name[0] = '\0';
      if (lib_name_addr != 0 &&
          read_string(ph, (uintptr_t) lib_name_addr, lib_name, sizeof(lib_name)) != true) {
         print_debug("can't read shared object name\n");
         // don't let failure to read the name stop opening the file.  If something is really wrong
         // it will fail later.
      }

      if (lib_name[0] != '\0') {
         // ignore empty lib names
         lib_fd = pathmap_open(lib_name);

         if (lib_fd < 0) {
            print_debug("can't open shared object %s\n", lib_name);
            // continue with other libraries...
         } else {
            if (read_elf_header(lib_fd, &elf_ehdr)) {
               lib_base = lib_base_diff + find_base_address(lib_fd, &elf_ehdr);
               print_debug("reading library %s @ 0x%lx [ 0x%lx ]\n",
                           lib_name, lib_base, lib_base_diff);
               // while adding library mappings we need to use "base difference".
               if (! read_lib_segments(ph, lib_fd, &elf_ehdr, lib_base_diff)) {
                  print_debug("can't read shared object's segments\n");
                  close(lib_fd);
                  return false;
               }
               add_lib_info_fd(ph, lib_name, lib_fd, lib_base);
               // Map info is added for the library (lib_name) so
               // we need to re-sort it before calling the p_pdread.
               if (sort_map_array(ph) != true)
                  return false;
            } else {
               print_debug("can't read ELF header for shared object %s\n", lib_name);
               close(lib_fd);
               // continue with other libraries...
            }
         }
      }

      // read next link_map address
      if (ps_pdread(ph, (psaddr_t) link_map_addr + LINK_MAP_NEXT_OFFSET,
                        &link_map_addr, sizeof(uintptr_t)) != PS_OK) {
         print_debug("can't read next link in link_map\n");
         return false;
      }
   }

   return true;
}
Пример #22
0
static int
handle_descr (const td_thragent_t *ta, td_thr_iter_f *callback,
	      void *cbdata_p, td_thr_state_e state, int ti_pri,
	      size_t cnt, pthread_descr descr)
{
  struct _pthread_descr_struct pds;
  size_t sizeof_descr = ta->sizeof_descr;
  td_thrhandle_t th;

  if (descr == NULL)
    {
      /* No descriptor (yet).  */
      if (cnt == 0)
	{
	  /* This is the main thread.  Create a fake descriptor.  */
	  memset (&pds, '\0', sizeof (pds));

	  /* Empty thread descriptor the thread library would create.  */
#if !defined USE_TLS || !TLS_DTV_AT_TP
	  pds.p_header.data.self = &pds;
#endif
	  pds.p_nextlive = pds.p_prevlive = &pds;
	  pds.p_tid = PTHREAD_THREADS_MAX;
	  /* The init code also sets up p_lock, p_errnop, p_herrnop, and
	     p_userstack but this should not be necessary here.  */

	  th.th_ta_p = (td_thragent_t *) ta;
	  th.th_unique = NULL;
	  if (callback (&th, cbdata_p) != 0)
	    return TD_DBERR;

	  /* All done successfully.  */
	  return TD_OK;
	}
      else if (cnt == 1)
	/* The manager is not yet started.  No big deal.  */
	return TD_OK;
      else
	/* For every other thread this should not happen.  */
	return TD_ERR;
    }

  if (ps_pdread (ta->ph, descr, &pds, sizeof_descr) != PS_OK)
    return TD_ERR;	/* XXX Other error value?  */

  /* The manager thread must be handled special.  The descriptor
     exists but the thread only gets created when the first
     `pthread_create' call is issued.  A clear indication that this
     happened is when the p_pid field is non-zero.  */
  if (cnt == 1 && pds.p_pid == 0)
    return TD_OK;

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

  /* Only if the priority level is as high or higher.  */
  if (pds.p_priority < ti_pri)
    return TD_OK;

  /* Test the state.
     XXX This is incomplete.  */
  if (state != TD_THR_ANY_STATE)
    return TD_OK;

  /* XXX For now we ignore threads which are not running anymore.
     The reason is that gdb tries to get the registers and fails.
     In future we should have a special mode of the thread library
     in which we keep the process around until the actual join
     operation happened.  */
  if (pds.p_exited != 0)
    return TD_OK;

  /* Yep, it matches.  Call the callback function.  */
  th.th_ta_p = (td_thragent_t *) ta;
  th.th_unique = descr;
  if (callback (&th, cbdata_p) != 0)
    return TD_DBERR;

  /* All done successfully.  */
  return TD_OK;
}
Пример #23
0
td_err_e
td_ta_new (struct ps_prochandle *ps, td_thragent_t **ta)
{
  psaddr_t addr;
  psaddr_t versaddr;
  char versbuf[sizeof (VERSION)];
  struct agent_list *elemp;

  LOG ("td_ta_new");

  /* Get the global event mask.  This is one of the variables which
     are new in the thread library to enable debugging.  If it is
     not available we cannot debug.  */
  if (td_lookup (ps, PTHREAD_THREADS_EVENTS, &addr) != PS_OK)
    return TD_NOLIBTHREAD;

  /* Check whether the versions match.  */
  if (td_lookup (ps, LINUXTHREADS_VERSION, &versaddr) != PS_OK)
    return TD_VERSION;
  if (ps_pdread (ps, versaddr, versbuf, sizeof (versbuf)) != PS_OK)
    return TD_ERR;

  versbuf[sizeof (versbuf) - 1] = '\0';
  if (strcmp (versbuf, VERSION) != 0)
    /* Not the right version.  */
    return TD_VERSION;

  /* Fill in the appropriate information.  */
  *ta = (td_thragent_t *) malloc (sizeof (td_thragent_t));
  if (*ta == NULL)
    return TD_MALLOC;

  /* Store the proc handle which we will pass to the callback functions
     back into the debugger.  */
  (*ta)->ph = ps;

  /* Remember the address.  */
  (*ta)->pthread_threads_eventsp = (td_thr_events_t *) addr;

  /* Get the pointer to the variable pointing to the thread descriptor
     with the last event.  */
  if (td_lookup (ps, PTHREAD_LAST_EVENT, &(*ta)->pthread_last_event) != PS_OK)
    {
    free_return:
      free (*ta);
      return TD_ERR;
    }

  /* Get the pointer to the variable containing the number of active
     threads.  */
  if (td_lookup (ps, PTHREAD_HANDLES_NUM, &(*ta)->pthread_handles_num)
      != PS_OK)
    goto free_return;

  /* See whether the library contains the necessary symbols.  */
  if (td_lookup (ps, PTHREAD_HANDLES, &addr) != PS_OK)
    goto free_return;

  (*ta)->handles = (struct pthread_handle_struct *) addr;


  if (td_lookup (ps, PTHREAD_KEYS, &addr) != PS_OK)
    goto free_return;

  /* Cast to the right type.  */
  (*ta)->keys = (struct pthread_key_struct *) addr;

  /* Find out about the maximum number of threads.  Old implementations
     don't provide this information.  In this case we assume that the
     debug  library is compiled with the same values.  */
  if (td_lookup (ps, LINUXTHREADS_PTHREAD_THREADS_MAX, &addr) != PS_OK)
    (*ta)->pthread_threads_max = PTHREAD_THREADS_MAX;
  else
    {
      if (ps_pdread (ps, addr, &(*ta)->pthread_threads_max, sizeof (int))
	  != PS_OK)
	goto free_return;
    }

  /* Similar for the maximum number of thread local data keys.  */
  if (td_lookup (ps, LINUXTHREADS_PTHREAD_KEYS_MAX, &addr) != PS_OK)
    (*ta)->pthread_keys_max = PTHREAD_KEYS_MAX;
  else
    {
      if (ps_pdread (ps, addr, &(*ta)->pthread_keys_max, sizeof (int))
	  != PS_OK)
	goto free_return;
    }

  /* And for the size of the second level arrays for the keys.  */
  if (td_lookup (ps, LINUXTHREADS_PTHREAD_SIZEOF_DESCR, &addr) != PS_OK)
    (*ta)->sizeof_descr = sizeof (struct _pthread_descr_struct);
  else
    {
      if (ps_pdread (ps, addr, &(*ta)->sizeof_descr, sizeof (int)) != PS_OK)
	goto free_return;
      /* Don't let bogons in the inferior make us mess ourselves.  */
      if ((*ta)->sizeof_descr > sizeof (struct _pthread_descr_struct))
	(*ta)->sizeof_descr = sizeof (struct _pthread_descr_struct);
    }

  /* Now add the new agent descriptor to the list.  */
  elemp = (struct agent_list *) malloc (sizeof (struct agent_list));
  if (elemp == NULL)
    {
      /* Argh, now that everything else worked...  */
      free (*ta);
      return TD_MALLOC;
    }

  /* We don't care for thread-safety here.  */
  elemp->ta = *ta;
  elemp->next = __td_agent_list;
  __td_agent_list = elemp;

  return TD_OK;
}