2 * Copyright (c) 2006,2009,2010 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>
35 #include "_libelf_ar.h"
40 * Convert a string bounded by `start' and `start+sz' (exclusive) to a
41 * number in the specified base.
44 _libelf_ar_get_number(const char *s
, size_t sz
, int base
, size_t *ret
)
54 /* skip leading blanks */
55 for (;s
< e
&& (c
= *s
) == ' '; s
++)
62 if (c
< '0' || c
> '9')
65 if (v
>= base
) /* Illegal digit. */
77 * Return the translated name for an archive member.
80 _libelf_ar_get_translated_name(const struct ar_hdr
*arh
, Elf
*ar
)
84 const char *buf
, *p
, *q
, *r
;
85 const size_t bufsize
= sizeof(arh
->ar_name
);
88 assert(ar
->e_kind
== ELF_K_AR
);
89 assert((const char *) arh
>= ar
->e_rawfile
&&
90 (const char *) arh
< ar
->e_rawfile
+ ar
->e_rawsize
);
95 * Check for extended naming.
97 * If the name matches the pattern "^/[0-9]+", it is an
98 * SVR4-style extended name. If the name matches the pattern
99 * "#1/[0-9]+", the entry uses BSD style extended naming.
101 if (buf
[0] == '/' && (c
= buf
[1]) >= '0' && c
<= '9') {
103 * The value in field ar_name is a decimal offset into
104 * the archive string table where the actual name
107 if (_libelf_ar_get_number(buf
+ 1, bufsize
- 1, 10,
109 LIBELF_SET_ERROR(ARCHIVE
, 0);
113 if (offset
> ar
->e_u
.e_ar
.e_rawstrtabsz
) {
114 LIBELF_SET_ERROR(ARCHIVE
, 0);
118 p
= q
= ar
->e_u
.e_ar
.e_rawstrtab
+ offset
;
119 r
= ar
->e_u
.e_ar
.e_rawstrtab
+ ar
->e_u
.e_ar
.e_rawstrtabsz
;
121 for (; p
< r
&& *p
!= '/'; p
++)
123 len
= p
- q
+ 1; /* space for the trailing NUL */
125 if ((s
= malloc(len
)) == NULL
) {
126 LIBELF_SET_ERROR(RESOURCE
, 0);
130 (void) strncpy(s
, q
, len
);
134 } else if (IS_EXTENDED_BSD_NAME(buf
)) {
135 r
= buf
+ LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE
;
137 if (_libelf_ar_get_number(r
, bufsize
-
138 LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE
, 10,
140 LIBELF_SET_ERROR(ARCHIVE
, 0);
145 * Allocate space for the file name plus a
148 if ((s
= malloc(len
+ 1)) == NULL
) {
149 LIBELF_SET_ERROR(RESOURCE
, 0);
154 * The file name follows the archive header.
156 q
= (const char *) (arh
+ 1);
158 (void) strncpy(s
, q
, len
);
167 * Skip back over trailing blanks from the end of the field.
168 * In the SVR4 format, a '/' is used as a terminator for
171 for (q
= buf
+ bufsize
- 1; q
>= buf
&& *q
== ' '; --q
)
177 * SVR4 style names: ignore the trailing
178 * character '/', but only if the name is not
179 * one of the special names "/" and "//".
182 (q
== (buf
+ 1) && *buf
!= '/'))
186 len
= q
- buf
+ 2; /* Add space for a trailing NUL. */
188 /* The buffer only had blanks. */
193 if ((s
= malloc(len
)) == NULL
) {
194 LIBELF_SET_ERROR(RESOURCE
, 0);
198 (void) strncpy(s
, buf
, len
);
205 * Return the raw name for an archive member, inclusive of any
206 * formatting characters.
209 _libelf_ar_get_raw_name(const struct ar_hdr
*arh
)
212 const size_t namesz
= sizeof(arh
->ar_name
);
214 if ((rawname
= malloc(namesz
+ 1)) == NULL
) {
215 LIBELF_SET_ERROR(RESOURCE
, 0);
219 (void) strncpy(rawname
, arh
->ar_name
, namesz
);
220 rawname
[namesz
] = '\0';
225 * Open an 'ar' archive.
228 _libelf_ar_open(Elf
*e
)
235 e
->e_kind
= ELF_K_AR
;
236 e
->e_u
.e_ar
.e_nchildren
= 0;
237 e
->e_u
.e_ar
.e_next
= (off_t
) -1;
240 * Look for special members.
243 s
= e
->e_rawfile
+ SARMAG
;
244 end
= e
->e_rawfile
+ e
->e_rawsize
;
246 assert(e
->e_rawsize
> 0);
249 * We use heuristics to determine the flavor of the archive we
252 * SVR4 flavor archives use the name "/ " and "// " for
255 * In BSD flavor archives the symbol table, if present, is the
256 * first archive with name "__.SYMDEF".
259 #define READ_AR_HEADER(S, ARH, SZ, END) \
261 if ((S) + sizeof((ARH)) > (END)) \
263 (void) memcpy(&(ARH), (S), sizeof((ARH))); \
264 if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \
266 if (_libelf_ar_get_number((ARH).ar_size, \
267 sizeof((ARH).ar_size), 10, &(SZ)) == 0) \
271 READ_AR_HEADER(s
, arh
, sz
, end
);
274 * Handle special archive members for the SVR4 format.
276 if (arh
.ar_name
[0] == '/') {
280 e
->e_flags
|= LIBELF_F_AR_VARIANT_SVR4
;
285 * The symbol table (file name "/ ") always comes before the
286 * string table (file name "// ").
288 if (arh
.ar_name
[1] == ' ') {
289 /* "/ " => symbol table. */
290 scanahead
= 1; /* The string table to follow. */
293 e
->e_u
.e_ar
.e_rawsymtab
= s
;
294 e
->e_u
.e_ar
.e_rawsymtabsz
= sz
;
296 sz
= LIBELF_ADJUST_AR_SIZE(sz
);
299 } else if (arh
.ar_name
[1] == '/' && arh
.ar_name
[2] == ' ') {
300 /* "// " => string table for long file names. */
302 e
->e_u
.e_ar
.e_rawstrtab
= s
;
303 e
->e_u
.e_ar
.e_rawstrtabsz
= sz
;
305 sz
= LIBELF_ADJUST_AR_SIZE(sz
);
310 * If the string table hasn't been seen yet, look for
311 * it in the next member.
314 READ_AR_HEADER(s
, arh
, sz
, end
);
316 if (arh
.ar_name
[0] == '/' && arh
.ar_name
[1] == '/' &&
317 arh
.ar_name
[2] == ' ') {
318 /* "// " => string table for long file names. */
321 e
->e_u
.e_ar
.e_rawstrtab
= s
;
322 e
->e_u
.e_ar
.e_rawstrtabsz
= sz
;
324 sz
= LIBELF_ADJUST_AR_SIZE(sz
);
328 } else if (strncmp(arh
.ar_name
, LIBELF_AR_BSD_SYMTAB_NAME
,
329 sizeof(LIBELF_AR_BSD_SYMTAB_NAME
) - 1) == 0) {
331 * BSD style archive symbol table.
334 e
->e_u
.e_ar
.e_rawsymtab
= s
;
335 e
->e_u
.e_ar
.e_rawsymtabsz
= sz
;
337 sz
= LIBELF_ADJUST_AR_SIZE(sz
);
342 * Update the 'next' offset, so that a subsequent elf_begin()
345 e
->e_u
.e_ar
.e_next
= (off_t
) (s
- e
->e_rawfile
);
350 LIBELF_SET_ERROR(ARCHIVE
, 0);