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