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: releng/10.2/lib/libelf/libelf_ar_util.c 210348 2010-07-21 12:54:34Z kaiw $"); 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 */ 42int 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 */ 79char * 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 */ 128char * 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 */ 181Elf * 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} 254