]>
Commit | Line | Data |
---|---|---|
2f84cc6a | 1 | /* Locate TLS data for a thread. |
04277e02 | 2 | Copyright (C) 2003-2019 Free Software Foundation, Inc. |
2f84cc6a RM |
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 | |
59ba27a6 | 16 | License along with the GNU C Library; if not, see |
5a82c748 | 17 | <https://www.gnu.org/licenses/>. */ |
2f84cc6a RM |
18 | |
19 | #include "thread_dbP.h" | |
f8aeae34 | 20 | #include <link.h> |
2f84cc6a | 21 | |
f8aeae34 AO |
22 | /* Get the DTV slotinfo list head entry from the dynamic loader state |
23 | into *LISTHEAD. */ | |
24 | static td_err_e | |
25 | dtv_slotinfo_list (td_thragent_t *ta, | |
26 | psaddr_t *listhead) | |
27 | { | |
28 | td_err_e err; | |
29 | psaddr_t head; | |
30 | ||
31 | if (ta->ta_addr__rtld_global == 0 | |
32 | && td_mod_lookup (ta->ph, LD_SO, SYM__rtld_global, | |
33 | &ta->ta_addr__rtld_global) != PS_OK) | |
34 | ta->ta_addr__rtld_global = (void*)-1; | |
35 | ||
36 | if (ta->ta_addr__rtld_global != (void*)-1) | |
37 | { | |
38 | err = DB_GET_FIELD (head, ta, ta->ta_addr__rtld_global, | |
39 | rtld_global, _dl_tls_dtv_slotinfo_list, 0); | |
40 | if (err != TD_OK) | |
41 | return err; | |
42 | } | |
43 | else | |
44 | { | |
45 | if (ta->ta_addr__dl_tls_dtv_slotinfo_list == 0 | |
46 | && td_mod_lookup (ta->ph, NULL, SYM__dl_tls_dtv_slotinfo_list, | |
47 | &ta->ta_addr__dl_tls_dtv_slotinfo_list) != PS_OK) | |
48 | return TD_ERR; | |
49 | ||
50 | err = _td_fetch_value (ta, ta->ta_var__dl_tls_dtv_slotinfo_list, | |
51 | SYM_DESC__dl_tls_dtv_slotinfo_list, | |
52 | 0, ta->ta_addr__dl_tls_dtv_slotinfo_list, &head); | |
53 | if (err != TD_OK) | |
54 | return err; | |
55 | } | |
56 | ||
57 | *listhead = head; | |
58 | return TD_OK; | |
59 | } | |
60 | ||
61 | /* Get the address of the DTV slotinfo entry for MODID into | |
62 | *DTVSLOTINFO. */ | |
63 | static td_err_e | |
64 | dtv_slotinfo (td_thragent_t *ta, | |
65 | unsigned long int modid, | |
66 | psaddr_t *dtvslotinfo) | |
67 | { | |
68 | td_err_e err; | |
69 | psaddr_t slot, temp; | |
70 | size_t slbase = 0; | |
71 | ||
72 | err = dtv_slotinfo_list (ta, &slot); | |
73 | if (err != TD_OK) | |
74 | return err; | |
75 | ||
76 | while (slot) | |
77 | { | |
78 | /* Get the number of entries in this list entry's array. */ | |
79 | err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list, len, 0); | |
80 | if (err != TD_OK) | |
81 | return err; | |
82 | size_t len = (uintptr_t)temp; | |
83 | ||
84 | /* Did we find the list entry for modid? */ | |
85 | if (modid < slbase + len) | |
86 | break; | |
87 | ||
88 | /* We didn't, so get the next list entry. */ | |
89 | slbase += len; | |
90 | err = DB_GET_FIELD (temp, ta, slot, dtv_slotinfo_list, | |
91 | next, 0); | |
92 | if (err != TD_OK) | |
93 | return err; | |
94 | slot = temp; | |
95 | } | |
96 | ||
97 | /* We reached the end of the list and found nothing. */ | |
98 | if (!slot) | |
99 | return TD_ERR; | |
100 | ||
101 | /* Take the slotinfo for modid from the list entry. */ | |
102 | err = DB_GET_FIELD_ADDRESS (temp, ta, slot, dtv_slotinfo_list, | |
103 | slotinfo, modid - slbase); | |
104 | if (err != TD_OK) | |
105 | return err; | |
106 | slot = temp; | |
107 | ||
108 | *dtvslotinfo = slot; | |
109 | return TD_OK; | |
110 | } | |
111 | ||
112 | /* Return in *BASE the base address of the TLS block for MODID within | |
113 | TH. | |
114 | ||
115 | It should return success and yield the correct pointer in any | |
116 | circumstance where the TLS block for the module and thread | |
117 | requested has already been initialized. | |
118 | ||
119 | It should fail with TD_TLSDEFER only when the thread could not | |
120 | possibly have observed any values in that TLS block. That way, the | |
121 | debugger can fall back to showing initial values from the PT_TLS | |
122 | segment (and refusing attempts to mutate) for the TD_TLSDEFER case, | |
123 | and never fail to make the values the program will actually see | |
124 | available to the user of the debugger. */ | |
2f84cc6a RM |
125 | td_err_e |
126 | td_thr_tlsbase (const td_thrhandle_t *th, | |
127 | unsigned long int modid, | |
128 | psaddr_t *base) | |
129 | { | |
7f08f55a | 130 | td_err_e err; |
f8aeae34 | 131 | psaddr_t dtv, dtvslot, dtvptr, temp; |
7f08f55a | 132 | |
2f84cc6a RM |
133 | if (modid < 1) |
134 | return TD_NOTLS; | |
135 | ||
7d9d8bd1 RM |
136 | psaddr_t pd = th->th_unique; |
137 | if (pd == 0) | |
138 | { | |
139 | /* This is the fake handle for the main thread before libpthread | |
140 | initialization. We are using 0 for its th_unique because we can't | |
141 | trust that its thread register has been initialized. But we need | |
142 | a real pointer to have any TLS access work. In case of dlopen'd | |
143 | libpthread, initialization might not be for quite some time. So | |
144 | try looking up the thread register now. Worst case, it's nonzero | |
145 | uninitialized garbage and we get bogus results for TLS access | |
146 | attempted too early. Tough. */ | |
147 | ||
148 | td_thrhandle_t main_th; | |
149 | err = __td_ta_lookup_th_unique (th->th_ta_p, ps_getpid (th->th_ta_p->ph), | |
150 | &main_th); | |
151 | if (err == 0) | |
152 | pd = main_th.th_unique; | |
153 | if (pd == 0) | |
154 | return TD_TLSDEFER; | |
155 | } | |
156 | ||
f8aeae34 AO |
157 | err = dtv_slotinfo (th->th_ta_p, modid, &temp); |
158 | if (err != TD_OK) | |
159 | return err; | |
160 | ||
161 | psaddr_t slot; | |
162 | err = DB_GET_STRUCT (slot, th->th_ta_p, temp, dtv_slotinfo); | |
163 | if (err != TD_OK) | |
164 | return err; | |
165 | ||
166 | /* Take the link_map from the slotinfo. */ | |
167 | psaddr_t map; | |
168 | err = DB_GET_FIELD_LOCAL (map, th->th_ta_p, slot, dtv_slotinfo, map, 0); | |
169 | if (err != TD_OK) | |
170 | return err; | |
171 | if (!map) | |
172 | return TD_ERR; | |
173 | ||
174 | /* Ok, the modid is good, now find out what DTV generation it | |
175 | requires. */ | |
176 | err = DB_GET_FIELD_LOCAL (temp, th->th_ta_p, slot, dtv_slotinfo, gen, 0); | |
177 | if (err != TD_OK) | |
178 | return err; | |
179 | size_t modgen = (uintptr_t)temp; | |
180 | ||
2f84cc6a | 181 | /* Get the DTV pointer from the thread descriptor. */ |
7d9d8bd1 | 182 | err = DB_GET_FIELD (dtv, th->th_ta_p, pd, pthread, dtvp, 0); |
7f08f55a RM |
183 | if (err != TD_OK) |
184 | return err; | |
2f84cc6a | 185 | |
f8aeae34 AO |
186 | psaddr_t dtvgenloc; |
187 | /* Get the DTV generation count at dtv[0].counter. */ | |
188 | err = DB_GET_FIELD_ADDRESS (dtvgenloc, th->th_ta_p, dtv, dtv, dtv, 0); | |
189 | if (err != TD_OK) | |
190 | return err; | |
191 | err = DB_GET_FIELD (temp, th->th_ta_p, dtvgenloc, dtv_t, counter, 0); | |
192 | if (err != TD_OK) | |
193 | return err; | |
194 | size_t dtvgen = (uintptr_t)temp; | |
195 | ||
196 | /* Is the DTV current enough? */ | |
197 | if (dtvgen < modgen) | |
198 | { | |
199 | try_static_tls: | |
200 | /* If the module uses Static TLS, we're still good. */ | |
201 | err = DB_GET_FIELD (temp, th->th_ta_p, map, link_map, l_tls_offset, 0); | |
202 | if (err != TD_OK) | |
203 | return err; | |
204 | ptrdiff_t tlsoff = (uintptr_t)temp; | |
205 | ||
206 | if (tlsoff != FORCED_DYNAMIC_TLS_OFFSET | |
207 | && tlsoff != NO_TLS_OFFSET) | |
208 | { | |
209 | psaddr_t tp = pd; | |
210 | ||
211 | #if TLS_TCB_AT_TP | |
212 | dtvptr = tp - tlsoff; | |
213 | #elif TLS_DTV_AT_TP | |
214 | dtvptr = tp + tlsoff + TLS_PRE_TCB_SIZE; | |
215 | #else | |
216 | # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" | |
217 | #endif | |
218 | ||
219 | *base = dtvptr; | |
220 | return TD_OK; | |
221 | } | |
222 | ||
223 | return TD_TLSDEFER; | |
224 | } | |
225 | ||
0fdd44dc RM |
226 | /* Find the corresponding entry in the DTV. */ |
227 | err = DB_GET_FIELD_ADDRESS (dtvslot, th->th_ta_p, dtv, dtv, dtv, modid); | |
228 | if (err != TD_OK) | |
229 | return err; | |
230 | ||
231 | /* Extract the TLS block address from that DTV slot. */ | |
232 | err = DB_GET_FIELD (dtvptr, th->th_ta_p, dtvslot, dtv_t, pointer_val, 0); | |
7f08f55a RM |
233 | if (err != TD_OK) |
234 | return err; | |
2f84cc6a RM |
235 | |
236 | /* It could be that the memory for this module is not allocated for | |
237 | the given thread. */ | |
7f08f55a | 238 | if ((uintptr_t) dtvptr & 1) |
f8aeae34 | 239 | goto try_static_tls; |
2f84cc6a | 240 | |
7f08f55a | 241 | *base = dtvptr; |
2f84cc6a | 242 | return TD_OK; |
2f84cc6a | 243 | } |