Blame nptl_db/td_ta_map_lwp2thr.c

Packit 6c4009
/* Which thread is running on an LWP?
Packit 6c4009
   Copyright (C) 2003-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include "thread_dbP.h"
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <byteswap.h>
Packit 6c4009
#include <sys/procfs.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
td_err_e
Packit 6c4009
__td_ta_lookup_th_unique (const td_thragent_t *ta_arg,
Packit 6c4009
			  lwpid_t lwpid, td_thrhandle_t *th)
Packit 6c4009
{
Packit 6c4009
  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
Packit 6c4009
  ps_err_e err;
Packit 6c4009
  td_err_e terr;
Packit 6c4009
  prgregset_t regs;
Packit 6c4009
  psaddr_t addr;
Packit 6c4009
Packit 6c4009
  if (ta->ta_howto == ta_howto_unknown)
Packit 6c4009
    {
Packit 6c4009
      /* We need to read in from the inferior the instructions what to do.  */
Packit 6c4009
      psaddr_t howto;
Packit 6c4009
Packit 6c4009
      err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto);
Packit 6c4009
      if (err == PS_OK)
Packit 6c4009
	{
Packit 6c4009
	  err = ps_pdread (ta->ph, howto,
Packit 6c4009
			   &ta->ta_howto_data.const_thread_area,
Packit 6c4009
 			   sizeof ta->ta_howto_data.const_thread_area);
Packit 6c4009
	  if (err != PS_OK)
Packit 6c4009
	    return TD_ERR;
Packit 6c4009
	  ta->ta_howto = ta_howto_const_thread_area;
Packit 6c4009
	  if (ta->ta_howto_data.const_thread_area & 0xff000000U)
Packit 6c4009
	    ta->ta_howto_data.const_thread_area
Packit 6c4009
	      = bswap_32 (ta->ta_howto_data.const_thread_area);
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  switch (sizeof (regs[0]))
Packit 6c4009
	    {
Packit 6c4009
	    case 8:
Packit 6c4009
	      err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto);
Packit 6c4009
	      if (err == PS_OK)
Packit 6c4009
		ta->ta_howto = ta_howto_reg;
Packit 6c4009
	      else if (err == PS_NOSYM)
Packit 6c4009
		{
Packit 6c4009
		  err = td_lookup (ta->ph,
Packit 6c4009
				   SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
Packit 6c4009
				   &howto);
Packit 6c4009
		  if (err == PS_OK)
Packit 6c4009
		    ta->ta_howto = ta_howto_reg_thread_area;
Packit 6c4009
		}
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    case 4:
Packit 6c4009
	      err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto);
Packit 6c4009
	      if (err == PS_OK)
Packit 6c4009
		ta->ta_howto = ta_howto_reg;
Packit 6c4009
	      else if (err == PS_NOSYM)
Packit 6c4009
		{
Packit 6c4009
		  err = td_lookup (ta->ph,
Packit 6c4009
				   SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
Packit 6c4009
				   &howto);
Packit 6c4009
		  if (err == PS_OK)
Packit 6c4009
		    ta->ta_howto = ta_howto_reg_thread_area;
Packit 6c4009
		}
Packit 6c4009
	      break;
Packit 6c4009
Packit 6c4009
	    default:
Packit 6c4009
	      abort ();
Packit 6c4009
	      return TD_DBERR;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (err != PS_OK)
Packit 6c4009
	    return TD_DBERR;
Packit 6c4009
Packit 6c4009
	  /* For either of these methods we read in the same descriptor.  */
Packit 6c4009
	  err = ps_pdread (ta->ph, howto,
Packit 6c4009
			   ta->ta_howto_data.reg, DB_SIZEOF_DESC);
Packit 6c4009
	  if (err != PS_OK)
Packit 6c4009
	    return TD_ERR;
Packit 6c4009
	  if (DB_DESC_SIZE (ta->ta_howto_data.reg) == 0)
Packit 6c4009
	    return TD_DBERR;
Packit 6c4009
	  if (DB_DESC_SIZE (ta->ta_howto_data.reg) & 0xff000000U)
Packit 6c4009
	    {
Packit 6c4009
	      /* Byte-swap these words, though we leave the size word
Packit 6c4009
		 in native order as the handy way to distinguish.  */
Packit 6c4009
	      DB_DESC_OFFSET (ta->ta_howto_data.reg)
Packit 6c4009
		= bswap_32 (DB_DESC_OFFSET (ta->ta_howto_data.reg));
Packit 6c4009
	      DB_DESC_NELEM (ta->ta_howto_data.reg)
Packit 6c4009
		= bswap_32 (DB_DESC_NELEM (ta->ta_howto_data.reg));
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  switch (ta->ta_howto)
Packit 6c4009
    {
Packit 6c4009
    default:
Packit 6c4009
      return TD_DBERR;
Packit 6c4009
Packit 6c4009
    case ta_howto_reg:
Packit 6c4009
      /* On most machines, we are just looking at a register.  */
Packit 6c4009
      if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
Packit 6c4009
	return TD_ERR;
Packit 6c4009
      terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg, -1,
Packit 6c4009
				    0, regs, &addr);
Packit 6c4009
      if (terr != TD_OK)
Packit 6c4009
	return terr;
Packit 6c4009
Packit 6c4009
      /* In this descriptor the nelem word is overloaded as the bias.  */
Packit 6c4009
      addr += (int32_t) DB_DESC_NELEM (ta->ta_howto_data.reg);
Packit 6c4009
      th->th_unique = addr;
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case ta_howto_const_thread_area:
Packit 6c4009
      /* Some hosts don't have this call and this case won't be used.  */
Packit 6c4009
# pragma weak ps_get_thread_area
Packit 6c4009
      if (&ps_get_thread_area == NULL)
Packit 6c4009
	return TD_NOCAPAB;
Packit 6c4009
Packit 6c4009
      /* A la x86-64, there is a magic index for get_thread_area.  */
Packit 6c4009
      if (ps_get_thread_area (ta->ph, lwpid,
Packit 6c4009
			      ta->ta_howto_data.const_thread_area,
Packit 6c4009
			      &th->th_unique) != PS_OK)
Packit 6c4009
	return TD_ERR;	/* XXX Other error value?  */
Packit 6c4009
      break;
Packit 6c4009
Packit 6c4009
    case ta_howto_reg_thread_area:
Packit 6c4009
      if (&ps_get_thread_area == NULL)
Packit 6c4009
	return TD_NOCAPAB;
Packit 6c4009
Packit 6c4009
      /* A la i386, a register holds the index for get_thread_area.  */
Packit 6c4009
      if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
Packit 6c4009
	return TD_ERR;
Packit 6c4009
      terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg_thread_area,
Packit 6c4009
				    -1, 0, regs, &addr);
Packit 6c4009
      if (terr != TD_OK)
Packit 6c4009
	return terr;
Packit 6c4009
      /* In this descriptor the nelem word is overloaded as scale factor.  */
Packit 6c4009
      if (ps_get_thread_area
Packit 6c4009
	  (ta->ph, lwpid,
Packit 6c4009
	   ((addr - (psaddr_t) 0)
Packit 6c4009
	    >> DB_DESC_NELEM (ta->ta_howto_data.reg_thread_area)),
Packit 6c4009
	   &th->th_unique) != PS_OK)
Packit 6c4009
	return TD_ERR;	/* XXX Other error value?  */
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Found it.  Now complete the `td_thrhandle_t' object.  */
Packit 6c4009
  th->th_ta_p = ta;
Packit 6c4009
Packit 6c4009
  return TD_OK;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
td_err_e
Packit 6c4009
td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
Packit 6c4009
		   lwpid_t lwpid, td_thrhandle_t *th)
Packit 6c4009
{
Packit 6c4009
  td_thragent_t *const ta = (td_thragent_t *) ta_arg;
Packit 6c4009
Packit 6c4009
  LOG ("td_ta_map_lwp2thr");
Packit 6c4009
Packit 6c4009
  /* Test whether the TA parameter is ok.  */
Packit 6c4009
  if (! ta_ok (ta))
Packit 6c4009
    return TD_BADTA;
Packit 6c4009
Packit 6c4009
  /* We cannot rely on thread registers and such information at all
Packit 6c4009
     before __pthread_initialize_minimal has gotten far enough.  They
Packit 6c4009
     sometimes contain garbage that would confuse us, left by the kernel
Packit 6c4009
     at exec.  So if it looks like initialization is incomplete, we only
Packit 6c4009
     fake a special descriptor for the initial thread.  */
Packit 6c4009
Packit 6c4009
  psaddr_t list;
Packit 6c4009
  td_err_e err = DB_GET_SYMBOL (list, ta, __stack_user);
Packit 6c4009
  if (err != TD_OK)
Packit 6c4009
    return err;
Packit 6c4009
Packit 6c4009
  err = DB_GET_FIELD (list, ta, list, list_t, next, 0);
Packit 6c4009
  if (err != TD_OK)
Packit 6c4009
    return err;
Packit 6c4009
Packit 6c4009
  if (list == 0)
Packit 6c4009
    {
Packit 6c4009
      if (ps_getpid (ta->ph) != lwpid)
Packit 6c4009
	return TD_ERR;
Packit 6c4009
      th->th_ta_p = ta;
Packit 6c4009
      th->th_unique = 0;
Packit 6c4009
      return TD_OK;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return __td_ta_lookup_th_unique (ta_arg, lwpid, th);
Packit 6c4009
}