2 * Copyright (c) 2006,2009 Joseph Koshy
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
39 * Convert a string bounded by `start' and `start+sz' (exclusive) to a
40 * number in the specified base.
43 _libelf_ar_get_number(char *s, size_t sz, int base, size_t *ret)
53 /* skip leading blanks */
54 for (;s < e && (c = *s) == ' '; s++)
61 if (c < '0' || c > '9')
64 if (v >= base) /* Illegal digit. */
76 * Retrieve a string from a name field. If `rawname' is set, leave
77 * ar(1) control characters in.
80 _libelf_ar_get_string(const char *buf, size_t bufsize, int rawname)
89 /* Skip back over trailing blanks. */
90 for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q)
95 * If the input buffer only had blanks in it,
96 * return a zero-length string.
102 * Remove the trailing '/' character, but only
103 * if the name isn't one of the special names
107 (q == (buf + 1) && *buf != '/'))
110 sz = q - buf + 2; /* Space for a trailing NUL. */
114 if ((r = malloc(sz)) == NULL) {
115 LIBELF_SET_ERROR(RESOURCE, 0);
119 (void) strncpy(r, buf, sz);
126 * Retrieve the full name of the archive member.
129 _libelf_ar_get_name(char *buf, size_t bufsize, Elf *e)
135 assert(e->e_kind == ELF_K_AR);
137 if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') {
139 * The value in field ar_name is a decimal offset into
140 * the archive string table where the actual name
143 if (_libelf_ar_get_number(buf + 1, bufsize - 1, 10,
145 LIBELF_SET_ERROR(ARCHIVE, 0);
149 if (offset > e->e_u.e_ar.e_rawstrtabsz) {
150 LIBELF_SET_ERROR(ARCHIVE, 0);
154 s = q = e->e_u.e_ar.e_rawstrtab + offset;
155 r = e->e_u.e_ar.e_rawstrtab + e->e_u.e_ar.e_rawstrtabsz;
157 for (s = q; s < r && *s != '/'; s++)
159 len = s - q + 1; /* space for the trailing NUL */
161 if ((s = malloc(len)) == NULL) {
162 LIBELF_SET_ERROR(RESOURCE, 0);
166 (void) strncpy(s, q, len);
175 return (_libelf_ar_get_string(buf, bufsize, 0));
179 * Open an 'ar' archive.
182 _libelf_ar_open(Elf *e)
189 e->e_kind = ELF_K_AR;
190 e->e_u.e_ar.e_nchildren = 0;
191 e->e_u.e_ar.e_next = (off_t) -1;
194 * Look for special members.
197 s = e->e_rawfile + SARMAG;
198 end = e->e_rawfile + e->e_rawsize;
200 assert(e->e_rawsize > 0);
203 * Look for magic names "/ " and "// " in the first two entries
206 for (i = 0; i < 2; i++) {
208 if (s + sizeof(arh) > end) {
209 LIBELF_SET_ERROR(ARCHIVE, 0);
213 (void) memcpy(&arh, s, sizeof(arh));
215 if (arh.ar_fmag[0] != '`' || arh.ar_fmag[1] != '\n') {
216 LIBELF_SET_ERROR(ARCHIVE, 0);
220 if (arh.ar_name[0] != '/') /* not a special symbol */
223 if (_libelf_ar_get_number(arh.ar_size, sizeof(arh.ar_size),
225 LIBELF_SET_ERROR(ARCHIVE, 0);
233 if (arh.ar_name[1] == ' ') { /* "/ " => symbol table */
235 e->e_u.e_ar.e_rawsymtab = s;
236 e->e_u.e_ar.e_rawsymtabsz = sz;
238 } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') {
240 /* "// " => string table for long file names */
241 e->e_u.e_ar.e_rawstrtab = s;
242 e->e_u.e_ar.e_rawstrtabsz = sz;
245 sz = LIBELF_ADJUST_AR_SIZE(sz);
250 e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile);