|
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 |
}
|