| /* Which thread is running on an LWP? |
| Copyright (C) 2003-2014 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, see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #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); |
| } |