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