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 /* 28 * Copyright (c) 1988 AT&T 29 * All Rights Reserved 30 */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include <ar.h> 35 #include <stdlib.h> 36 #include <memory.h> 37 #include <errno.h> 38 #include <libelf.h> 39 #include <sys/mman.h> 40 #include "decl.h" 41 #include "member.h" 42 #include "msg.h" 43 44 static const char armag[] = ARMAG; 45 46 47 /* 48 * Initialize archive member 49 */ 50 Elf * 51 _elf_member(int fd, Elf * ref, unsigned flags) 52 { 53 register Elf *elf; 54 Member *mh; 55 size_t base; 56 57 if (ref->ed_nextoff >= ref->ed_fsz) 58 return (0); 59 if (ref->ed_fd == -1) /* disabled */ 60 fd = -1; 61 if (flags & EDF_WRITE) { 62 _elf_seterr(EREQ_ARRDWR, 0); 63 return (0); 64 } 65 if (ref->ed_fd != fd) { 66 _elf_seterr(EREQ_ARMEMFD, 0); 67 return (0); 68 } 69 if ((_elf_vm(ref, ref->ed_nextoff, sizeof (struct ar_hdr)) != 70 OK_YES) || ((mh = _elf_armem(ref, 71 ref->ed_ident + ref->ed_nextoff, ref->ed_fsz)) == 0)) 72 return (0); 73 74 base = ref->ed_nextoff + sizeof (struct ar_hdr); 75 if (ref->ed_fsz - base < mh->m_hdr.ar_size) { 76 _elf_seterr(EFMT_ARMEMSZ, 0); 77 return (0); 78 } 79 if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { 80 _elf_seterr(EMEM_ELF, errno); 81 return (0); 82 } 83 ++ref->ed_activ; 84 elf->ed_parent = ref; 85 elf->ed_fd = fd; 86 elf->ed_myflags |= flags; 87 elf->ed_armem = mh; 88 elf->ed_fsz = mh->m_hdr.ar_size; 89 elf->ed_baseoff = ref->ed_baseoff + base; 90 elf->ed_memoff = base - mh->m_slide; 91 elf->ed_siboff = base + elf->ed_fsz + (elf->ed_fsz & 1); 92 ref->ed_nextoff = elf->ed_siboff; 93 elf->ed_image = ref->ed_image; 94 elf->ed_imagesz = ref->ed_imagesz; 95 elf->ed_vm = ref->ed_vm; 96 elf->ed_vmsz = ref->ed_vmsz; 97 elf->ed_ident = ref->ed_ident + base - mh->m_slide; 98 99 /* 100 * If this member is the archive string table, 101 * we've already altered the bytes. 102 */ 103 104 if (ref->ed_arstroff == ref->ed_nextoff) 105 elf->ed_status = ES_COOKED; 106 return (elf); 107 } 108 109 110 Elf * 111 _elf_regular(int fd, unsigned flags) /* initialize regular file */ 112 { 113 Elf *elf; 114 115 if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { 116 _elf_seterr(EMEM_ELF, errno); 117 return (0); 118 } 119 120 NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf)) 121 elf->ed_fd = fd; 122 elf->ed_myflags |= flags; 123 if (_elf_inmap(elf) != OK_YES) { 124 free(elf); 125 return (0); 126 } 127 NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf)) 128 return (elf); 129 } 130 131 132 Elf * 133 _elf_config(Elf * elf) 134 { 135 char *base; 136 unsigned encode; 137 138 ELFRWLOCKINIT(&elf->ed_rwlock); 139 140 /* 141 * Determine if this is a ELF file. 142 */ 143 base = elf->ed_ident; 144 if ((elf->ed_fsz >= EI_NIDENT) && 145 (_elf_vm(elf, (size_t)0, (size_t)EI_NIDENT) == OK_YES) && 146 (base[EI_MAG0] == ELFMAG0) && 147 (base[EI_MAG1] == ELFMAG1) && 148 (base[EI_MAG2] == ELFMAG2) && 149 (base[EI_MAG3] == ELFMAG3)) { 150 elf->ed_kind = ELF_K_ELF; 151 elf->ed_class = base[EI_CLASS]; 152 elf->ed_encode = base[EI_DATA]; 153 if ((elf->ed_version = base[EI_VERSION]) == 0) 154 elf->ed_version = 1; 155 elf->ed_identsz = EI_NIDENT; 156 157 /* 158 * Allow writing only if originally specified read only. 159 * This is only necessary if the file must be translating 160 * from one encoding to another. 161 */ 162 ELFACCESSDATA(encode, _elf_encode) 163 if ((elf->ed_vm == 0) && ((elf->ed_myflags & EDF_WRITE) == 0) && 164 (elf->ed_encode != encode)) { 165 if (mprotect((char *)elf->ed_image, elf->ed_imagesz, 166 PROT_READ|PROT_WRITE) == -1) { 167 _elf_seterr(EIO_VM, errno); 168 return (0); 169 } 170 } 171 return (elf); 172 } 173 174 /* 175 * Determine if this is an Archive 176 */ 177 if ((elf->ed_fsz >= SARMAG) && 178 (_elf_vm(elf, (size_t)0, (size_t)SARMAG) == OK_YES) && 179 (memcmp(base, armag, SARMAG) == 0)) { 180 _elf_arinit(elf); 181 elf->ed_kind = ELF_K_AR; 182 elf->ed_identsz = SARMAG; 183 return (elf); 184 } 185 186 /* 187 * Return a few ident bytes, but not so many that 188 * getident() must read a large file. 512 is arbitrary. 189 */ 190 191 elf->ed_kind = ELF_K_NONE; 192 if ((elf->ed_identsz = elf->ed_fsz) > 512) 193 elf->ed_identsz = 512; 194 195 return (elf); 196 } 197 198 Elf * 199 elf_memory(char *image, size_t sz) 200 { 201 Elf *elf; 202 unsigned work; 203 204 /* 205 * version() no called yet? 206 */ 207 ELFACCESSDATA(work, _elf_work) 208 if (work == EV_NONE) { 209 _elf_seterr(ESEQ_VER, 0); 210 return (0); 211 } 212 213 if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { 214 _elf_seterr(EMEM_ELF, errno); 215 return (0); 216 } 217 NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf)) 218 elf->ed_fd = -1; 219 elf->ed_myflags |= EDF_READ | EDF_MEMORY; 220 elf->ed_image = elf->ed_ident = image; 221 elf->ed_imagesz = elf->ed_fsz = elf->ed_identsz = sz; 222 elf->ed_kind = ELF_K_ELF; 223 elf->ed_class = image[EI_CLASS]; 224 elf->ed_encode = image[EI_DATA]; 225 if ((elf->ed_version = image[EI_VERSION]) == 0) 226 elf->ed_version = 1; 227 elf->ed_identsz = EI_NIDENT; 228 elf->ed_activ = 1; 229 elf = _elf_config(elf); 230 NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf)) 231 return (elf); 232 } 233 234 /* 235 * The following is a private interface between the linkers (ld & ld.so.1) 236 * and libelf. 237 * 238 * elf_begin(0, ELF_C_IMAGE, ref) 239 * Return a new elf_descriptor which uses the memory image from 240 * ref as the base image of the elf file. Before this elf_begin() 241 * is called an elf_update(ref, ELF_C_WRIMAGE) must have been 242 * done to the ref elf descriptor. 243 * The ELF_C_IMAGE is unique in that modificatino of the Elf structure 244 * is illegal (no elf_new*()) but you can modify the actual 245 * data image of the file in question. 246 * 247 * When you are done processing this file you can then perform a 248 * elf_end() on it. 249 * 250 * NOTE: if an elf_update(ref, ELF_C_WRITE) is done on the ref Elf 251 * descriptor then the memory image that the ELF_C_IMAGE 252 * is using has been discarded. The proper calling convention 253 * for this is as follows: 254 * 255 * elf1 = elf_begin(fd, ELF_C_WRITE, 0); 256 * ... 257 * elf_update(elf1, ELF_C_WRIMAGE); build memory image 258 * elf2 = elf_begin(0, ELF_C_IMAGE, elf1); 259 * ... 260 * elf_end(elf2); 261 * elf_updage(elf1, ELF_C_WRITE); flush memory image to disk 262 * elf_end(elf1); 263 * 264 * 265 * elf_begin(0, ELF_C_IMAGE, 0); 266 * returns a pointer to an elf descriptor as if it were opened 267 * with ELF_C_WRITE except that it has no file descriptor and it 268 * will not create a file. It's to be used with the command: 269 * 270 * elf_update(elf, ELF_C_WRIMAGE) 271 * 272 * which will build a memory image instead of a file image. 273 * The memory image is allocated via dynamic memory (malloc) and 274 * can be free with a subsequent call to 275 * 276 * elf_update(elf, ELF_C_WRITE) 277 * 278 * NOTE: that if elf_end(elf) is called it will not free the 279 * memory image if it is still allocated. It is then 280 * the callers responsiblity to free it via a call 281 * to free(). 282 * 283 * Here is a potential calling sequence for this interface: 284 * 285 * elf1 = elf_begin(0, ELF_C_IMAGE, 0); 286 * ... 287 * elf_update(elf1, ELF_C_WRIMAGE); build memory image 288 * elf2 = elf_begin(0, ELF_C_IMAGE, elf1); 289 * ... 290 * image_ptr = elf32_getehdr(elf2); get pointer to image 291 * elf_end(elf2); 292 * elf_end(elf1); 293 * ... 294 * use image 295 * ... 296 * free(image_ptr); 297 */ 298 299 Elf * 300 elf_begin(int fd, Elf_Cmd cmd, Elf *ref) 301 { 302 register Elf *elf; 303 unsigned work; 304 unsigned flags = 0; 305 306 ELFACCESSDATA(work, _elf_work) 307 if (work == EV_NONE) /* version() not called yet */ 308 { 309 _elf_seterr(ESEQ_VER, 0); 310 return (0); 311 } 312 switch (cmd) { 313 default: 314 _elf_seterr(EREQ_BEGIN, 0); 315 return (0); 316 317 case ELF_C_NULL: 318 return (0); 319 320 case ELF_C_IMAGE: 321 if (ref) { 322 char *image; 323 size_t imagesz; 324 ELFRLOCK(ref); 325 if ((image = ref->ed_wrimage) == 0) { 326 _elf_seterr(EREQ_NOWRIMAGE, 0); 327 ELFUNLOCK(ref); 328 return (0); 329 } 330 imagesz = ref->ed_wrimagesz; 331 ELFUNLOCK(ref); 332 return (elf_memory(image, imagesz)); 333 } 334 /* FALLTHROUGH */ 335 case ELF_C_WRITE: 336 if ((elf = (Elf *)calloc(1, sizeof (Elf))) == 0) { 337 _elf_seterr(EMEM_ELF, errno); 338 return (0); 339 } 340 NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf)) 341 ELFRWLOCKINIT(&elf->ed_rwlock); 342 elf->ed_fd = fd; 343 elf->ed_activ = 1; 344 elf->ed_myflags |= EDF_WRITE; 345 if (cmd == ELF_C_IMAGE) 346 elf->ed_myflags |= EDF_WRALLOC; 347 NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf)) 348 return (elf); 349 case ELF_C_RDWR: 350 flags = EDF_WRITE | EDF_READ; 351 break; 352 353 case ELF_C_READ: 354 flags = EDF_READ; 355 break; 356 } 357 358 /* 359 * A null ref asks for a new file 360 * Non-null ref bumps the activation count 361 * or gets next archive member 362 */ 363 364 if (ref == 0) { 365 if ((elf = _elf_regular(fd, flags)) == 0) 366 return (0); 367 } else { 368 ELFWLOCK(ref); 369 if ((ref->ed_myflags & flags) != flags) { 370 _elf_seterr(EREQ_RDWR, 0); 371 ELFUNLOCK(ref); 372 return (0); 373 } 374 /* 375 * new activation ? 376 */ 377 if (ref->ed_kind != ELF_K_AR) { 378 ++ref->ed_activ; 379 ELFUNLOCK(ref); 380 return (ref); 381 } 382 if ((elf = _elf_member(fd, ref, flags)) == 0) { 383 ELFUNLOCK(ref); 384 return (0); 385 } 386 ELFUNLOCK(ref); 387 } 388 389 NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*elf)) 390 elf->ed_activ = 1; 391 elf = _elf_config(elf); 392 NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*elf)) 393 394 return (elf); 395 } 396