]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/elftoolchain/libelf/libelf_ar_util.c
Merge OpenSSL 1.0.1h.
[FreeBSD/FreeBSD.git] / contrib / elftoolchain / libelf / libelf_ar_util.c
1 /*-
2  * Copyright (c) 2006,2009,2010 Joseph Koshy
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28
29 #include <assert.h>
30 #include <libelf.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include "_libelf.h"
35 #include "_libelf_ar.h"
36
37 ELFTC_VCSID("$Id: libelf_ar_util.c 2365 2011-12-29 04:36:44Z jkoshy $");
38
39 /*
40  * Convert a string bounded by `start' and `start+sz' (exclusive) to a
41  * number in the specified base.
42  */
43 int
44 _libelf_ar_get_number(const char *s, size_t sz, int base, size_t *ret)
45 {
46         int c, v;
47         size_t r;
48         const char *e;
49
50         assert(base <= 10);
51
52         e = s + sz;
53
54         /* skip leading blanks */
55         for (;s < e && (c = *s) == ' '; s++)
56                 ;
57
58         r = 0L;
59         for (;s < e; s++) {
60                 if ((c = *s) == ' ')
61                         break;
62                 if (c < '0' || c > '9')
63                         return (0);
64                 v = c - '0';
65                 if (v >= base)          /* Illegal digit. */
66                         break;
67                 r *= base;
68                 r += v;
69         }
70
71         *ret = r;
72
73         return (1);
74 }
75
76 /*
77  * Return the translated name for an archive member.
78  */
79 char *
80 _libelf_ar_get_translated_name(const struct ar_hdr *arh, Elf *ar)
81 {
82         char c, *s;
83         size_t len, offset;
84         const char *buf, *p, *q, *r;
85         const size_t bufsize = sizeof(arh->ar_name);
86
87         assert(arh != NULL);
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);
91
92         buf = arh->ar_name;
93
94         /*
95          * Check for extended naming.
96          *
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.
100          */
101         if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') {
102                 /*
103                  * The value in field ar_name is a decimal offset into
104                  * the archive string table where the actual name
105                  * resides.
106                  */
107                 if (_libelf_ar_get_number(buf + 1, bufsize - 1, 10,
108                         &offset) == 0) {
109                         LIBELF_SET_ERROR(ARCHIVE, 0);
110                         return (NULL);
111                 }
112
113                 if (offset > ar->e_u.e_ar.e_rawstrtabsz) {
114                         LIBELF_SET_ERROR(ARCHIVE, 0);
115                         return (NULL);
116                 }
117
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;
120
121                 for (; p < r && *p != '/'; p++)
122                         ;
123                 len = p - q + 1; /* space for the trailing NUL */
124
125                 if ((s = malloc(len)) == NULL) {
126                         LIBELF_SET_ERROR(RESOURCE, 0);
127                         return (NULL);
128                 }
129
130                 (void) strncpy(s, q, len - 1);
131                 s[len - 1] = '\0';
132
133                 return (s);
134         } else if (IS_EXTENDED_BSD_NAME(buf)) {
135                 r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE;
136
137                 if (_libelf_ar_get_number(r, bufsize -
138                         LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10,
139                         &len) == 0) {
140                         LIBELF_SET_ERROR(ARCHIVE, 0);
141                         return (NULL);
142                 }
143
144                 /*
145                  * Allocate space for the file name plus a
146                  * trailing NUL.
147                  */
148                 if ((s = malloc(len + 1)) == NULL) {
149                         LIBELF_SET_ERROR(RESOURCE, 0);
150                         return (NULL);
151                 }
152
153                 /*
154                  * The file name follows the archive header.
155                  */
156                 q = (const char *) (arh + 1);
157
158                 (void) strncpy(s, q, len);
159                 s[len] = '\0';
160
161                 return (s);
162         }
163
164         /*
165          * A 'normal' name.
166          *
167          * Skip back over trailing blanks from the end of the field.
168          * In the SVR4 format, a '/' is used as a terminator for
169          * non-special names.
170          */
171         for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q)
172                 ;
173
174         if (q >= buf) {
175                 if (*q == '/') {
176                         /*
177                          * SVR4 style names: ignore the trailing
178                          * character '/', but only if the name is not
179                          * one of the special names "/" and "//".
180                          */
181                         if (q > buf + 1 ||
182                             (q == (buf + 1) && *buf != '/'))
183                                 q--;
184                 }
185
186                 len = q - buf + 2; /* Add space for a trailing NUL. */
187         } else {
188                 /* The buffer only had blanks. */
189                 buf = "";
190                 len = 1;
191         }
192
193         if ((s = malloc(len)) == NULL) {
194                 LIBELF_SET_ERROR(RESOURCE, 0);
195                 return (NULL);
196         }
197
198         (void) strncpy(s, buf, len - 1);
199         s[len - 1] = '\0';
200
201         return (s);
202 }
203
204 /*
205  * Return the raw name for an archive member, inclusive of any
206  * formatting characters.
207  */
208 char *
209 _libelf_ar_get_raw_name(const struct ar_hdr *arh)
210 {
211         char *rawname;
212         const size_t namesz = sizeof(arh->ar_name);
213
214         if ((rawname = malloc(namesz + 1)) == NULL) {
215                 LIBELF_SET_ERROR(RESOURCE, 0);
216                 return (NULL);
217         }
218
219         (void) strncpy(rawname, arh->ar_name, namesz);
220         rawname[namesz] = '\0';
221         return (rawname);
222 }
223
224 /*
225  * Open an 'ar' archive.
226  */
227 Elf *
228 _libelf_ar_open(Elf *e, int reporterror)
229 {
230         size_t sz;
231         int scanahead;
232         char *s, *end;
233         struct ar_hdr arh;
234
235         _libelf_init_elf(e, ELF_K_AR);
236
237         e->e_u.e_ar.e_nchildren = 0;
238         e->e_u.e_ar.e_next = (off_t) -1;
239
240         /*
241          * Look for special members.
242          */
243
244         s = e->e_rawfile + SARMAG;
245         end = e->e_rawfile + e->e_rawsize;
246
247         assert(e->e_rawsize > 0);
248
249         /*
250          * We use heuristics to determine the flavor of the archive we
251          * are examining.
252          *
253          * SVR4 flavor archives use the name "/ " and "// " for
254          * special members.
255          *
256          * In BSD flavor archives the symbol table, if present, is the
257          * first archive with name "__.SYMDEF".
258          */
259
260 #define READ_AR_HEADER(S, ARH, SZ, END)                                 \
261         do {                                                            \
262                 if ((S) + sizeof((ARH)) > (END))                        \
263                         goto error;                                     \
264                 (void) memcpy(&(ARH), (S), sizeof((ARH)));              \
265                 if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \
266                         goto error;                                     \
267                 if (_libelf_ar_get_number((ARH).ar_size,                \
268                     sizeof((ARH).ar_size), 10, &(SZ)) == 0)             \
269                         goto error;                                     \
270         } while (0)
271
272         READ_AR_HEADER(s, arh, sz, end);
273
274         /*
275          * Handle special archive members for the SVR4 format.
276          */
277         if (arh.ar_name[0] == '/') {
278
279                 assert(sz > 0);
280
281                 e->e_flags |= LIBELF_F_AR_VARIANT_SVR4;
282
283                 scanahead = 0;
284
285                 /*
286                  * The symbol table (file name "/ ") always comes before the
287                  * string table (file name "// ").
288                  */
289                 if (arh.ar_name[1] == ' ') {
290                         /* "/ " => symbol table. */
291                         scanahead = 1;  /* The string table to follow. */
292
293                         s += sizeof(arh);
294                         e->e_u.e_ar.e_rawsymtab = s;
295                         e->e_u.e_ar.e_rawsymtabsz = sz;
296
297                         sz = LIBELF_ADJUST_AR_SIZE(sz);
298                         s += sz;
299
300                 } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') {
301                         /* "// " => string table for long file names. */
302                         s += sizeof(arh);
303                         e->e_u.e_ar.e_rawstrtab = s;
304                         e->e_u.e_ar.e_rawstrtabsz = sz;
305
306                         sz = LIBELF_ADJUST_AR_SIZE(sz);
307                         s += sz;
308                 }
309
310                 /*
311                  * If the string table hasn't been seen yet, look for
312                  * it in the next member.
313                  */
314                 if (scanahead) {
315                         READ_AR_HEADER(s, arh, sz, end);
316
317                         /* "// " => string table for long file names. */
318                         if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' &&
319                             arh.ar_name[2] == ' ') {
320
321                                 s += sizeof(arh);
322
323                                 e->e_u.e_ar.e_rawstrtab = s;
324                                 e->e_u.e_ar.e_rawstrtabsz = sz;
325
326                                 sz = LIBELF_ADJUST_AR_SIZE(sz);
327                                 s += sz;
328                         }
329                 }
330         } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME,
331                 sizeof(LIBELF_AR_BSD_SYMTAB_NAME) - 1) == 0) {
332                 /*
333                  * BSD style archive symbol table.
334                  */
335                 s += sizeof(arh);
336                 e->e_u.e_ar.e_rawsymtab = s;
337                 e->e_u.e_ar.e_rawsymtabsz = sz;
338
339                 sz = LIBELF_ADJUST_AR_SIZE(sz);
340                 s += sz;
341         }
342
343         /*
344          * Update the 'next' offset, so that a subsequent elf_begin()
345          * works as expected.
346          */
347         e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile);
348
349         return (e);
350
351 error:
352         if (!reporterror) {
353                 e->e_kind = ELF_K_NONE;
354                 return (e);
355         }
356
357         LIBELF_SET_ERROR(ARCHIVE, 0);
358         return (NULL);
359 }