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 Elf_Scn * s; 95 Elf_Scn * end; 96 97 if (cnt == 0) 98 return (OK_YES); 99 100 if ((s = malloc(cnt * sizeof (Elf_Scn))) == 0) { 101 _elf_seterr(EMEM_SCN, errno); 102 return (OK_NO); 103 } 104 elf->ed_scntabsz = cnt; 105 end = s + cnt; 106 elf->ed_hdscn = s; 107 do { 108 *s = _elf_snode_init.sb_scn; 109 s->s_elf = elf; 110 s->s_next = s + 1; 111 s->s_index = s - elf->ed_hdscn; 112 s->s_shdr = (Shdr*)s->s_elf->ed_shdr + s->s_index; 113 ELFMUTEXINIT(&s->s_mutex); 114 115 /* 116 * Section has not yet been cooked! 117 * 118 * We don't cook a section until it's data is actually 119 * referenced. 120 */ 121 s->s_myflags = 0; 122 } while (++s < end); 123 124 elf->ed_tlscn = --s; 125 s->s_next = 0; 126 127 /* 128 * Section index SHN_UNDEF (0) does not and cannot 129 * have a data buffer. Fix it here. Also mark the 130 * initial section as being allocated for the block 131 */ 132 133 s = elf->ed_hdscn; 134 s->s_myflags = SF_ALLOC; 135 s->s_hdnode = 0; 136 s->s_tlnode = 0; 137 return (OK_YES); 138 } 139 140 141 Okay 142 _elf_cookscn(Elf_Scn * s) 143 { 144 Elf * elf; 145 Shdr * sh; 146 register Dnode * d = &s->s_dnode; 147 size_t fsz, msz; 148 unsigned work; 149 150 s->s_hdnode = s->s_tlnode = d; 151 s->s_err = 0; 152 s->s_shflags = 0; 153 s->s_uflags = 0; 154 155 156 /* 157 * Prepare d_data for inspection, but don't actually 158 * translate data until needed. Leave the READY 159 * flag off. NOBITS sections see zero size. 160 */ 161 elf = s->s_elf; 162 sh = s->s_shdr; 163 164 d->db_scn = s; 165 d->db_off = sh->sh_offset; 166 d->db_data.d_align = sh->sh_addralign; 167 d->db_data.d_version = elf->ed_version; 168 ELFACCESSDATA(work, _elf_work) 169 d->db_data.d_type = _elf_mtype(elf, sh->sh_type, work); 170 d->db_data.d_buf = 0; 171 d->db_data.d_off = 0; 172 fsz = elf_fsize(d->db_data.d_type, 1, elf->ed_version); 173 msz = _elf_msize(d->db_data.d_type, elf->ed_version); 174 d->db_data.d_size = MAX(sh->sh_size, (sh->sh_size / fsz) * msz); 175 d->db_shsz = sh->sh_size; 176 d->db_raw = 0; 177 d->db_buf = 0; 178 d->db_uflags = 0; 179 d->db_myflags = 0; 180 d->db_next = 0; 181 182 if (sh->sh_type != SHT_NOBITS) 183 d->db_fsz = sh->sh_size; 184 else 185 d->db_fsz = 0; 186 187 s->s_myflags |= SF_READY; 188 189 return (OK_YES); 190 } 191 192 193 194 Snode * 195 _elf_snode() 196 { 197 register Snode *s; 198 199 if ((s = malloc(sizeof (Snode))) == 0) { 200 _elf_seterr(EMEM_SNODE, errno); 201 return (0); 202 } 203 *s = _elf_snode_init; 204 ELFMUTEXINIT(&s->sb_scn.s_mutex); 205 s->sb_scn.s_myflags = SF_ALLOC | SF_READY; 206 s->sb_scn.s_shdr = &s->sb_shdr; 207 return (s); 208 } 209 210 211 212 int 213 _elf_ehdr(Elf * elf, int inplace) 214 { 215 register size_t fsz; /* field size */ 216 Elf_Data dst, src; 217 218 fsz = elf_fsize(ELF_T_EHDR, 1, elf->ed_version); 219 if (fsz > elf->ed_fsz) { 220 _elf_seterr(EFMT_EHDRSZ, 0); 221 return (-1); 222 } 223 if (inplace && (fsz >= sizeof (Ehdr))) { 224 /* 225 * The translated Ehdr will fit over the original Ehdr. 226 */ 227 /* LINTED */ 228 elf->ed_ehdr = (Ehdr *)elf->ed_ident; 229 elf->ed_status = ES_COOKED; 230 } else { 231 elf->ed_ehdr = malloc(sizeof (Ehdr)); 232 if (elf->ed_ehdr == 0) { 233 _elf_seterr(EMEM_EHDR, errno); 234 return (-1); 235 } 236 elf->ed_myflags |= EDF_EHALLOC; 237 } 238 239 /* 240 * Memory size >= fsz, because otherwise the memory version 241 * loses information and cannot accurately implement the 242 * file. 243 */ 244 245 src.d_buf = (Elf_Void *)elf->ed_ident; 246 src.d_type = ELF_T_EHDR; 247 src.d_size = fsz; 248 src.d_version = elf->ed_version; 249 dst.d_buf = (Elf_Void *)elf->ed_ehdr; 250 dst.d_size = sizeof (Ehdr); 251 dst.d_version = EV_CURRENT; 252 253 if ((_elf_vm(elf, (size_t)0, fsz) != OK_YES) || 254 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) { 255 if (elf->ed_myflags & EDF_EHALLOC) { 256 elf->ed_myflags &= ~EDF_EHALLOC; 257 free(elf->ed_ehdr); 258 } 259 elf->ed_ehdr = 0; 260 return (-1); 261 } 262 263 if (((Ehdr*)elf->ed_ehdr)->e_ident[EI_CLASS] != ELFCLASS) { 264 _elf_seterr(EREQ_CLASS, 0); 265 if (elf->ed_myflags & EDF_EHALLOC) { 266 elf->ed_myflags &= ~EDF_EHALLOC; 267 free(elf->ed_ehdr); 268 } 269 elf->ed_ehdr = 0; 270 return (-1); 271 } 272 273 if (((Ehdr*)elf->ed_ehdr)->e_version != elf->ed_version) { 274 _elf_seterr(EFMT_VER2, 0); 275 if (elf->ed_myflags & EDF_EHALLOC) { 276 elf->ed_myflags &= ~EDF_EHALLOC; 277 free(elf->ed_ehdr); 278 } 279 elf->ed_ehdr = 0; 280 return (-1); 281 } 282 283 return (0); 284 } 285 286 287 288 int 289 _elf_phdr(Elf * elf, int inplace) 290 { 291 register size_t fsz, msz; 292 Elf_Data dst, src; 293 Ehdr * eh = elf->ed_ehdr; /* must be present */ 294 unsigned work; 295 296 if (eh->e_phnum == 0) 297 return (0); 298 299 fsz = elf_fsize(ELF_T_PHDR, 1, elf->ed_version); 300 if (eh->e_phentsize != fsz) { 301 _elf_seterr(EFMT_PHDRSZ, 0); 302 return (-1); 303 } 304 305 fsz *= eh->e_phnum; 306 ELFACCESSDATA(work, _elf_work) 307 msz = _elf_msize(ELF_T_PHDR, work) * eh->e_phnum; 308 if ((eh->e_phoff == 0) || 309 (elf->ed_fsz <= eh->e_phoff) || 310 (elf->ed_fsz - eh->e_phoff < fsz)) { 311 _elf_seterr(EFMT_PHTAB, 0); 312 return (-1); 313 } 314 315 if (inplace && fsz >= msz && eh->e_phoff % sizeof (ElfField) == 0) { 316 elf->ed_phdr = (Elf_Void *)(elf->ed_ident + eh->e_phoff); 317 elf->ed_status = ES_COOKED; 318 } else { 319 if ((elf->ed_phdr = malloc(msz)) == 0) { 320 _elf_seterr(EMEM_PHDR, errno); 321 return (-1); 322 } 323 elf->ed_myflags |= EDF_PHALLOC; 324 } 325 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_phoff); 326 src.d_type = ELF_T_PHDR; 327 src.d_size = fsz; 328 src.d_version = elf->ed_version; 329 dst.d_buf = elf->ed_phdr; 330 dst.d_size = msz; 331 dst.d_version = work; 332 if ((_elf_vm(elf, (size_t)eh->e_phoff, fsz) != OK_YES) || 333 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) { 334 if (elf->ed_myflags & EDF_PHALLOC) { 335 elf->ed_myflags &= ~EDF_PHALLOC; 336 free(elf->ed_phdr); 337 } 338 elf->ed_phdr = 0; 339 return (-1); 340 } 341 elf->ed_phdrsz = msz; 342 return (0); 343 } 344 345 346 347 int 348 _elf_shdr(Elf * elf, int inplace) 349 { 350 register size_t fsz, msz; 351 size_t scncnt; 352 Elf_Data dst, src; 353 register Ehdr *eh = elf->ed_ehdr; /* must be present */ 354 355 if ((eh->e_shnum == 0) && (eh->e_shoff == 0)) 356 return (0); 357 358 fsz = elf_fsize(ELF_T_SHDR, 1, elf->ed_version); 359 if (eh->e_shentsize != fsz) { 360 _elf_seterr(EFMT_SHDRSZ, 0); 361 return (-1); 362 } 363 /* 364 * If we are dealing with a file with 'extended section 365 * indexes' - then we need to load the first section 366 * header. The actual section count is stored in 367 * Shdr[0].sh_size. 368 */ 369 if ((scncnt = eh->e_shnum) == 0) { 370 Shdr sh; 371 if ((eh->e_shoff == 0) || 372 (elf->ed_fsz <= eh->e_shoff) || 373 (elf->ed_fsz - eh->e_shoff < fsz)) { 374 _elf_seterr(EFMT_SHTAB, 0); 375 return (-1); 376 } 377 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff); 378 src.d_type = ELF_T_SHDR; 379 src.d_size = fsz; 380 src.d_version = elf->ed_version; 381 dst.d_buf = (Elf_Void *)&sh; 382 dst.d_size = sizeof (Shdr); 383 dst.d_version = EV_CURRENT; 384 if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) || 385 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0)) { 386 return (-1); 387 } 388 scncnt = sh.sh_size; 389 } 390 391 fsz *= scncnt; 392 msz = scncnt * sizeof (Shdr); 393 if ((eh->e_shoff == 0) || 394 (elf->ed_fsz <= eh->e_shoff) || 395 (elf->ed_fsz - eh->e_shoff < fsz)) { 396 _elf_seterr(EFMT_SHTAB, 0); 397 return (-1); 398 } 399 400 if (inplace && (fsz >= msz) && 401 ((eh->e_shoff % sizeof (ElfField)) == 0)) { 402 /* LINTED */ 403 elf->ed_shdr = (Shdr *)(elf->ed_ident + eh->e_shoff); 404 elf->ed_status = ES_COOKED; 405 } else { 406 if ((elf->ed_shdr = malloc(msz)) == 0) { 407 _elf_seterr(EMEM_SHDR, errno); 408 return (-1); 409 } 410 elf->ed_myflags |= EDF_SHALLOC; 411 } 412 src.d_buf = (Elf_Void *)(elf->ed_ident + eh->e_shoff); 413 src.d_type = ELF_T_SHDR; 414 src.d_size = fsz; 415 src.d_version = elf->ed_version; 416 dst.d_buf = (Elf_Void *)elf->ed_shdr; 417 dst.d_size = msz; 418 dst.d_version = EV_CURRENT; 419 if ((_elf_vm(elf, (size_t)eh->e_shoff, fsz) != OK_YES) || 420 (elf_xlatetom(&dst, &src, elf->ed_encode) == 0) || 421 (_elf_prepscn(elf, scncnt) != OK_YES)) { 422 if (elf->ed_myflags & EDF_SHALLOC) { 423 elf->ed_myflags &= ~EDF_SHALLOC; 424 free(elf->ed_shdr); 425 } 426 elf->ed_shdr = 0; 427 return (-1); 428 } 429 return (0); 430 } 431