Print this page
smatch clean rtld
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/sgs/rtld/common/tls.c
+++ new/usr/src/cmd/sgs/rtld/common/tls.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 #include <stdio.h>
28 28 #include <strings.h>
29 29 #include <sys/types.h>
30 30 #include <dlfcn.h>
31 31 #include <libc_int.h>
32 32 #include <_rtld.h>
33 33 #include <_elf.h>
34 34 #include <msg.h>
35 35 #include <debug.h>
36 36
37 37 #define TLSBLOCKCNT 16 /* number of blocks of tmi_bits to allocate */
38 38 /* at a time. */
39 39 typedef struct {
40 40 uint_t *tmi_bits;
41 41 ulong_t tmi_lowfree;
42 42 ulong_t tmi_cnt;
43 43 } Tlsmodid;
44 44
45 45 static Tlsmodid tmid = {0, 0, 0};
46 46
47 47 static ulong_t
48 48 tls_getmodid()
49 49 {
50 50 ulong_t ndx, cnt;
51 51
52 52 if (tmid.tmi_bits == 0) {
53 53 if ((tmid.tmi_bits =
54 54 calloc(TLSBLOCKCNT, sizeof (uint_t))) == NULL)
55 55 return ((ulong_t)-1);
56 56 tmid.tmi_bits[0] = 1;
57 57 tmid.tmi_lowfree = 1;
58 58 tmid.tmi_cnt = TLSBLOCKCNT;
59 59 return (0);
60 60 }
61 61
62 62 for (cnt = tmid.tmi_lowfree / (sizeof (uint_t) * 8);
63 63 cnt < tmid.tmi_cnt; cnt++) {
64 64 uint_t bits;
65 65
66 66 /*
67 67 * If all bits are assigned - move on.
68 68 */
69 69 if ((tmid.tmi_bits[cnt] ^ ~((uint_t)0)) == 0)
70 70 continue;
71 71
72 72 for (ndx = 0, bits = 1; bits; bits = bits << 1, ndx++) {
73 73 if ((tmid.tmi_bits[cnt] & bits) == 0) {
74 74 tmid.tmi_bits[cnt] |= bits;
75 75 ndx = (cnt * (sizeof (uint_t)) * 8) + ndx;
76 76 tmid.tmi_lowfree = ndx + 1;
77 77 return (ndx);
78 78 }
79 79 }
80 80 }
81 81
82 82 /*
83 83 * All bits taken - must allocate a new block
84 84 */
85 85 if ((tmid.tmi_bits = realloc(tmid.tmi_bits,
86 86 ((tmid.tmi_cnt * sizeof (uint_t)) +
87 87 (TLSBLOCKCNT * sizeof (uint_t))))) == NULL)
88 88 return ((ulong_t)-1);
89 89
90 90 /*
91 91 * Clear out the tail of the new allocation.
92 92 */
93 93 bzero(&(tmid.tmi_bits[tmid.tmi_cnt]), TLSBLOCKCNT * sizeof (uint_t));
94 94 tmid.tmi_bits[tmid.tmi_cnt] = 1;
95 95 ndx = (tmid.tmi_cnt * sizeof (uint_t)) * 8;
96 96 tmid.tmi_lowfree = ndx + 1;
97 97 tmid.tmi_cnt += TLSBLOCKCNT;
98 98
99 99 return (ndx);
100 100 }
101 101
102 102 void
103 103 tls_freemodid(ulong_t modid)
104 104 {
105 105 ulong_t i;
106 106 uint_t j;
107 107
108 108 i = modid / (sizeof (uint_t) * 8);
109 109 /* LINTED */
110 110 j = modid % (sizeof (uint_t) * 8);
111 111 j = ~(1 << j);
112 112 tmid.tmi_bits[i] &= j;
113 113 if (modid < tmid.tmi_lowfree)
114 114 tmid.tmi_lowfree = modid;
115 115 }
116 116
117 117 void
118 118 tls_modaddrem(Rt_map *lmp, uint_t flag)
119 119 {
120 120 Lm_list *lml = LIST(lmp);
121 121 TLS_modinfo tmi;
122 122 Phdr *tlsphdr;
123 123 int (*fptr)(TLS_modinfo *);
124 124
125 125 if (flag & TM_FLG_MODADD) {
126 126 fptr = lml->lm_lcs[CI_TLS_MODADD].lc_un.lc_func;
127 127 } else if (FLAGS1(lmp) & FL1_RT_TLSADD) {
128 128 fptr = lml->lm_lcs[CI_TLS_MODREM].lc_un.lc_func;
129 129 } else {
130 130 return;
131 131 }
132 132
133 133 tlsphdr = PTTLS(lmp);
134 134
135 135 bzero(&tmi, sizeof (tmi));
136 136 tmi.tm_modname = PATHNAME(lmp);
137 137 tmi.tm_modid = TLSMODID(lmp);
138 138 tmi.tm_tlsblock = (void *)(tlsphdr->p_vaddr);
139 139
140 140 if (!(FLAGS(lmp) & FLG_RT_FIXED))
141 141 tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock +
142 142 ADDR(lmp));
143 143
144 144 tmi.tm_filesz = tlsphdr->p_filesz;
145 145 tmi.tm_memsz = tlsphdr->p_memsz;
146 146 tmi.tm_flags = 0;
147 147 tmi.tm_stattlsoffset = 0;
148 148
149 149 DBG_CALL(Dbg_tls_modactivity(LIST(lmp), &tmi, flag));
150 150 (void) (*fptr)(&tmi);
151 151
152 152 /*
153 153 * Tag that this link-map has registered its TLS, and, if this object
154 154 * is being removed, free up the module id.
155 155 */
156 156 FLAGS1(lmp) |= FL1_RT_TLSADD;
157 157
158 158 if (flag & TM_FLG_MODREM)
159 159 tls_freemodid(TLSMODID(lmp));
160 160 }
161 161
162 162 static ulong_t tls_static_size = 0; /* static TLS buffer size */
163 163 static ulong_t tls_static_resv = 512; /* (extra) static TLS reservation */
164 164
165 165 /*
166 166 * Track any static TLS use, retain the TLS header, and assign a TLS module
167 167 * identifier.
168 168 */
169 169 int
170 170 tls_assign(Lm_list *lml, Rt_map *lmp, Phdr *phdr)
171 171 {
172 172 ulong_t memsz = S_ROUND(phdr->p_memsz, M_TLSSTATALIGN);
173 173 ulong_t filesz = phdr->p_filesz;
174 174 ulong_t resv = tls_static_resv;
175 175
176 176 /*
177 177 * If this object explicitly references static TLS, then there are some
178 178 * limitations.
179 179 */
180 180 if (FLAGS1(lmp) & FL1_RT_TLSSTAT) {
181 181 /*
182 182 * Static TLS is only available to objects on the primary
183 183 * link-map list.
184 184 */
185 185 if (((lml->lm_flags & LML_FLG_BASELM) == 0) ||
186 186 ((rtld_flags2 & RT_FL2_NOPLM) != 0)) {
187 187 eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TLS_STATBASE),
188 188 NAME(lmp));
189 189 return (0);
190 190 }
191 191
192 192 /*
193 193 * All TLS blocks that are processed before thread
194 194 * initialization, are registered with libc. This
195 195 * initialization is carried out through a handshake with libc
196 196 * prior to executing any user code (ie. before the first .init
197 197 * sections are called). As part of this initialization, a
198 198 * small backup TLS reservation is added (tls_static_resv).
199 199 * Only explicit static TLS references that can be satisfied by
200 200 * this TLS backup reservation can be satisfied.
201 201 */
202 202 if (rtld_flags2 & RT_FL2_PLMSETUP) {
203 203 /*
204 204 * Initialized static TLS can not be satisfied from the
205 205 * TLS backup reservation.
206 206 */
207 207 if (filesz) {
208 208 eprintf(lml, ERR_FATAL,
209 209 MSG_INTL(MSG_TLS_STATINIT), NAME(lmp));
210 210 return (0);
211 211 }
212 212
213 213 /*
214 214 * Make sure the backup reservation is sufficient.
215 215 */
216 216 if (memsz > tls_static_resv) {
217 217 eprintf(lml, ERR_FATAL,
218 218 MSG_INTL(MSG_TLS_STATSIZE), NAME(lmp),
219 219 EC_XWORD(memsz), EC_XWORD(tls_static_resv));
220 220 return (0);
221 221 }
222 222
223 223 tls_static_resv -= memsz;
224 224 }
225 225 }
226 226
227 227 /*
228 228 * If we haven't yet initialized threads, or this static reservation can
229 229 * be satisfied from the TLS backup reservation, determine the total
230 230 * static TLS size, and assign this object a static TLS offset.
231 231 */
232 232 if (((rtld_flags2 & RT_FL2_PLMSETUP) == 0) ||
233 233 (FLAGS1(lmp) & FL1_RT_TLSSTAT)) {
234 234 tls_static_size += memsz;
235 235 TLSSTATOFF(lmp) = tls_static_size;
236 236 }
237 237
238 238 /*
239 239 * Retain the PT_TLS header, obtain a new module identifier, and
240 240 * indicate that this link-map list contains a new TLS object.
241 241 */
242 242 PTTLS(lmp) = phdr;
243 243 TLSMODID(lmp) = tls_getmodid();
244 244
245 245 /*
246 246 * Now that we have a TLS module id, generate any static TLS reservation
247 247 * diagnostic.
248 248 */
249 249 if (resv != tls_static_resv)
250 250 DBG_CALL(Dbg_tls_static_resv(lmp, memsz, tls_static_resv));
251 251
252 252 return (++lml->lm_tls);
253 253 }
254 254
255 255 int
256 256 tls_statmod(Lm_list *lml, Rt_map *lmp)
257 257 {
258 258 uint_t tlsmodndx, tlsmodcnt = lml->lm_tls;
259 259 TLS_modinfo **tlsmodlist, *tlsbuflist;
260 260 Phdr *tlsphdr;
261 261 int (*fptr)(TLS_modinfo **, ulong_t);
262 262
263 263 fptr = lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func;
264 264
265 265 /*
266 266 * Allocate a buffer to report the TLS modules, the buffer consists of:
267 267 *
↓ open down ↓ |
267 lines elided |
↑ open up ↑ |
268 268 * TLS_modinfo * ptrs[tlsmodcnt + 1]
269 269 * TLS_modinfo bufs[tlsmodcnt]
270 270 *
271 271 * The ptrs are initialized to the bufs - except the last one which
272 272 * null terminates the array.
273 273 *
274 274 * Note, even if no TLS has yet been observed, we still supply a
275 275 * TLS buffer with a single null entry. This allows us to initialize
276 276 * the backup TLS reservation.
277 277 */
278 - if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
279 - (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == NULL)
278 + if ((tlsmodlist = calloc(1, (sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
279 + (sizeof (TLS_modinfo) * tlsmodcnt))) == NULL)
280 280 return (0);
281 281
282 282 lml->lm_tls = 0;
283 283
284 284 /*
285 285 * If we don't have any TLS modules - report that and return.
286 286 */
287 287 if (tlsmodcnt == 0) {
288 288 if (fptr != NULL)
289 289 (void) (*fptr)(tlsmodlist, tls_static_resv);
290 290 DBG_CALL(Dbg_tls_static_block(&lml_main, 0, 0,
291 291 tls_static_resv));
292 292 return (1);
293 293 }
294 294
295 295 /*
296 296 * Initialize the TLS buffer.
297 297 */
298 298 tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist +
299 299 ((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));
300 300
301 301 for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++)
302 302 tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx];
303 303
304 304 /*
305 305 * Account for the initial dtv ptr in the TLSSIZE calculation.
306 306 */
307 307 tlsmodndx = 0;
308 308 for (lmp = lml->lm_head; lmp; lmp = NEXT_RT_MAP(lmp)) {
309 309 if (THIS_IS_NOT_ELF(lmp) ||
310 310 (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0))
311 311 continue;
312 312
313 313 tlsphdr = PTTLS(lmp);
314 314
315 315 tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp);
316 316 tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp);
317 317 tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr);
318 318
319 319 if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
320 320 tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)
321 321 ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock +
322 322 ADDR(lmp));
323 323 }
324 324 tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz;
325 325 tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz;
326 326 tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS;
327 327 tlsmodlist[tlsmodndx]->tm_stattlsoffset = TLSSTATOFF(lmp);
328 328 tlsmodndx++;
329 329 }
330 330
331 331 DBG_CALL(Dbg_tls_static_block(&lml_main, (void *)tlsmodlist,
332 332 tls_static_size, tls_static_resv));
333 333 (void) (*fptr)(tlsmodlist, (tls_static_size + tls_static_resv));
334 334
335 335 /*
336 336 * We're done with the list - clean it up.
337 337 */
338 338 free(tlsmodlist);
339 339 return (1);
340 340 }
↓ open down ↓ |
51 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX