xref: /openbsd/lib/libelf/libelf_ar.c (revision a1b5ec25)
1*a1b5ec25Sjsg /*-
2*a1b5ec25Sjsg  * Copyright (c) 2006,2008,2010 Joseph Koshy
3*a1b5ec25Sjsg  * All rights reserved.
4*a1b5ec25Sjsg  *
5*a1b5ec25Sjsg  * Redistribution and use in source and binary forms, with or without
6*a1b5ec25Sjsg  * modification, are permitted provided that the following conditions
7*a1b5ec25Sjsg  * are met:
8*a1b5ec25Sjsg  * 1. Redistributions of source code must retain the above copyright
9*a1b5ec25Sjsg  *    notice, this list of conditions and the following disclaimer.
10*a1b5ec25Sjsg  * 2. Redistributions in binary form must reproduce the above copyright
11*a1b5ec25Sjsg  *    notice, this list of conditions and the following disclaimer in the
12*a1b5ec25Sjsg  *    documentation and/or other materials provided with the distribution.
13*a1b5ec25Sjsg  *
14*a1b5ec25Sjsg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND
15*a1b5ec25Sjsg  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*a1b5ec25Sjsg  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*a1b5ec25Sjsg  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*a1b5ec25Sjsg  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*a1b5ec25Sjsg  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*a1b5ec25Sjsg  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*a1b5ec25Sjsg  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*a1b5ec25Sjsg  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*a1b5ec25Sjsg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*a1b5ec25Sjsg  * SUCH DAMAGE.
25*a1b5ec25Sjsg  */
26*a1b5ec25Sjsg 
27*a1b5ec25Sjsg #include <assert.h>
28*a1b5ec25Sjsg #include <ctype.h>
29*a1b5ec25Sjsg #include <libelf.h>
30*a1b5ec25Sjsg #include <stdlib.h>
31*a1b5ec25Sjsg #include <string.h>
32*a1b5ec25Sjsg #include <stdint.h>
33*a1b5ec25Sjsg 
34*a1b5ec25Sjsg #include "_libelf.h"
35*a1b5ec25Sjsg #include "_libelf_ar.h"
36*a1b5ec25Sjsg 
37*a1b5ec25Sjsg ELFTC_VCSID("$Id: libelf_ar.c,v 1.1 2019/02/01 05:27:38 jsg Exp $");
38*a1b5ec25Sjsg 
39*a1b5ec25Sjsg #define	LIBELF_NALLOC_SIZE	16
40*a1b5ec25Sjsg 
41*a1b5ec25Sjsg /*
42*a1b5ec25Sjsg  * `ar' archive handling.
43*a1b5ec25Sjsg  *
44*a1b5ec25Sjsg  * `ar' archives start with signature `ARMAG'.  Each archive member is
45*a1b5ec25Sjsg  * preceded by a header containing meta-data for the member.  This
46*a1b5ec25Sjsg  * header is described in <ar.h> (struct ar_hdr).  The header always
47*a1b5ec25Sjsg  * starts on an even address.  File data is padded with "\n"
48*a1b5ec25Sjsg  * characters to keep this invariant.
49*a1b5ec25Sjsg  *
50*a1b5ec25Sjsg  * Special considerations for `ar' archives:
51*a1b5ec25Sjsg  *
52*a1b5ec25Sjsg  * There are two variants of the `ar' archive format: traditional BSD
53*a1b5ec25Sjsg  * and SVR4.  These differ in the way long file names are treated, and
54*a1b5ec25Sjsg  * in the layout of the archive symbol table.
55*a1b5ec25Sjsg  *
56*a1b5ec25Sjsg  * The `ar' header only has space for a 16 character file name.
57*a1b5ec25Sjsg  *
58*a1b5ec25Sjsg  * In the SVR4 format, file names are terminated with a '/', so this
59*a1b5ec25Sjsg  * effectively leaves 15 characters for the actual file name.  Longer
60*a1b5ec25Sjsg  * file names stored in a separate 'string table' and referenced
61*a1b5ec25Sjsg  * indirectly from the name field.  The string table itself appears as
62*a1b5ec25Sjsg  * an archive member with name "// ".  An `indirect' file name in an
63*a1b5ec25Sjsg  * `ar' header matches the pattern "/[0-9]*". The digits form a
64*a1b5ec25Sjsg  * decimal number that corresponds to a byte offset into the string
65*a1b5ec25Sjsg  * table where the actual file name of the object starts.  Strings in
66*a1b5ec25Sjsg  * the string table are padded to start on even addresses.
67*a1b5ec25Sjsg  *
68*a1b5ec25Sjsg  * In the BSD format, file names can be up to 16 characters.  File
69*a1b5ec25Sjsg  * names shorter than 16 characters are padded to 16 characters using
70*a1b5ec25Sjsg  * (ASCII) space characters.  File names with embedded spaces and file
71*a1b5ec25Sjsg  * names longer than 16 characters are stored immediately after the
72*a1b5ec25Sjsg  * archive header and the name field set to a special indirect name
73*a1b5ec25Sjsg  * matching the pattern "#1/[0-9]+".  The digits form a decimal number
74*a1b5ec25Sjsg  * that corresponds to the actual length of the file name following
75*a1b5ec25Sjsg  * the archive header.  The content of the archive member immediately
76*a1b5ec25Sjsg  * follows the file name, and the size field of the archive member
77*a1b5ec25Sjsg  * holds the sum of the sizes of the member and of the appended file
78*a1b5ec25Sjsg  * name.
79*a1b5ec25Sjsg  *
80*a1b5ec25Sjsg  * Archives may also have a symbol table (see ranlib(1)), mapping
81*a1b5ec25Sjsg  * program symbols to object files inside the archive.
82*a1b5ec25Sjsg  *
83*a1b5ec25Sjsg  * In the SVR4 format, a symbol table uses a file name of "/ " in its
84*a1b5ec25Sjsg  * archive header.  The symbol table is structured as:
85*a1b5ec25Sjsg  *  - a 4-byte count of entries stored as a binary value, MSB first
86*a1b5ec25Sjsg  *  - 'n' 4-byte offsets, stored as binary values, MSB first
87*a1b5ec25Sjsg  *  - 'n' NUL-terminated strings, for ELF symbol names, stored unpadded.
88*a1b5ec25Sjsg  *
89*a1b5ec25Sjsg  * In the BSD format, the symbol table uses a file name of "__.SYMDEF".
90*a1b5ec25Sjsg  * It is structured as two parts:
91*a1b5ec25Sjsg  *  - The first part is an array of "ranlib" structures preceded by
92*a1b5ec25Sjsg  *    the size of the array in bytes.  Each "ranlib" structure
93*a1b5ec25Sjsg  *    describes one symbol.  Each structure contains an offset into
94*a1b5ec25Sjsg  *    the string table for the symbol name, and a file offset into the
95*a1b5ec25Sjsg  *    archive for the member defining the symbol.
96*a1b5ec25Sjsg  *  - The second part is a string table containing NUL-terminated
97*a1b5ec25Sjsg  *    strings, preceded by the size of the string table in bytes.
98*a1b5ec25Sjsg  *
99*a1b5ec25Sjsg  * If the symbol table and string table are is present in an archive
100*a1b5ec25Sjsg  * they must be the very first objects and in that order.
101*a1b5ec25Sjsg  */
102*a1b5ec25Sjsg 
103*a1b5ec25Sjsg 
104*a1b5ec25Sjsg /*
105*a1b5ec25Sjsg  * Retrieve an archive header descriptor.
106*a1b5ec25Sjsg  */
107*a1b5ec25Sjsg 
108*a1b5ec25Sjsg Elf_Arhdr *
109*a1b5ec25Sjsg _libelf_ar_gethdr(Elf *e)
110*a1b5ec25Sjsg {
111*a1b5ec25Sjsg 	Elf *parent;
112*a1b5ec25Sjsg 	Elf_Arhdr *eh;
113*a1b5ec25Sjsg 	char *namelen;
114*a1b5ec25Sjsg 	size_t n, nlen;
115*a1b5ec25Sjsg 	struct ar_hdr *arh;
116*a1b5ec25Sjsg 
117*a1b5ec25Sjsg 	if ((parent = e->e_parent) == NULL) {
118*a1b5ec25Sjsg 		LIBELF_SET_ERROR(ARGUMENT, 0);
119*a1b5ec25Sjsg 		return (NULL);
120*a1b5ec25Sjsg 	}
121*a1b5ec25Sjsg 
122*a1b5ec25Sjsg 	assert((e->e_flags & LIBELF_F_AR_HEADER) == 0);
123*a1b5ec25Sjsg 
124*a1b5ec25Sjsg 	arh = (struct ar_hdr *) (uintptr_t) e->e_hdr.e_rawhdr;
125*a1b5ec25Sjsg 
126*a1b5ec25Sjsg 	assert((uintptr_t) arh >= (uintptr_t) parent->e_rawfile + SARMAG);
127*a1b5ec25Sjsg 	assert((uintptr_t) arh <= (uintptr_t) parent->e_rawfile +
128*a1b5ec25Sjsg 	    parent->e_rawsize - sizeof(struct ar_hdr));
129*a1b5ec25Sjsg 
130*a1b5ec25Sjsg 	if ((eh = malloc(sizeof(Elf_Arhdr))) == NULL) {
131*a1b5ec25Sjsg 		LIBELF_SET_ERROR(RESOURCE, 0);
132*a1b5ec25Sjsg 		return (NULL);
133*a1b5ec25Sjsg 	}
134*a1b5ec25Sjsg 
135*a1b5ec25Sjsg 	e->e_hdr.e_arhdr = eh;
136*a1b5ec25Sjsg 	e->e_flags |= LIBELF_F_AR_HEADER;
137*a1b5ec25Sjsg 
138*a1b5ec25Sjsg 	eh->ar_name = eh->ar_rawname = NULL;
139*a1b5ec25Sjsg 
140*a1b5ec25Sjsg 	if ((eh->ar_name = _libelf_ar_get_translated_name(arh, parent)) ==
141*a1b5ec25Sjsg 	    NULL)
142*a1b5ec25Sjsg 		goto error;
143*a1b5ec25Sjsg 
144*a1b5ec25Sjsg 	if (_libelf_ar_get_number(arh->ar_uid, sizeof(arh->ar_uid), 10,
145*a1b5ec25Sjsg 	    &n) == 0)
146*a1b5ec25Sjsg 		goto error;
147*a1b5ec25Sjsg 	eh->ar_uid = (uid_t) n;
148*a1b5ec25Sjsg 
149*a1b5ec25Sjsg 	if (_libelf_ar_get_number(arh->ar_gid, sizeof(arh->ar_gid), 10,
150*a1b5ec25Sjsg 	    &n) == 0)
151*a1b5ec25Sjsg 		goto error;
152*a1b5ec25Sjsg 	eh->ar_gid = (gid_t) n;
153*a1b5ec25Sjsg 
154*a1b5ec25Sjsg 	if (_libelf_ar_get_number(arh->ar_mode, sizeof(arh->ar_mode), 8,
155*a1b5ec25Sjsg 	    &n) == 0)
156*a1b5ec25Sjsg 		goto error;
157*a1b5ec25Sjsg 	eh->ar_mode = (mode_t) n;
158*a1b5ec25Sjsg 
159*a1b5ec25Sjsg 	if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10,
160*a1b5ec25Sjsg 	    &n) == 0)
161*a1b5ec25Sjsg 		goto error;
162*a1b5ec25Sjsg 
163*a1b5ec25Sjsg 	/*
164*a1b5ec25Sjsg 	 * Get the true size of the member if extended naming is being used.
165*a1b5ec25Sjsg 	 */
166*a1b5ec25Sjsg 	if (IS_EXTENDED_BSD_NAME(arh->ar_name)) {
167*a1b5ec25Sjsg 		namelen = arh->ar_name +
168*a1b5ec25Sjsg 		    LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE;
169*a1b5ec25Sjsg 		if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) -
170*a1b5ec25Sjsg 		    LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nlen) == 0)
171*a1b5ec25Sjsg 			goto error;
172*a1b5ec25Sjsg 		n -= nlen;
173*a1b5ec25Sjsg 	}
174*a1b5ec25Sjsg 
175*a1b5ec25Sjsg 	eh->ar_size = n;
176*a1b5ec25Sjsg 
177*a1b5ec25Sjsg 	if ((eh->ar_rawname = _libelf_ar_get_raw_name(arh)) == NULL)
178*a1b5ec25Sjsg 		goto error;
179*a1b5ec25Sjsg 
180*a1b5ec25Sjsg 	eh->ar_flags = 0;
181*a1b5ec25Sjsg 
182*a1b5ec25Sjsg 	return (eh);
183*a1b5ec25Sjsg 
184*a1b5ec25Sjsg  error:
185*a1b5ec25Sjsg 	if (eh) {
186*a1b5ec25Sjsg 		if (eh->ar_name)
187*a1b5ec25Sjsg 			free(eh->ar_name);
188*a1b5ec25Sjsg 		if (eh->ar_rawname)
189*a1b5ec25Sjsg 			free(eh->ar_rawname);
190*a1b5ec25Sjsg 		free(eh);
191*a1b5ec25Sjsg 	}
192*a1b5ec25Sjsg 
193*a1b5ec25Sjsg 	e->e_flags &= ~LIBELF_F_AR_HEADER;
194*a1b5ec25Sjsg 	e->e_hdr.e_rawhdr = (unsigned char *) arh;
195*a1b5ec25Sjsg 
196*a1b5ec25Sjsg 	return (NULL);
197*a1b5ec25Sjsg }
198*a1b5ec25Sjsg 
199*a1b5ec25Sjsg Elf *
200*a1b5ec25Sjsg _libelf_ar_open_member(int fd, Elf_Cmd c, Elf *elf)
201*a1b5ec25Sjsg {
202*a1b5ec25Sjsg 	Elf *e;
203*a1b5ec25Sjsg 	off_t next;
204*a1b5ec25Sjsg 	size_t nsz, sz;
205*a1b5ec25Sjsg 	struct ar_hdr *arh;
206*a1b5ec25Sjsg 	char *member, *namelen;
207*a1b5ec25Sjsg 
208*a1b5ec25Sjsg 	assert(elf->e_kind == ELF_K_AR);
209*a1b5ec25Sjsg 
210*a1b5ec25Sjsg 	next = elf->e_u.e_ar.e_next;
211*a1b5ec25Sjsg 
212*a1b5ec25Sjsg 	/*
213*a1b5ec25Sjsg 	 * `next' is only set to zero by elf_next() when the last
214*a1b5ec25Sjsg 	 * member of an archive is processed.
215*a1b5ec25Sjsg 	 */
216*a1b5ec25Sjsg 	if (next == (off_t) 0)
217*a1b5ec25Sjsg 		return (NULL);
218*a1b5ec25Sjsg 
219*a1b5ec25Sjsg 	assert((next & 1) == 0);
220*a1b5ec25Sjsg 
221*a1b5ec25Sjsg 	arh = (struct ar_hdr *) (elf->e_rawfile + next);
222*a1b5ec25Sjsg 
223*a1b5ec25Sjsg 	/*
224*a1b5ec25Sjsg 	 * Retrieve the size of the member.
225*a1b5ec25Sjsg 	 */
226*a1b5ec25Sjsg 	if (_libelf_ar_get_number(arh->ar_size, sizeof(arh->ar_size), 10,
227*a1b5ec25Sjsg 	    &sz) == 0) {
228*a1b5ec25Sjsg 		LIBELF_SET_ERROR(ARCHIVE, 0);
229*a1b5ec25Sjsg 		return (NULL);
230*a1b5ec25Sjsg 	}
231*a1b5ec25Sjsg 
232*a1b5ec25Sjsg 	/*
233*a1b5ec25Sjsg 	 * Adjust the size field for members in BSD archives using
234*a1b5ec25Sjsg 	 * extended naming.
235*a1b5ec25Sjsg 	 */
236*a1b5ec25Sjsg 	if (IS_EXTENDED_BSD_NAME(arh->ar_name)) {
237*a1b5ec25Sjsg 		namelen = arh->ar_name +
238*a1b5ec25Sjsg 		    LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE;
239*a1b5ec25Sjsg 		if (_libelf_ar_get_number(namelen, sizeof(arh->ar_name) -
240*a1b5ec25Sjsg 		    LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, &nsz) == 0) {
241*a1b5ec25Sjsg 			LIBELF_SET_ERROR(ARCHIVE, 0);
242*a1b5ec25Sjsg 			return (NULL);
243*a1b5ec25Sjsg 		}
244*a1b5ec25Sjsg 
245*a1b5ec25Sjsg 		member = (char *) (arh + 1) + nsz;
246*a1b5ec25Sjsg 		sz -= nsz;
247*a1b5ec25Sjsg 	} else
248*a1b5ec25Sjsg 		member = (char *) (arh + 1);
249*a1b5ec25Sjsg 
250*a1b5ec25Sjsg 
251*a1b5ec25Sjsg 	if ((e = elf_memory(member, sz)) == NULL)
252*a1b5ec25Sjsg 		return (NULL);
253*a1b5ec25Sjsg 
254*a1b5ec25Sjsg 	e->e_fd = fd;
255*a1b5ec25Sjsg 	e->e_cmd = c;
256*a1b5ec25Sjsg 	e->e_hdr.e_rawhdr = (unsigned char *) arh;
257*a1b5ec25Sjsg 
258*a1b5ec25Sjsg 	elf->e_u.e_ar.e_nchildren++;
259*a1b5ec25Sjsg 	e->e_parent = elf;
260*a1b5ec25Sjsg 
261*a1b5ec25Sjsg 	return (e);
262*a1b5ec25Sjsg }
263*a1b5ec25Sjsg 
264*a1b5ec25Sjsg /*
265*a1b5ec25Sjsg  * A BSD-style ar(1) symbol table has the following layout:
266*a1b5ec25Sjsg  *
267*a1b5ec25Sjsg  * - A count of bytes used by the following array of 'ranlib'
268*a1b5ec25Sjsg  *   structures, stored as a 'long'.
269*a1b5ec25Sjsg  * - An array of 'ranlib' structures.  Each array element is
270*a1b5ec25Sjsg  *   two 'long's in size.
271*a1b5ec25Sjsg  * - A count of bytes used for the following symbol table.
272*a1b5ec25Sjsg  * - The symbol table itself.
273*a1b5ec25Sjsg  */
274*a1b5ec25Sjsg 
275*a1b5ec25Sjsg /*
276*a1b5ec25Sjsg  * A helper macro to read in a 'long' value from the archive.
277*a1b5ec25Sjsg  *
278*a1b5ec25Sjsg  * We use memcpy() since the source pointer may be misaligned with
279*a1b5ec25Sjsg  * respect to the natural alignment for a C 'long'.
280*a1b5ec25Sjsg  */
281*a1b5ec25Sjsg #define	GET_LONG(P, V)do {				\
282*a1b5ec25Sjsg 		memcpy(&(V), (P), sizeof(long));	\
283*a1b5ec25Sjsg 		(P) += sizeof(long);			\
284*a1b5ec25Sjsg 	} while (0)
285*a1b5ec25Sjsg 
286*a1b5ec25Sjsg Elf_Arsym *
287*a1b5ec25Sjsg _libelf_ar_process_bsd_symtab(Elf *e, size_t *count)
288*a1b5ec25Sjsg {
289*a1b5ec25Sjsg 	Elf_Arsym *symtab, *sym;
290*a1b5ec25Sjsg 	unsigned int n, nentries;
291*a1b5ec25Sjsg 	unsigned char *end, *p, *p0, *s, *s0;
292*a1b5ec25Sjsg 	const size_t entrysize = 2 * sizeof(long);
293*a1b5ec25Sjsg 	long arraysize, fileoffset, stroffset, strtabsize;
294*a1b5ec25Sjsg 
295*a1b5ec25Sjsg 	assert(e != NULL);
296*a1b5ec25Sjsg 	assert(count != NULL);
297*a1b5ec25Sjsg 	assert(e->e_u.e_ar.e_symtab == NULL);
298*a1b5ec25Sjsg 
299*a1b5ec25Sjsg 	symtab = NULL;
300*a1b5ec25Sjsg 
301*a1b5ec25Sjsg 	/*
302*a1b5ec25Sjsg 	 * The BSD symbol table always contains the count fields even
303*a1b5ec25Sjsg 	 * if there are no entries in it.
304*a1b5ec25Sjsg 	 */
305*a1b5ec25Sjsg 	if (e->e_u.e_ar.e_rawsymtabsz < 2 * sizeof(long))
306*a1b5ec25Sjsg 		goto symtaberror;
307*a1b5ec25Sjsg 
308*a1b5ec25Sjsg 	p = p0 = (unsigned char *) e->e_u.e_ar.e_rawsymtab;
309*a1b5ec25Sjsg 	end = p0 + e->e_u.e_ar.e_rawsymtabsz;
310*a1b5ec25Sjsg 
311*a1b5ec25Sjsg 	/*
312*a1b5ec25Sjsg 	 * Retrieve the size of the array of ranlib descriptors and
313*a1b5ec25Sjsg 	 * check it for validity.
314*a1b5ec25Sjsg 	 */
315*a1b5ec25Sjsg 	GET_LONG(p, arraysize);
316*a1b5ec25Sjsg 
317*a1b5ec25Sjsg 	if (arraysize < 0 || p0 + arraysize >= end ||
318*a1b5ec25Sjsg 	    ((size_t) arraysize % entrysize != 0))
319*a1b5ec25Sjsg 		goto symtaberror;
320*a1b5ec25Sjsg 
321*a1b5ec25Sjsg 	/*
322*a1b5ec25Sjsg 	 * Check the value of the string table size.
323*a1b5ec25Sjsg 	 */
324*a1b5ec25Sjsg 	s = p + arraysize;
325*a1b5ec25Sjsg 	GET_LONG(s, strtabsize);
326*a1b5ec25Sjsg 
327*a1b5ec25Sjsg 	s0 = s;			/* Start of string table. */
328*a1b5ec25Sjsg 	if (strtabsize < 0 || s0 + strtabsize > end)
329*a1b5ec25Sjsg 		goto symtaberror;
330*a1b5ec25Sjsg 
331*a1b5ec25Sjsg 	nentries = (size_t) arraysize / entrysize;
332*a1b5ec25Sjsg 
333*a1b5ec25Sjsg 	/*
334*a1b5ec25Sjsg 	 * Allocate space for the returned Elf_Arsym array.
335*a1b5ec25Sjsg 	 */
336*a1b5ec25Sjsg 	if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries + 1))) == NULL) {
337*a1b5ec25Sjsg 		LIBELF_SET_ERROR(RESOURCE, 0);
338*a1b5ec25Sjsg 		return (NULL);
339*a1b5ec25Sjsg 	}
340*a1b5ec25Sjsg 
341*a1b5ec25Sjsg 	/* Read in symbol table entries. */
342*a1b5ec25Sjsg 	for (n = 0, sym = symtab; n < nentries; n++, sym++) {
343*a1b5ec25Sjsg 		GET_LONG(p, stroffset);
344*a1b5ec25Sjsg 		GET_LONG(p, fileoffset);
345*a1b5ec25Sjsg 
346*a1b5ec25Sjsg 		if (stroffset < 0 || fileoffset <  0 ||
347*a1b5ec25Sjsg 		    (size_t) fileoffset >= e->e_rawsize)
348*a1b5ec25Sjsg 			goto symtaberror;
349*a1b5ec25Sjsg 
350*a1b5ec25Sjsg 		s = s0 + stroffset;
351*a1b5ec25Sjsg 
352*a1b5ec25Sjsg 		if (s >= end)
353*a1b5ec25Sjsg 			goto symtaberror;
354*a1b5ec25Sjsg 
355*a1b5ec25Sjsg 		sym->as_off = (off_t) fileoffset;
356*a1b5ec25Sjsg 		sym->as_hash = elf_hash((char *) s);
357*a1b5ec25Sjsg 		sym->as_name = (char *) s;
358*a1b5ec25Sjsg 	}
359*a1b5ec25Sjsg 
360*a1b5ec25Sjsg 	/* Fill up the sentinel entry. */
361*a1b5ec25Sjsg 	sym->as_name = NULL;
362*a1b5ec25Sjsg 	sym->as_hash = ~0UL;
363*a1b5ec25Sjsg 	sym->as_off = (off_t) 0;
364*a1b5ec25Sjsg 
365*a1b5ec25Sjsg 	/* Remember the processed symbol table. */
366*a1b5ec25Sjsg 	e->e_u.e_ar.e_symtab = symtab;
367*a1b5ec25Sjsg 
368*a1b5ec25Sjsg 	*count = e->e_u.e_ar.e_symtabsz = nentries + 1;
369*a1b5ec25Sjsg 
370*a1b5ec25Sjsg 	return (symtab);
371*a1b5ec25Sjsg 
372*a1b5ec25Sjsg symtaberror:
373*a1b5ec25Sjsg 	if (symtab)
374*a1b5ec25Sjsg 		free(symtab);
375*a1b5ec25Sjsg 	LIBELF_SET_ERROR(ARCHIVE, 0);
376*a1b5ec25Sjsg 	return (NULL);
377*a1b5ec25Sjsg }
378*a1b5ec25Sjsg 
379*a1b5ec25Sjsg /*
380*a1b5ec25Sjsg  * An SVR4-style ar(1) symbol table has the following layout:
381*a1b5ec25Sjsg  *
382*a1b5ec25Sjsg  * - The first 4 bytes are a binary count of the number of entries in the
383*a1b5ec25Sjsg  *   symbol table, stored MSB-first.
384*a1b5ec25Sjsg  * - Then there are 'n' 4-byte binary offsets, also stored MSB first.
385*a1b5ec25Sjsg  * - Following this, there are 'n' null-terminated strings.
386*a1b5ec25Sjsg  */
387*a1b5ec25Sjsg 
388*a1b5ec25Sjsg #define	GET_WORD(P, V) do {			\
389*a1b5ec25Sjsg 		(V) = 0;			\
390*a1b5ec25Sjsg 		(V) = (P)[0]; (V) <<= 8;	\
391*a1b5ec25Sjsg 		(V) += (P)[1]; (V) <<= 8;	\
392*a1b5ec25Sjsg 		(V) += (P)[2]; (V) <<= 8;	\
393*a1b5ec25Sjsg 		(V) += (P)[3];			\
394*a1b5ec25Sjsg 	} while (0)
395*a1b5ec25Sjsg 
396*a1b5ec25Sjsg #define	INTSZ	4
397*a1b5ec25Sjsg 
398*a1b5ec25Sjsg 
399*a1b5ec25Sjsg Elf_Arsym *
400*a1b5ec25Sjsg _libelf_ar_process_svr4_symtab(Elf *e, size_t *count)
401*a1b5ec25Sjsg {
402*a1b5ec25Sjsg 	uint32_t off;
403*a1b5ec25Sjsg 	size_t n, nentries;
404*a1b5ec25Sjsg 	Elf_Arsym *symtab, *sym;
405*a1b5ec25Sjsg 	unsigned char *p, *s, *end;
406*a1b5ec25Sjsg 
407*a1b5ec25Sjsg 	assert(e != NULL);
408*a1b5ec25Sjsg 	assert(count != NULL);
409*a1b5ec25Sjsg 	assert(e->e_u.e_ar.e_symtab == NULL);
410*a1b5ec25Sjsg 
411*a1b5ec25Sjsg 	symtab = NULL;
412*a1b5ec25Sjsg 
413*a1b5ec25Sjsg 	if (e->e_u.e_ar.e_rawsymtabsz < INTSZ)
414*a1b5ec25Sjsg 		goto symtaberror;
415*a1b5ec25Sjsg 
416*a1b5ec25Sjsg 	p = (unsigned char *) e->e_u.e_ar.e_rawsymtab;
417*a1b5ec25Sjsg 	end = p + e->e_u.e_ar.e_rawsymtabsz;
418*a1b5ec25Sjsg 
419*a1b5ec25Sjsg 	GET_WORD(p, nentries);
420*a1b5ec25Sjsg 	p += INTSZ;
421*a1b5ec25Sjsg 
422*a1b5ec25Sjsg 	if (nentries == 0 || p + nentries * INTSZ >= end)
423*a1b5ec25Sjsg 		goto symtaberror;
424*a1b5ec25Sjsg 
425*a1b5ec25Sjsg 	/* Allocate space for a nentries + a sentinel. */
426*a1b5ec25Sjsg 	if ((symtab = malloc(sizeof(Elf_Arsym) * (nentries+1))) == NULL) {
427*a1b5ec25Sjsg 		LIBELF_SET_ERROR(RESOURCE, 0);
428*a1b5ec25Sjsg 		return (NULL);
429*a1b5ec25Sjsg 	}
430*a1b5ec25Sjsg 
431*a1b5ec25Sjsg 	s = p + (nentries * INTSZ); /* start of the string table. */
432*a1b5ec25Sjsg 
433*a1b5ec25Sjsg 	for (n = nentries, sym = symtab; n > 0; n--) {
434*a1b5ec25Sjsg 		if (s >= end)
435*a1b5ec25Sjsg 			goto symtaberror;
436*a1b5ec25Sjsg 
437*a1b5ec25Sjsg 		GET_WORD(p, off);
438*a1b5ec25Sjsg 		if (off >= e->e_rawsize)
439*a1b5ec25Sjsg 			goto symtaberror;
440*a1b5ec25Sjsg 
441*a1b5ec25Sjsg 		sym->as_off = (off_t) off;
442*a1b5ec25Sjsg 		sym->as_hash = elf_hash((char *) s);
443*a1b5ec25Sjsg 		sym->as_name = (char *) s;
444*a1b5ec25Sjsg 
445*a1b5ec25Sjsg 		p += INTSZ;
446*a1b5ec25Sjsg 		sym++;
447*a1b5ec25Sjsg 
448*a1b5ec25Sjsg 		for (; s < end && *s++ != '\0';) /* skip to next string */
449*a1b5ec25Sjsg 			;
450*a1b5ec25Sjsg 	}
451*a1b5ec25Sjsg 
452*a1b5ec25Sjsg 	/* Fill up the sentinel entry. */
453*a1b5ec25Sjsg 	sym->as_name = NULL;
454*a1b5ec25Sjsg 	sym->as_hash = ~0UL;
455*a1b5ec25Sjsg 	sym->as_off = (off_t) 0;
456*a1b5ec25Sjsg 
457*a1b5ec25Sjsg 	*count = e->e_u.e_ar.e_symtabsz = nentries + 1;
458*a1b5ec25Sjsg 	e->e_u.e_ar.e_symtab = symtab;
459*a1b5ec25Sjsg 
460*a1b5ec25Sjsg 	return (symtab);
461*a1b5ec25Sjsg 
462*a1b5ec25Sjsg symtaberror:
463*a1b5ec25Sjsg 	if (symtab)
464*a1b5ec25Sjsg 		free(symtab);
465*a1b5ec25Sjsg 	LIBELF_SET_ERROR(ARCHIVE, 0);
466*a1b5ec25Sjsg 	return (NULL);
467*a1b5ec25Sjsg }
468