]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libelf/libelf_ar_util.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / lib / libelf / libelf_ar_util.c
1 /*-
2  * Copyright (c) 2006,2009 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 __FBSDID("$FreeBSD$");
29
30 #include <ar.h>
31 #include <assert.h>
32 #include <libelf.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "_libelf.h"
37
38 /*
39  * Convert a string bounded by `start' and `start+sz' (exclusive) to a
40  * number in the specified base.
41  */
42 int
43 _libelf_ar_get_number(char *s, size_t sz, int base, size_t *ret)
44 {
45         int c, v;
46         size_t r;
47         char *e;
48
49         assert(base <= 10);
50
51         e = s + sz;
52
53         /* skip leading blanks */
54         for (;s < e && (c = *s) == ' '; s++)
55                 ;
56
57         r = 0L;
58         for (;s < e; s++) {
59                 if ((c = *s) == ' ')
60                         break;
61                 if (c < '0' || c > '9')
62                         return (0);
63                 v = c - '0';
64                 if (v >= base)          /* Illegal digit. */
65                         break;
66                 r *= base;
67                 r += v;
68         }
69
70         *ret = r;
71
72         return (1);
73 }
74
75 /*
76  * Retrieve a string from a name field.  If `rawname' is set, leave
77  * ar(1) control characters in.
78  */
79 char *
80 _libelf_ar_get_string(const char *buf, size_t bufsize, int rawname)
81 {
82         const char *q;
83         char *r;
84         size_t sz;
85
86         if (rawname)
87                 sz = bufsize + 1;
88         else {
89                 /* Skip back over trailing blanks. */
90                 for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q)
91                         ;
92
93                 if (q < buf) {
94                         /*
95                          * If the input buffer only had blanks in it,
96                          * return a zero-length string.
97                          */
98                         buf = "";
99                         sz = 1;
100                 } else {
101                         /*
102                          * Remove the trailing '/' character, but only
103                          * if the name isn't one of the special names
104                          * "/" and "//".
105                          */
106                         if (q > buf + 1 ||
107                             (q == (buf + 1) && *buf != '/'))
108                                 q--;
109
110                         sz = q - buf + 2; /* Space for a trailing NUL. */
111                 }
112         }
113
114         if ((r = malloc(sz)) == NULL) {
115                 LIBELF_SET_ERROR(RESOURCE, 0);
116                 return (NULL);
117         }
118
119         (void) strncpy(r, buf, sz);
120         r[sz - 1] = '\0';
121
122         return (r);
123 }
124
125 /*
126  * Retrieve the full name of the archive member.
127  */
128 char *
129 _libelf_ar_get_name(char *buf, size_t bufsize, Elf *e)
130 {
131         char c, *q, *r, *s;
132         size_t len;
133         size_t offset;
134
135         assert(e->e_kind == ELF_K_AR);
136
137         if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') {
138                 /*
139                  * The value in field ar_name is a decimal offset into
140                  * the archive string table where the actual name
141                  * resides.
142                  */
143                 if (_libelf_ar_get_number(buf + 1, bufsize - 1, 10,
144                     &offset) == 0) {
145                         LIBELF_SET_ERROR(ARCHIVE, 0);
146                         return (NULL);
147                 }
148
149                 if (offset > e->e_u.e_ar.e_rawstrtabsz) {
150                         LIBELF_SET_ERROR(ARCHIVE, 0);
151                         return (NULL);
152                 }
153
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;
156
157                 for (s = q; s < r && *s != '/'; s++)
158                         ;
159                 len = s - q + 1; /* space for the trailing NUL */
160
161                 if ((s = malloc(len)) == NULL) {
162                         LIBELF_SET_ERROR(RESOURCE, 0);
163                         return (NULL);
164                 }
165
166                 (void) strncpy(s, q, len);
167                 s[len - 1] = '\0';
168
169                 return (s);
170         }
171
172         /*
173          * Normal 'name'
174          */
175         return (_libelf_ar_get_string(buf, bufsize, 0));
176 }
177
178 /*
179  * Open an 'ar' archive.
180  */
181 Elf *
182 _libelf_ar_open(Elf *e)
183 {
184         int i;
185         char *s, *end;
186         size_t sz;
187         struct ar_hdr arh;
188
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;
192
193         /*
194          * Look for special members.
195          */
196
197         s = e->e_rawfile + SARMAG;
198         end = e->e_rawfile + e->e_rawsize;
199
200         assert(e->e_rawsize > 0);
201
202         /*
203          * Look for magic names "/ " and "// " in the first two entries
204          * of the archive.
205          */
206         for (i = 0; i < 2; i++) {
207
208                 if (s + sizeof(arh) > end) {
209                         LIBELF_SET_ERROR(ARCHIVE, 0);
210                         return (NULL);
211                 }
212
213                 (void) memcpy(&arh, s, sizeof(arh));
214
215                 if (arh.ar_fmag[0] != '`' || arh.ar_fmag[1] != '\n') {
216                         LIBELF_SET_ERROR(ARCHIVE, 0);
217                         return (NULL);
218                 }
219
220                 if (arh.ar_name[0] != '/')      /* not a special symbol */
221                         break;
222
223                 if (_libelf_ar_get_number(arh.ar_size, sizeof(arh.ar_size),
224                         10, &sz) == 0) {
225                         LIBELF_SET_ERROR(ARCHIVE, 0);
226                         return (NULL);
227                 }
228
229                 assert(sz > 0);
230
231                 s += sizeof(arh);
232
233                 if (arh.ar_name[1] == ' ') {    /* "/ " => symbol table */
234
235                         e->e_u.e_ar.e_rawsymtab = s;
236                         e->e_u.e_ar.e_rawsymtabsz = sz;
237
238                 } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') {
239
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;
243                 }
244
245                 sz = LIBELF_ADJUST_AR_SIZE(sz);
246
247                 s += sz;
248         }
249
250         e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile);
251
252         return (e);
253 }