2003-09-08 Roland McGrath <roland@redhat.com>
[kopensolaris-gnu/glibc.git] / nptl_db / td_ta_map_lwp2thr.c
1 /* Which thread is running on an LWP?
2    Copyright (C) 2003 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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include "thread_dbP.h"
21 #include <stdlib.h>
22 #include <byteswap.h>
23 #include <sys/procfs.h>
24
25
26 td_err_e
27 td_ta_map_lwp2thr (const td_thragent_t *ta_arg,
28                    lwpid_t lwpid, td_thrhandle_t *th)
29 {
30   td_thragent_t *const ta = (td_thragent_t *) ta_arg;
31   ps_err_e err;
32   td_err_e terr;
33   prgregset_t regs;
34   psaddr_t addr;
35
36   LOG ("td_ta_map_lwp2thr");
37
38   /* Test whether the TA parameter is ok.  */
39   if (! ta_ok (ta))
40     return TD_BADTA;
41
42   if (ta->ta_howto == ta_howto_unknown)
43     {
44       /* We need to read in from the inferior the instructions what to do.  */
45       psaddr_t howto;
46
47       err = td_lookup (ta->ph, SYM_TH_UNIQUE_CONST_THREAD_AREA, &howto);
48       if (err == PS_OK)
49         {
50           err = ps_pdread (ta->ph, howto,
51                            &ta->ta_howto_data.const_thread_area,
52                            sizeof ta->ta_howto_data.const_thread_area);
53           if (err != PS_OK)
54             return TD_ERR;
55           ta->ta_howto = ta_howto_const_thread_area;
56           if (ta->ta_howto_data.const_thread_area & 0xff000000U)
57             ta->ta_howto_data.const_thread_area
58               = bswap_32 (ta->ta_howto_data.const_thread_area);
59         }
60       else
61         {
62           switch (sizeof (regs[0]))
63             {
64             case 8:
65               err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER64, &howto);
66               if (err == PS_OK)
67                 ta->ta_howto = ta_howto_reg;
68               else if (err == PS_NOSYM)
69                 {
70                   err = td_lookup (ta->ph,
71                                    SYM_TH_UNIQUE_REGISTER64_THREAD_AREA,
72                                    &howto);
73                   if (err == PS_OK)
74                     ta->ta_howto = ta_howto_reg_thread_area;
75                 }
76               break;
77
78             case 4:
79               err = td_lookup (ta->ph, SYM_TH_UNIQUE_REGISTER32, &howto);
80               if (err == PS_OK)
81                 ta->ta_howto = ta_howto_reg;
82               else if (err == PS_NOSYM)
83                 {
84                   err = td_lookup (ta->ph,
85                                    SYM_TH_UNIQUE_REGISTER32_THREAD_AREA,
86                                    &howto);
87                   if (err == PS_OK)
88                     ta->ta_howto = ta_howto_reg_thread_area;
89                 }
90               break;
91
92             default:
93               abort ();
94               return TD_DBERR;
95             }
96
97           if (err != PS_OK)
98             return TD_DBERR;
99
100           /* For either of these methods we read in the same descriptor.  */
101           err = ps_pdread (ta->ph, howto,
102                            ta->ta_howto_data.reg, DB_SIZEOF_DESC);
103           if (err != PS_OK)
104             return TD_ERR;
105           if (DB_DESC_SIZE (ta->ta_howto_data.reg) == 0)
106             return TD_DBERR;
107           if (DB_DESC_SIZE (ta->ta_howto_data.reg) & 0xff000000U)
108             {
109               /* Byte-swap these words, though we leave the size word
110                  in native order as the handy way to distinguish.  */
111               DB_DESC_OFFSET (ta->ta_howto_data.reg)
112                 = bswap_32 (DB_DESC_OFFSET (ta->ta_howto_data.reg));
113               DB_DESC_NELEM (ta->ta_howto_data.reg)
114                 = bswap_32 (DB_DESC_NELEM (ta->ta_howto_data.reg));
115             }
116         }
117     }
118
119   switch (ta->ta_howto)
120     {
121     case ta_howto_unknown:
122       return TD_DBERR;
123
124     default:
125       abort ();
126       return TD_DBERR;
127
128     case ta_howto_reg:
129       /* On most machines, we are just looking at a register.  */
130       if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
131         return TD_ERR;
132       terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg, -1,
133                                     0, regs, &addr);
134       if (terr != TD_OK)
135         return terr;
136       /* In this descriptor the nelem word is overloaded as the bias.  */
137       addr += (int32_t) DB_DESC_NELEM (ta->ta_howto_data.reg);
138       th->th_unique = addr;
139       break;
140
141     case ta_howto_const_thread_area:
142       /* Some hosts don't have this call and this case won't be used.  */
143 # pragma weak ps_get_thread_area
144       if (&ps_get_thread_area == NULL)
145         return TD_NOCAPAB;
146
147        /* A la x86-64, there is a constant magic index for get_thread_area.  */
148        if (ps_get_thread_area (ta->ph, lwpid,
149                                ta->ta_howto_data.const_thread_area,
150                                &th->th_unique) != PS_OK)
151          return TD_ERR; /* XXX Other error value?  */
152        break;
153
154      case ta_howto_reg_thread_area:
155       if (&ps_get_thread_area == NULL)
156         return TD_NOCAPAB;
157
158        /* A la i386, there is a register with an index for get_thread_area.  */
159        if (ps_lgetregs (ta->ph, lwpid, regs) != PS_OK)
160          return TD_ERR;
161        terr = _td_fetch_value_local (ta, ta->ta_howto_data.reg_thread_area, -1,
162                                      0, regs, &addr);
163       if (terr != TD_OK)
164         return terr;
165       /* In this descriptor the nelem word is overloaded as scale factor.  */
166       if (ps_get_thread_area
167           (ta->ph, lwpid,
168            ((addr - (psaddr_t) 0)
169             >> DB_DESC_NELEM (ta->ta_howto_data.reg_thread_area)),
170            &th->th_unique) != PS_OK)
171         return TD_ERR;  /* XXX Other error value?  */
172       break;
173     }
174
175   /* Found it.  Now complete the `td_thrhandle_t' object.  */
176   th->th_ta_p = (td_thragent_t *) ta;
177
178   return TD_OK;
179 }