1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2001-2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 29 #include <stdio.h> 30 #include <strings.h> 31 #include <sys/types.h> 32 #include <dlfcn.h> 33 #include <libc_int.h> 34 #include <_rtld.h> 35 #include <_elf.h> 36 #include <conv.h> 37 #include <msg.h> 38 #include <debug.h> 39 40 41 static void (* fptr_tls_modadd)(TLS_modinfo *) = 0; 42 static void (* fptr_tls_modrem)(TLS_modinfo *) = 0; 43 static void (* fptr_tls_statmods)(TLS_modinfo **, unsigned long) = 0; 44 45 static int tlsinitialized = 0; 46 static unsigned long tls_static_size = 0; /* static TLS buffer size */ 47 48 #define TLSBLOCKCNT 16 /* number of blocks of tmi_bits to allocate */ 49 /* at a time. */ 50 typedef struct { 51 uint_t *tmi_bits; 52 ulong_t tmi_lowfree; 53 ulong_t tmi_cnt; 54 } Tlsmodid; 55 56 static Tlsmodid tmid = {0, 0, 0}; 57 58 unsigned long 59 tls_getmodid() 60 { 61 ulong_t ndx; 62 ulong_t i; 63 64 if (tmid.tmi_bits == 0) { 65 if ((tmid.tmi_bits = 66 (uint_t *)calloc(TLSBLOCKCNT, sizeof (uint_t))) == 0) 67 return ((unsigned long)-1); 68 tmid.tmi_bits[0] = 1; 69 tmid.tmi_lowfree = 1; 70 tmid.tmi_cnt = TLSBLOCKCNT; 71 return (0); 72 } 73 74 for (i = tmid.tmi_lowfree / (sizeof (uint_t) * 8); 75 i < tmid.tmi_cnt; i++) { 76 uint_t j; 77 /* 78 * If all bits are assigned - move on. 79 */ 80 if ((tmid.tmi_bits[i] ^ ~((uint_t)0)) == 0) 81 continue; 82 for (ndx = 0, j = 1; j; j = j << 1, ndx++) { 83 if ((tmid.tmi_bits[i] & j) == 0) { 84 tmid.tmi_bits[i] |= j; 85 ndx = (i * (sizeof (uint_t)) * 8) + ndx; 86 tmid.tmi_lowfree = ndx + 1; 87 return (ndx); 88 } 89 } 90 } 91 92 /* 93 * All bits taken - must allocate a new block 94 */ 95 if ((tmid.tmi_bits = (uint_t *)realloc(tmid.tmi_bits, 96 ((tmid.tmi_cnt * sizeof (uint_t)) + 97 (TLSBLOCKCNT * sizeof (uint_t))))) == 0) 98 return ((unsigned long)-1); 99 /* 100 * clear out the tail of the new allocation 101 */ 102 bzero(&(tmid.tmi_bits[tmid.tmi_cnt]), TLSBLOCKCNT * sizeof (uint_t)); 103 tmid.tmi_bits[tmid.tmi_cnt] = 1; 104 ndx = (tmid.tmi_cnt * sizeof (uint_t)) * 8; 105 tmid.tmi_lowfree = ndx + 1; 106 tmid.tmi_cnt += TLSBLOCKCNT; 107 108 return (ndx); 109 } 110 111 112 void 113 tls_freemodid(unsigned long modid) 114 { 115 ulong_t i; 116 uint_t j; 117 118 i = modid / (sizeof (uint_t) * 8); 119 /* LINTED */ 120 j = modid % (sizeof (uint_t) * 8); 121 j = ~(1 << j); 122 tmid.tmi_bits[i] &= j; 123 if (modid < tmid.tmi_lowfree) 124 tmid.tmi_lowfree = modid; 125 } 126 127 128 void 129 tls_setroutines(Lm_list *lml, void * modadd, void * modrem, void * statmod) 130 { 131 /* 132 * If a version of libc/libthread gives us only a subset 133 * of the TLS interfaces - it's confused and we discard 134 * the whole lot. 135 */ 136 if (!modadd || !modrem || !statmod) 137 return; 138 139 if ((fptr_tls_modadd == 0) || (lml->lm_flags & LML_FLG_BASELM)) 140 fptr_tls_modadd = (void(*)(TLS_modinfo *)) modadd; 141 if ((fptr_tls_modrem == 0) || (lml->lm_flags & LML_FLG_BASELM)) 142 fptr_tls_modrem = (void(*)(TLS_modinfo *)) modrem; 143 /* 144 * The 'statmods' interface is only relevent for the 145 * primary link-map - ignore all other instances. 146 */ 147 if (lml->lm_flags & LML_FLG_BASELM) 148 fptr_tls_statmods = 149 (void(*)(TLS_modinfo **, unsigned long)) statmod; 150 } 151 152 153 void 154 tls_modactivity(Rt_map * lmp, uint_t flag) 155 { 156 TLS_modinfo tmi; 157 Phdr * tlsphdr; 158 void (* fptr)(TLS_modinfo *); 159 160 if (flag & TM_FLG_MODADD) 161 fptr = fptr_tls_modadd; 162 else 163 fptr = fptr_tls_modrem; 164 165 /* 166 * We only report TLS modactivity for the primary link-map 167 * after all the objects have been loaded and we've reported 168 * the STATIC tls modlist (see tls_report_modules()). 169 */ 170 if (((tlsinitialized == 0) && 171 (LIST(lmp)->lm_flags & LML_FLG_BASELM)) || 172 (fptr == 0) || (lmp == 0) || (FCT(lmp) != &elf_fct) || 173 (PTTLS(lmp) == 0)) 174 return; 175 176 tlsphdr = PTTLS(lmp); 177 178 bzero(&tmi, sizeof (tmi)); 179 tmi.tm_modname = PATHNAME(lmp); 180 tmi.tm_modid = TLSMODID(lmp); 181 tmi.tm_tlsblock = (void *)(tlsphdr->p_vaddr); 182 if (!(FLAGS(lmp) & FLG_RT_FIXED)) 183 tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock + 184 ADDR(lmp)); 185 tmi.tm_filesz = tlsphdr->p_filesz; 186 tmi.tm_memsz = tlsphdr->p_memsz; 187 tmi.tm_flags = 0; 188 tmi.tm_stattlsoffset = 0; 189 190 DBG_CALL(Dbg_tls_modactivity(&tmi, flag)); 191 fptr(&tmi); 192 193 /* 194 * Free up the moduleid 195 */ 196 if (flag & TM_FLG_MODREM) 197 tls_freemodid(TLSMODID(lmp)); 198 } 199 200 201 void 202 tls_assign_soffset(Rt_map * lmp) 203 { 204 if (PTTLS(lmp) == 0) 205 return; 206 207 /* 208 * Only objects on the primary link-map list are associated 209 * with the STATIC tls block. 210 */ 211 if (LIST(lmp)->lm_flags & LML_FLG_BASELM) { 212 tls_static_size += S_ROUND(PTTLS(lmp)->p_memsz, M_TLSSTATALIGN); 213 TLSSTATOFF(lmp) = tls_static_size; 214 } 215 216 /* 217 * Everyone get's a dynamic TLS modid 218 */ 219 TLSMODID(lmp) = tls_getmodid(); 220 } 221 222 int 223 tls_report_modules() 224 { 225 Rt_map * lmp; 226 uint_t tlsmodcnt; 227 uint_t tlsmodndx; 228 TLS_modinfo ** tlsmodlist; 229 TLS_modinfo * tlsbuflist; 230 Phdr * tlsphdr; 231 232 tlsinitialized++; 233 /* 234 * Scan through all objects to determine how many have TLS 235 * storage. 236 */ 237 tlsmodcnt = 0; 238 for (lmp = lml_main.lm_head; lmp; lmp = (Rt_map *)NEXT(lmp)) { 239 if ((FCT(lmp) != &elf_fct) || 240 (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0)) 241 continue; 242 tlsmodcnt++; 243 244 if (fptr_tls_statmods) 245 continue; 246 247 /* 248 * If a module has TLS - but the TLS interfaces 249 * are not present (no libthread?). Then this is 250 * a fatal condition. 251 */ 252 eprintf(ERR_FATAL, MSG_INTL(MSG_ERR_TLS_NOTLS), 253 NAME(lmp)); 254 return (0); 255 } 256 257 /* 258 * If we don't have any TLS modules - report that and return. 259 */ 260 if (tlsmodcnt == 0) { 261 if (fptr_tls_statmods != 0) 262 fptr_tls_statmods(0, 0); 263 return (1); 264 } 265 266 /* 267 * Allocate a buffer to report the TLS modules, the buffer consists of: 268 * 269 * TLS_modinfo * ptrs[tlsmodcnt + 1] 270 * TLS_modinfo bufs[tlsmodcnt] 271 * 272 * The ptrs are initialized to the bufs - except the last 273 * one which null terminates the array. 274 */ 275 if ((tlsmodlist = calloc((sizeof (TLS_modinfo *) * tlsmodcnt + 1) + 276 (sizeof (TLS_modinfo) * tlsmodcnt), 1)) == 0) 277 return (0); 278 279 tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist + 280 ((tlsmodcnt + 1) * sizeof (TLS_modinfo *))); 281 for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++) 282 tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx]; 283 284 /* 285 * Account for the initial dtv ptr in the TLSSIZE calculation. 286 */ 287 tlsmodndx = 0; 288 for (lmp = lml_main.lm_head; lmp; lmp = (Rt_map *)NEXT(lmp)) { 289 if ((FCT(lmp) != &elf_fct) || 290 (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0)) 291 continue; 292 293 tlsphdr = PTTLS(lmp); 294 295 tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp); 296 tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp); 297 tlsmodlist[tlsmodndx]->tm_tlsblock = 298 (void *)(tlsphdr->p_vaddr); 299 if (!(FLAGS(lmp) & FLG_RT_FIXED)) 300 tlsmodlist[tlsmodndx]->tm_tlsblock = 301 (void *)((uintptr_t)tlsmodlist[ 302 tlsmodndx]->tm_tlsblock + ADDR(lmp)); 303 tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz; 304 tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz; 305 tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS; 306 tlsmodlist[tlsmodndx]->tm_stattlsoffset = 307 TLSSTATOFF(lmp); 308 tlsmodndx++; 309 } 310 311 DBG_CALL(Dbg_tls_static_block((void *)tlsmodlist, tls_static_size)); 312 fptr_tls_statmods(tlsmodlist, tls_static_size); 313 314 /* 315 * We're done with the list - clean it up. 316 */ 317 free(tlsmodlist); 318 return (1); 319 } 320