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