(root)/
glibc-2.38/
nptl_db/
td_ta_map_lwp2thr.c
       1  /* Which thread is running on an LWP?
       2     Copyright (C) 2003-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include "thread_dbP.h"
      20  #include <stdlib.h>
      21  #include <byteswap.h>
      22  #include <sys/procfs.h>
      23  
      24  
      25  td_err_e
      26  __td_ta_lookup_th_unique (const td_thragent_t *ta_arg,
      27  			  lwpid_t lwpid, td_thrhandle_t *th)
      28  {
      29    td_thragent_t *const ta = (td_thragent_t *) ta_arg;
      30    ps_err_e err;
      31    td_err_e terr;
      32    prgregset_t regs;
      33    psaddr_t addr;
      34  
      35    if (ta->ta_howto == ta_howto_unknown)
      36      {
      37        /* We need to read in from the inferior the instructions what to do.  */
      38        psaddr_t howto;
      39  
      40        err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto);
      41        if (err == PS_OK)
      42  	{
      43  	  err = ps_pdread (ta->ph, howto,
      44  			   &ta->ta_howto_data.const_thread_area,
      45   			   sizeof ta->ta_howto_data.const_thread_area);
      46  	  if (err != PS_OK)
      47  	    return TD_ERR;
      48  	  ta->ta_howto = ta_howto_const_thread_area;
      49  	  if (ta->ta_howto_data.const_thread_area & 0xff000000U)
      50  	    ta->ta_howto_data.const_thread_area
      51  	      = bswap_32 (ta->ta_howto_data.const_thread_area);
      52  	}
      53        else
      54  	{
      55  	  switch (sizeof (regs[0]))
      56  	    {
      57  	    case 8:
      58  	      err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto);
      59  	      if (err == PS_OK)
      60  		ta->ta_howto = ta_howto_reg;
      61  	      else if (err == PS_NOSYM)
      62  		{
      63  		  err = td_lookup (ta->ph,
      64  				   SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
      65  				   &howto);
      66  		  if (err == PS_OK)
      67  		    ta->ta_howto = ta_howto_reg_thread_area;
      68  		}
      69  	      break;
      70  
      71  	    case 4:
      72  	      err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto);
      73  	      if (err == PS_OK)
      74  		ta->ta_howto = ta_howto_reg;
      75  	      else if (err == PS_NOSYM)
      76  		{
      77  		  err = td_lookup (ta->ph,
      78  				   SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
      79  				   &howto);
      80  		  if (err == PS_OK)
      81  		    ta->ta_howto = ta_howto_reg_thread_area;
      82  		}
      83  	      break;
      84  
      85  	    default:
      86  	      abort ();
      87  	      return TD_DBERR;
      88  	    }
      89  
      90  	  if (err != PS_OK)
      91  	    return TD_DBERR;
      92  
      93  	  /* For either of these methods we read in the same descriptor.  */
      94  	  err = ps_pdread (ta->ph, howto,
      95  			   ta->ta_howto_data.reg, DB_SIZEOF_DESC);
      96  	  if (err != PS_OK)
      97  	    return TD_ERR;
      98  	  if (DB_DESC_SIZE (ta->ta_howto_data.reg) == 0)
      99  	    return TD_DBERR;
     100  	  if (DB_DESC_SIZE (ta->ta_howto_data.reg) & 0xff000000U)
     101  	    {
     102  	      /* Byte-swap these words, though we leave the size word
     103  		 in native order as the handy way to distinguish.  */
     104  	      DB_DESC_OFFSET (ta->ta_howto_data.reg)
     105  		= bswap_32 (DB_DESC_OFFSET (ta->ta_howto_data.reg));
     106  	      DB_DESC_NELEM (ta->ta_howto_data.reg)
     107  		= bswap_32 (DB_DESC_NELEM (ta->ta_howto_data.reg));
     108  	    }
     109  	}
     110      }
     111  
     112    switch (ta->ta_howto)
     113      {
     114      default:
     115        return TD_DBERR;
     116  
     117      case ta_howto_reg:
     118        /* On most machines, we are just looking at a register.  */
     119        if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
     120  	return TD_ERR;
     121        terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg, -1,
     122  				    0, regs, &addr);
     123        if (terr != TD_OK)
     124  	return terr;
     125  
     126        /* In this descriptor the nelem word is overloaded as the bias.  */
     127        addr += (int32_t) DB_DESC_NELEM (ta->ta_howto_data.reg);
     128        th->th_unique = addr;
     129        break;
     130  
     131      case ta_howto_const_thread_area:
     132        /* Some hosts don't have this call and this case won't be used.  */
     133  # pragma weak ps_get_thread_area
     134        if (&ps_get_thread_area == NULL)
     135  	return TD_NOCAPAB;
     136  
     137        /* A la x86-64, there is a magic index for get_thread_area.  */
     138        if (ps_get_thread_area (ta->ph, lwpid,
     139  			      ta->ta_howto_data.const_thread_area,
     140  			      &th->th_unique) != PS_OK)
     141  	return TD_ERR;	/* XXX Other error value?  */
     142        break;
     143  
     144      case ta_howto_reg_thread_area:
     145        if (&ps_get_thread_area == NULL)
     146  	return TD_NOCAPAB;
     147  
     148        /* A la i386, a register holds the index for get_thread_area.  */
     149        if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
     150  	return TD_ERR;
     151        terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg_thread_area,
     152  				    -1, 0, regs, &addr);
     153        if (terr != TD_OK)
     154  	return terr;
     155        /* In this descriptor the nelem word is overloaded as scale factor.  */
     156        if (ps_get_thread_area
     157  	  (ta->ph, lwpid,
     158  	   ((addr - (psaddr_t) 0)
     159  	    >> DB_DESC_NELEM (ta->ta_howto_data.reg_thread_area)),
     160  	   &th->th_unique) != PS_OK)
     161  	return TD_ERR;	/* XXX Other error value?  */
     162        break;
     163      }
     164  
     165    /* Found it.  Now complete the `td_thrhandle_t' object.  */
     166    th->th_ta_p = ta;
     167  
     168    return TD_OK;
     169  }
     170  
     171  td_err_e
     172  td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
     173  		   lwpid_t lwpid, td_thrhandle_t *th)
     174  {
     175    td_thragent_t *const ta = (td_thragent_t *) ta_arg;
     176  
     177    LOG ("td_ta_map_lwp2thr");
     178  
     179    /* Test whether the TA parameter is ok.  */
     180    if (! ta_ok (ta))
     181      return TD_BADTA;
     182  
     183    /* We cannot rely on thread registers and such information at all
     184       before __pthread_initialize_minimal has gotten far enough.  They
     185       sometimes contain garbage that would confuse us, left by the kernel
     186       at exec.  So if it looks like initialization is incomplete, we only
     187       fake a special descriptor for the initial thread.  */
     188  
     189    psaddr_t list;
     190    td_err_e err = __td_ta_stack_user (ta, &list);
     191    if (err != TD_OK)
     192      return err;
     193  
     194    err = DB_GET_FIELD (list, ta, list, list_t, next, 0);
     195    if (err != TD_OK)
     196      return err;
     197  
     198    if (list == 0)
     199      {
     200        if (ps_getpid (ta->ph) != lwpid)
     201  	return TD_ERR;
     202        th->th_ta_p = ta;
     203        th->th_unique = 0;
     204        return TD_OK;
     205      }
     206  
     207    return __td_ta_lookup_th_unique (ta_arg, lwpid, th);
     208  }