tools/elf4rom/libs/libelf-0.8.10/lib/begin.c
changeset 34 92d87f2e53c2
equal deleted inserted replaced
33:1af5c1be89f8 34:92d87f2e53c2
       
     1 /*
       
     2  * begin.c - implementation of the elf_begin(3) and elf_memory(3) functions.
       
     3  * Copyright (C) 1995 - 2004 Michael Riepe
       
     4  * 
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Library General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2 of the License, or (at your option) any later version.
       
     9  * 
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Library General Public License for more details.
       
    14  * 
       
    15  * You should have received a copy of the GNU Library General Public
       
    16  * License along with this library; if not, write to the Free Software
       
    17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    18  */
       
    19 
       
    20 #include <private.h>
       
    21 
       
    22 #ifndef lint
       
    23 static const char rcsid[] = "@(#) $Id: begin.c,v 1.20 2006/08/17 23:59:58 michael Exp $";
       
    24 #endif /* lint */
       
    25 
       
    26 #if HAVE_AR_H
       
    27 #include <ar.h>
       
    28 #else /* HAVE_AR_H */
       
    29 
       
    30 #define ARMAG	"!<arch>\n"
       
    31 #define SARMAG	8
       
    32 
       
    33 struct ar_hdr {
       
    34     char    ar_name[16];
       
    35     char    ar_date[12];
       
    36     char    ar_uid[6];
       
    37     char    ar_gid[6];
       
    38     char    ar_mode[8];
       
    39     char    ar_size[10];
       
    40     char    ar_fmag[2];
       
    41 };
       
    42 
       
    43 #define ARFMAG	"`\n"
       
    44 
       
    45 #endif /* HAVE_AR_H */
       
    46 
       
    47 static const Elf _elf_init = INIT_ELF;
       
    48 static const char fmag[] = ARFMAG;
       
    49 
       
    50 static unsigned long
       
    51 getnum(const char *str, size_t len, int base, size_t *err) {
       
    52     unsigned long result = 0;
       
    53 
       
    54     while (len && *str == ' ') {
       
    55 	str++; len--;
       
    56     }
       
    57     while (len && *str >= '0' && (*str - '0') < base) {
       
    58 	result = base * result + *str++ - '0'; len--;
       
    59     }
       
    60     while (len && *str == ' ') {
       
    61 	str++; len--;
       
    62     }
       
    63     if (len) {
       
    64 	*err = len;
       
    65     }
       
    66     return result;
       
    67 }
       
    68 
       
    69 static void
       
    70 _elf_init_ar(Elf *elf) {
       
    71     struct ar_hdr *hdr;
       
    72     size_t offset;
       
    73     size_t size;
       
    74     size_t err = 0;
       
    75 
       
    76     elf->e_kind = ELF_K_AR;
       
    77     elf->e_idlen = SARMAG;
       
    78     elf->e_off = SARMAG;
       
    79 
       
    80     /* process special members */
       
    81     offset = SARMAG;
       
    82     while (!elf->e_strtab && offset + sizeof(*hdr) <= elf->e_size) {
       
    83 	hdr = (struct ar_hdr*)(elf->e_data + offset);
       
    84 	if (memcmp(hdr->ar_fmag, fmag, sizeof(fmag) - 1)) {
       
    85 	    break;
       
    86 	}
       
    87 	if (hdr->ar_name[0] != '/') {
       
    88 	    break;
       
    89 	}
       
    90 	size = getnum(hdr->ar_size, sizeof(hdr->ar_size), 10, &err);
       
    91 	if (err || !size) {
       
    92 	    break;
       
    93 	}
       
    94 	offset += sizeof(*hdr);
       
    95 	if (offset + size > elf->e_size) {
       
    96 	    break;
       
    97 	}
       
    98 	if (hdr->ar_name[1] == '/' && hdr->ar_name[2] == ' ') {
       
    99 	    elf->e_strtab = elf->e_data + offset;
       
   100 	    elf->e_strlen = size;
       
   101 	    break;
       
   102 	}
       
   103 	if (hdr->ar_name[1] != ' ') {
       
   104 	    break;
       
   105 	}
       
   106 	/*
       
   107 	 * Windows (.lib) archives provide two symbol tables
       
   108 	 * The first one is the one we want.
       
   109 	 */
       
   110 	if (!elf->e_symtab) {
       
   111 	    elf->e_symtab = elf->e_data + offset;
       
   112 	    elf->e_symlen = size;
       
   113 	}
       
   114 	offset += size + (size & 1);
       
   115     }
       
   116 }
       
   117 
       
   118 static Elf_Arhdr*
       
   119 _elf_arhdr(Elf *arf) {
       
   120     struct ar_hdr *hdr;
       
   121     Elf_Arhdr *arhdr;
       
   122     size_t namelen;
       
   123     size_t tmp;
       
   124     char *name;
       
   125     size_t err = 0;
       
   126 
       
   127     if (arf->e_off == arf->e_size) {
       
   128 	/* no error! */
       
   129 	return NULL;
       
   130     }
       
   131     if (arf->e_off < 0 || arf->e_off > arf->e_size) {
       
   132 	seterr(ERROR_OUTSIDE);
       
   133 	return NULL;
       
   134     }
       
   135     if (arf->e_off + sizeof(*hdr) > arf->e_size) {
       
   136 	seterr(ERROR_TRUNC_ARHDR);
       
   137 	return NULL;
       
   138     }
       
   139     elf_assert(arf->e_data != NULL);
       
   140     hdr = (struct ar_hdr*)(arf->e_data + arf->e_off);
       
   141     if (memcmp(hdr->ar_fmag, fmag, sizeof(fmag) - 1)) {
       
   142 	seterr(ERROR_ARFMAG);
       
   143 	return NULL;
       
   144     }
       
   145 
       
   146     name = hdr->ar_name;
       
   147     for (namelen = sizeof(hdr->ar_name); namelen > 0; namelen--) {
       
   148 	if (name[namelen - 1] != ' ') {
       
   149 	    break;
       
   150 	}
       
   151     }
       
   152     if (name[0] == '/') {
       
   153 	if (name[1] >= '0' && name[1] <= '9') {
       
   154 	    if (!arf->e_strtab) {
       
   155 		seterr(ERROR_ARSTRTAB);
       
   156 		return NULL;
       
   157 	    }
       
   158 	    tmp = getnum(&name[1], namelen - 1, 10, &err);
       
   159 	    if (err) {
       
   160 		seterr(ERROR_ARSPECIAL);
       
   161 		return NULL;
       
   162 	    }
       
   163 	    if (tmp < 0 || tmp >= arf->e_strlen) {
       
   164 		seterr(ERROR_ARSTRTAB);
       
   165 		return NULL;
       
   166 	    }
       
   167 	    for (namelen = tmp; namelen < arf->e_strlen; namelen++) {
       
   168 		if (arf->e_strtab[namelen] == '/') {
       
   169 		    break;
       
   170 		}
       
   171 	    }
       
   172 	    if (namelen == arf->e_strlen) {
       
   173 		seterr(ERROR_ARSTRTAB);
       
   174 		return NULL;
       
   175 	    }
       
   176 	    name = arf->e_strtab + tmp;
       
   177 	    namelen -= tmp;
       
   178 	}
       
   179 	else if (namelen != 1 && !(namelen == 2 && name[1] == '/')) {
       
   180 	    seterr(ERROR_ARSPECIAL);
       
   181 	    return NULL;
       
   182 	}
       
   183     }
       
   184     else if (namelen > 0 && name[namelen - 1] == '/') {
       
   185 	namelen--;
       
   186     }
       
   187     /* XXX some broken software omits the trailing slash
       
   188     else {
       
   189 	namelen = 0;
       
   190     }
       
   191     */
       
   192 
       
   193     if (!(arhdr = (Elf_Arhdr*)malloc(sizeof(*arhdr) +
       
   194 		     sizeof(hdr->ar_name) + namelen + 2))) {
       
   195 	seterr(ERROR_MEM_ARHDR);
       
   196 	return NULL;
       
   197     }
       
   198 
       
   199     arhdr->ar_name = NULL;
       
   200     arhdr->ar_rawname = (char*)(arhdr + 1);
       
   201     arhdr->ar_date = getnum(hdr->ar_date, sizeof(hdr->ar_date), 10, &err);
       
   202     arhdr->ar_uid = getnum(hdr->ar_uid, sizeof(hdr->ar_uid), 10, &err);
       
   203     arhdr->ar_gid = getnum(hdr->ar_gid, sizeof(hdr->ar_gid), 10, &err);
       
   204     arhdr->ar_mode = getnum(hdr->ar_mode, sizeof(hdr->ar_mode), 8, &err);
       
   205     arhdr->ar_size = getnum(hdr->ar_size, sizeof(hdr->ar_size), 10, &err);
       
   206     if (err) {
       
   207 	free(arhdr);
       
   208 	seterr(ERROR_ARHDR);
       
   209 	return NULL;
       
   210     }
       
   211     if (arf->e_off + sizeof(struct ar_hdr) + arhdr->ar_size > arf->e_size) {
       
   212 	free(arhdr);
       
   213 	seterr(ERROR_TRUNC_MEMBER);
       
   214 	return NULL;
       
   215     }
       
   216 
       
   217     memcpy(arhdr->ar_rawname, hdr->ar_name, sizeof(hdr->ar_name));
       
   218     arhdr->ar_rawname[sizeof(hdr->ar_name)] = '\0';
       
   219 
       
   220     if (namelen) {
       
   221 	arhdr->ar_name = arhdr->ar_rawname + sizeof(hdr->ar_name) + 1;
       
   222 	memcpy(arhdr->ar_name, name, namelen);
       
   223 	arhdr->ar_name[namelen] = '\0';
       
   224     }
       
   225 
       
   226     return arhdr;
       
   227 }
       
   228 
       
   229 static void
       
   230 _elf_check_type(Elf *elf, size_t size) {
       
   231     elf->e_idlen = size;
       
   232     if (size >= EI_NIDENT && !memcmp(elf->e_data, ELFMAG, SELFMAG)) {
       
   233 	elf->e_kind = ELF_K_ELF;
       
   234 	elf->e_idlen = EI_NIDENT;
       
   235 	elf->e_class = elf->e_data[EI_CLASS];
       
   236 	elf->e_encoding = elf->e_data[EI_DATA];
       
   237 	elf->e_version = elf->e_data[EI_VERSION];
       
   238     }
       
   239     else if (size >= SARMAG && !memcmp(elf->e_data, ARMAG, SARMAG)) {
       
   240 	_elf_init_ar(elf);
       
   241     }
       
   242 }
       
   243 
       
   244 Elf*
       
   245 elf_begin(int fd, Elf_Cmd cmd, Elf *ref) {
       
   246     Elf_Arhdr *arhdr = NULL;
       
   247     size_t size = 0;
       
   248     off_t off;
       
   249     Elf *elf;
       
   250 
       
   251     elf_assert(_elf_init.e_magic == ELF_MAGIC);
       
   252     if (_elf_version == EV_NONE) {
       
   253 	seterr(ERROR_VERSION_UNSET);
       
   254 	return NULL;
       
   255     }
       
   256     else if (cmd == ELF_C_NULL) {
       
   257 	return NULL;
       
   258     }
       
   259     else if (cmd == ELF_C_WRITE) {
       
   260 	ref = NULL;
       
   261     }
       
   262     else if (cmd != ELF_C_READ && cmd != ELF_C_RDWR) {
       
   263 	seterr(ERROR_INVALID_CMD);
       
   264 	return NULL;
       
   265     }
       
   266     else if (ref) {
       
   267 	elf_assert(ref->e_magic == ELF_MAGIC);
       
   268 	if (!ref->e_readable || (cmd == ELF_C_RDWR && !ref->e_writable)) {
       
   269 	    seterr(ERROR_CMDMISMATCH);
       
   270 	    return NULL;
       
   271 	}
       
   272 	if (ref->e_kind != ELF_K_AR) {
       
   273 	    ref->e_count++;
       
   274 	    return ref;
       
   275 	}
       
   276 	if (cmd == ELF_C_RDWR) {
       
   277 	    seterr(ERROR_MEMBERWRITE);
       
   278 	    return NULL;
       
   279 	}
       
   280 	if (ref->e_memory) {
       
   281 	    fd = ref->e_fd;
       
   282 	}
       
   283 	else if (fd != ref->e_fd) {
       
   284 	    seterr(ERROR_FDMISMATCH);
       
   285 	    return NULL;
       
   286 	}
       
   287 	if (!(arhdr = _elf_arhdr(ref))) {
       
   288 	    return NULL;
       
   289 	}
       
   290 	size = arhdr->ar_size;
       
   291     }
       
   292     else if ((off = lseek(fd, (off_t)0, SEEK_END)) == (off_t)-1
       
   293 	  || (off_t)(size = off) != off) {
       
   294 	seterr(ERROR_IO_GETSIZE);
       
   295 	return NULL;
       
   296     }
       
   297 
       
   298     if (!(elf = (Elf*)malloc(sizeof(Elf)))) {
       
   299 	seterr(ERROR_MEM_ELF);
       
   300 	return NULL;
       
   301     }
       
   302     *elf = _elf_init;
       
   303     elf->e_fd = fd;
       
   304     elf->e_parent = ref;
       
   305     elf->e_size = elf->e_dsize = size;
       
   306 
       
   307     if (cmd != ELF_C_READ) {
       
   308 	elf->e_writable = 1;
       
   309     }
       
   310     if (cmd != ELF_C_WRITE) {
       
   311 	elf->e_readable = 1;
       
   312     }
       
   313     else {
       
   314 	return elf;
       
   315     }
       
   316 
       
   317     if (ref) {
       
   318 	size_t offset = ref->e_off + sizeof(struct ar_hdr);
       
   319 	Elf *xelf;
       
   320 
       
   321 	elf_assert(arhdr);
       
   322 	elf->e_arhdr = arhdr;
       
   323 	elf->e_base = ref->e_base + offset;
       
   324 	/*
       
   325 	 * Share the archive's memory image. To avoid
       
   326 	 * multiple independent elf descriptors if the
       
   327 	 * same member is requested twice, scan the list
       
   328 	 * of open members for duplicates.
       
   329 	 *
       
   330 	 * I don't know how SVR4 handles this case. Don't rely on it.
       
   331 	 */
       
   332 	for (xelf = ref->e_members; xelf; xelf = xelf->e_link) {
       
   333 	    elf_assert(xelf->e_parent == ref);
       
   334 	    if (xelf->e_base == elf->e_base) {
       
   335 		free(arhdr);
       
   336 		free(elf);
       
   337 		xelf->e_count++;
       
   338 		return xelf;
       
   339 	    }
       
   340 	}
       
   341 	if (size == 0) {
       
   342 	    elf->e_data = NULL;
       
   343 	}
       
   344 #if 1
       
   345 	else {
       
   346 	    /*
       
   347 	     * Archive members may be misaligned.  Freezing them will
       
   348 	     * cause libelf to allocate buffers for translated data,
       
   349 	     * which should be properly aligned in all cases.
       
   350 	     */
       
   351 	    elf_assert(!ref->e_cooked);
       
   352 	    elf->e_data = elf->e_rawdata = ref->e_data + offset;
       
   353 	}
       
   354 #else
       
   355 	else if (ref->e_data == ref->e_rawdata) {
       
   356 	    elf_assert(!ref->e_cooked);
       
   357 	    /*
       
   358 	     * archive is frozen - freeze member, too
       
   359 	     */
       
   360 	    elf->e_data = elf->e_rawdata = ref->e_data + offset;
       
   361 	}
       
   362 	else {
       
   363 	    elf_assert(!ref->e_memory);
       
   364 	    elf->e_data = ref->e_data + offset;
       
   365 	    /*
       
   366 	     * The member's memory image may have been modified if
       
   367 	     * the member has been processed before. Since we need the
       
   368 	     * original image, we have to re-read the archive file.
       
   369 	     * Will fail if the archive's file descriptor is disabled.
       
   370 	     */
       
   371 	    if (!ref->e_cooked) {
       
   372 		ref->e_cooked = 1;
       
   373 	    }
       
   374 	    else if (!_elf_read(ref, elf->e_data, offset, size)) {
       
   375 		free(arhdr);
       
   376 		free(elf);
       
   377 		return NULL;
       
   378 	    }
       
   379 	}
       
   380 #endif
       
   381 	elf->e_next = offset + size + (size & 1);
       
   382 	elf->e_disabled = ref->e_disabled;
       
   383 	elf->e_memory = ref->e_memory;
       
   384 	/* parent/child linking */
       
   385 	elf->e_link = ref->e_members;
       
   386 	ref->e_members = elf;
       
   387 	ref->e_count++;
       
   388 	/* Slowaris compatibility - do not rely on this! */
       
   389 	ref->e_off = elf->e_next;
       
   390     }
       
   391     else if (size) {
       
   392 #if HAVE_MMAP
       
   393 	/*
       
   394 	 * Using mmap on writable files will interfere with elf_update
       
   395 	 */
       
   396 	if (!elf->e_writable && (elf->e_data = _elf_mmap(elf))) {
       
   397 	    elf->e_unmap_data = 1;
       
   398 	}
       
   399 	else
       
   400 #endif /* HAVE_MMAP */
       
   401 	if (!(elf->e_data = _elf_read(elf, NULL, 0, size))) {
       
   402 	    free(elf);
       
   403 	    return NULL;
       
   404 	}
       
   405     }
       
   406 
       
   407     _elf_check_type(elf, size);
       
   408     return elf;
       
   409 }
       
   410 
       
   411 Elf*
       
   412 elf_memory(char *image, size_t size) {
       
   413     Elf *elf;
       
   414 
       
   415     elf_assert(_elf_init.e_magic == ELF_MAGIC);
       
   416     if (_elf_version == EV_NONE) {
       
   417 	seterr(ERROR_VERSION_UNSET);
       
   418 	return NULL;
       
   419     }
       
   420     else if (size == 0 || image == NULL) {
       
   421 	/* TODO: set error code? */
       
   422 	return NULL;
       
   423     }
       
   424 
       
   425     if (!(elf = (Elf*)malloc(sizeof(Elf)))) {
       
   426 	seterr(ERROR_MEM_ELF);
       
   427 	return NULL;
       
   428     }
       
   429     *elf = _elf_init;
       
   430     elf->e_size = elf->e_dsize = size;
       
   431     elf->e_data = elf->e_rawdata = image;
       
   432     elf->e_readable = 1;
       
   433     elf->e_disabled = 1;
       
   434     elf->e_memory = 1;
       
   435 
       
   436     _elf_check_type(elf, size);
       
   437     return elf;
       
   438 }
       
   439 
       
   440 #if __LIBELF64
       
   441 
       
   442 int
       
   443 gelf_getclass(Elf *elf) {
       
   444     if (elf && elf->e_kind == ELF_K_ELF && valid_class(elf->e_class)) {
       
   445 	return elf->e_class;
       
   446     }
       
   447     return ELFCLASSNONE;
       
   448 }
       
   449 
       
   450 #endif /* __LIBELF64 */