xref: /freebsd/contrib/elftoolchain/libelf/libelf_ar.c (revision d003e0d7fe0d3a9b4b2c5835bb3f0f6faf3ab538)
12de3b87aSKai Wang /*-
22de3b87aSKai Wang  * Copyright (c) 2006,2008,2010 Joseph Koshy
32de3b87aSKai Wang  * All rights reserved.
42de3b87aSKai Wang  *
52de3b87aSKai Wang  * Redistribution and use in source and binary forms, with or without
62de3b87aSKai Wang  * modification, are permitted provided that the following conditions
72de3b87aSKai Wang  * are met:
82de3b87aSKai Wang  * 1. Redistributions of source code must retain the above copyright
92de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer.
102de3b87aSKai Wang  * 2. Redistributions in binary form must reproduce the above copyright
112de3b87aSKai Wang  *    notice, this list of conditions and the following disclaimer in the
122de3b87aSKai Wang  *    documentation and/or other materials provided with the distribution.
132de3b87aSKai Wang  *
142de3b87aSKai Wang  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND
152de3b87aSKai Wang  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162de3b87aSKai Wang  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172de3b87aSKai Wang  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182de3b87aSKai Wang  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192de3b87aSKai Wang  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202de3b87aSKai Wang  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212de3b87aSKai Wang  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222de3b87aSKai Wang  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232de3b87aSKai Wang  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242de3b87aSKai Wang  * SUCH DAMAGE.
252de3b87aSKai Wang  */
262de3b87aSKai Wang 
272de3b87aSKai Wang #include <assert.h>
282de3b87aSKai Wang #include <ctype.h>
292de3b87aSKai Wang #include <libelf.h>
302de3b87aSKai Wang #include <stdlib.h>
312de3b87aSKai Wang #include <string.h>
322de3b87aSKai Wang 
332de3b87aSKai Wang #include "_libelf.h"
342de3b87aSKai Wang #include "_libelf_ar.h"
352de3b87aSKai Wang 
36*d003e0d7SEd Maste ELFTC_VCSID("$Id: libelf_ar.c 3712 2019-03-16 22:23:34Z jkoshy $");
372de3b87aSKai Wang 
382de3b87aSKai Wang #define	LIBELF_NALLOC_SIZE	16
392de3b87aSKai Wang 
402de3b87aSKai Wang /*
412de3b87aSKai Wang  * `ar' archive handling.
422de3b87aSKai Wang  *
432de3b87aSKai Wang  * `ar' archives start with signature `ARMAG'.  Each archive member is
442de3b87aSKai Wang  * preceded by a header containing meta-data for the member.  This
452de3b87aSKai Wang  * header is described in <ar.h> (struct ar_hdr).  The header always
462de3b87aSKai Wang  * starts on an even address.  File data is padded with "\n"
472de3b87aSKai Wang  * characters to keep this invariant.
482de3b87aSKai Wang  *
492de3b87aSKai Wang  * Special considerations for `ar' archives:
502de3b87aSKai Wang  *
512de3b87aSKai Wang  * There are two variants of the `ar' archive format: traditional BSD
522de3b87aSKai Wang  * and SVR4.  These differ in the way long file names are treated, and
532de3b87aSKai Wang  * in the layout of the archive symbol table.
542de3b87aSKai Wang  *
552de3b87aSKai Wang  * The `ar' header only has space for a 16 character file name.
562de3b87aSKai Wang  *
572de3b87aSKai Wang  * In the SVR4 format, file names are terminated with a '/', so this
582de3b87aSKai Wang  * effectively leaves 15 characters for the actual file name.  Longer
592de3b87aSKai Wang  * file names stored in a separate 'string table' and referenced
602de3b87aSKai Wang  * indirectly from the name field.  The string table itself appears as
612de3b87aSKai Wang  * an archive member with name "// ".  An `indirect' file name in an
622de3b87aSKai Wang  * `ar' header matches the pattern "/[0-9]*". The digits form a
632de3b87aSKai Wang  * decimal number that corresponds to a byte offset into the string
642de3b87aSKai Wang  * table where the actual file name of the object starts.  Strings in
652de3b87aSKai Wang  * the string table are padded to start on even addresses.
662de3b87aSKai Wang  *
672de3b87aSKai Wang  * In the BSD format, file names can be up to 16 characters.  File
682de3b87aSKai Wang  * names shorter than 16 characters are padded to 16 characters using
692de3b87aSKai Wang  * (ASCII) space characters.  File names with embedded spaces and file
702de3b87aSKai Wang  * names longer than 16 characters are stored immediately after the
712de3b87aSKai Wang  * archive header and the name field set to a special indirect name
722de3b87aSKai Wang  * matching the pattern "#1/[0-9]+".  The digits form a decimal number
732de3b87aSKai Wang  * that corresponds to the actual length of the file name following
742de3b87aSKai Wang  * the archive header.  The content of the archive member immediately
752de3b87aSKai Wang  * follows the file name, and the size field of the archive member
762de3b87aSKai Wang  * holds the sum of the sizes of the member and of the appended file
772de3b87aSKai Wang  * name.
782de3b87aSKai Wang  *
792de3b87aSKai Wang  * Archives may also have a symbol table (see ranlib(1)), mapping
802de3b87aSKai Wang  * program symbols to object files inside the archive.
812de3b87aSKai Wang  *
822de3b87aSKai Wang  * In the SVR4 format, a symbol table uses a file name of "/ " in its
832de3b87aSKai Wang  * archive header.  The symbol table is structured as:
842de3b87aSKai Wang  *  - a 4-byte count of entries stored as a binary value, MSB first
852de3b87aSKai Wang  *  - 'n' 4-byte offsets, stored as binary values, MSB first
862de3b87aSKai Wang  *  - 'n' NUL-terminated strings, for ELF symbol names, stored unpadded.
872de3b87aSKai Wang  *
882de3b87aSKai Wang  * In the BSD format, the symbol table uses a file name of "__.SYMDEF".
892de3b87aSKai Wang  * It is structured as two parts:
902de3b87aSKai Wang  *  - The first part is an array of "ranlib" structures preceded by
912de3b87aSKai Wang  *    the size of the array in bytes.  Each "ranlib" structure
922de3b87aSKai Wang  *    describes one symbol.  Each structure contains an offset into
932de3b87aSKai Wang  *    the string table for the symbol name, and a file offset into the
942de3b87aSKai Wang  *    archive for the member defining the symbol.
952de3b87aSKai Wang  *  - The second part is a string table containing NUL-terminated
962de3b87aSKai Wang  *    strings, preceded by the size of the string table in bytes.
972de3b87aSKai Wang  *
982de3b87aSKai Wang  * If the symbol table and string table are is present in an archive
992de3b87aSKai Wang  * they must be the very first objects and in that order.
1002de3b87aSKai Wang  */
1012de3b87aSKai Wang 
1022de3b87aSKai Wang 
1032de3b87aSKai Wang /*
1042de3b87aSKai Wang  * Retrieve an archive header descriptor.
1052de3b87aSKai Wang  */
1062de3b87aSKai Wang 
1072de3b87aSKai Wang Elf_Arhdr *
_libelf_ar_gethdr(Elf * e)1082de3b87aSKai Wang _libelf_ar_gethdr(Elf *e)
1092de3b87aSKai Wang {
1102de3b87aSKai Wang 	Elf *parent;
1112de3b87aSKai Wang 	Elf_Arhdr *eh;
112cf781b2eSEd Maste 	char *namelen;
1132de3b87aSKai Wang 	size_t n, nlen;
1142de3b87aSKai Wang 	struct ar_hdr *arh;
1152de3b87aSKai Wang 
1162de3b87aSKai Wang 	if ((parent = e->e_parent) == NULL) {
1172de3b87aSKai Wang 		LIBELF_SET_ERROR(ARGUMENT, 0);
1182de3b87aSKai Wang 		return (NULL);
1192de3b87aSKai Wang 	}
1202de3b87aSKai Wang 
1212de3b87aSKai Wang 	assert((e->e_flags & LIBELF_F_AR_HEADER) == 0);
1222de3b87aSKai Wang 
1232de3b87aSKai Wang 	arh = (struct ar_hdr *) (uintptr_t) e->e_hdr.e_rawhdr;
1242de3b87aSKai Wang 
1252de3b87aSKai Wang 	assert((uintptr_t) arh >= (uintptr_t) parent->e_rawfile + SARMAG);
126*d003e0d7SEd Maste 
127*d003e0d7SEd Maste 	/*
128*d003e0d7SEd Maste 	 * There needs to be enough space remaining in the file for the
129*d003e0d7SEd Maste 	 * archive header.
130*d003e0d7SEd Maste 	 */
131*d003e0d7SEd Maste 	if ((uintptr_t) arh > (uintptr_t) parent->e_rawfile +
132*d003e0d7SEd Maste 	    (uintptr_t) parent->e_rawsize - sizeof(struct ar_hdr)) {
133*d003e0d7SEd Maste 		LIBELF_SET_ERROR(ARCHIVE, 0);
134*d003e0d7SEd Maste 		return (NULL);
135*d003e0d7SEd Maste 	}
1362de3b87aSKai Wang 
1372de3b87aSKai Wang 	if ((eh = malloc(sizeof(Elf_Arhdr))) == NULL) {
1382de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, 0);
1392de3b87aSKai Wang 		return (NULL);
1402de3b87aSKai Wang 	}
1412de3b87aSKai Wang 
1422de3b87aSKai Wang 	e->e_hdr.e_arhdr = eh;
1432de3b87aSKai Wang 	e->e_flags |= LIBELF_F_AR_HEADER;
1442de3b87aSKai Wang 
1452de3b87aSKai Wang 	eh->ar_name = eh->ar_rawname = NULL;
1462de3b87aSKai Wang 
1472de3b87aSKai Wang 	if ((eh->ar_name = _libelf_ar_get_translated_name(arh, parent)) ==
1482de3b87aSKai Wang 	    NULL)
1492de3b87aSKai Wang 		goto error;
1502de3b87aSKai Wang 
1512de3b87aSKai Wang 	if (_libelf_ar_get_number(arh->ar_uid, sizeof(arh->ar_uid), 10,
1522de3b87aSKai Wang 	    &n) == 0)
1532de3b87aSKai Wang 		goto error;
1542de3b87aSKai Wang 	eh->ar_uid = (uid_t) n;
1552de3b87aSKai Wang 
1562de3b87aSKai Wang 	if (_libelf_ar_get_number(arh->ar_gid, sizeof(arh->ar_gid), 10,
1572de3b87aSKai Wang 	    &n) == 0)
1582de3b87aSKai Wang 		goto error;
1592de3b87aSKai Wang 	eh->ar_gid = (gid_t) n;
1602de3b87aSKai Wang 
1612de3b87aSKai Wang 	if (_libelf_ar_get_number(arh->ar_mode, sizeof(arh->ar_mode), 8,
1622de3b87aSKai Wang 	    &n) == 0)
1632de3b87aSKai Wang 		goto error;
1642de3b87aSKai Wang 	eh->ar_mode = (mode_t) n;
1652de3b87aSKai Wang 
1662de3b87aSKai Wang 	if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10,
1672de3b87aSKai Wang 	    &n) == 0)
1682de3b87aSKai Wang 		goto error;
1692de3b87aSKai Wang 
1702de3b87aSKai Wang 	/*
1712de3b87aSKai Wang 	 * Get the true size of the member if extended naming is being used.
1722de3b87aSKai Wang 	 */
1732de3b87aSKai Wang 	if (IS_EXTENDED_BSD_NAME(arh->ar_name)) {
1742de3b87aSKai Wang 		namelen = arh->ar_name +
1752de3b87aSKai Wang 		    LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE;
1762de3b87aSKai Wang 		if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) -
1772de3b87aSKai Wang 		    LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nlen) == 0)
1782de3b87aSKai Wang 			goto error;
1792de3b87aSKai Wang 		n -= nlen;
1802de3b87aSKai Wang 	}
1812de3b87aSKai Wang 
1822de3b87aSKai Wang 	eh->ar_size = n;
1832de3b87aSKai Wang 
1842de3b87aSKai Wang 	if ((eh->ar_rawname = _libelf_ar_get_raw_name(arh)) == NULL)
1852de3b87aSKai Wang 		goto error;
1862de3b87aSKai Wang 
1872de3b87aSKai Wang 	eh->ar_flags = 0;
1882de3b87aSKai Wang 
1892de3b87aSKai Wang 	return (eh);
1902de3b87aSKai Wang 
1912de3b87aSKai Wang  error:
1922de3b87aSKai Wang 	if (eh) {
1932de3b87aSKai Wang 		if (eh->ar_name)
1942de3b87aSKai Wang 			free(eh->ar_name);
1952de3b87aSKai Wang 		if (eh->ar_rawname)
1962de3b87aSKai Wang 			free(eh->ar_rawname);
1972de3b87aSKai Wang 		free(eh);
1982de3b87aSKai Wang 	}
1992de3b87aSKai Wang 
2002de3b87aSKai Wang 	e->e_flags &= ~LIBELF_F_AR_HEADER;
201cf781b2eSEd Maste 	e->e_hdr.e_rawhdr = (unsigned char *) arh;
2022de3b87aSKai Wang 
2032de3b87aSKai Wang 	return (NULL);
2042de3b87aSKai Wang }
2052de3b87aSKai Wang 
2062de3b87aSKai Wang Elf *
_libelf_ar_open_member(int fd,Elf_Cmd c,Elf * elf)2072de3b87aSKai Wang _libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
2082de3b87aSKai Wang {
2092de3b87aSKai Wang 	Elf *e;
210cf781b2eSEd Maste 	size_t nsz, sz;
211*d003e0d7SEd Maste 	off_t next, end;
2122de3b87aSKai Wang 	struct ar_hdr *arh;
213cf781b2eSEd Maste 	char *member, *namelen;
2142de3b87aSKai Wang 
2152de3b87aSKai Wang 	assert(elf->e_kind == ELF_K_AR);
2162de3b87aSKai Wang 
2172de3b87aSKai Wang 	next = elf->e_u.e_ar.e_next;
2182de3b87aSKai Wang 
2192de3b87aSKai Wang 	/*
2202de3b87aSKai Wang 	 * `next' is only set to zero by elf_next() when the last
2212de3b87aSKai Wang 	 * member of an archive is processed.
2222de3b87aSKai Wang 	 */
2232de3b87aSKai Wang 	if (next == (off_t) 0)
2242de3b87aSKai Wang 		return (NULL);
2252de3b87aSKai Wang 
2262de3b87aSKai Wang 	assert((next & 1) == 0);
2272de3b87aSKai Wang 
228*d003e0d7SEd Maste 	/*
229*d003e0d7SEd Maste 	 * There needs to be enough space in the file to contain an
230*d003e0d7SEd Maste 	 * ar(1) header.
231*d003e0d7SEd Maste 	 */
232*d003e0d7SEd Maste 	end = next + (off_t) sizeof(struct ar_hdr);
233*d003e0d7SEd Maste 	if ((uintmax_t) end < (uintmax_t) next || /* Overflow. */
234*d003e0d7SEd Maste 	    end > (off_t) elf->e_rawsize) {
235*d003e0d7SEd Maste 		LIBELF_SET_ERROR(ARCHIVE, 0);
236*d003e0d7SEd Maste 		return (NULL);
237*d003e0d7SEd Maste 	}
238*d003e0d7SEd Maste 
2392de3b87aSKai Wang 	arh = (struct ar_hdr *) (elf->e_rawfile + next);
2402de3b87aSKai Wang 
2412de3b87aSKai Wang 	/*
2422de3b87aSKai Wang 	 * Retrieve the size of the member.
2432de3b87aSKai Wang 	 */
2442de3b87aSKai Wang 	if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10,
2452de3b87aSKai Wang 	    &sz) == 0) {
2462de3b87aSKai Wang 		LIBELF_SET_ERROR(ARCHIVE, 0);
2472de3b87aSKai Wang 		return (NULL);
2482de3b87aSKai Wang 	}
2492de3b87aSKai Wang 
2502de3b87aSKai Wang 	/*
251*d003e0d7SEd Maste 	 * Check if the archive member that follows will fit in the
252*d003e0d7SEd Maste 	 * containing archive.
253*d003e0d7SEd Maste 	 */
254*d003e0d7SEd Maste 	end += (off_t) sz;
255*d003e0d7SEd Maste 	if (end < next || /* Overflow. */
256*d003e0d7SEd Maste 	    end > (off_t) elf->e_rawsize) {
257*d003e0d7SEd Maste 		LIBELF_SET_ERROR(ARCHIVE, 0);
258*d003e0d7SEd Maste 		return (NULL);
259*d003e0d7SEd Maste 	}
260*d003e0d7SEd Maste 
261*d003e0d7SEd Maste 	/*
2622de3b87aSKai Wang 	 * Adjust the size field for members in BSD archives using
2632de3b87aSKai Wang 	 * extended naming.
2642de3b87aSKai Wang 	 */
2652de3b87aSKai Wang 	if (IS_EXTENDED_BSD_NAME(arh->ar_name)) {
2662de3b87aSKai Wang 		namelen = arh->ar_name +
2672de3b87aSKai Wang 		    LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE;
2682de3b87aSKai Wang 		if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) -
2692de3b87aSKai Wang 		    LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nsz) == 0) {
2702de3b87aSKai Wang 			LIBELF_SET_ERROR(ARCHIVE, 0);
2712de3b87aSKai Wang 			return (NULL);
2722de3b87aSKai Wang 		}
2732de3b87aSKai Wang 
2742de3b87aSKai Wang 		member = (char *) (arh + 1) + nsz;
2752de3b87aSKai Wang 		sz -= nsz;
2762de3b87aSKai Wang 	} else
2772de3b87aSKai Wang 		member = (char *) (arh + 1);
2782de3b87aSKai Wang 
2792de3b87aSKai Wang 
280cf781b2eSEd Maste 	if ((e = elf_memory(member, sz)) == NULL)
2812de3b87aSKai Wang 		return (NULL);
2822de3b87aSKai Wang 
2832de3b87aSKai Wang 	e->e_fd = fd;
2842de3b87aSKai Wang 	e->e_cmd = c;
285cf781b2eSEd Maste 	e->e_hdr.e_rawhdr = (unsigned char *) arh;
2862de3b87aSKai Wang 
2872de3b87aSKai Wang 	elf->e_u.e_ar.e_nchildren++;
2882de3b87aSKai Wang 	e->e_parent = elf;
2892de3b87aSKai Wang 
2902de3b87aSKai Wang 	return (e);
2912de3b87aSKai Wang }
2922de3b87aSKai Wang 
2932de3b87aSKai Wang /*
2942de3b87aSKai Wang  * A BSD-style ar(1) symbol table has the following layout:
2952de3b87aSKai Wang  *
2962de3b87aSKai Wang  * - A count of bytes used by the following array of 'ranlib'
2972de3b87aSKai Wang  *   structures, stored as a 'long'.
2982de3b87aSKai Wang  * - An array of 'ranlib' structures.  Each array element is
2992de3b87aSKai Wang  *   two 'long's in size.
3002de3b87aSKai Wang  * - A count of bytes used for the following symbol table.
3012de3b87aSKai Wang  * - The symbol table itself.
3022de3b87aSKai Wang  */
3032de3b87aSKai Wang 
3042de3b87aSKai Wang /*
305cf781b2eSEd Maste  * A helper macro to read in a 'long' value from the archive.
306cf781b2eSEd Maste  *
307cf781b2eSEd Maste  * We use memcpy() since the source pointer may be misaligned with
308cf781b2eSEd Maste  * respect to the natural alignment for a C 'long'.
3092de3b87aSKai Wang  */
3102de3b87aSKai Wang #define	GET_LONG(P, V)do {				\
3112de3b87aSKai Wang 		memcpy(&(V), (P), sizeof(long));	\
3122de3b87aSKai Wang 		(P) += sizeof(long);			\
3132de3b87aSKai Wang 	} while (0)
3142de3b87aSKai Wang 
3152de3b87aSKai Wang Elf_Arsym *
_libelf_ar_process_bsd_symtab(Elf * e,size_t * count)3162de3b87aSKai Wang _libelf_ar_process_bsd_symtab(Elf *e, size_t *count)
3172de3b87aSKai Wang {
3182de3b87aSKai Wang 	Elf_Arsym *symtab, *sym;
319*d003e0d7SEd Maste 	unsigned int n;
320*d003e0d7SEd Maste 	size_t nentries;
3212de3b87aSKai Wang 	unsigned char *end, *p, *p0, *s, *s0;
322cf781b2eSEd Maste 	const size_t entrysize = 2 * sizeof(long);
323cf781b2eSEd Maste 	long arraysize, fileoffset, stroffset, strtabsize;
3242de3b87aSKai Wang 
3252de3b87aSKai Wang 	assert(e != NULL);
3262de3b87aSKai Wang 	assert(count != NULL);
3272de3b87aSKai Wang 	assert(e->e_u.e_ar.e_symtab == NULL);
3282de3b87aSKai Wang 
3292de3b87aSKai Wang 	symtab = NULL;
3302de3b87aSKai Wang 
3312de3b87aSKai Wang 	/*
3322de3b87aSKai Wang 	 * The BSD symbol table always contains the count fields even
3332de3b87aSKai Wang 	 * if there are no entries in it.
3342de3b87aSKai Wang 	 */
3352de3b87aSKai Wang 	if (e->e_u.e_ar.e_rawsymtabsz < 2 * sizeof(long))
3362de3b87aSKai Wang 		goto symtaberror;
3372de3b87aSKai Wang 
3382de3b87aSKai Wang 	p = p0 = (unsigned char *) e->e_u.e_ar.e_rawsymtab;
3392de3b87aSKai Wang 	end = p0 + e->e_u.e_ar.e_rawsymtabsz;
3402de3b87aSKai Wang 
3412de3b87aSKai Wang 	/*
3422de3b87aSKai Wang 	 * Retrieve the size of the array of ranlib descriptors and
3432de3b87aSKai Wang 	 * check it for validity.
3442de3b87aSKai Wang 	 */
3452de3b87aSKai Wang 	GET_LONG(p, arraysize);
3462de3b87aSKai Wang 
347cf781b2eSEd Maste 	if (arraysize < 0 || p0 + arraysize >= end ||
348cf781b2eSEd Maste 	    ((size_t) arraysize % entrysize != 0))
3492de3b87aSKai Wang 		goto symtaberror;
3502de3b87aSKai Wang 
3512de3b87aSKai Wang 	/*
3522de3b87aSKai Wang 	 * Check the value of the string table size.
3532de3b87aSKai Wang 	 */
3542de3b87aSKai Wang 	s = p + arraysize;
3552de3b87aSKai Wang 	GET_LONG(s, strtabsize);
3562de3b87aSKai Wang 
3572de3b87aSKai Wang 	s0 = s;			/* Start of string table. */
358cf781b2eSEd Maste 	if (strtabsize < 0 || s0 + strtabsize > end)
3592de3b87aSKai Wang 		goto symtaberror;
3602de3b87aSKai Wang 
361cf781b2eSEd Maste 	nentries = (size_t) arraysize / entrysize;
3622de3b87aSKai Wang 
3632de3b87aSKai Wang 	/*
3642de3b87aSKai Wang 	 * Allocate space for the returned Elf_Arsym array.
3652de3b87aSKai Wang 	 */
3662de3b87aSKai Wang 	if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries + 1))) == NULL) {
3672de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, 0);
3682de3b87aSKai Wang 		return (NULL);
3692de3b87aSKai Wang 	}
3702de3b87aSKai Wang 
3712de3b87aSKai Wang 	/* Read in symbol table entries. */
3722de3b87aSKai Wang 	for (n = 0, sym = symtab; n < nentries; n++, sym++) {
3732de3b87aSKai Wang 		GET_LONG(p, stroffset);
3742de3b87aSKai Wang 		GET_LONG(p, fileoffset);
3752de3b87aSKai Wang 
376cf781b2eSEd Maste 		if (stroffset < 0 || fileoffset <  0 ||
377*d003e0d7SEd Maste 		    (off_t) fileoffset >= e->e_rawsize)
378cf781b2eSEd Maste 			goto symtaberror;
379cf781b2eSEd Maste 
3802de3b87aSKai Wang 		s = s0 + stroffset;
3812de3b87aSKai Wang 
3822de3b87aSKai Wang 		if (s >= end)
3832de3b87aSKai Wang 			goto symtaberror;
3842de3b87aSKai Wang 
385cf781b2eSEd Maste 		sym->as_off = (off_t) fileoffset;
3862de3b87aSKai Wang 		sym->as_hash = elf_hash((char *) s);
3872de3b87aSKai Wang 		sym->as_name = (char *) s;
3882de3b87aSKai Wang 	}
3892de3b87aSKai Wang 
3902de3b87aSKai Wang 	/* Fill up the sentinel entry. */
3912de3b87aSKai Wang 	sym->as_name = NULL;
3922de3b87aSKai Wang 	sym->as_hash = ~0UL;
3932de3b87aSKai Wang 	sym->as_off = (off_t) 0;
3942de3b87aSKai Wang 
3952de3b87aSKai Wang 	/* Remember the processed symbol table. */
3962de3b87aSKai Wang 	e->e_u.e_ar.e_symtab = symtab;
3972de3b87aSKai Wang 
3982de3b87aSKai Wang 	*count = e->e_u.e_ar.e_symtabsz = nentries + 1;
3992de3b87aSKai Wang 
4002de3b87aSKai Wang 	return (symtab);
4012de3b87aSKai Wang 
4022de3b87aSKai Wang symtaberror:
4032de3b87aSKai Wang 	if (symtab)
4042de3b87aSKai Wang 		free(symtab);
4052de3b87aSKai Wang 	LIBELF_SET_ERROR(ARCHIVE, 0);
4062de3b87aSKai Wang 	return (NULL);
4072de3b87aSKai Wang }
4082de3b87aSKai Wang 
4092de3b87aSKai Wang /*
4102de3b87aSKai Wang  * An SVR4-style ar(1) symbol table has the following layout:
4112de3b87aSKai Wang  *
4122de3b87aSKai Wang  * - The first 4 bytes are a binary count of the number of entries in the
4132de3b87aSKai Wang  *   symbol table, stored MSB-first.
4142de3b87aSKai Wang  * - Then there are 'n' 4-byte binary offsets, also stored MSB first.
4152de3b87aSKai Wang  * - Following this, there are 'n' null-terminated strings.
4162de3b87aSKai Wang  */
4172de3b87aSKai Wang 
4182de3b87aSKai Wang #define	GET_WORD(P, V) do {			\
4192de3b87aSKai Wang 		(V) = 0;			\
4202de3b87aSKai Wang 		(V) = (P)[0]; (V) <<= 8;	\
4212de3b87aSKai Wang 		(V) += (P)[1]; (V) <<= 8;	\
4222de3b87aSKai Wang 		(V) += (P)[2]; (V) <<= 8;	\
4232de3b87aSKai Wang 		(V) += (P)[3];			\
4242de3b87aSKai Wang 	} while (0)
4252de3b87aSKai Wang 
4262de3b87aSKai Wang #define	INTSZ	4
4272de3b87aSKai Wang 
4282de3b87aSKai Wang 
4292de3b87aSKai Wang Elf_Arsym *
_libelf_ar_process_svr4_symtab(Elf * e,size_t * count)4302de3b87aSKai Wang _libelf_ar_process_svr4_symtab(Elf *e, size_t *count)
4312de3b87aSKai Wang {
432cf781b2eSEd Maste 	uint32_t off;
433cf781b2eSEd Maste 	size_t n, nentries;
4342de3b87aSKai Wang 	Elf_Arsym *symtab, *sym;
4352de3b87aSKai Wang 	unsigned char *p, *s, *end;
4362de3b87aSKai Wang 
4372de3b87aSKai Wang 	assert(e != NULL);
4382de3b87aSKai Wang 	assert(count != NULL);
4392de3b87aSKai Wang 	assert(e->e_u.e_ar.e_symtab == NULL);
4402de3b87aSKai Wang 
4412de3b87aSKai Wang 	symtab = NULL;
4422de3b87aSKai Wang 
4432de3b87aSKai Wang 	if (e->e_u.e_ar.e_rawsymtabsz < INTSZ)
4442de3b87aSKai Wang 		goto symtaberror;
4452de3b87aSKai Wang 
4462de3b87aSKai Wang 	p = (unsigned char *) e->e_u.e_ar.e_rawsymtab;
4472de3b87aSKai Wang 	end = p + e->e_u.e_ar.e_rawsymtabsz;
4482de3b87aSKai Wang 
4492de3b87aSKai Wang 	GET_WORD(p, nentries);
4502de3b87aSKai Wang 	p += INTSZ;
4512de3b87aSKai Wang 
4522de3b87aSKai Wang 	if (nentries == 0 || p + nentries * INTSZ >= end)
4532de3b87aSKai Wang 		goto symtaberror;
4542de3b87aSKai Wang 
4552de3b87aSKai Wang 	/* Allocate space for a nentries + a sentinel. */
4562de3b87aSKai Wang 	if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries+1))) == NULL) {
4572de3b87aSKai Wang 		LIBELF_SET_ERROR(RESOURCE, 0);
4582de3b87aSKai Wang 		return (NULL);
4592de3b87aSKai Wang 	}
4602de3b87aSKai Wang 
4612de3b87aSKai Wang 	s = p + (nentries * INTSZ); /* start of the string table. */
4622de3b87aSKai Wang 
4632de3b87aSKai Wang 	for (n = nentries, sym = symtab; n > 0; n--) {
4642de3b87aSKai Wang 		if (s >= end)
4652de3b87aSKai Wang 			goto symtaberror;
4662de3b87aSKai Wang 
4672de3b87aSKai Wang 		GET_WORD(p, off);
468cf781b2eSEd Maste 		if (off >= e->e_rawsize)
469cf781b2eSEd Maste 			goto symtaberror;
4702de3b87aSKai Wang 
471cf781b2eSEd Maste 		sym->as_off = (off_t) off;
4722de3b87aSKai Wang 		sym->as_hash = elf_hash((char *) s);
4732de3b87aSKai Wang 		sym->as_name = (char *) s;
4742de3b87aSKai Wang 
4752de3b87aSKai Wang 		p += INTSZ;
4762de3b87aSKai Wang 		sym++;
4772de3b87aSKai Wang 
4782de3b87aSKai Wang 		for (; s < end && *s++ != '\0';) /* skip to next string */
4792de3b87aSKai Wang 			;
4802de3b87aSKai Wang 	}
4812de3b87aSKai Wang 
4822de3b87aSKai Wang 	/* Fill up the sentinel entry. */
4832de3b87aSKai Wang 	sym->as_name = NULL;
4842de3b87aSKai Wang 	sym->as_hash = ~0UL;
4852de3b87aSKai Wang 	sym->as_off = (off_t) 0;
4862de3b87aSKai Wang 
4872de3b87aSKai Wang 	*count = e->e_u.e_ar.e_symtabsz = nentries + 1;
4882de3b87aSKai Wang 	e->e_u.e_ar.e_symtab = symtab;
4892de3b87aSKai Wang 
4902de3b87aSKai Wang 	return (symtab);
4912de3b87aSKai Wang 
4922de3b87aSKai Wang symtaberror:
4932de3b87aSKai Wang 	if (symtab)
4942de3b87aSKai Wang 		free(symtab);
4952de3b87aSKai Wang 	LIBELF_SET_ERROR(ARCHIVE, 0);
4962de3b87aSKai Wang 	return (NULL);
4972de3b87aSKai Wang }
498