17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57257d1b4Sraf  * Common Development and Distribution License (the "License").
67257d1b4Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate 
227c478bd9Sstevel@tonic-gate /*
23ba7866cdSAli Bahrami  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267257d1b4Sraf /*	Copyright (c) 1988 AT&T	*/
27*7dbbfe77SToomas Soome /*	  All Rights Reserved	*/
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <errno.h>
317c478bd9Sstevel@tonic-gate #include <libelf.h>
327c478bd9Sstevel@tonic-gate #include "decl.h"
337c478bd9Sstevel@tonic-gate #include "msg.h"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /*
377c478bd9Sstevel@tonic-gate  * Convert archive symbol table to memory format
387c478bd9Sstevel@tonic-gate  *
39ba7866cdSAli Bahrami  * This takes a pointer to file's archive symbol table, alignment
40ba7866cdSAli Bahrami  * unconstrained.  Returns null terminated vector of Elf_Arsym
41ba7866cdSAli Bahrami  * structures. Elf_Arsym uses size_t to represent offsets, which
42ba7866cdSAli Bahrami  * will be 32-bit in 32-bit versions, and 64-bits otherwise.
43ba7866cdSAli Bahrami  *
44ba7866cdSAli Bahrami  * There are two forms of archive symbol table, the original 32-bit
45ba7866cdSAli Bahrami  * form, and a 64-bit form originally found in IRIX64. The two formats
46ba7866cdSAli Bahrami  * differ only in the width of the integer word:
47ba7866cdSAli Bahrami  *
48ba7866cdSAli Bahrami  *		# offsets	4/8-byte word
49ba7866cdSAli Bahrami  *		offset[0...]	4/8-byte word each
507c478bd9Sstevel@tonic-gate  *		strings		null-terminated, for offset[x]
51ba7866cdSAli Bahrami  *
52ba7866cdSAli Bahrami  * By default, the 64-bit form is only used when the archive exceeds
53ba7866cdSAli Bahrami  * the limits of 32-bits (4GB) in size. However, this is not required,
54ba7866cdSAli Bahrami  * and the ar -S option can be used to create a 64-bit symbol table in
55ba7866cdSAli Bahrami  * an archive that is under 4GB.
56ba7866cdSAli Bahrami  *
57ba7866cdSAli Bahrami  * Both 32 and 64-bit versions of libelf can read the 32-bit format
58ba7866cdSAli Bahrami  * without loss of information. Similarly, a 64-bit version of libelf
59ba7866cdSAli Bahrami  * will have no problem reading a 64-bit symbol table. This leaves the
60ba7866cdSAli Bahrami  * case where a 32-bit libelf reads a 64-bit symbol table, which requires
61ba7866cdSAli Bahrami  * some explanation. The offsets in a 64-bit symbol table will have zeros
62ba7866cdSAli Bahrami  * in the upper half of the words until the size of the archive exceeds 4GB.
63ba7866cdSAli Bahrami  * However, 32-bit libelf is unable to read any files larger than 2GB
64ba7866cdSAli Bahrami  * (see comments in update.c). As such, any archive that the 32-bit version
65ba7866cdSAli Bahrami  * of this code will encounter will be under 4GB in size. The upper 4
66ba7866cdSAli Bahrami  * bytes of each word will be zero, and can be safely ignored.
677c478bd9Sstevel@tonic-gate  */
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 
70ba7866cdSAli Bahrami /*
71ba7866cdSAli Bahrami  * Offsets in archive headers are written in MSB (large endian) order
72ba7866cdSAli Bahrami  * on all platforms, regardless of native byte order. These macros read
73ba7866cdSAli Bahrami  * 4 and 8 byte values from unaligned memory.
74ba7866cdSAli Bahrami  *
75ba7866cdSAli Bahrami  * note:
76ba7866cdSAli Bahrami  * -	The get8() macro for 32-bit code can ignore the first 4 bytes of
77ba7866cdSAli Bahrami  *	of the word, because they are known to be 0.
78ba7866cdSAli Bahrami  *
79ba7866cdSAli Bahrami  * -	The inner most value in these macros is cast to an unsigned integer
80ba7866cdSAli Bahrami  *	of the final width in order to prevent the C comilier from doing
81ba7866cdSAli Bahrami  *	unwanted sign extension when the topmost bit of a byte is set.
82ba7866cdSAli Bahrami  */
83ba7866cdSAli Bahrami #define	get4(p)	(((((((uint32_t)p[0]<<8)+p[1])<<8)+p[2])<<8)+p[3])
847c478bd9Sstevel@tonic-gate 
85ba7866cdSAli Bahrami #ifdef _LP64
86ba7866cdSAli Bahrami #define	get8(p)	(((((((((((((((uint64_t)p[0]<<8)+p[1])<<8)+p[2])<<8)+	\
87ba7866cdSAli Bahrami     p[3])<<8)+p[4])<<8)+p[5])<<8)+p[6])<<8)+p[7])
88ba7866cdSAli Bahrami #else
89ba7866cdSAli Bahrami #define	get8(p)	(((((((uint64_t)p[4]<<8)+p[5])<<8)+p[6])<<8)+p[7])
90ba7866cdSAli Bahrami #endif
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 
93ba7866cdSAli Bahrami static Elf_Void *
arsym(Byte * off,size_t sz,size_t * e,int is64)94ba7866cdSAli Bahrami arsym(Byte *off, size_t sz, size_t *e, int is64)
957c478bd9Sstevel@tonic-gate {
967c478bd9Sstevel@tonic-gate 	char		*endstr = (char *)off + sz;
97*7dbbfe77SToomas Soome 	char		*str = NULL;
987c478bd9Sstevel@tonic-gate 	Byte		*endoff;
997c478bd9Sstevel@tonic-gate 	Elf_Void	*oas;
100ba7866cdSAli Bahrami 	size_t		eltsize = is64 ? 8 : 4;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 	{
103*7dbbfe77SToomas Soome 		size_t	n;
1047c478bd9Sstevel@tonic-gate 
105ba7866cdSAli Bahrami 		if (is64) {
106ba7866cdSAli Bahrami 			if (sz < 8 || (sz - 8) / 8 < (n = get8(off))) {
107ba7866cdSAli Bahrami 				_elf_seterr(EFMT_ARSYMSZ, 0);
10887c72343SRichard Lowe 				return (NULL);
109ba7866cdSAli Bahrami 			}
110ba7866cdSAli Bahrami 		} else {
111ba7866cdSAli Bahrami 			if (sz < 4 || (sz - 4) / 4 < (n = get4(off))) {
112ba7866cdSAli Bahrami 				_elf_seterr(EFMT_ARSYMSZ, 0);
11387c72343SRichard Lowe 				return (NULL);
114ba7866cdSAli Bahrami 			}
1157c478bd9Sstevel@tonic-gate 		}
116ba7866cdSAli Bahrami 		off += eltsize;
117ba7866cdSAli Bahrami 		endoff = off + n * eltsize;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 		/*
12087c72343SRichard Lowe 		 * If there are symbols in the symbol table, a
12187c72343SRichard Lowe 		 * string table must be present and NULL terminated.
12287c72343SRichard Lowe 		 *
12387c72343SRichard Lowe 		 * The format dictates that the string table must always be
12487c72343SRichard Lowe 		 * present, however in the case of an archive containing no
12587c72343SRichard Lowe 		 * symbols GNU ar will not create one.  We are permissive for
12687c72343SRichard Lowe 		 * the sake of compatibility.
1277c478bd9Sstevel@tonic-gate 		 */
12887c72343SRichard Lowe 		if ((n > 0) && (((str = (char *)endoff) >= endstr) ||
12987c72343SRichard Lowe 		    (*(endstr - 1) != '\0'))) {
1307c478bd9Sstevel@tonic-gate 			_elf_seterr(EFMT_ARSYM, 0);
13187c72343SRichard Lowe 			return (NULL);
1327c478bd9Sstevel@tonic-gate 		}
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 		/*
13587c72343SRichard Lowe 		 * There is always at least one entry returned if a symtab
13687c72343SRichard Lowe 		 * exists since the table's last entry is an artificial one
13787c72343SRichard Lowe 		 * with a NULL as_name, but is included in the count.
13887c72343SRichard Lowe 		 *
1397c478bd9Sstevel@tonic-gate 		 * overflow can occur here, but not likely
1407c478bd9Sstevel@tonic-gate 		 */
1417c478bd9Sstevel@tonic-gate 		*e = n + 1;
14287c72343SRichard Lowe 		if ((oas = calloc(n + 1, sizeof (Elf_Arsym))) == NULL) {
1437c478bd9Sstevel@tonic-gate 			_elf_seterr(EMEM_ARSYM, errno);
14487c72343SRichard Lowe 			return (NULL);
1457c478bd9Sstevel@tonic-gate 		}
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 	{
148*7dbbfe77SToomas Soome 		Elf_Arsym	*as = (Elf_Arsym *)oas;
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate 		while (off < endoff) {
1517c478bd9Sstevel@tonic-gate 			if (str >= endstr) {
1527c478bd9Sstevel@tonic-gate 				_elf_seterr(EFMT_ARSYMSTR, 0);
1537c478bd9Sstevel@tonic-gate 				free(oas);
15487c72343SRichard Lowe 				return (NULL);
1557c478bd9Sstevel@tonic-gate 			}
156ba7866cdSAli Bahrami 			if (is64)
157ba7866cdSAli Bahrami 				as->as_off = get8(off);
158ba7866cdSAli Bahrami 			else
159ba7866cdSAli Bahrami 				as->as_off = get4(off);
1607c478bd9Sstevel@tonic-gate 			as->as_name = str;
1617c478bd9Sstevel@tonic-gate 			as->as_hash = elf_hash(str);
1627c478bd9Sstevel@tonic-gate 			++as;
163ba7866cdSAli Bahrami 			off += eltsize;
1647c478bd9Sstevel@tonic-gate 			while (*str++ != '\0')
1657c478bd9Sstevel@tonic-gate 				/* LINTED */
1667c478bd9Sstevel@tonic-gate 				;
1677c478bd9Sstevel@tonic-gate 		}
16887c72343SRichard Lowe 		as->as_name = NULL;
1697c478bd9Sstevel@tonic-gate 		as->as_off = 0;
1707c478bd9Sstevel@tonic-gate 		as->as_hash = ~(unsigned long)0L;
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 	return (oas);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate Elf_Arsym *
elf_getarsym(Elf * elf,size_t * ptr)1777257d1b4Sraf elf_getarsym(Elf *elf, size_t *ptr)
1787c478bd9Sstevel@tonic-gate {
1797257d1b4Sraf 	Byte		*as;
1807c478bd9Sstevel@tonic-gate 	size_t		sz;
1817257d1b4Sraf 	Elf_Arsym	*rc;
182ba7866cdSAli Bahrami 	int		is64;
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate 	if (ptr != 0)
1857c478bd9Sstevel@tonic-gate 		*ptr = 0;
186ba7866cdSAli Bahrami 	if (elf == NULL)
1877c478bd9Sstevel@tonic-gate 		return (0);
1887c478bd9Sstevel@tonic-gate 	ELFRLOCK(elf);
1897c478bd9Sstevel@tonic-gate 	if (elf->ed_kind != ELF_K_AR) {
1907c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf);
1917c478bd9Sstevel@tonic-gate 		_elf_seterr(EREQ_AR, 0);
1927c478bd9Sstevel@tonic-gate 		return (0);
1937c478bd9Sstevel@tonic-gate 	}
1947c478bd9Sstevel@tonic-gate 	if ((as = (Byte *)elf->ed_arsym) == 0) {
1957c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf);
1967c478bd9Sstevel@tonic-gate 		return (0);
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 	if (elf->ed_myflags & EDF_ASALLOC) {
1997c478bd9Sstevel@tonic-gate 		if (ptr != 0)
2007c478bd9Sstevel@tonic-gate 			*ptr = elf->ed_arsymsz;
2017c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf);
2027c478bd9Sstevel@tonic-gate 		/* LINTED */
2037c478bd9Sstevel@tonic-gate 		return ((Elf_Arsym *)as);
2047c478bd9Sstevel@tonic-gate 	}
205ba7866cdSAli Bahrami 	is64 = (elf->ed_myflags & EDF_ARSYM64) != 0;
206ba7866cdSAli Bahrami 
2077c478bd9Sstevel@tonic-gate 	/*
2087c478bd9Sstevel@tonic-gate 	 * We're gonna need a write lock.
2097c478bd9Sstevel@tonic-gate 	 */
2107c478bd9Sstevel@tonic-gate 	ELFUNLOCK(elf)
2117c478bd9Sstevel@tonic-gate 	ELFWLOCK(elf)
2127c478bd9Sstevel@tonic-gate 	sz = elf->ed_arsymsz;
2137c478bd9Sstevel@tonic-gate 	if (_elf_vm(elf, (size_t)(as - (Byte *)elf->ed_ident), sz) !=
2147c478bd9Sstevel@tonic-gate 	    OK_YES) {
2157c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf);
2167c478bd9Sstevel@tonic-gate 		return (0);
2177c478bd9Sstevel@tonic-gate 	}
218ba7866cdSAli Bahrami 	if ((elf->ed_arsym = arsym(as, sz, &elf->ed_arsymsz, is64)) == 0) {
2197c478bd9Sstevel@tonic-gate 		ELFUNLOCK(elf);
2207c478bd9Sstevel@tonic-gate 		return (0);
2217c478bd9Sstevel@tonic-gate 	}
2227c478bd9Sstevel@tonic-gate 	elf->ed_myflags |= EDF_ASALLOC;
2237c478bd9Sstevel@tonic-gate 	if (ptr != 0)
2247c478bd9Sstevel@tonic-gate 		*ptr = elf->ed_arsymsz;
2257c478bd9Sstevel@tonic-gate 	rc = (Elf_Arsym *)elf->ed_arsym;
2267c478bd9Sstevel@tonic-gate 	ELFUNLOCK(elf);
2277c478bd9Sstevel@tonic-gate 	return (rc);
2287c478bd9Sstevel@tonic-gate }
229ba7866cdSAli Bahrami 
230ba7866cdSAli Bahrami /*
231ba7866cdSAli Bahrami  * Private function to obtain the value sizeof() would return
232ba7866cdSAli Bahrami  * for a word from the symbol table from the given archive. Normally,
233ba7866cdSAli Bahrami  * this is an unimportant implementation detail hidden within
234ba7866cdSAli Bahrami  * elf_getarsym(). However, it is useful to elfdump for formatting the
235ba7866cdSAli Bahrami  * output correctly, and for the file command.
236ba7866cdSAli Bahrami  *
237ba7866cdSAli Bahrami  * exit:
238ba7866cdSAli Bahrami  *	Returns 4 (32-bit) or 8 (64-bit) if a symbol table is present.
239ba7866cdSAli Bahrami  *	Returns 0 in all other cases.
240ba7866cdSAli Bahrami  */
241ba7866cdSAli Bahrami size_t
_elf_getarsymwordsize(Elf * elf)242ba7866cdSAli Bahrami _elf_getarsymwordsize(Elf *elf)
243ba7866cdSAli Bahrami {
244ba7866cdSAli Bahrami 	size_t	size;
245ba7866cdSAli Bahrami 
246ba7866cdSAli Bahrami 	if (elf == NULL)
247ba7866cdSAli Bahrami 		return (0);
248ba7866cdSAli Bahrami 
249ba7866cdSAli Bahrami 	ELFRLOCK(elf);
250ba7866cdSAli Bahrami 	if ((elf->ed_kind == ELF_K_AR) && (elf->ed_arsym != 0))
251ba7866cdSAli Bahrami 		size = (elf->ed_myflags & EDF_ARSYM64) ? 8 : 4;
252ba7866cdSAli Bahrami 	else
253ba7866cdSAli Bahrami 		size = 0;
254ba7866cdSAli Bahrami 	ELFUNLOCK(elf);
255ba7866cdSAli Bahrami 
256ba7866cdSAli Bahrami 	return (size);
257ba7866cdSAli Bahrami }
258