1210348Skaiw/*- 2210348Skaiw * Copyright (c) 2006,2009 Joseph Koshy 3210348Skaiw * All rights reserved. 4210348Skaiw * 5210348Skaiw * Redistribution and use in source and binary forms, with or without 6210348Skaiw * modification, are permitted provided that the following conditions 7210348Skaiw * are met: 8210348Skaiw * 1. Redistributions of source code must retain the above copyright 9210348Skaiw * notice, this list of conditions and the following disclaimer. 10210348Skaiw * 2. Redistributions in binary form must reproduce the above copyright 11210348Skaiw * notice, this list of conditions and the following disclaimer in the 12210348Skaiw * documentation and/or other materials provided with the distribution. 13210348Skaiw * 14210348Skaiw * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS `AS IS' AND 15210348Skaiw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16210348Skaiw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17210348Skaiw * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18210348Skaiw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19210348Skaiw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20210348Skaiw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21210348Skaiw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22210348Skaiw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23210348Skaiw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24210348Skaiw * SUCH DAMAGE. 25210348Skaiw */ 26210348Skaiw 27210348Skaiw#include <sys/cdefs.h> 28210348Skaiw__FBSDID("$FreeBSD$"); 29210348Skaiw 30210348Skaiw#include <ar.h> 31210348Skaiw#include <assert.h> 32210348Skaiw#include <libelf.h> 33210348Skaiw#include <stdlib.h> 34210348Skaiw#include <string.h> 35210348Skaiw 36210348Skaiw#include "_libelf.h" 37210348Skaiw 38210348Skaiw/* 39210348Skaiw * Convert a string bounded by `start' and `start+sz' (exclusive) to a 40210348Skaiw * number in the specified base. 41210348Skaiw */ 42210348Skaiwint 43210348Skaiw_libelf_ar_get_number(char *s, size_t sz, int base, size_t *ret) 44210348Skaiw{ 45210348Skaiw int c, v; 46210348Skaiw size_t r; 47210348Skaiw char *e; 48210348Skaiw 49210348Skaiw assert(base <= 10); 50210348Skaiw 51210348Skaiw e = s + sz; 52210348Skaiw 53210348Skaiw /* skip leading blanks */ 54210348Skaiw for (;s < e && (c = *s) == ' '; s++) 55210348Skaiw ; 56210348Skaiw 57210348Skaiw r = 0L; 58210348Skaiw for (;s < e; s++) { 59210348Skaiw if ((c = *s) == ' ') 60210348Skaiw break; 61210348Skaiw if (c < '0' || c > '9') 62210348Skaiw return (0); 63210348Skaiw v = c - '0'; 64210348Skaiw if (v >= base) /* Illegal digit. */ 65210348Skaiw break; 66210348Skaiw r *= base; 67210348Skaiw r += v; 68210348Skaiw } 69210348Skaiw 70210348Skaiw *ret = r; 71210348Skaiw 72210348Skaiw return (1); 73210348Skaiw} 74210348Skaiw 75210348Skaiw/* 76210348Skaiw * Retrieve a string from a name field. If `rawname' is set, leave 77210348Skaiw * ar(1) control characters in. 78210348Skaiw */ 79210348Skaiwchar * 80210348Skaiw_libelf_ar_get_string(const char *buf, size_t bufsize, int rawname) 81210348Skaiw{ 82210348Skaiw const char *q; 83210348Skaiw char *r; 84210348Skaiw size_t sz; 85210348Skaiw 86210348Skaiw if (rawname) 87210348Skaiw sz = bufsize + 1; 88210348Skaiw else { 89210348Skaiw /* Skip back over trailing blanks. */ 90210348Skaiw for (q = buf + bufsize - 1; q >= buf && *q == ' '; --q) 91210348Skaiw ; 92210348Skaiw 93210348Skaiw if (q < buf) { 94210348Skaiw /* 95210348Skaiw * If the input buffer only had blanks in it, 96210348Skaiw * return a zero-length string. 97210348Skaiw */ 98210348Skaiw buf = ""; 99210348Skaiw sz = 1; 100210348Skaiw } else { 101210348Skaiw /* 102210348Skaiw * Remove the trailing '/' character, but only 103210348Skaiw * if the name isn't one of the special names 104210348Skaiw * "/" and "//". 105210348Skaiw */ 106210348Skaiw if (q > buf + 1 || 107210348Skaiw (q == (buf + 1) && *buf != '/')) 108210348Skaiw q--; 109210348Skaiw 110210348Skaiw sz = q - buf + 2; /* Space for a trailing NUL. */ 111210348Skaiw } 112210348Skaiw } 113210348Skaiw 114210348Skaiw if ((r = malloc(sz)) == NULL) { 115210348Skaiw LIBELF_SET_ERROR(RESOURCE, 0); 116210348Skaiw return (NULL); 117210348Skaiw } 118210348Skaiw 119210348Skaiw (void) strncpy(r, buf, sz); 120210348Skaiw r[sz - 1] = '\0'; 121210348Skaiw 122210348Skaiw return (r); 123210348Skaiw} 124210348Skaiw 125210348Skaiw/* 126210348Skaiw * Retrieve the full name of the archive member. 127210348Skaiw */ 128210348Skaiwchar * 129210348Skaiw_libelf_ar_get_name(char *buf, size_t bufsize, Elf *e) 130210348Skaiw{ 131210348Skaiw char c, *q, *r, *s; 132210348Skaiw size_t len; 133210348Skaiw size_t offset; 134210348Skaiw 135210348Skaiw assert(e->e_kind == ELF_K_AR); 136210348Skaiw 137210348Skaiw if (buf[0] == '/' && (c = buf[1]) >= '0' && c <= '9') { 138210348Skaiw /* 139210348Skaiw * The value in field ar_name is a decimal offset into 140210348Skaiw * the archive string table where the actual name 141210348Skaiw * resides. 142210348Skaiw */ 143210348Skaiw if (_libelf_ar_get_number(buf + 1, bufsize - 1, 10, 144210348Skaiw &offset) == 0) { 145210348Skaiw LIBELF_SET_ERROR(ARCHIVE, 0); 146210348Skaiw return (NULL); 147210348Skaiw } 148210348Skaiw 149210348Skaiw if (offset > e->e_u.e_ar.e_rawstrtabsz) { 150210348Skaiw LIBELF_SET_ERROR(ARCHIVE, 0); 151210348Skaiw return (NULL); 152210348Skaiw } 153210348Skaiw 154210348Skaiw s = q = e->e_u.e_ar.e_rawstrtab + offset; 155210348Skaiw r = e->e_u.e_ar.e_rawstrtab + e->e_u.e_ar.e_rawstrtabsz; 156210348Skaiw 157210348Skaiw for (s = q; s < r && *s != '/'; s++) 158210348Skaiw ; 159210348Skaiw len = s - q + 1; /* space for the trailing NUL */ 160210348Skaiw 161210348Skaiw if ((s = malloc(len)) == NULL) { 162210348Skaiw LIBELF_SET_ERROR(RESOURCE, 0); 163210348Skaiw return (NULL); 164210348Skaiw } 165210348Skaiw 166210348Skaiw (void) strncpy(s, q, len); 167210348Skaiw s[len - 1] = '\0'; 168210348Skaiw 169210348Skaiw return (s); 170210348Skaiw } 171210348Skaiw 172210348Skaiw /* 173210348Skaiw * Normal 'name' 174210348Skaiw */ 175210348Skaiw return (_libelf_ar_get_string(buf, bufsize, 0)); 176210348Skaiw} 177210348Skaiw 178210348Skaiw/* 179210348Skaiw * Open an 'ar' archive. 180210348Skaiw */ 181210348SkaiwElf * 182210348Skaiw_libelf_ar_open(Elf *e) 183210348Skaiw{ 184210348Skaiw int i; 185210348Skaiw char *s, *end; 186210348Skaiw size_t sz; 187210348Skaiw struct ar_hdr arh; 188210348Skaiw 189210348Skaiw e->e_kind = ELF_K_AR; 190210348Skaiw e->e_u.e_ar.e_nchildren = 0; 191210348Skaiw e->e_u.e_ar.e_next = (off_t) -1; 192210348Skaiw 193210348Skaiw /* 194210348Skaiw * Look for special members. 195210348Skaiw */ 196210348Skaiw 197210348Skaiw s = e->e_rawfile + SARMAG; 198210348Skaiw end = e->e_rawfile + e->e_rawsize; 199210348Skaiw 200210348Skaiw assert(e->e_rawsize > 0); 201210348Skaiw 202210348Skaiw /* 203210348Skaiw * Look for magic names "/ " and "// " in the first two entries 204210348Skaiw * of the archive. 205210348Skaiw */ 206210348Skaiw for (i = 0; i < 2; i++) { 207210348Skaiw 208210348Skaiw if (s + sizeof(arh) > end) { 209210348Skaiw LIBELF_SET_ERROR(ARCHIVE, 0); 210210348Skaiw return (NULL); 211210348Skaiw } 212210348Skaiw 213210348Skaiw (void) memcpy(&arh, s, sizeof(arh)); 214210348Skaiw 215210348Skaiw if (arh.ar_fmag[0] != '`' || arh.ar_fmag[1] != '\n') { 216210348Skaiw LIBELF_SET_ERROR(ARCHIVE, 0); 217210348Skaiw return (NULL); 218210348Skaiw } 219210348Skaiw 220210348Skaiw if (arh.ar_name[0] != '/') /* not a special symbol */ 221210348Skaiw break; 222210348Skaiw 223210348Skaiw if (_libelf_ar_get_number(arh.ar_size, sizeof(arh.ar_size), 224210348Skaiw 10, &sz) == 0) { 225210348Skaiw LIBELF_SET_ERROR(ARCHIVE, 0); 226210348Skaiw return (NULL); 227210348Skaiw } 228210348Skaiw 229210348Skaiw assert(sz > 0); 230210348Skaiw 231210348Skaiw s += sizeof(arh); 232210348Skaiw 233210348Skaiw if (arh.ar_name[1] == ' ') { /* "/ " => symbol table */ 234210348Skaiw 235210348Skaiw e->e_u.e_ar.e_rawsymtab = s; 236210348Skaiw e->e_u.e_ar.e_rawsymtabsz = sz; 237210348Skaiw 238210348Skaiw } else if (arh.ar_name[1] == '/' && arh.ar_name[2] == ' ') { 239210348Skaiw 240210348Skaiw /* "// " => string table for long file names */ 241210348Skaiw e->e_u.e_ar.e_rawstrtab = s; 242210348Skaiw e->e_u.e_ar.e_rawstrtabsz = sz; 243210348Skaiw } 244210348Skaiw 245210348Skaiw sz = LIBELF_ADJUST_AR_SIZE(sz); 246210348Skaiw 247210348Skaiw s += sz; 248210348Skaiw } 249210348Skaiw 250210348Skaiw e->e_u.e_ar.e_next = (off_t) (s - e->e_rawfile); 251210348Skaiw 252210348Skaiw return (e); 253210348Skaiw} 254