xref: /onnv-gate/usr/src/cmd/sgs/libelf/common/getarsym.c (revision 12792:1f56a791e275)
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 
226812Sraf /*
23*12792SAli.Bahrami@Oracle.COM  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
246812Sraf  */
256812Sraf 
260Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdlib.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <libelf.h>
320Sstevel@tonic-gate #include "decl.h"
330Sstevel@tonic-gate #include "msg.h"
340Sstevel@tonic-gate 
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  * Convert archive symbol table to memory format
38*12792SAli.Bahrami@Oracle.COM  *
39*12792SAli.Bahrami@Oracle.COM  * This takes a pointer to file's archive symbol table, alignment
40*12792SAli.Bahrami@Oracle.COM  * unconstrained.  Returns null terminated vector of Elf_Arsym
41*12792SAli.Bahrami@Oracle.COM  * structures. Elf_Arsym uses size_t to represent offsets, which
42*12792SAli.Bahrami@Oracle.COM  * will be 32-bit in 32-bit versions, and 64-bits otherwise.
43*12792SAli.Bahrami@Oracle.COM  *
44*12792SAli.Bahrami@Oracle.COM  * There are two forms of archive symbol table, the original 32-bit
45*12792SAli.Bahrami@Oracle.COM  * form, and a 64-bit form originally found in IRIX64. The two formats
46*12792SAli.Bahrami@Oracle.COM  * differ only in the width of the integer word:
47*12792SAli.Bahrami@Oracle.COM  *
48*12792SAli.Bahrami@Oracle.COM  *		# offsets	4/8-byte word
49*12792SAli.Bahrami@Oracle.COM  *		offset[0...]	4/8-byte word each
50*12792SAli.Bahrami@Oracle.COM  *		strings		null-terminated, for offset[x]
510Sstevel@tonic-gate  *
52*12792SAli.Bahrami@Oracle.COM  * By default, the 64-bit form is only used when the archive exceeds
53*12792SAli.Bahrami@Oracle.COM  * the limits of 32-bits (4GB) in size. However, this is not required,
54*12792SAli.Bahrami@Oracle.COM  * and the ar -S option can be used to create a 64-bit symbol table in
55*12792SAli.Bahrami@Oracle.COM  * an archive that is under 4GB.
56*12792SAli.Bahrami@Oracle.COM  *
57*12792SAli.Bahrami@Oracle.COM  * Both 32 and 64-bit versions of libelf can read the 32-bit format
58*12792SAli.Bahrami@Oracle.COM  * without loss of information. Similarly, a 64-bit version of libelf
59*12792SAli.Bahrami@Oracle.COM  * will have no problem reading a 64-bit symbol table. This leaves the
60*12792SAli.Bahrami@Oracle.COM  * case where a 32-bit libelf reads a 64-bit symbol table, which requires
61*12792SAli.Bahrami@Oracle.COM  * some explanation. The offsets in a 64-bit symbol table will have zeros
62*12792SAli.Bahrami@Oracle.COM  * in the upper half of the words until the size of the archive exceeds 4GB.
63*12792SAli.Bahrami@Oracle.COM  * However, 32-bit libelf is unable to read any files larger than 2GB
64*12792SAli.Bahrami@Oracle.COM  * (see comments in update.c). As such, any archive that the 32-bit version
65*12792SAli.Bahrami@Oracle.COM  * of this code will encounter will be under 4GB in size. The upper 4
66*12792SAli.Bahrami@Oracle.COM  * bytes of each word will be zero, and can be safely ignored.
670Sstevel@tonic-gate  */
680Sstevel@tonic-gate 
690Sstevel@tonic-gate 
70*12792SAli.Bahrami@Oracle.COM /*
71*12792SAli.Bahrami@Oracle.COM  * Offsets in archive headers are written in MSB (large endian) order
72*12792SAli.Bahrami@Oracle.COM  * on all platforms, regardless of native byte order. These macros read
73*12792SAli.Bahrami@Oracle.COM  * 4 and 8 byte values from unaligned memory.
74*12792SAli.Bahrami@Oracle.COM  *
75*12792SAli.Bahrami@Oracle.COM  * note:
76*12792SAli.Bahrami@Oracle.COM  * -	The get8() macro for 32-bit code can ignore the first 4 bytes of
77*12792SAli.Bahrami@Oracle.COM  *	of the word, because they are known to be 0.
78*12792SAli.Bahrami@Oracle.COM  *
79*12792SAli.Bahrami@Oracle.COM  * -	The inner most value in these macros is cast to an unsigned integer
80*12792SAli.Bahrami@Oracle.COM  *	of the final width in order to prevent the C comilier from doing
81*12792SAli.Bahrami@Oracle.COM  *	unwanted sign extension when the topmost bit of a byte is set.
82*12792SAli.Bahrami@Oracle.COM  */
83*12792SAli.Bahrami@Oracle.COM #define	get4(p)	(((((((uint32_t)p[0]<<8)+p[1])<<8)+p[2])<<8)+p[3])
84*12792SAli.Bahrami@Oracle.COM 
85*12792SAli.Bahrami@Oracle.COM #ifdef _LP64
86*12792SAli.Bahrami@Oracle.COM #define	get8(p)	(((((((((((((((uint64_t)p[0]<<8)+p[1])<<8)+p[2])<<8)+	\
87*12792SAli.Bahrami@Oracle.COM     p[3])<<8)+p[4])<<8)+p[5])<<8)+p[6])<<8)+p[7])
88*12792SAli.Bahrami@Oracle.COM #else
89*12792SAli.Bahrami@Oracle.COM #define	get8(p)	(((((((uint64_t)p[4]<<8)+p[5])<<8)+p[6])<<8)+p[7])
90*12792SAli.Bahrami@Oracle.COM #endif
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 
93*12792SAli.Bahrami@Oracle.COM static Elf_Void *
arsym(Byte * off,size_t sz,size_t * e,int is64)94*12792SAli.Bahrami@Oracle.COM arsym(Byte *off, size_t sz, size_t *e, int is64)
950Sstevel@tonic-gate {
960Sstevel@tonic-gate 	char		*endstr = (char *)off + sz;
970Sstevel@tonic-gate 	register char	*str;
980Sstevel@tonic-gate 	Byte		*endoff;
990Sstevel@tonic-gate 	Elf_Void	*oas;
100*12792SAli.Bahrami@Oracle.COM 	size_t		eltsize = is64 ? 8 : 4;
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate 	{
1030Sstevel@tonic-gate 		register size_t	n;
1040Sstevel@tonic-gate 
105*12792SAli.Bahrami@Oracle.COM 		if (is64) {
106*12792SAli.Bahrami@Oracle.COM 			if (sz < 8 || (sz - 8) / 8 < (n = get8(off))) {
107*12792SAli.Bahrami@Oracle.COM 				_elf_seterr(EFMT_ARSYMSZ, 0);
108*12792SAli.Bahrami@Oracle.COM 				return (0);
109*12792SAli.Bahrami@Oracle.COM 			}
110*12792SAli.Bahrami@Oracle.COM 		} else {
111*12792SAli.Bahrami@Oracle.COM 			if (sz < 4 || (sz - 4) / 4 < (n = get4(off))) {
112*12792SAli.Bahrami@Oracle.COM 				_elf_seterr(EFMT_ARSYMSZ, 0);
113*12792SAli.Bahrami@Oracle.COM 				return (0);
114*12792SAli.Bahrami@Oracle.COM 			}
1150Sstevel@tonic-gate 		}
116*12792SAli.Bahrami@Oracle.COM 		off += eltsize;
117*12792SAli.Bahrami@Oracle.COM 		endoff = off + n * eltsize;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 		/*
1200Sstevel@tonic-gate 		 * string table must be present, null terminated
1210Sstevel@tonic-gate 		 */
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 		if (((str = (char *)endoff) >= endstr) ||
1240Sstevel@tonic-gate 		    (*(endstr - 1) != '\0')) {
1250Sstevel@tonic-gate 			_elf_seterr(EFMT_ARSYM, 0);
1260Sstevel@tonic-gate 			return (0);
1270Sstevel@tonic-gate 		}
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate 		/*
1300Sstevel@tonic-gate 		 * overflow can occur here, but not likely
1310Sstevel@tonic-gate 		 */
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 		*e = n + 1;
1340Sstevel@tonic-gate 		n = sizeof (Elf_Arsym) * (n + 1);
1350Sstevel@tonic-gate 		if ((oas = malloc(n)) == 0) {
1360Sstevel@tonic-gate 			_elf_seterr(EMEM_ARSYM, errno);
1370Sstevel@tonic-gate 			return (0);
1380Sstevel@tonic-gate 		}
1390Sstevel@tonic-gate 	}
1400Sstevel@tonic-gate 	{
1410Sstevel@tonic-gate 		register Elf_Arsym	*as = (Elf_Arsym *)oas;
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 		while (off < endoff) {
1440Sstevel@tonic-gate 			if (str >= endstr) {
1450Sstevel@tonic-gate 				_elf_seterr(EFMT_ARSYMSTR, 0);
1460Sstevel@tonic-gate 				free(oas);
1470Sstevel@tonic-gate 				return (0);
1480Sstevel@tonic-gate 			}
149*12792SAli.Bahrami@Oracle.COM 			if (is64)
150*12792SAli.Bahrami@Oracle.COM 				as->as_off = get8(off);
151*12792SAli.Bahrami@Oracle.COM 			else
152*12792SAli.Bahrami@Oracle.COM 				as->as_off = get4(off);
1530Sstevel@tonic-gate 			as->as_name = str;
1540Sstevel@tonic-gate 			as->as_hash = elf_hash(str);
1550Sstevel@tonic-gate 			++as;
156*12792SAli.Bahrami@Oracle.COM 			off += eltsize;
1570Sstevel@tonic-gate 			while (*str++ != '\0')
1580Sstevel@tonic-gate 				/* LINTED */
1590Sstevel@tonic-gate 				;
1600Sstevel@tonic-gate 		}
1610Sstevel@tonic-gate 		as->as_name = 0;
1620Sstevel@tonic-gate 		as->as_off = 0;
1630Sstevel@tonic-gate 		as->as_hash = ~(unsigned long)0L;
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 	return (oas);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate Elf_Arsym *
elf_getarsym(Elf * elf,size_t * ptr)1706812Sraf elf_getarsym(Elf *elf, size_t *ptr)
1710Sstevel@tonic-gate {
1726812Sraf 	Byte		*as;
1730Sstevel@tonic-gate 	size_t		sz;
1746812Sraf 	Elf_Arsym	*rc;
175*12792SAli.Bahrami@Oracle.COM 	int		is64;
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate 	if (ptr != 0)
1780Sstevel@tonic-gate 		*ptr = 0;
179*12792SAli.Bahrami@Oracle.COM 	if (elf == NULL)
1800Sstevel@tonic-gate 		return (0);
1810Sstevel@tonic-gate 	ELFRLOCK(elf);
1820Sstevel@tonic-gate 	if (elf->ed_kind != ELF_K_AR) {
1830Sstevel@tonic-gate 		ELFUNLOCK(elf);
1840Sstevel@tonic-gate 		_elf_seterr(EREQ_AR, 0);
1850Sstevel@tonic-gate 		return (0);
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate 	if ((as = (Byte *)elf->ed_arsym) == 0) {
1880Sstevel@tonic-gate 		ELFUNLOCK(elf);
1890Sstevel@tonic-gate 		return (0);
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 	if (elf->ed_myflags & EDF_ASALLOC) {
1920Sstevel@tonic-gate 		if (ptr != 0)
1930Sstevel@tonic-gate 			*ptr = elf->ed_arsymsz;
1940Sstevel@tonic-gate 		ELFUNLOCK(elf);
1950Sstevel@tonic-gate 		/* LINTED */
1960Sstevel@tonic-gate 		return ((Elf_Arsym *)as);
1970Sstevel@tonic-gate 	}
198*12792SAli.Bahrami@Oracle.COM 	is64 = (elf->ed_myflags & EDF_ARSYM64) != 0;
199*12792SAli.Bahrami@Oracle.COM 
2000Sstevel@tonic-gate 	/*
2010Sstevel@tonic-gate 	 * We're gonna need a write lock.
2020Sstevel@tonic-gate 	 */
2030Sstevel@tonic-gate 	ELFUNLOCK(elf)
2040Sstevel@tonic-gate 	ELFWLOCK(elf)
2050Sstevel@tonic-gate 	sz = elf->ed_arsymsz;
2060Sstevel@tonic-gate 	if (_elf_vm(elf, (size_t)(as - (Byte *)elf->ed_ident), sz) !=
2070Sstevel@tonic-gate 	    OK_YES) {
2080Sstevel@tonic-gate 		ELFUNLOCK(elf);
2090Sstevel@tonic-gate 		return (0);
2100Sstevel@tonic-gate 	}
211*12792SAli.Bahrami@Oracle.COM 	if ((elf->ed_arsym = arsym(as, sz, &elf->ed_arsymsz, is64)) == 0) {
2120Sstevel@tonic-gate 		ELFUNLOCK(elf);
2130Sstevel@tonic-gate 		return (0);
2140Sstevel@tonic-gate 	}
2150Sstevel@tonic-gate 	elf->ed_myflags |= EDF_ASALLOC;
2160Sstevel@tonic-gate 	if (ptr != 0)
2170Sstevel@tonic-gate 		*ptr = elf->ed_arsymsz;
2180Sstevel@tonic-gate 	rc = (Elf_Arsym *)elf->ed_arsym;
2190Sstevel@tonic-gate 	ELFUNLOCK(elf);
2200Sstevel@tonic-gate 	return (rc);
2210Sstevel@tonic-gate }
222*12792SAli.Bahrami@Oracle.COM 
223*12792SAli.Bahrami@Oracle.COM /*
224*12792SAli.Bahrami@Oracle.COM  * Private function to obtain the value sizeof() would return
225*12792SAli.Bahrami@Oracle.COM  * for a word from the symbol table from the given archive. Normally,
226*12792SAli.Bahrami@Oracle.COM  * this is an unimportant implementation detail hidden within
227*12792SAli.Bahrami@Oracle.COM  * elf_getarsym(). However, it is useful to elfdump for formatting the
228*12792SAli.Bahrami@Oracle.COM  * output correctly, and for the file command.
229*12792SAli.Bahrami@Oracle.COM  *
230*12792SAli.Bahrami@Oracle.COM  * exit:
231*12792SAli.Bahrami@Oracle.COM  *	Returns 4 (32-bit) or 8 (64-bit) if a symbol table is present.
232*12792SAli.Bahrami@Oracle.COM  *	Returns 0 in all other cases.
233*12792SAli.Bahrami@Oracle.COM  */
234*12792SAli.Bahrami@Oracle.COM size_t
_elf_getarsymwordsize(Elf * elf)235*12792SAli.Bahrami@Oracle.COM _elf_getarsymwordsize(Elf *elf)
236*12792SAli.Bahrami@Oracle.COM {
237*12792SAli.Bahrami@Oracle.COM 	size_t	size;
238*12792SAli.Bahrami@Oracle.COM 
239*12792SAli.Bahrami@Oracle.COM 	if (elf == NULL)
240*12792SAli.Bahrami@Oracle.COM 		return (0);
241*12792SAli.Bahrami@Oracle.COM 
242*12792SAli.Bahrami@Oracle.COM 	ELFRLOCK(elf);
243*12792SAli.Bahrami@Oracle.COM 	if ((elf->ed_kind == ELF_K_AR) && (elf->ed_arsym != 0))
244*12792SAli.Bahrami@Oracle.COM 		size = (elf->ed_myflags & EDF_ARSYM64) ? 8 : 4;
245*12792SAli.Bahrami@Oracle.COM 	else
246*12792SAli.Bahrami@Oracle.COM 		size = 0;
247*12792SAli.Bahrami@Oracle.COM 	ELFUNLOCK(elf);
248*12792SAli.Bahrami@Oracle.COM 
249*12792SAli.Bahrami@Oracle.COM 	return (size);
250*12792SAli.Bahrami@Oracle.COM }
251