10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
56812Sraf * Common Development and Distribution License (the "License").
66812Sraf * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
216812Sraf
220Sstevel@tonic-gate /*
23*12792SAli.Bahrami@Oracle.COM * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
276812Sraf * Copyright (c) 1988 AT&T
286812Sraf * All Rights Reserved
290Sstevel@tonic-gate */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <ar.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <memory.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include <libelf.h>
360Sstevel@tonic-gate #include "decl.h"
370Sstevel@tonic-gate #include "msg.h"
380Sstevel@tonic-gate #include "member.h"
390Sstevel@tonic-gate
400Sstevel@tonic-gate #define MANGLE '\177'
410Sstevel@tonic-gate
420Sstevel@tonic-gate
430Sstevel@tonic-gate /*
440Sstevel@tonic-gate * Archive processing
450Sstevel@tonic-gate * When processing an archive member, two things can happen
460Sstevel@tonic-gate * that are a little tricky.
470Sstevel@tonic-gate *
480Sstevel@tonic-gate * Sliding
490Sstevel@tonic-gate * Sliding support is left in for backward compatibility and for
500Sstevel@tonic-gate * support of Archives produced on other systems. The bundled
510Sstevel@tonic-gate * ar(1) produces archives with all members on a 4 byte boundry,
520Sstevel@tonic-gate * so current archives should need no sliding.
530Sstevel@tonic-gate *
540Sstevel@tonic-gate * Archive members that are only 2-byte aligned within the file will
550Sstevel@tonic-gate * be slid. To reuse the file's memory image, the library slides an
560Sstevel@tonic-gate * archive member into its header to align the bytes. This means
570Sstevel@tonic-gate * the header must be disposable.
580Sstevel@tonic-gate *
590Sstevel@tonic-gate * Header reuse
600Sstevel@tonic-gate * Because the library can trample the header, it must be preserved to
610Sstevel@tonic-gate * avoid restrictions on archive member reuse. That is, if the member
620Sstevel@tonic-gate * header changes, the library may see garbage the next time it looks
630Sstevel@tonic-gate * at the header. After extracting the original header, the library
640Sstevel@tonic-gate * appends it to the parents `ed_memlist' list, thus future lookups first
650Sstevel@tonic-gate * check this list to determine if a member has previously been processed
660Sstevel@tonic-gate * and whether sliding occured.
670Sstevel@tonic-gate */
680Sstevel@tonic-gate
690Sstevel@tonic-gate
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate * Size check
720Sstevel@tonic-gate * If the header is too small, the following generates a negative
730Sstevel@tonic-gate * subscript for x.x and fails to compile.
740Sstevel@tonic-gate *
750Sstevel@tonic-gate * The check is based on sizeof (Elf64) because that's always going
760Sstevel@tonic-gate * to be at least as big as Elf32.
770Sstevel@tonic-gate */
780Sstevel@tonic-gate
790Sstevel@tonic-gate struct x
800Sstevel@tonic-gate {
810Sstevel@tonic-gate char x[sizeof (struct ar_hdr) - 3 * sizeof (Elf64) - 1];
820Sstevel@tonic-gate };
830Sstevel@tonic-gate
840Sstevel@tonic-gate
850Sstevel@tonic-gate
860Sstevel@tonic-gate static const char fmag[] = ARFMAG;
870Sstevel@tonic-gate
880Sstevel@tonic-gate
890Sstevel@tonic-gate /*
900Sstevel@tonic-gate * Convert a string starting at 'p' and ending at 'end' into
910Sstevel@tonic-gate * an integer. Base is the base of the number being converted
920Sstevel@tonic-gate * (either 8 or 10).
930Sstevel@tonic-gate *
940Sstevel@tonic-gate * Returns the converted integer of the string being scaned.
950Sstevel@tonic-gate */
960Sstevel@tonic-gate unsigned long
_elf_number(char * p,char * end,int base)976812Sraf _elf_number(char *p, char *end, int base)
980Sstevel@tonic-gate {
990Sstevel@tonic-gate register unsigned c;
1000Sstevel@tonic-gate register unsigned long n = 0;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate while (p < end) {
1030Sstevel@tonic-gate if ((c = *p - '0') >= base) {
1040Sstevel@tonic-gate while (*p++ == ' ')
1050Sstevel@tonic-gate if (p >= end)
1060Sstevel@tonic-gate return (n);
1070Sstevel@tonic-gate return (0);
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate n *= base;
1100Sstevel@tonic-gate n += c;
1110Sstevel@tonic-gate ++p;
1120Sstevel@tonic-gate }
1130Sstevel@tonic-gate return (n);
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate * Convert ar_hdr to Member
1190Sstevel@tonic-gate * Converts ascii file representation to the binary memory values.
1200Sstevel@tonic-gate */
1210Sstevel@tonic-gate Member *
_elf_armem(Elf * elf,char * file,size_t fsz)1226812Sraf _elf_armem(Elf *elf, char *file, size_t fsz)
1230Sstevel@tonic-gate {
1240Sstevel@tonic-gate register struct ar_hdr *f = (struct ar_hdr *)file;
1250Sstevel@tonic-gate register Member *m;
1260Sstevel@tonic-gate register Memlist *l, * ol;
1270Sstevel@tonic-gate register Memident *i;
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate if (fsz < sizeof (struct ar_hdr)) {
1300Sstevel@tonic-gate _elf_seterr(EFMT_ARHDRSZ, 0);
1310Sstevel@tonic-gate return (0);
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate * Determine in this member has already been processed
1360Sstevel@tonic-gate */
1370Sstevel@tonic-gate for (l = elf->ed_memlist, ol = l; l; ol = l, l = l->m_next)
1380Sstevel@tonic-gate for (i = (Memident *)(l + 1); i < l->m_free; i++)
1390Sstevel@tonic-gate if (i->m_offset == file)
1400Sstevel@tonic-gate return (i->m_member);
1410Sstevel@tonic-gate
1420Sstevel@tonic-gate if (f->ar_fmag[0] != fmag[0] || f->ar_fmag[1] != fmag[1]) {
1430Sstevel@tonic-gate _elf_seterr(EFMT_ARFMAG, 0);
1440Sstevel@tonic-gate return (0);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate /*
1480Sstevel@tonic-gate * Allocate a new member structure and assign it to the next free
1490Sstevel@tonic-gate * free memlist ident.
1500Sstevel@tonic-gate */
1510Sstevel@tonic-gate if ((m = (Member *)malloc(sizeof (Member))) == 0) {
1520Sstevel@tonic-gate _elf_seterr(EMEM_ARMEM, errno);
1530Sstevel@tonic-gate return (0);
1540Sstevel@tonic-gate }
1550Sstevel@tonic-gate if ((elf->ed_memlist == 0) || (ol->m_free == ol->m_end)) {
1560Sstevel@tonic-gate if ((l = (Memlist *)malloc(sizeof (Memlist) +
1570Sstevel@tonic-gate (sizeof (Memident) * MEMIDENTNO))) == 0) {
1580Sstevel@tonic-gate _elf_seterr(EMEM_ARMEM, errno);
1590Sstevel@tonic-gate return (0);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate l->m_next = 0;
1620Sstevel@tonic-gate l->m_free = (Memident *)(l + 1);
1630Sstevel@tonic-gate l->m_end = (Memident *)((uintptr_t)l->m_free +
1646812Sraf (sizeof (Memident) * MEMIDENTNO));
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate if (elf->ed_memlist == 0)
1670Sstevel@tonic-gate elf->ed_memlist = l;
1680Sstevel@tonic-gate else
1690Sstevel@tonic-gate ol->m_next = l;
1700Sstevel@tonic-gate ol = l;
1710Sstevel@tonic-gate }
1720Sstevel@tonic-gate ol->m_free->m_offset = file;
1730Sstevel@tonic-gate ol->m_free->m_member = m;
1740Sstevel@tonic-gate ol->m_free++;
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate m->m_err = 0;
1770Sstevel@tonic-gate (void) memcpy(m->m_name, f->ar_name, ARSZ(ar_name));
1780Sstevel@tonic-gate m->m_name[ARSZ(ar_name)] = '\0';
1790Sstevel@tonic-gate m->m_hdr.ar_name = m->m_name;
1800Sstevel@tonic-gate (void) memcpy(m->m_raw, f->ar_name, ARSZ(ar_name));
1810Sstevel@tonic-gate m->m_raw[ARSZ(ar_name)] = '\0';
1820Sstevel@tonic-gate m->m_hdr.ar_rawname = m->m_raw;
1830Sstevel@tonic-gate m->m_slide = 0;
1840Sstevel@tonic-gate
1850Sstevel@tonic-gate /*
1860Sstevel@tonic-gate * Classify file name.
1870Sstevel@tonic-gate * If a name error occurs, delay until getarhdr().
1880Sstevel@tonic-gate */
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate if (f->ar_name[0] != '/') { /* regular name */
1910Sstevel@tonic-gate register char *p;
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate p = &m->m_name[sizeof (m->m_name)];
1940Sstevel@tonic-gate while (*--p != '/')
1950Sstevel@tonic-gate if (p <= m->m_name)
1960Sstevel@tonic-gate break;
1970Sstevel@tonic-gate *p = '\0';
1980Sstevel@tonic-gate } else if (f->ar_name[1] >= '0' && f->ar_name[1] <= '9') { /* strtab */
1990Sstevel@tonic-gate register unsigned long j;
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate j = _elf_number(&f->ar_name[1],
2026812Sraf &f->ar_name[ARSZ(ar_name)], 10);
2030Sstevel@tonic-gate if (j < elf->ed_arstrsz)
2040Sstevel@tonic-gate m->m_hdr.ar_name = elf->ed_arstr + j;
2050Sstevel@tonic-gate else {
2060Sstevel@tonic-gate m->m_hdr.ar_name = 0;
2070Sstevel@tonic-gate /*LINTED*/ /* MSG_INTL(EFMT_ARSTRNM) */
2080Sstevel@tonic-gate m->m_err = (int)EFMT_ARSTRNM;
2090Sstevel@tonic-gate }
2100Sstevel@tonic-gate } else if (f->ar_name[1] == ' ') /* "/" */
2110Sstevel@tonic-gate m->m_name[1] = '\0';
2120Sstevel@tonic-gate else if (f->ar_name[1] == '/' && f->ar_name[2] == ' ') /* "//" */
2130Sstevel@tonic-gate m->m_name[2] = '\0';
214*12792SAli.Bahrami@Oracle.COM else if (f->ar_name[1] == 'S' && f->ar_name[2] == 'Y' &&
215*12792SAli.Bahrami@Oracle.COM f->ar_name[3] == 'M' && f->ar_name[4] == '6' &&
216*12792SAli.Bahrami@Oracle.COM f->ar_name[5] == '4' && f->ar_name[6] == '/' &&
217*12792SAli.Bahrami@Oracle.COM f->ar_name[7] == ' ') /* "/SYM64/" */
218*12792SAli.Bahrami@Oracle.COM m->m_name[7] = '\0';
2190Sstevel@tonic-gate else { /* "/?" */
2200Sstevel@tonic-gate m->m_hdr.ar_name = 0;
2210Sstevel@tonic-gate /*LINTED*/ /* MSG_INTL(EFMT_ARUNKNM) */
2220Sstevel@tonic-gate m->m_err = (int)EFMT_ARUNKNM;
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate m->m_hdr.ar_date = (time_t)_elf_number(f->ar_date,
2266812Sraf &f->ar_date[ARSZ(ar_date)], 10);
2270Sstevel@tonic-gate /* LINTED */
2280Sstevel@tonic-gate m->m_hdr.ar_uid = (uid_t)_elf_number(f->ar_uid,
2296812Sraf &f->ar_uid[ARSZ(ar_uid)], 10);
2300Sstevel@tonic-gate /* LINTED */
2310Sstevel@tonic-gate m->m_hdr.ar_gid = (gid_t)_elf_number(f->ar_gid,
2326812Sraf &f->ar_gid[ARSZ(ar_gid)], 10);
2330Sstevel@tonic-gate /* LINTED */
2340Sstevel@tonic-gate m->m_hdr.ar_mode = (mode_t)_elf_number(f->ar_mode,
2356812Sraf &f->ar_mode[ARSZ(ar_mode)], 8);
2360Sstevel@tonic-gate m->m_hdr.ar_size = (off_t)_elf_number(f->ar_size,
2376812Sraf &f->ar_size[ARSZ(ar_size)], 10);
2380Sstevel@tonic-gate
2390Sstevel@tonic-gate return (m);
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate * Initial archive processing
2450Sstevel@tonic-gate * An archive may have two special members.
246*12792SAli.Bahrami@Oracle.COM *
247*12792SAli.Bahrami@Oracle.COM * A symbol table, named / or /SYM64/, must be first if it is present.
248*12792SAli.Bahrami@Oracle.COM * Both forms use the same layout differing in the width of the
249*12792SAli.Bahrami@Oracle.COM * integer type used (32 or 64-bit respectively).
250*12792SAli.Bahrami@Oracle.COM *
251*12792SAli.Bahrami@Oracle.COM * A long name string table, named //, must precede all "normal"
252*12792SAli.Bahrami@Oracle.COM * members. This string table is used to hold the names of archive
253*12792SAli.Bahrami@Oracle.COM * members with names that are longer than 15 characters. It should not
254*12792SAli.Bahrami@Oracle.COM * be confused with the string table found at the end of the symbol
255*12792SAli.Bahrami@Oracle.COM * table, which is used to hold symbol names.
2560Sstevel@tonic-gate *
2570Sstevel@tonic-gate * This code "peeks" at headers but doesn't change them.
2580Sstevel@tonic-gate * Later processing wants original headers.
2590Sstevel@tonic-gate *
2600Sstevel@tonic-gate * String table is converted, changing '/' name terminators
2610Sstevel@tonic-gate * to nulls. The last byte in the string table, which should
2620Sstevel@tonic-gate * be '\n', is set to nil, guaranteeing null termination. That
2630Sstevel@tonic-gate * byte should be '\n', but this code doesn't check.
2640Sstevel@tonic-gate *
2650Sstevel@tonic-gate * The symbol table conversion is delayed until needed.
2660Sstevel@tonic-gate */
2670Sstevel@tonic-gate void
_elf_arinit(Elf * elf)2680Sstevel@tonic-gate _elf_arinit(Elf * elf)
2690Sstevel@tonic-gate {
2706812Sraf char *base = elf->ed_ident;
2716812Sraf register char *end = base + elf->ed_fsz;
2726812Sraf register struct ar_hdr *a;
2736812Sraf register char *hdr = base + SARMAG;
2746812Sraf register char *mem;
2750Sstevel@tonic-gate int j;
2760Sstevel@tonic-gate size_t sz = SARMAG;
2770Sstevel@tonic-gate
2780Sstevel@tonic-gate elf->ed_status = ES_COOKED;
2790Sstevel@tonic-gate elf->ed_nextoff = SARMAG;
2800Sstevel@tonic-gate for (j = 0; j < 2; ++j) { /* 2 special members */
2810Sstevel@tonic-gate unsigned long n;
2820Sstevel@tonic-gate
2830Sstevel@tonic-gate if (((end - hdr) < sizeof (struct ar_hdr)) ||
2840Sstevel@tonic-gate (_elf_vm(elf, (size_t)(SARMAG),
2850Sstevel@tonic-gate sizeof (struct ar_hdr)) != OK_YES))
2860Sstevel@tonic-gate return;
2870Sstevel@tonic-gate
2880Sstevel@tonic-gate a = (struct ar_hdr *)hdr;
2890Sstevel@tonic-gate mem = (char *)a + sizeof (struct ar_hdr);
2900Sstevel@tonic-gate n = _elf_number(a->ar_size, &a->ar_size[ARSZ(ar_size)], 10);
2910Sstevel@tonic-gate if ((end - mem < n) || (a->ar_name[0] != '/') ||
2920Sstevel@tonic-gate ((sz = n) != n)) {
2930Sstevel@tonic-gate return;
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate
2960Sstevel@tonic-gate hdr = mem + sz;
297*12792SAli.Bahrami@Oracle.COM if (a->ar_name[1] == ' ') { /* 32-bit symbol table */
2980Sstevel@tonic-gate elf->ed_arsym = mem;
2990Sstevel@tonic-gate elf->ed_arsymsz = sz;
3000Sstevel@tonic-gate elf->ed_arsymoff = (char *)a - base;
3010Sstevel@tonic-gate } else if (a->ar_name[1] == '/' && a->ar_name[2] == ' ') {
302*12792SAli.Bahrami@Oracle.COM /* Long name string table */
3030Sstevel@tonic-gate int k;
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate if (_elf_vm(elf, (size_t)(mem - elf->ed_ident),
3060Sstevel@tonic-gate sz) != OK_YES)
3070Sstevel@tonic-gate return;
3080Sstevel@tonic-gate if (elf->ed_vm == 0) {
3096812Sraf char *nmem;
3100Sstevel@tonic-gate if ((nmem = malloc(sz)) == 0) {
3110Sstevel@tonic-gate _elf_seterr(EMEM_ARSTR, errno);
3120Sstevel@tonic-gate return;
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate (void) memcpy(nmem, mem, sz);
3150Sstevel@tonic-gate elf->ed_myflags |= EDF_ASTRALLOC;
3160Sstevel@tonic-gate mem = nmem;
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate elf->ed_arstr = mem;
3200Sstevel@tonic-gate elf->ed_arstrsz = sz;
3210Sstevel@tonic-gate elf->ed_arstroff = (char *)a - base;
3220Sstevel@tonic-gate for (k = 0; k < sz; k++) {
3230Sstevel@tonic-gate if (*mem == '/')
3240Sstevel@tonic-gate *mem = '\0';
3250Sstevel@tonic-gate ++mem;
3260Sstevel@tonic-gate }
3270Sstevel@tonic-gate *(mem - 1) = '\0';
328*12792SAli.Bahrami@Oracle.COM } else if (a->ar_name[1] == 'S' && a->ar_name[2] == 'Y' &&
329*12792SAli.Bahrami@Oracle.COM a->ar_name[3] == 'M' && a->ar_name[4] == '6' &&
330*12792SAli.Bahrami@Oracle.COM a->ar_name[5] == '4' && a->ar_name[6] == '/' &&
331*12792SAli.Bahrami@Oracle.COM a->ar_name[7] == ' ') {
332*12792SAli.Bahrami@Oracle.COM /* 64-bit symbol table */
333*12792SAli.Bahrami@Oracle.COM elf->ed_arsym = mem;
334*12792SAli.Bahrami@Oracle.COM elf->ed_arsymsz = sz;
335*12792SAli.Bahrami@Oracle.COM elf->ed_arsymoff = (char *)a - base;
336*12792SAli.Bahrami@Oracle.COM elf->ed_myflags |= EDF_ARSYM64;
3370Sstevel@tonic-gate } else {
3380Sstevel@tonic-gate return;
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate hdr += sz & 1;
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate }
343