File: | src/lib/libelf/libelf_ar_util.c |
Warning: | line 55, column 18 Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 <assert.h> |
28 | #include <libelf.h> |
29 | #include <stdlib.h> |
30 | #include <string.h> |
31 | |
32 | #include "_libelf.h" |
33 | #include "_libelf_ar.h" |
34 | |
35 | ELFTC_VCSID("$Id: libelf_ar_util.c,v 1.1 2019/02/01 05:27:38 jsg Exp $"); |
36 | |
37 | /* |
38 | * Convert a string bounded by `start' and `start+sz' (exclusive) to a |
39 | * number in the specified base. |
40 | */ |
41 | int |
42 | _libelf_ar_get_number(const char *src, size_t sz, unsigned int base, |
43 | size_t *ret) |
44 | { |
45 | size_t r; |
46 | unsigned int c, v; |
47 | const unsigned char *e, *s; |
48 | |
49 | assert(base <= 10)((base <= 10) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c" , 49, __func__, "base <= 10")); |
50 | |
51 | s = (const unsigned char *) src; |
52 | e = s + sz; |
53 | |
54 | /* skip leading blanks */ |
55 | for (;s < e && (c = *s) == ' '; s++) |
Although the value stored to 'c' is used in the enclosing expression, the value is never actually read from 'c' | |
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 *s; |
83 | unsigned char c; |
84 | size_t len, offset; |
85 | const unsigned char *buf, *p, *q, *r; |
86 | const size_t bufsize = sizeof(arh->ar_name); |
87 | |
88 | assert(arh != NULL)((arh != ((void *)0)) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c" , 88, __func__, "arh != NULL")); |
89 | assert(ar->e_kind == ELF_K_AR)((ar->e_kind == ELF_K_AR) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c" , 89, __func__, "ar->e_kind == ELF_K_AR")); |
90 | assert((const unsigned char *) arh >= ar->e_rawfile &&(((const unsigned char *) arh >= ar->e_rawfile && (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize ) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c" , 91, __func__, "(const unsigned char *) arh >= ar->e_rawfile && (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize" )) |
91 | (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize)(((const unsigned char *) arh >= ar->e_rawfile && (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize ) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c" , 91, __func__, "(const unsigned char *) arh >= ar->e_rawfile && (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize" )); |
92 | |
93 | buf = (const unsigned char *) arh->ar_name; |
94 | |
95 | /* |
96 | * Check for extended naming. |
97 | * |
98 | * If the name matches the pattern "^/[0-9]+", it is an |
99 | * SVR4-style extended name. If the name matches the pattern |
100 | * "#1/[0-9]+", the entry uses BSD style extended naming. |
101 | */ |
102 | if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') { |
103 | /* |
104 | * The value in field ar_name is a decimal offset into |
105 | * the archive string table where the actual name |
106 | * resides. |
107 | */ |
108 | if (_libelf_ar_get_number((const char *) (buf + 1), |
109 | bufsize - 1, 10, &offset) == 0) { |
110 | LIBELF_SET_ERROR(ARCHIVE, 0)do { (_libelf.libelf_error) = (((ELF_E_ARCHIVE) & 0xFF) | (((0)) << 8)); } while (0); |
111 | return (NULL((void *)0)); |
112 | } |
113 | |
114 | if (offset > ar->e_u.e_ar.e_rawstrtabsz) { |
115 | LIBELF_SET_ERROR(ARCHIVE, 0)do { (_libelf.libelf_error) = (((ELF_E_ARCHIVE) & 0xFF) | (((0)) << 8)); } while (0); |
116 | return (NULL((void *)0)); |
117 | } |
118 | |
119 | p = q = ar->e_u.e_ar.e_rawstrtab + offset; |
120 | r = ar->e_u.e_ar.e_rawstrtab + ar->e_u.e_ar.e_rawstrtabsz; |
121 | |
122 | for (; p < r && *p != '/'; p++) |
123 | ; |
124 | len = (size_t) (p - q + 1); /* space for the trailing NUL */ |
125 | |
126 | if ((s = malloc(len)) == NULL((void *)0)) { |
127 | LIBELF_SET_ERROR(RESOURCE, 0)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) | (((0)) << 8)); } while (0); |
128 | return (NULL((void *)0)); |
129 | } |
130 | |
131 | (void) strncpy(s, (const char *) q, len - 1); |
132 | s[len - 1] = '\0'; |
133 | |
134 | return (s); |
135 | } else if (IS_EXTENDED_BSD_NAME(buf)(strncmp((const char *) (buf), "#1/", (sizeof("#1/") - 1)) == 0)) { |
136 | r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE(sizeof("#1/") - 1); |
137 | |
138 | if (_libelf_ar_get_number((const char *) r, bufsize - |
139 | LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE(sizeof("#1/") - 1), 10, |
140 | &len) == 0) { |
141 | LIBELF_SET_ERROR(ARCHIVE, 0)do { (_libelf.libelf_error) = (((ELF_E_ARCHIVE) & 0xFF) | (((0)) << 8)); } while (0); |
142 | return (NULL((void *)0)); |
143 | } |
144 | |
145 | /* |
146 | * Allocate space for the file name plus a |
147 | * trailing NUL. |
148 | */ |
149 | if ((s = malloc(len + 1)) == NULL((void *)0)) { |
150 | LIBELF_SET_ERROR(RESOURCE, 0)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) | (((0)) << 8)); } while (0); |
151 | return (NULL((void *)0)); |
152 | } |
153 | |
154 | /* |
155 | * The file name follows the archive header. |
156 | */ |
157 | q = (const unsigned char *) (arh + 1); |
158 | |
159 | (void) strncpy(s, (const char *) q, len); |
160 | s[len] = '\0'; |
161 | |
162 | return (s); |
163 | } |
164 | |
165 | /* |
166 | * A 'normal' name. |
167 | * |
168 | * Skip back over trailing blanks from the end of the field. |
169 | * In the SVR4 format, a '/' is used as a terminator for |
170 | * non-special names. |
171 | */ |
172 | for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q) |
173 | ; |
174 | |
175 | if (q >= buf) { |
176 | if (*q == '/') { |
177 | /* |
178 | * SVR4 style names: ignore the trailing |
179 | * character '/', but only if the name is not |
180 | * one of the special names "/" and "//". |
181 | */ |
182 | if (q > buf + 1 || |
183 | (q == (buf + 1) && *buf != '/')) |
184 | q--; |
185 | } |
186 | |
187 | len = (size_t) (q - buf + 2); /* Space for a trailing NUL. */ |
188 | } else { |
189 | /* The buffer only had blanks. */ |
190 | buf = (const unsigned char *) ""; |
191 | len = 1; |
192 | } |
193 | |
194 | if ((s = malloc(len)) == NULL((void *)0)) { |
195 | LIBELF_SET_ERROR(RESOURCE, 0)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) | (((0)) << 8)); } while (0); |
196 | return (NULL((void *)0)); |
197 | } |
198 | |
199 | (void) strncpy(s, (const char *) buf, len - 1); |
200 | s[len - 1] = '\0'; |
201 | |
202 | return (s); |
203 | } |
204 | |
205 | /* |
206 | * Return the raw name for an archive member, inclusive of any |
207 | * formatting characters. |
208 | */ |
209 | char * |
210 | _libelf_ar_get_raw_name(const struct ar_hdr *arh) |
211 | { |
212 | char *rawname; |
213 | const size_t namesz = sizeof(arh->ar_name); |
214 | |
215 | if ((rawname = malloc(namesz + 1)) == NULL((void *)0)) { |
216 | LIBELF_SET_ERROR(RESOURCE, 0)do { (_libelf.libelf_error) = (((ELF_E_RESOURCE) & 0xFF) | (((0)) << 8)); } while (0); |
217 | return (NULL((void *)0)); |
218 | } |
219 | |
220 | (void) strncpy(rawname, arh->ar_name, namesz); |
221 | rawname[namesz] = '\0'; |
222 | return (rawname); |
223 | } |
224 | |
225 | /* |
226 | * Open an 'ar' archive. |
227 | */ |
228 | Elf * |
229 | _libelf_ar_open(Elf *e, int reporterror) |
230 | { |
231 | size_t sz; |
232 | int scanahead; |
233 | struct ar_hdr arh; |
234 | unsigned char *s, *end; |
235 | |
236 | _libelf_init_elf(e, ELF_K_AR); |
237 | |
238 | e->e_u.e_ar.e_nchildren = 0; |
239 | e->e_u.e_ar.e_next = (off_t) -1; |
240 | |
241 | /* |
242 | * Look for special members. |
243 | */ |
244 | |
245 | s = e->e_rawfile + SARMAG8; |
246 | end = e->e_rawfile + e->e_rawsize; |
247 | |
248 | assert(e->e_rawsize > 0)((e->e_rawsize > 0) ? (void)0 : __assert2("/usr/src/lib/libelf/libelf_ar_util.c" , 248, __func__, "e->e_rawsize > 0")); |
249 | |
250 | /* |
251 | * We use heuristics to determine the flavor of the archive we |
252 | * are examining. |
253 | * |
254 | * SVR4 flavor archives use the name "/ " and "// " for |
255 | * special members. |
256 | * |
257 | * In BSD flavor archives the symbol table, if present, is the |
258 | * first archive with name "__.SYMDEF". |
259 | */ |
260 | |
261 | #define READ_AR_HEADER(S, ARH, SZ, END)do { if ((S) + sizeof((ARH)) > (END)) goto error; (void) memcpy (&(ARH), (S), sizeof((ARH))); if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') goto error; if (_libelf_ar_get_number ((char *) (ARH).ar_size, sizeof((ARH).ar_size), 10, &(SZ) ) == 0) goto error; } while (0) \ |
262 | do { \ |
263 | if ((S) + sizeof((ARH)) > (END)) \ |
264 | goto error; \ |
265 | (void) memcpy(&(ARH), (S), sizeof((ARH))); \ |
266 | if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \ |
267 | goto error; \ |
268 | if (_libelf_ar_get_number((char *) (ARH).ar_size, \ |
269 | sizeof((ARH).ar_size), 10, &(SZ)) == 0) \ |
270 | goto error; \ |
271 | } while (0) |
272 | |
273 | READ_AR_HEADER(s, arh, sz, end)do { if ((s) + sizeof((arh)) > (end)) goto error; (void) memcpy (&(arh), (s), sizeof((arh))); if ((arh).ar_fmag[0] != '`' || (arh).ar_fmag[1] != '\n') goto error; if (_libelf_ar_get_number ((char *) (arh).ar_size, sizeof((arh).ar_size), 10, &(sz) ) == 0) goto error; } while (0); |
274 | |
275 | /* |
276 | * Handle special archive members for the SVR4 format. |
277 | */ |
278 | if (arh.ar_name[0] == '/') { |
279 | if (sz == 0) |
280 | goto error; |
281 | |
282 | e->e_flags |= LIBELF_F_AR_VARIANT_SVR40x020000U; |
283 | |
284 | scanahead = 0; |
285 | |
286 | /* |
287 | * The symbol table (file name "/ ") always comes before the |
288 | * string table (file name "// "). |
289 | */ |
290 | if (arh.ar_name[1] == ' ') { |
291 | /* "/ " => symbol table. */ |
292 | scanahead = 1; /* The string table to follow. */ |
293 | |
294 | s += sizeof(arh); |
295 | e->e_u.e_ar.e_rawsymtab = s; |
296 | e->e_u.e_ar.e_rawsymtabsz = sz; |
297 | |
298 | sz = LIBELF_ADJUST_AR_SIZE(sz)(((sz) + 1U) & ~1U); |
299 | s += sz; |
300 | |
301 | } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') { |
302 | /* "// " => string table for long file names. */ |
303 | s += sizeof(arh); |
304 | e->e_u.e_ar.e_rawstrtab = s; |
305 | e->e_u.e_ar.e_rawstrtabsz = sz; |
306 | |
307 | sz = LIBELF_ADJUST_AR_SIZE(sz)(((sz) + 1U) & ~1U); |
308 | s += sz; |
309 | } |
310 | |
311 | /* |
312 | * If the string table hasn't been seen yet, look for |
313 | * it in the next member. |
314 | */ |
315 | if (scanahead) { |
316 | READ_AR_HEADER(s, arh, sz, end)do { if ((s) + sizeof((arh)) > (end)) goto error; (void) memcpy (&(arh), (s), sizeof((arh))); if ((arh).ar_fmag[0] != '`' || (arh).ar_fmag[1] != '\n') goto error; if (_libelf_ar_get_number ((char *) (arh).ar_size, sizeof((arh).ar_size), 10, &(sz) ) == 0) goto error; } while (0); |
317 | |
318 | /* "// " => string table for long file names. */ |
319 | if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' && |
320 | arh.ar_name[2] == ' ') { |
321 | |
322 | s += sizeof(arh); |
323 | |
324 | e->e_u.e_ar.e_rawstrtab = s; |
325 | e->e_u.e_ar.e_rawstrtabsz = sz; |
326 | |
327 | sz = LIBELF_ADJUST_AR_SIZE(sz)(((sz) + 1U) & ~1U); |
328 | s += sz; |
329 | } |
330 | } |
331 | } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME"__.SYMDEF", |
332 | sizeof(LIBELF_AR_BSD_SYMTAB_NAME"__.SYMDEF") - 1) == 0) { |
333 | /* |
334 | * BSD style archive symbol table. |
335 | */ |
336 | s += sizeof(arh); |
337 | e->e_u.e_ar.e_rawsymtab = s; |
338 | e->e_u.e_ar.e_rawsymtabsz = sz; |
339 | |
340 | sz = LIBELF_ADJUST_AR_SIZE(sz)(((sz) + 1U) & ~1U); |
341 | s += sz; |
342 | } |
343 | |
344 | /* |
345 | * Update the 'next' offset, so that a subsequent elf_begin() |
346 | * works as expected. |
347 | */ |
348 | e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile); |
349 | |
350 | return (e); |
351 | |
352 | error: |
353 | if (!reporterror) { |
354 | e->e_kind = ELF_K_NONE; |
355 | return (e); |
356 | } |
357 | |
358 | LIBELF_SET_ERROR(ARCHIVE, 0)do { (_libelf.libelf_error) = (((ELF_E_ARCHIVE) & 0xFF) | (((0)) << 8)); } while (0); |
359 | return (NULL((void *)0)); |
360 | } |