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