xref: /titanic_50/usr/src/cmd/sgs/libld/common/groups.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include	<stdio.h>
30 #include	<string.h>
31 #include	<link.h>
32 #include	"debug.h"
33 #include	"msg.h"
34 #include	"_libld.h"
35 
36 
37 /*
38  * Given a group signature symbol - scan through the global list
39  * of GROUP sections to determine if we have a conflict/discard.
40  * If this is the first time we see a group signature - add it to the
41  * global list.
42  *
43  * Returns:
44  *		0	-	Group kept and added to global list.
45  *		1	-	Group should be discarded.
46  */
47 uintptr_t
48 scan_global_groups(Group_desc * gdesc, Ofl_desc * ofl)
49 {
50 	Group_desc *	_gdesc;
51 	Listnode *	lnp;
52 
53 	/*
54 	 * Scan through global list - if we find a group of the
55 	 * same name - we return 0 saying this new group should
56 	 * be discarded (since only COMDAT's get here currently).
57 	 */
58 	for (LIST_TRAVERSE(&ofl->ofl_groups, lnp, _gdesc))
59 		if (strcmp(_gdesc->gd_symname, gdesc->gd_symname) == 0) {
60 			gdesc->gd_flags |= GRP_FLG_DISCARD;
61 			return (1);
62 		}
63 
64 	if (list_appendc(&ofl->ofl_groups, gdesc) == 0)
65 		return (S_ERROR);
66 
67 	return (0);
68 }
69 
70 
71 Group_desc *
72 get_group_desc(Ofl_desc *ofl, Is_desc *isp)
73 {
74 	Ifl_desc	*ifl = isp->is_file;
75 	Elf		*elf = ifl->ifl_elf;
76 	uint_t		scnndx = isp->is_scnndx;
77 	Group_desc	*gdesc;
78 	Listnode	*lnp;
79 
80 
81 	/*
82 	 * If this is the first section of with the SHF_GROUP flag
83 	 * set - then we havn't yet scanned for - and found our
84 	 * group sections.  If thats so - do it now.
85 	 */
86 	if (ifl->ifl_groups.head == 0) {
87 		Elf_Scn		*scn = 0;
88 		while (scn = elf_nextscn(elf, scn)) {
89 			Shdr		*shdr;
90 			Shdr		*_shdr;
91 			Sym		*sym;
92 			const char	*symname;
93 			Elf_Scn		*_scn;
94 			Elf_Data	*data;
95 
96 			shdr = elf_getshdr(scn);
97 			if (shdr->sh_type != SHT_GROUP)
98 				continue;
99 
100 			/*
101 			 * Confirm that the sh_link points to a
102 			 * valid section.
103 			 */
104 			if ((shdr->sh_link == SHN_UNDEF) ||
105 			    (shdr->sh_link >= ifl->ifl_shnum)) {
106 				eprintf(ERR_FATAL, MSG_INTL(MSG_FIL_INVSHLINK),
107 					ifl->ifl_name, elf_strptr(elf,
108 					ifl->ifl_shstrndx,
109 					shdr->sh_name),
110 					EC_XWORD(shdr->sh_link));
111 				ofl->ofl_flags |= FLG_OF_FATAL;
112 				continue;
113 			}
114 
115 			if (shdr->sh_entsize == 0) {
116 				eprintf(ERR_FATAL,
117 					MSG_INTL(MSG_FIL_INVSHENTSIZE),
118 					ifl->ifl_name, elf_strptr(elf,
119 					ifl->ifl_shstrndx,
120 					shdr->sh_name),
121 					EC_XWORD(shdr->sh_entsize));
122 				ofl->ofl_flags |= FLG_OF_FATAL;
123 				continue;
124 			}
125 
126 			/*
127 			 * Get associated symbol table
128 			 */
129 			_scn = elf_getscn(elf, shdr->sh_link);
130 			_shdr = elf_getshdr(_scn);
131 
132 			/*
133 			 * Sanity check the sh_link field (which points to
134 			 * a symbol table entry) against the size of the
135 			 * symbol table.
136 			 */
137 			if ((shdr->sh_info == SHN_UNDEF) ||
138 			    (shdr->sh_info >= (Word)(_shdr->sh_size /
139 			    _shdr->sh_entsize))) {
140 				eprintf(ERR_FATAL, MSG_INTL(MSG_FIL_INVSHINFO),
141 					ifl->ifl_name, elf_strptr(elf,
142 					ifl->ifl_shstrndx,
143 					shdr->sh_name),
144 					EC_XWORD(shdr->sh_info));
145 				ofl->ofl_flags |= FLG_OF_FATAL;
146 				continue;
147 			}
148 
149 			data = elf_getdata(_scn, 0);
150 			sym = data->d_buf;
151 			sym += shdr->sh_info;
152 			symname = elf_strptr(elf, _shdr->sh_link, sym->st_name);
153 
154 			if ((gdesc = libld_calloc(sizeof (Group_desc), 1)) == 0)
155 				return ((Group_desc *)S_ERROR);
156 
157 			gdesc->gd_gsectname = elf_strptr(elf,
158 				ifl->ifl_shstrndx, shdr->sh_name);
159 			gdesc->gd_symname = symname;
160 			gdesc->gd_sym = sym;
161 			gdesc->gd_scn = scn;
162 			data = elf_getdata(scn, 0);
163 			gdesc->gd_groupdata = data->d_buf;
164 			gdesc->gd_gdcnt = data->d_size / sizeof (Word);
165 			/*
166 			 * If this group is a COMDAT group - then we
167 			 * need to find the 'signature' symbol to determine
168 			 * if this is group is to be kept or discarded.
169 			 */
170 			if (gdesc->gd_groupdata[0] & GRP_COMDAT) {
171 				if ((ELF_ST_BIND(sym->st_info) != STB_LOCAL) &&
172 				    (sym->st_shndx != SHN_UNDEF)) {
173 					if (scan_global_groups(gdesc, ofl)
174 					    == S_ERROR)
175 						return ((Group_desc *)S_ERROR);
176 				}
177 			}
178 			if (list_appendc(&ifl->ifl_groups, gdesc) == 0)
179 				return ((Group_desc *)S_ERROR);
180 		}
181 	}
182 
183 	/*
184 	 * Now we scan through the GROUP sections associated with
185 	 * this file - to find the matching group section.
186 	 */
187 	for (LIST_TRAVERSE(&ifl->ifl_groups, lnp, gdesc)) {
188 		size_t	i;
189 		Word *	gdata;
190 		if (isp->is_shdr->sh_type == SHT_GROUP) {
191 			if ((size_t)isp->is_scnndx ==
192 			    elf_ndxscn(gdesc->gd_scn)) {
193 				isp->is_group = gdesc;
194 				return (gdesc);
195 			}
196 			continue;
197 		}
198 
199 		gdata = gdesc->gd_groupdata;
200 		for (i = 1; i < gdesc->gd_gdcnt; i++) {
201 			if (gdata[i] == scnndx) {
202 				isp->is_group = gdesc;
203 				return (gdesc);
204 			}
205 		}
206 	}
207 	eprintf(ERR_FATAL, MSG_INTL(MSG_ELF_NOGROUPSECT), ifl->ifl_name,
208 		isp->is_name);
209 	ofl->ofl_flags |= FLG_OF_FATAL;
210 	return ((Group_desc *)0);
211 }
212