12de3b87aSKai Wang /*- 22de3b87aSKai Wang * Copyright (c) 2006,2009,2010 Joseph Koshy 32de3b87aSKai Wang * All rights reserved. 42de3b87aSKai Wang * 52de3b87aSKai Wang * Redistribution and use in source and binary forms, with or without 62de3b87aSKai Wang * modification, are permitted provided that the following conditions 72de3b87aSKai Wang * are met: 82de3b87aSKai Wang * 1. Redistributions of source code must retain the above copyright 92de3b87aSKai Wang * notice, this list of conditions and the following disclaimer. 102de3b87aSKai Wang * 2. Redistributions in binary form must reproduce the above copyright 112de3b87aSKai Wang * notice, this list of conditions and the following disclaimer in the 122de3b87aSKai Wang * documentation and/or other materials provided with the distribution. 132de3b87aSKai Wang * 142de3b87aSKai Wang * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND 152de3b87aSKai Wang * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 162de3b87aSKai Wang * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 172de3b87aSKai Wang * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 182de3b87aSKai Wang * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 192de3b87aSKai Wang * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 202de3b87aSKai Wang * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 212de3b87aSKai Wang * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 222de3b87aSKai Wang * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 232de3b87aSKai Wang * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 242de3b87aSKai Wang * SUCH DAMAGE. 252de3b87aSKai Wang */ 262de3b87aSKai Wang 272de3b87aSKai Wang #include <sys/cdefs.h> 282de3b87aSKai Wang 292de3b87aSKai Wang #include <assert.h> 302de3b87aSKai Wang #include <libelf.h> 312de3b87aSKai Wang #include <stdlib.h> 322de3b87aSKai Wang #include <string.h> 332de3b87aSKai Wang 342de3b87aSKai Wang #include "_libelf.h" 352de3b87aSKai Wang #include "_libelf_ar.h" 362de3b87aSKai Wang 37cf781b2eSEd Maste ELFTC_VCSID("$Id: libelf_ar_util.c 3013 2014-03-23 06:16:59Z jkoshy $"); 382de3b87aSKai Wang 392de3b87aSKai Wang /* 402de3b87aSKai Wang * Convert a string bounded by `start' and `start+sz' (exclusive) to a 412de3b87aSKai Wang * number in the specified base. 422de3b87aSKai Wang */ 432de3b87aSKai Wang int 44cf781b2eSEd Maste _libelf_ar_get_number(const char *src, size_t sz, unsigned int base, 45cf781b2eSEd Maste size_t *ret) 462de3b87aSKai Wang { 472de3b87aSKai Wang size_t r; 48cf781b2eSEd Maste unsigned int c, v; 49cf781b2eSEd Maste const unsigned char *e, *s; 502de3b87aSKai Wang 512de3b87aSKai Wang assert(base <= 10); 522de3b87aSKai Wang 53cf781b2eSEd Maste s = (const unsigned char *) src; 542de3b87aSKai Wang e = s + sz; 552de3b87aSKai Wang 562de3b87aSKai Wang /* skip leading blanks */ 572de3b87aSKai Wang for (;s < e && (c = *s) == ' '; s++) 582de3b87aSKai Wang ; 592de3b87aSKai Wang 602de3b87aSKai Wang r = 0L; 612de3b87aSKai Wang for (;s < e; s++) { 622de3b87aSKai Wang if ((c = *s) == ' ') 632de3b87aSKai Wang break; 642de3b87aSKai Wang if (c < '0' || c > '9') 652de3b87aSKai Wang return (0); 662de3b87aSKai Wang v = c - '0'; 672de3b87aSKai Wang if (v >= base) /* Illegal digit. */ 682de3b87aSKai Wang break; 692de3b87aSKai Wang r *= base; 702de3b87aSKai Wang r += v; 712de3b87aSKai Wang } 722de3b87aSKai Wang 732de3b87aSKai Wang *ret = r; 742de3b87aSKai Wang 752de3b87aSKai Wang return (1); 762de3b87aSKai Wang } 772de3b87aSKai Wang 782de3b87aSKai Wang /* 792de3b87aSKai Wang * Return the translated name for an archive member. 802de3b87aSKai Wang */ 812de3b87aSKai Wang char * 822de3b87aSKai Wang _libelf_ar_get_translated_name(const struct ar_hdr *arh, Elf *ar) 832de3b87aSKai Wang { 84cf781b2eSEd Maste char *s; 85cf781b2eSEd Maste unsigned char c; 862de3b87aSKai Wang size_t len, offset; 87cf781b2eSEd Maste const unsigned char *buf, *p, *q, *r; 882de3b87aSKai Wang const size_t bufsize = sizeof(arh->ar_name); 892de3b87aSKai Wang 902de3b87aSKai Wang assert(arh != NULL); 912de3b87aSKai Wang assert(ar->e_kind == ELF_K_AR); 92cf781b2eSEd Maste assert((const unsigned char *) arh >= ar->e_rawfile && 93cf781b2eSEd Maste (const unsigned char *) arh < ar->e_rawfile + ar->e_rawsize); 942de3b87aSKai Wang 95cf781b2eSEd Maste buf = (const unsigned char *) arh->ar_name; 962de3b87aSKai Wang 972de3b87aSKai Wang /* 982de3b87aSKai Wang * Check for extended naming. 992de3b87aSKai Wang * 1002de3b87aSKai Wang * If the name matches the pattern "^/[0-9]+", it is an 1012de3b87aSKai Wang * SVR4-style extended name. If the name matches the pattern 1022de3b87aSKai Wang * "#1/[0-9]+", the entry uses BSD style extended naming. 1032de3b87aSKai Wang */ 1042de3b87aSKai Wang if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') { 1052de3b87aSKai Wang /* 1062de3b87aSKai Wang * The value in field ar_name is a decimal offset into 1072de3b87aSKai Wang * the archive string table where the actual name 1082de3b87aSKai Wang * resides. 1092de3b87aSKai Wang */ 110cf781b2eSEd Maste if (_libelf_ar_get_number((const char *) (buf + 1), 111cf781b2eSEd Maste bufsize - 1, 10, &offset) == 0) { 1122de3b87aSKai Wang LIBELF_SET_ERROR(ARCHIVE, 0); 1132de3b87aSKai Wang return (NULL); 1142de3b87aSKai Wang } 1152de3b87aSKai Wang 1162de3b87aSKai Wang if (offset > ar->e_u.e_ar.e_rawstrtabsz) { 1172de3b87aSKai Wang LIBELF_SET_ERROR(ARCHIVE, 0); 1182de3b87aSKai Wang return (NULL); 1192de3b87aSKai Wang } 1202de3b87aSKai Wang 1212de3b87aSKai Wang p = q = ar->e_u.e_ar.e_rawstrtab + offset; 1222de3b87aSKai Wang r = ar->e_u.e_ar.e_rawstrtab + ar->e_u.e_ar.e_rawstrtabsz; 1232de3b87aSKai Wang 1242de3b87aSKai Wang for (; p < r && *p != '/'; p++) 1252de3b87aSKai Wang ; 126cf781b2eSEd Maste len = (size_t) (p - q + 1); /* space for the trailing NUL */ 1272de3b87aSKai Wang 1282de3b87aSKai Wang if ((s = malloc(len)) == NULL) { 1292de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0); 1302de3b87aSKai Wang return (NULL); 1312de3b87aSKai Wang } 1322de3b87aSKai Wang 133cf781b2eSEd Maste (void) strncpy(s, (const char *) q, len - 1); 1342de3b87aSKai Wang s[len - 1] = '\0'; 1352de3b87aSKai Wang 1362de3b87aSKai Wang return (s); 1372de3b87aSKai Wang } else if (IS_EXTENDED_BSD_NAME(buf)) { 1382de3b87aSKai Wang r = buf + LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE; 1392de3b87aSKai Wang 140cf781b2eSEd Maste if (_libelf_ar_get_number((const char *) r, bufsize - 1412de3b87aSKai Wang LIBELF_AR_BSD_EXTENDED_NAME_PREFIX_SIZE, 10, 1422de3b87aSKai Wang &len) == 0) { 1432de3b87aSKai Wang LIBELF_SET_ERROR(ARCHIVE, 0); 1442de3b87aSKai Wang return (NULL); 1452de3b87aSKai Wang } 1462de3b87aSKai Wang 1472de3b87aSKai Wang /* 1482de3b87aSKai Wang * Allocate space for the file name plus a 1492de3b87aSKai Wang * trailing NUL. 1502de3b87aSKai Wang */ 1512de3b87aSKai Wang if ((s = malloc(len + 1)) == NULL) { 1522de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0); 1532de3b87aSKai Wang return (NULL); 1542de3b87aSKai Wang } 1552de3b87aSKai Wang 1562de3b87aSKai Wang /* 1572de3b87aSKai Wang * The file name follows the archive header. 1582de3b87aSKai Wang */ 159cf781b2eSEd Maste q = (const unsigned char *) (arh + 1); 1602de3b87aSKai Wang 161cf781b2eSEd Maste (void) strncpy(s, (const char *) q, len); 1622de3b87aSKai Wang s[len] = '\0'; 1632de3b87aSKai Wang 1642de3b87aSKai Wang return (s); 1652de3b87aSKai Wang } 1662de3b87aSKai Wang 1672de3b87aSKai Wang /* 1682de3b87aSKai Wang * A 'normal' name. 1692de3b87aSKai Wang * 1702de3b87aSKai Wang * Skip back over trailing blanks from the end of the field. 1712de3b87aSKai Wang * In the SVR4 format, a '/' is used as a terminator for 1722de3b87aSKai Wang * non-special names. 1732de3b87aSKai Wang */ 1742de3b87aSKai Wang for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q) 1752de3b87aSKai Wang ; 1762de3b87aSKai Wang 1772de3b87aSKai Wang if (q >= buf) { 1782de3b87aSKai Wang if (*q == '/') { 1792de3b87aSKai Wang /* 1802de3b87aSKai Wang * SVR4 style names: ignore the trailing 1812de3b87aSKai Wang * character '/', but only if the name is not 1822de3b87aSKai Wang * one of the special names "/" and "//". 1832de3b87aSKai Wang */ 1842de3b87aSKai Wang if (q > buf + 1 || 1852de3b87aSKai Wang (q == (buf + 1) && *buf != '/')) 1862de3b87aSKai Wang q--; 1872de3b87aSKai Wang } 1882de3b87aSKai Wang 189cf781b2eSEd Maste len = (size_t) (q - buf + 2); /* Space for a trailing NUL. */ 1902de3b87aSKai Wang } else { 1912de3b87aSKai Wang /* The buffer only had blanks. */ 192cf781b2eSEd Maste buf = (const unsigned char *) ""; 1932de3b87aSKai Wang len = 1; 1942de3b87aSKai Wang } 1952de3b87aSKai Wang 1962de3b87aSKai Wang if ((s = malloc(len)) == NULL) { 1972de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0); 1982de3b87aSKai Wang return (NULL); 1992de3b87aSKai Wang } 2002de3b87aSKai Wang 201cf781b2eSEd Maste (void) strncpy(s, (const char *) buf, len - 1); 2022de3b87aSKai Wang s[len - 1] = '\0'; 2032de3b87aSKai Wang 2042de3b87aSKai Wang return (s); 2052de3b87aSKai Wang } 2062de3b87aSKai Wang 2072de3b87aSKai Wang /* 2082de3b87aSKai Wang * Return the raw name for an archive member, inclusive of any 2092de3b87aSKai Wang * formatting characters. 2102de3b87aSKai Wang */ 2112de3b87aSKai Wang char * 2122de3b87aSKai Wang _libelf_ar_get_raw_name(const struct ar_hdr *arh) 2132de3b87aSKai Wang { 2142de3b87aSKai Wang char *rawname; 2152de3b87aSKai Wang const size_t namesz = sizeof(arh->ar_name); 2162de3b87aSKai Wang 2172de3b87aSKai Wang if ((rawname = malloc(namesz + 1)) == NULL) { 2182de3b87aSKai Wang LIBELF_SET_ERROR(RESOURCE, 0); 2192de3b87aSKai Wang return (NULL); 2202de3b87aSKai Wang } 2212de3b87aSKai Wang 2222de3b87aSKai Wang (void) strncpy(rawname, arh->ar_name, namesz); 2232de3b87aSKai Wang rawname[namesz] = '\0'; 2242de3b87aSKai Wang return (rawname); 2252de3b87aSKai Wang } 2262de3b87aSKai Wang 2272de3b87aSKai Wang /* 2282de3b87aSKai Wang * Open an 'ar' archive. 2292de3b87aSKai Wang */ 2302de3b87aSKai Wang Elf * 2312de3b87aSKai Wang _libelf_ar_open(Elf *e, int reporterror) 2322de3b87aSKai Wang { 2332de3b87aSKai Wang size_t sz; 2342de3b87aSKai Wang int scanahead; 2352de3b87aSKai Wang struct ar_hdr arh; 236cf781b2eSEd Maste unsigned char *s, *end; 2372de3b87aSKai Wang 2382de3b87aSKai Wang _libelf_init_elf(e, ELF_K_AR); 2392de3b87aSKai Wang 2402de3b87aSKai Wang e->e_u.e_ar.e_nchildren = 0; 2412de3b87aSKai Wang e->e_u.e_ar.e_next = (off_t) -1; 2422de3b87aSKai Wang 2432de3b87aSKai Wang /* 2442de3b87aSKai Wang * Look for special members. 2452de3b87aSKai Wang */ 2462de3b87aSKai Wang 2472de3b87aSKai Wang s = e->e_rawfile + SARMAG; 2482de3b87aSKai Wang end = e->e_rawfile + e->e_rawsize; 2492de3b87aSKai Wang 2502de3b87aSKai Wang assert(e->e_rawsize > 0); 2512de3b87aSKai Wang 2522de3b87aSKai Wang /* 2532de3b87aSKai Wang * We use heuristics to determine the flavor of the archive we 2542de3b87aSKai Wang * are examining. 2552de3b87aSKai Wang * 2562de3b87aSKai Wang * SVR4 flavor archives use the name "/ " and "// " for 2572de3b87aSKai Wang * special members. 2582de3b87aSKai Wang * 2592de3b87aSKai Wang * In BSD flavor archives the symbol table, if present, is the 2602de3b87aSKai Wang * first archive with name "__.SYMDEF". 2612de3b87aSKai Wang */ 2622de3b87aSKai Wang 2632de3b87aSKai Wang #define READ_AR_HEADER(S, ARH, SZ, END) \ 2642de3b87aSKai Wang do { \ 2652de3b87aSKai Wang if ((S) + sizeof((ARH)) > (END)) \ 2662de3b87aSKai Wang goto error; \ 2672de3b87aSKai Wang (void) memcpy(&(ARH), (S), sizeof((ARH))); \ 2682de3b87aSKai Wang if ((ARH).ar_fmag[0] != '`' || (ARH).ar_fmag[1] != '\n') \ 2692de3b87aSKai Wang goto error; \ 270cf781b2eSEd Maste if (_libelf_ar_get_number((char *) (ARH).ar_size, \ 2712de3b87aSKai Wang sizeof((ARH).ar_size), 10, &(SZ)) == 0) \ 2722de3b87aSKai Wang goto error; \ 2732de3b87aSKai Wang } while (0) 2742de3b87aSKai Wang 2752de3b87aSKai Wang READ_AR_HEADER(s, arh, sz, end); 2762de3b87aSKai Wang 2772de3b87aSKai Wang /* 2782de3b87aSKai Wang * Handle special archive members for the SVR4 format. 2792de3b87aSKai Wang */ 2802de3b87aSKai Wang if (arh.ar_name[0] == '/') { 2812de3b87aSKai Wang 282*bc5438c5SEd Maste if (sz == 0) 283*bc5438c5SEd Maste goto error; 2842de3b87aSKai Wang 2852de3b87aSKai Wang e->e_flags |= LIBELF_F_AR_VARIANT_SVR4; 2862de3b87aSKai Wang 2872de3b87aSKai Wang scanahead = 0; 2882de3b87aSKai Wang 2892de3b87aSKai Wang /* 2902de3b87aSKai Wang * The symbol table (file name "/ ") always comes before the 2912de3b87aSKai Wang * string table (file name "// "). 2922de3b87aSKai Wang */ 2932de3b87aSKai Wang if (arh.ar_name[1] == ' ') { 2942de3b87aSKai Wang /* "/ " => symbol table. */ 2952de3b87aSKai Wang scanahead = 1; /* The string table to follow. */ 2962de3b87aSKai Wang 2972de3b87aSKai Wang s += sizeof(arh); 2982de3b87aSKai Wang e->e_u.e_ar.e_rawsymtab = s; 2992de3b87aSKai Wang e->e_u.e_ar.e_rawsymtabsz = sz; 3002de3b87aSKai Wang 3012de3b87aSKai Wang sz = LIBELF_ADJUST_AR_SIZE(sz); 3022de3b87aSKai Wang s += sz; 3032de3b87aSKai Wang 3042de3b87aSKai Wang } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') { 3052de3b87aSKai Wang /* "// " => string table for long file names. */ 3062de3b87aSKai Wang s += sizeof(arh); 3072de3b87aSKai Wang e->e_u.e_ar.e_rawstrtab = s; 3082de3b87aSKai Wang e->e_u.e_ar.e_rawstrtabsz = sz; 3092de3b87aSKai Wang 3102de3b87aSKai Wang sz = LIBELF_ADJUST_AR_SIZE(sz); 3112de3b87aSKai Wang s += sz; 3122de3b87aSKai Wang } 3132de3b87aSKai Wang 3142de3b87aSKai Wang /* 3152de3b87aSKai Wang * If the string table hasn't been seen yet, look for 3162de3b87aSKai Wang * it in the next member. 3172de3b87aSKai Wang */ 3182de3b87aSKai Wang if (scanahead) { 3192de3b87aSKai Wang READ_AR_HEADER(s, arh, sz, end); 3202de3b87aSKai Wang 3212de3b87aSKai Wang /* "// " => string table for long file names. */ 3222de3b87aSKai Wang if (arh.ar_name[0] == '/' && arh.ar_name[1] == '/' && 3232de3b87aSKai Wang arh.ar_name[2] == ' ') { 3242de3b87aSKai Wang 3252de3b87aSKai Wang s += sizeof(arh); 3262de3b87aSKai Wang 3272de3b87aSKai Wang e->e_u.e_ar.e_rawstrtab = s; 3282de3b87aSKai Wang e->e_u.e_ar.e_rawstrtabsz = sz; 3292de3b87aSKai Wang 3302de3b87aSKai Wang sz = LIBELF_ADJUST_AR_SIZE(sz); 3312de3b87aSKai Wang s += sz; 3322de3b87aSKai Wang } 3332de3b87aSKai Wang } 3342de3b87aSKai Wang } else if (strncmp(arh.ar_name, LIBELF_AR_BSD_SYMTAB_NAME, 3352de3b87aSKai Wang sizeof(LIBELF_AR_BSD_SYMTAB_NAME) - 1) == 0) { 3362de3b87aSKai Wang /* 3372de3b87aSKai Wang * BSD style archive symbol table. 3382de3b87aSKai Wang */ 3392de3b87aSKai Wang s += sizeof(arh); 3402de3b87aSKai Wang e->e_u.e_ar.e_rawsymtab = s; 3412de3b87aSKai Wang e->e_u.e_ar.e_rawsymtabsz = sz; 3422de3b87aSKai Wang 3432de3b87aSKai Wang sz = LIBELF_ADJUST_AR_SIZE(sz); 3442de3b87aSKai Wang s += sz; 3452de3b87aSKai Wang } 3462de3b87aSKai Wang 3472de3b87aSKai Wang /* 3482de3b87aSKai Wang * Update the 'next' offset, so that a subsequent elf_begin() 3492de3b87aSKai Wang * works as expected. 3502de3b87aSKai Wang */ 3512de3b87aSKai Wang e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile); 3522de3b87aSKai Wang 3532de3b87aSKai Wang return (e); 3542de3b87aSKai Wang 3552de3b87aSKai Wang error: 3562de3b87aSKai Wang if (!reporterror) { 3572de3b87aSKai Wang e->e_kind = ELF_K_NONE; 3582de3b87aSKai Wang return (e); 3592de3b87aSKai Wang } 3602de3b87aSKai Wang 3612de3b87aSKai Wang LIBELF_SET_ERROR(ARCHIVE, 0); 3622de3b87aSKai Wang return (NULL); 3632de3b87aSKai Wang } 364