source: rtems-tools/linkers/elftoolchain/libelf/libelf_ar_util.c @ ec24a37

4.104.115
Last change on this file since ec24a37 was ec24a37, checked in by Chris Johns <chrisj@…>, on 05/06/12 at 22:47:11

Add to git.

  • Property mode set to 100644
File size: 8.0 KB
Line 
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
37LIBELF_VCSID("$Id: libelf_ar_util.c 2066 2011-10-26 15:40:28Z jkoshy $");
38
39/*
40 * Convert a string bounded by `start' and `start+sz' (exclusive) to a
41 * number in the specified base.
42 */
43int
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 */
79char *
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 */
208char *
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 */
227Elf *
228_libelf_ar_open(Elf *e)
229{
230        int scanahead;
231        char *s, *end;
232        size_t sz;
233        struct ar_hdr arh;
234
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;
238
239        /*
240         * Look for special members.
241         */
242
243        s = e->e_rawfile + SARMAG;
244        end = e->e_rawfile + e->e_rawsize;
245
246        assert(e->e_rawsize > 0);
247
248        /*
249         * We use heuristics to determine the flavor of the archive we
250         * are examining.
251         *
252         * SVR4 flavor archives use the name "/ " and "// " for
253         * special members.
254         *
255         * In BSD flavor archives the symbol table, if present, is the
256         * first archive with name "__.SYMDEF".
257         */
258
259#define READ_AR_HEADER(S, ARH, SZ, END)                                 \
260        do {                                                            \
261                if ((S) + sizeof((ARH)) > (END))                        \
262                        goto error;                                     \
263                (void) memcpy(&(ARH), (S), sizeof((ARH)));              \
264                if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \
265                        goto error;                                     \
266                if (_libelf_ar_get_number((ARH).ar_size,                \
267                    sizeof((ARH).ar_size), 10, &(SZ)) == 0)             \
268                        goto error;                                     \
269        } while (0)
270
271        READ_AR_HEADER(s, arh, sz, end);
272
273        /*
274         * Handle special archive members for the SVR4 format.
275         */
276        if (arh.ar_name[0] == '/') {
277
278                assert(sz > 0);
279
280                e->e_flags |= LIBELF_F_AR_VARIANT_SVR4;
281
282                scanahead = 0;
283
284                /*
285                 * The symbol table (file name "/ ") always comes before the
286                 * string table (file name "// ").
287                 */
288                if (arh.ar_name[1] == ' ') {
289                        /* "/ " => symbol table. */
290                        scanahead = 1;  /* The string table to follow. */
291
292                        s += sizeof(arh);
293                        e->e_u.e_ar.e_rawsymtab = s;
294                        e->e_u.e_ar.e_rawsymtabsz = sz;
295
296                        sz = LIBELF_ADJUST_AR_SIZE(sz);
297                        s += sz;
298
299                } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') {
300                        /* "// " => string table for long file names. */
301                        s += sizeof(arh);
302                        e->e_u.e_ar.e_rawstrtab = s;
303                        e->e_u.e_ar.e_rawstrtabsz = sz;
304
305                        sz = LIBELF_ADJUST_AR_SIZE(sz);
306                        s += sz;
307                }
308
309                /*
310                 * If the string table hasn't been seen yet, look for
311                 * it in the next member.
312                 */
313                if (scanahead) {
314                        READ_AR_HEADER(s, arh, sz, end);
315
316                        /* "// " => string table for long file names. */
317                        if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' &&
318                            arh.ar_name[2] == ' ') {
319
320                                s += sizeof(arh);
321
322                                e->e_u.e_ar.e_rawstrtab = s;
323                                e->e_u.e_ar.e_rawstrtabsz = sz;
324
325                                sz = LIBELF_ADJUST_AR_SIZE(sz);
326                                s += sz;
327                        }
328                }
329        } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME,
330                sizeof(LIBELF_AR_BSD_SYMTAB_NAME) - 1) == 0) {
331                /*
332                 * BSD style archive symbol table.
333                 */
334                s += sizeof(arh);
335                e->e_u.e_ar.e_rawsymtab = s;
336                e->e_u.e_ar.e_rawsymtabsz = sz;
337
338                sz = LIBELF_ADJUST_AR_SIZE(sz);
339                s += sz;
340        }
341
342        /*
343         * Update the 'next' offset, so that a subsequent elf_begin()
344         * works as expected.
345         */
346        e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile);
347
348        return (e);
349
350error:
351        LIBELF_SET_ERROR(ARCHIVE, 0);
352        return (NULL);
353
354}
Note: See TracBrowser for help on using the repository browser.