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 2008 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*      Copyright (c) 1988 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 #pragma ident   "%Z%%M% %I%     %E% SMI"
  31 
  32 /*
  33  * This stuff used to live in cook.c, but was moved out to
  34  * facilitate dual (Elf32 and Elf64) compilation.  See block
  35  * comment in cook.c for more info.
  36  */
  37 
  38 #include <string.h>
  39 #include <ar.h>
  40 #include <stdlib.h>
  41 #include <errno.h>
  42 #include "decl.h"
  43 #include "member.h"
  44 #include "msg.h"
  45 
  46 /*
  47  * This module is compiled twice, the second time having
  48  * -D_ELF64 defined.  The following set of macros, along
  49  * with machelf.h, represent the differences between the
  50  * two compilations.  Be careful *not* to add any class-
  51  * dependent code (anything that has elf32 or elf64 in the
  52  * name) to this code without hiding it behind a switch-
  53  * able macro like these.
  54  */
  55 #if     defined(_ELF64)
  56 #define Snode           Snode64
  57 #define ELFCLASS        ELFCLASS64
  58 #define ElfField        Elf64
  59 #define _elf_snode_init _elf64_snode_init
  60 #define _elf_prepscan   _elf64_prepscan
  61 #define _elf_cookscn    _elf64_cookscn
  62 #define _elf_mtype      _elf64_mtype
  63 #define _elf_msize      _elf64_msize
  64 #define elf_fsize       elf64_fsize
  65 #define _elf_snode      _elf64_snode
  66 #define _elf_ehdr       _elf64_ehdr
  67 #define elf_xlatetom    elf64_xlatetom
  68 #define _elf_phdr       _elf64_phdr
  69 #define _elf_shdr       _elf64_shdr
  70 #define _elf_prepscn    _elf64_prepscn
  71 
  72 #else  /* Elf32 */
  73 #define Snode           Snode32
  74 #define ELFCLASS        ELFCLASS32
  75 #define ElfField        Elf32
  76 #define _elf_snode_init _elf32_snode_init
  77 #define _elf_prepscan   _elf32_prepscan
  78 #define _elf_cookscn    _elf32_cookscn
  79 #define _elf_mtype      _elf32_mtype
  80 #define _elf_msize      _elf32_msize
  81 #define elf_fsize       elf32_fsize
  82 #define _elf_snode      _elf32_snode
  83 #define _elf_ehdr       _elf32_ehdr
  84 #define elf_xlatetom    elf32_xlatetom
  85 #define _elf_phdr       _elf32_phdr
  86 #define _elf_shdr       _elf32_shdr
  87 #define _elf_prepscn    _elf32_prepscn
  88 
  89 #endif /* _ELF64 */
  90 
  91 
  92 static Okay
  93 _elf_prepscn(Elf *elf, size_t cnt)
  94 {
  95         NOTE(ASSUMING_PROTECTED(*elf))
  96         Elf_Scn *       s;
  97         Elf_Scn *       end;
  98 
  99         if (cnt == 0)
 100                 return (OK_YES);
 101 
 102         if ((s = malloc(cnt * sizeof (Elf_Scn))) == 0) {
 103                 _elf_seterr(EMEM_SCN, errno);
 104                 return (OK_NO);
 105         }
 106         NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*s))
 107         elf->ed_scntabsz = cnt;
 108         end = s + cnt;
 109         elf->ed_hdscn = s;
 110         do {
 111                 *s = _elf_snode_init.sb_scn;
 112                 s->s_elf = elf;
 113                 s->s_next = s + 1;
 114                 s->s_index = s - elf->ed_hdscn;
 115                 s->s_shdr = (Shdr*)s->s_elf->ed_shdr + s->s_index;
 116                 ELFMUTEXINIT(&s->s_mutex);
 117 
 118                 /*
 119                  * Section has not yet been cooked!
 120                  *
 121                  * We don't cook a section until it's data is actually
 122                  * referenced.
 123                  */
 124                 s->s_myflags = 0;
 125         } while (++s < end);
 126 
 127         elf->ed_tlscn = --s;
 128         s->s_next = 0;
 129 
 130         /*
 131          * Section index SHN_UNDEF (0) does not and cannot
 132          * have a data buffer.  Fix it here.  Also mark the
 133          * initial section as being allocated for the block
 134          */
 135 
 136         s = elf->ed_hdscn;
 137         s->s_myflags = SF_ALLOC;
 138         s->s_hdnode = 0;
 139         s->s_tlnode = 0;
 140         NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*s))
 141         return (OK_YES);
 142 }
 143 
 144 
 145 Okay
 146 _elf_cookscn(Elf_Scn * s)
 147 {
 148         NOTE(ASSUMING_PROTECTED(*s, *(s->s_elf)))
 149         Elf *                   elf;
 150         Shdr *                  sh;
 151         register Dnode *        d = &s->s_dnode;
 152         size_t                  fsz, msz;
 153         unsigned                work;
 154 
 155         NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*d))
 156         s->s_hdnode = s->s_tlnode = d;
 157         s->s_err = 0;
 158         s->s_shflags = 0;
 159         s->s_uflags = 0;
 160 
 161 
 162         /*
 163          * Prepare d_data for inspection, but don't actually
 164          * translate data until needed.  Leave the READY
 165          * flag off.  NOBITS sections see zero size.
 166          */
 167         elf = s->s_elf;
 168         sh = s->s_shdr;
 169 
 170         d->db_scn = s;
 171         d->db_off = sh->sh_offset;
 172         d->db_data.d_align = sh->sh_addralign;
 173         d->db_data.d_version = elf->ed_version;
 174         ELFACCESSDATA(work, _elf_work)
 175         d->db_data.d_type = _elf_mtype(elf, sh->sh_type, work);
 176         d->db_data.d_buf = 0;
 177         d->db_data.d_off = 0;
 178         fsz = elf_fsize(d->db_data.d_type, 1, elf->ed_version);
 179         msz = _elf_msize(d->db_data.d_type, elf->ed_version);
 180         d->db_data.d_size = (sh->sh_size / fsz) * msz;
 181         d->db_shsz = sh->sh_size;
 182         d->db_raw = 0;
 183         d->db_buf = 0;
 184         d->db_uflags = 0;
 185         d->db_myflags = 0;
 186         d->db_next = 0;
 187 
 188         if (sh->sh_type != SHT_NOBITS)
 189                 d->db_fsz = sh->sh_size;
 190         else
 191                 d->db_fsz = 0;
 192 
 193         s->s_myflags |= SF_READY;
 194 
 195         NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*d))
 196         return (OK_YES);
 197 }
 198 
 199 
 200 
 201 Snode *
 202 _elf_snode()
 203 {
 204         register Snode  *s;
 205 
 206         if ((s = malloc(sizeof (Snode))) == 0) {
 207                 _elf_seterr(EMEM_SNODE, errno);
 208                 return (0);
 209         }
 210         *s = _elf_snode_init;
 211         ELFMUTEXINIT(&s->sb_scn.s_mutex);
 212         s->sb_scn.s_myflags = SF_ALLOC | SF_READY;
 213         s->sb_scn.s_shdr = &s->sb_shdr;
 214         return (s);
 215 }
 216 
 217 
 218 
 219 int
 220 _elf_ehdr(Elf * elf, int inplace)
 221 {
 222         NOTE(ASSUMING_PROTECTED(*elf))
 223         register size_t fsz;            /* field size */
 224         Elf_Data        dst, src;
 225 
 226         fsz = elf_fsize(ELF_T_EHDR, 1, elf->ed_version);
 227         if (fsz > elf->ed_fsz) {
 228                 _elf_seterr(EFMT_EHDRSZ, 0);
 229                 return (-1);
 230         }
 231         if (inplace && (fsz >= sizeof (Ehdr))) {
 232                 /*
 233                  * The translated Ehdr will fit over the original Ehdr.
 234                  */
 235                 /* LINTED */
 236                 elf->ed_ehdr = (Ehdr *)elf->ed_ident;
 237                 elf->ed_status = ES_COOKED;
 238         } else {
 239                 elf->ed_ehdr = malloc(sizeof (Ehdr));
 240                 if (elf->ed_ehdr == 0) {
 241                         _elf_seterr(EMEM_EHDR, errno);
 242                         return (-1);
 243                 }
 244                 elf->ed_myflags |= EDF_EHALLOC;
 245         }
 246 
 247         /*
 248          * Memory size >= fsz, because otherwise the memory version
 249          * loses information and cannot accurately implement the
 250          * file.
 251          */
 252 
 253         src.d_buf = (Elf_Void *)elf->ed_ident;
 254         src.d_type = ELF_T_EHDR;
 255         src.d_size = fsz;
 256         src.d_version = elf->ed_version;
 257         dst.d_buf = (Elf_Void *)elf->ed_ehdr;
 258         dst.d_size = sizeof (Ehdr);
 259         dst.d_version = EV_CURRENT;
 260 
 261         if ((_elf_vm(elf, (size_t)0, fsz) != OK_YES) ||
 262             (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
 263                 if (elf->ed_myflags & EDF_EHALLOC) {
 264                         elf->ed_myflags &= ~EDF_EHALLOC;
 265                         free(elf->ed_ehdr);
 266                 }
 267                 elf->ed_ehdr = 0;
 268                 return (-1);
 269         }
 270 
 271         if (((Ehdr*)elf->ed_ehdr)->e_ident[EI_CLASS] != ELFCLASS) {
 272                 _elf_seterr(EREQ_CLASS, 0);
 273                 if (elf->ed_myflags & EDF_EHALLOC) {
 274                         elf->ed_myflags &= ~EDF_EHALLOC;
 275                         free(elf->ed_ehdr);
 276                 }
 277                 elf->ed_ehdr = 0;
 278                 return (-1);
 279         }
 280 
 281         if (((Ehdr*)elf->ed_ehdr)->e_version != elf->ed_version) {
 282                 _elf_seterr(EFMT_VER2, 0);
 283                 if (elf->ed_myflags & EDF_EHALLOC) {
 284                         elf->ed_myflags &= ~EDF_EHALLOC;
 285                         free(elf->ed_ehdr);
 286                 }
 287                 elf->ed_ehdr = 0;
 288                 return (-1);
 289         }
 290 
 291         return (0);
 292 }
 293 
 294 
 295 
 296 int
 297 _elf_phdr(Elf * elf, int inplace)
 298 {
 299         NOTE(ASSUMING_PROTECTED(*elf))
 300         register size_t         fsz, msz;
 301         Elf_Data                dst, src;
 302         Ehdr *                  eh = elf->ed_ehdr;   /* must be present */
 303         unsigned                work;
 304 
 305         if (eh->e_phnum == 0)
 306                 return (0);
 307 
 308         fsz = elf_fsize(ELF_T_PHDR, 1, elf->ed_version);
 309         if (eh->e_phentsize != fsz) {
 310                 _elf_seterr(EFMT_PHDRSZ, 0);
 311                 return (-1);
 312         }
 313 
 314         fsz *= eh->e_phnum;
 315         ELFACCESSDATA(work, _elf_work)
 316         msz = _elf_msize(ELF_T_PHDR, work) * eh->e_phnum;
 317         if ((eh->e_phoff == 0) ||
 318             ((fsz + eh->e_phoff) > elf->ed_fsz)) {
 319                 _elf_seterr(EFMT_PHTAB, 0);
 320                 return (-1);
 321         }
 322 
 323         if (inplace && fsz >= msz && eh->e_phoff % sizeof (ElfField) == 0) {
 324                 elf->ed_phdr = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
 325                 elf->ed_status = ES_COOKED;
 326         } else {
 327                 if ((elf->ed_phdr = malloc(msz)) == 0) {
 328                         _elf_seterr(EMEM_PHDR, errno);
 329                         return (-1);
 330                 }
 331                 elf->ed_myflags |= EDF_PHALLOC;
 332         }
 333         src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_phoff);
 334         src.d_type = ELF_T_PHDR;
 335         src.d_size = fsz;
 336         src.d_version = elf->ed_version;
 337         dst.d_buf = elf->ed_phdr;
 338         dst.d_size = msz;
 339         dst.d_version = work;
 340         if ((_elf_vm(elf, (size_t)eh->e_phoff, fsz) != OK_YES) ||
 341             (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
 342                 if (elf->ed_myflags & EDF_PHALLOC) {
 343                         elf->ed_myflags &= ~EDF_PHALLOC;
 344                         free(elf->ed_phdr);
 345                 }
 346                 elf->ed_phdr = 0;
 347                 return (-1);
 348         }
 349         elf->ed_phdrsz = msz;
 350         return (0);
 351 }
 352 
 353 
 354 
 355 int
 356 _elf_shdr(Elf * elf, int inplace)
 357 {
 358         NOTE(ASSUMING_PROTECTED(*elf))
 359         register size_t         fsz, msz;
 360         size_t                  scncnt;
 361         Elf_Data                dst, src;
 362         register Ehdr           *eh = elf->ed_ehdr;  /* must be present */
 363 
 364         if ((eh->e_shnum == 0) && (eh->e_shoff == 0))
 365                 return (0);
 366 
 367         fsz = elf_fsize(ELF_T_SHDR, 1, elf->ed_version);
 368         if (eh->e_shentsize != fsz) {
 369                 _elf_seterr(EFMT_SHDRSZ, 0);
 370                 return (-1);
 371         }
 372         /*
 373          * If we are dealing with a file with 'extended section
 374          * indexes' - then we need to load the first section
 375          * header.  The actual section count is stored in
 376          * Shdr[0].sh_size.
 377          */
 378         if ((scncnt = eh->e_shnum) == 0) {
 379                 Shdr    sh;
 380                 if ((eh->e_shoff == 0) ||
 381                     (elf->ed_fsz <= eh->e_shoff) ||
 382                     (elf->ed_fsz - eh->e_shoff < fsz)) {
 383                         _elf_seterr(EFMT_SHTAB, 0);
 384                         return (-1);
 385                 }
 386                 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
 387                 src.d_type = ELF_T_SHDR;
 388                 src.d_size = fsz;
 389                 src.d_version = elf->ed_version;
 390                 dst.d_buf = (Elf_Void *)&sh;
 391                 dst.d_size = sizeof (Shdr);
 392                 dst.d_version = EV_CURRENT;
 393                 if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
 394                     (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) {
 395                         return (-1);
 396                 }
 397                 scncnt = sh.sh_size;
 398         }
 399 
 400         fsz *= scncnt;
 401         msz = scncnt * sizeof (Shdr);
 402         if ((eh->e_shoff == 0) ||
 403             (elf->ed_fsz <= eh->e_shoff) ||
 404             (elf->ed_fsz - eh->e_shoff < fsz)) {
 405                 _elf_seterr(EFMT_SHTAB, 0);
 406                 return (-1);
 407         }
 408 
 409         if (inplace && (fsz >= msz) &&
 410             ((eh->e_shoff % sizeof (ElfField)) == 0)) {
 411                 /* LINTED */
 412                 elf->ed_shdr = (Shdr *)(elf->ed_ident + eh->e_shoff);
 413                 elf->ed_status = ES_COOKED;
 414         } else {
 415                 if ((elf->ed_shdr = malloc(msz)) == 0) {
 416                         _elf_seterr(EMEM_SHDR, errno);
 417                         return (-1);
 418                 }
 419                 elf->ed_myflags |= EDF_SHALLOC;
 420         }
 421         src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff);
 422         src.d_type = ELF_T_SHDR;
 423         src.d_size = fsz;
 424         src.d_version = elf->ed_version;
 425         dst.d_buf = (Elf_Void *)elf->ed_shdr;
 426         dst.d_size = msz;
 427         dst.d_version = EV_CURRENT;
 428         if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) ||
 429             (elf_xlatetom(&dst, &src, elf->ed_encode) == 0) ||
 430             (_elf_prepscn(elf, scncnt) != OK_YES)) {
 431                 if (elf->ed_myflags & EDF_SHALLOC) {
 432                         elf->ed_myflags &= ~EDF_SHALLOC;
 433                         free(elf->ed_shdr);
 434                 }
 435                 elf->ed_shdr = 0;
 436                 return (-1);
 437         }
 438         return (0);
 439 }