xref: /illumos-gate/usr/src/cmd/sgs/elfedit/common/elfedit_machelf.c (revision e4d060fb4c00d44cd578713eb9a921f594b733b8)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * ELFCLASS specific code for elfedit, built once for each class
29  */
30 #include	<stdlib.h>
31 #include	<stdio.h>
32 #include	<unistd.h>
33 #include	<_machelf.h>
34 #include	<libelf.h>
35 #include	<strings.h>
36 #include	<sgs.h>
37 #include	"msg.h"
38 #include	"_elfedit.h"
39 
40 
41 
42 /*
43  * Look up the elfedit_symtab_t that corresponds to the symbol table
44  * referenced by the sh_link field of the given auxiliary section.
45  *
46  * entry:
47  *	obj_state - Partially constructed object state from
48  *		elfedit_init_obj_state().
49  *	auxsec - Section that is associated with the symbol table section
50  *
51  * exit:
52  *	Returns the pointer to the elfedit_symtab_t entry that is
53  *	referenced by the auxiliary section. If not found,
54  *	outputs a debug message, and returns NULL.
55  */
56 static elfedit_symtab_t *
57 get_symtab(elfedit_obj_state_t *obj_state, elfedit_section_t *auxsec)
58 {
59 	elfedit_symtab_t *symtab = obj_state->os_symtab;
60 	Word	sh_link = auxsec->sec_shdr->sh_link;
61 	Word	i;
62 
63 	for (i = 0; i < obj_state->os_symtabnum; i++, symtab++)
64 		if (symtab->symt_shndx == sh_link)
65 			return (symtab);
66 
67 	/*
68 	 * If we don't return above, it doesn't reference a valid
69 	 * symbol table. Issue warning.
70 	 */
71 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_AUX_LINK),
72 	    EC_WORD(auxsec->sec_shndx), auxsec->sec_name,
73 	    EC_WORD(sh_link));
74 
75 	return (NULL);
76 }
77 
78 
79 /*
80  * Fill in state.elf.obj_state with a a dynamically allocated
81  * elfedit_obj_state_t struct of the appropriate ELFCLASS.
82  * This pre-chewed form is fed to each command, reducing the amount
83  * of ELF boilerplate code each command needs to contain.
84  *
85  * entry:
86  *	file - Name of file to process
87  *	fd - Descriptor of open file which has been successfully
88  *		processed by elf_begin().
89  *	elf - Elf handle returned by elf_begin
90  *
91  * exit:
92  *	An elfedit_obj_state_t struct of the appropriate ELFCLASS has
93  *	been dynamically allocated, and state.elf.obj_state references it.
94  *	On failure, this routine does not return to the caller.
95  *
96  * note: The resulting elfedit_obj_state_t is allocated from a single
97  *	piece of memory, such that a single call to free() suffices
98  *	to release it as well as any memory it references.
99  */
100 #ifdef _ELF64
101 void
102 elfedit64_init_obj_state(const char *file, int fd, Elf *elf)
103 #else
104 void
105 elfedit32_init_obj_state(const char *file, int fd, Elf *elf)
106 #endif
107 {
108 #define	INITIAL_SYMTABNDX_ALLOC	5
109 
110 	/*
111 	 * These macros are used to call functions from libelf.
112 	 *
113 	 * LIBELF_FAIL encapsulates the common way in which we handle
114 	 * all of these errors: libelf_fail_name is set and execution
115 	 * jumps to the libelf_failure label for handling.
116 	 *
117 	 * LIBELF is used for the common case in which the function returns
118 	 * NULL for failure and something else for success.
119 	 */
120 #define	LIBELF_FAIL(_name) { libelf_fail_name = _name; goto libelf_failure; }
121 #define	LIBELF(_libelf_expr, _name) \
122 	if ((_libelf_expr) == NULL) \
123 		LIBELF_FAIL(_name)
124 
125 	const char *libelf_fail_name;	/* Used for LIBELF errors */
126 
127 	Elf_Scn			*scn;
128 	Elf_Data		*data;
129 	uint_t			ndx;
130 	size_t			len, os_size, secarr_size;
131 	char			*names = 0;
132 	size_t			names_len;
133 	elfedit_section_t	*_cache;
134 	elfedit_obj_state_t	tstate;
135 	elfedit_obj_state_t	*obj_state = NULL;
136 	Word			*symtabndx = NULL;
137 	Word			symtabndx_size = 0;
138 	elfedit_symtab_t	*symtab;
139 
140 	tstate.os_file = file;
141 	tstate.os_fd = fd;
142 	tstate.os_elf = elf;
143 	tstate.os_dynndx = SHN_UNDEF;
144 	tstate.os_symtabnum = 0;
145 
146 	LIBELF(tstate.os_ehdr = elf_getehdr(tstate.os_elf),
147 	    MSG_ORIG(MSG_ELF_GETEHDR))
148 
149 	/* Program header array count and address */
150 	if (elf_getphdrnum(tstate.os_elf, &tstate.os_phnum) == -1)
151 		LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETPHDRNUM))
152 	if (tstate.os_phnum > 0) {
153 		LIBELF((tstate.os_phdr = elf_getphdr(tstate.os_elf)),
154 		    MSG_ORIG(MSG_ELF_GETPHDR))
155 	} else {
156 		tstate.os_phdr = NULL;
157 	}
158 
159 	if (elf_getshdrnum(tstate.os_elf, &tstate.os_shnum) == -1)
160 		LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETSHDRNUM))
161 
162 	/*
163 	 * Obtain the .shstrtab data buffer to provide the required section
164 	 * name strings.
165 	 */
166 	if (elf_getshdrstrndx(tstate.os_elf, &tstate.os_shstrndx) == -1)
167 		LIBELF_FAIL(MSG_ORIG(MSG_ELF_GETSHDRSTRNDX))
168 	LIBELF((scn = elf_getscn(tstate.os_elf, tstate.os_shstrndx)),
169 	    MSG_ORIG(MSG_ELF_GETSCN))
170 	LIBELF((data = elf_getdata(scn, NULL)), MSG_ORIG(MSG_ELF_GETDATA))
171 	names = data->d_buf;
172 	names_len = (names == NULL) ? 0 : data->d_size;
173 
174 	/*
175 	 * Count the number of symbol tables and capture their indexes.
176 	 * Find the dynamic section.
177 	 */
178 	for (ndx = 1, scn = NULL; scn = elf_nextscn(tstate.os_elf, scn);
179 	    ndx++) {
180 		Shdr *shdr;
181 
182 		LIBELF(shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR));
183 
184 		switch (shdr->sh_type) {
185 		case SHT_DYNAMIC:
186 			/* Save index of dynamic section for use below */
187 			tstate.os_dynndx = ndx;
188 			break;
189 
190 		case SHT_SYMTAB:
191 		case SHT_DYNSYM:
192 		case SHT_SUNW_LDYNSYM:
193 			if (symtabndx_size <= tstate.os_symtabnum) {
194 				symtabndx_size = (symtabndx_size == 0) ?
195 				    INITIAL_SYMTABNDX_ALLOC :
196 				    (symtabndx_size * 2);
197 				symtabndx = elfedit_realloc(
198 				    MSG_INTL(MSG_ALLOC_SYMTABOS), symtabndx,
199 				    symtabndx_size * sizeof (symtabndx[0]));
200 			}
201 			symtabndx[tstate.os_symtabnum++] = ndx;
202 			break;
203 		}
204 	}
205 
206 	/*
207 	 * Allocate space to hold the state. We allocate space for everything
208 	 * in one chunk to make releasing it easy:
209 	 *	(1) elfedit_obj_state_t struct
210 	 *	(2) The array of elfedit_section_t items referenced from
211 	 *		the elfedit_obj_state_t struct.
212 	 *	(3) The array of elfedit_symtab_t items referenced from
213 	 *		the elfedit_obj_state_t struct.
214 	 *	(4) The file name.
215 	 *
216 	 * Note that we round up the size of (1) and (2) to a double boundary
217 	 * to ensure proper alignment of (2) and (3). (4) can align on any
218 	 * boundary.
219 	 */
220 	os_size = S_DROUND(sizeof (tstate));
221 	secarr_size = (tstate.os_shnum * sizeof (elfedit_section_t));
222 	secarr_size = S_DROUND(secarr_size);
223 	len = strlen(tstate.os_file) + 1;
224 	obj_state = elfedit_malloc(MSG_INTL(MSG_ALLOC_OBJSTATE),
225 	    os_size + secarr_size +
226 	    (tstate.os_symtabnum * sizeof (elfedit_symtab_t)) + len);
227 	*obj_state = tstate;
228 
229 	/*LINTED E_BAD_PTR_CAST_ALIGN*/
230 	obj_state->os_secarr = (elfedit_section_t *)
231 	    ((char *)obj_state + os_size);
232 	if (obj_state->os_symtabnum == 0)
233 		obj_state->os_symtab = NULL;
234 	else
235 		/*LINTED E_BAD_PTR_CAST_ALIGN*/
236 		obj_state->os_symtab = (elfedit_symtab_t *)
237 		    ((char *)obj_state->os_secarr + secarr_size);
238 	obj_state->os_file =
239 	    (char *)(obj_state->os_symtab + tstate.os_symtabnum);
240 	(void) strncpy((char *)obj_state->os_file, tstate.os_file, len);
241 
242 	/*
243 	 * Fill in obj_state->os_secarr with information for each section.
244 	 * At the same time, fill in obj_state->os_symtab with the symbol
245 	 * table related data.
246 	 */
247 	bzero(obj_state->os_secarr, sizeof (obj_state->os_secarr[0]));
248 	_cache = obj_state->os_secarr;
249 	LIBELF(scn = elf_getscn(tstate.os_elf, 0),
250 	    MSG_ORIG(MSG_ELF_GETSCN));
251 	_cache->sec_scn = scn;
252 	LIBELF(_cache->sec_shdr = elf_getshdr(scn), MSG_ORIG(MSG_ELF_GETSHDR));
253 	_cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ?
254 	    (names + _cache->sec_shdr->sh_name) : MSG_INTL(MSG_UNKNOWNSECNAM);
255 	_cache++;
256 
257 	if (obj_state->os_symtab != NULL) {
258 		bzero(obj_state->os_symtab,
259 		    sizeof (obj_state->os_symtab[0]) * obj_state->os_symtabnum);
260 		for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++)
261 			obj_state->os_symtab[ndx].symt_shndx = symtabndx[ndx];
262 		free(symtabndx);
263 	}
264 
265 	for (ndx = 1, scn = NULL; scn = elf_nextscn(tstate.os_elf, scn);
266 	    ndx++, _cache++) {
267 		_cache->sec_shndx = ndx;
268 		_cache->sec_scn = scn;
269 		LIBELF(_cache->sec_shdr = elf_getshdr(scn),
270 		    MSG_ORIG(MSG_ELF_GETSHDR))
271 		_cache->sec_data = elf_getdata(scn, NULL);
272 		_cache->sec_name = (_cache->sec_shdr->sh_name < names_len) ?
273 		    (names + _cache->sec_shdr->sh_name) :
274 		    MSG_INTL(MSG_UNKNOWNSECNAM);
275 
276 		switch (_cache->sec_shdr->sh_type) {
277 		case SHT_SYMTAB_SHNDX:
278 			symtab = get_symtab(obj_state, _cache);
279 			symtab->symt_xshndx = ndx;
280 			break;
281 
282 		case SHT_SUNW_syminfo:
283 			symtab = get_symtab(obj_state, _cache);
284 			symtab->symt_syminfo = ndx;
285 			break;
286 
287 		case SHT_SUNW_versym:
288 			symtab = get_symtab(obj_state, _cache);
289 			symtab->symt_versym = ndx;
290 			break;
291 		}
292 	}
293 
294 	/*
295 	 * Sanity check the symbol tables, and discard any auxiliary
296 	 * sections without enough elements.
297 	 */
298 	symtab = obj_state->os_symtab;
299 	for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) {
300 		elfedit_section_t	*symsec;
301 		Word			symsec_cnt, aux_cnt;
302 
303 		symsec = &obj_state->os_secarr[symtab->symt_shndx];
304 		symsec_cnt = symsec->sec_shdr->sh_size / sizeof (Sym);
305 
306 		/* Extended section indexes */
307 		if (symtab->symt_xshndx != SHN_UNDEF) {
308 			_cache = &obj_state->os_secarr[symtab->symt_xshndx];
309 			aux_cnt = _cache->sec_shdr->sh_size / sizeof (Word);
310 			if (symsec_cnt > aux_cnt)
311 				elfedit_msg(ELFEDIT_MSG_DEBUG,
312 				    MSG_INTL(MSG_DEBUG_AUX_SIZE),
313 				    EC_WORD(ndx), _cache->sec_name,
314 				    EC_WORD(aux_cnt),
315 				    EC_WORD(symsec->sec_shndx),
316 				    symsec->sec_name, EC_WORD(aux_cnt));
317 		}
318 
319 		/* Syminfo */
320 		if (symtab->symt_syminfo != SHN_UNDEF) {
321 			_cache = &obj_state->os_secarr[symtab->symt_syminfo];
322 			aux_cnt = _cache->sec_shdr->sh_size / sizeof (Syminfo);
323 			if (symsec_cnt > aux_cnt)
324 				elfedit_msg(ELFEDIT_MSG_DEBUG,
325 				    MSG_INTL(MSG_DEBUG_AUX_SIZE),
326 				    EC_WORD(ndx), _cache->sec_name,
327 				    EC_WORD(aux_cnt),
328 				    EC_WORD(symsec->sec_shndx),
329 				    symsec->sec_name, EC_WORD(aux_cnt));
330 		}
331 
332 		/* Versym */
333 		if (symtab->symt_versym != SHN_UNDEF) {
334 			_cache = &obj_state->os_secarr[symtab->symt_versym];
335 			aux_cnt = _cache->sec_shdr->sh_size / sizeof (Versym);
336 			if (symsec_cnt > aux_cnt)
337 				elfedit_msg(ELFEDIT_MSG_DEBUG,
338 				    MSG_INTL(MSG_DEBUG_AUX_SIZE),
339 				    EC_WORD(ndx), _cache->sec_name,
340 				    EC_WORD(aux_cnt),
341 				    EC_WORD(symsec->sec_shndx),
342 				    symsec->sec_name, EC_WORD(aux_cnt));
343 		}
344 	}
345 
346 	/*
347 	 * If this object has a dynsym section with a FLAGS_1 field,
348 	 * then set the DF_1_EDITED bit. elfedit allows changes that
349 	 * can break the resulting program, so knowing that a file was
350 	 * edited can be helpful when encountering a core file or other
351 	 * unexpected failure in the field. A single bit can't tell you
352 	 * what was changed, but it will alert you to the possibility that
353 	 * some additional questions might be in order.
354 	 */
355 	if (obj_state->os_dynndx != SHN_UNDEF) {
356 		Word			i;
357 		Word			numdyn;
358 		elfedit_section_t	*dynsec;
359 		elfedit_dyn_elt_t	flags_1_elt;
360 		elfedit_dyn_elt_t	null_elt;
361 		Dyn			*dyn;
362 
363 		dynsec = &obj_state->os_secarr[obj_state->os_dynndx];
364 		dyn = (Dyn *) dynsec->sec_data->d_buf;
365 		numdyn = dynsec->sec_shdr->sh_size /
366 		    dynsec->sec_shdr->sh_entsize;
367 		elfedit_dyn_elt_init(&flags_1_elt);
368 		elfedit_dyn_elt_init(&null_elt);
369 		for (i = 0; i < numdyn; i++) {
370 
371 			switch (dyn[i].d_tag) {
372 			case DT_NULL:
373 				/*
374 				 * Remember state of the first DT_NULL. If there
375 				 * are more than one (i.e. the first one is not
376 				 * in the final spot), and there is no flags1,
377 				 * then we will turn the first one into a
378 				 * DT_FLAGS_1.
379 				 */
380 				if (!null_elt.dn_seen)
381 					elfedit_dyn_elt_save(&null_elt, i,
382 					    &dyn[i]);
383 				break;
384 
385 			case DT_FLAGS_1:
386 				elfedit_dyn_elt_save(&flags_1_elt, i, &dyn[i]);
387 				break;
388 			}
389 		}
390 		/* If don't have a flags1 field, can we make one from a NULL? */
391 		if (!flags_1_elt.dn_seen && null_elt.dn_seen &&
392 		    (null_elt.dn_ndx < (numdyn - 1))) {
393 			elfedit_msg(ELFEDIT_MSG_DEBUG,
394 			    MSG_INTL(MSG_DEBUG_NULL2DYNFL1),
395 			    EC_WORD(obj_state->os_dynndx),
396 			    dynsec->sec_name, EC_WORD(null_elt.dn_ndx));
397 			flags_1_elt.dn_seen = 1;
398 			flags_1_elt.dn_ndx = null_elt.dn_ndx;
399 			flags_1_elt.dn_dyn.d_tag = DT_FLAGS_1;
400 			flags_1_elt.dn_dyn.d_un.d_val = 0;
401 		}
402 		/*
403 		 * If there is a flags 1 field, add the edit flag if
404 		 * it is not present, and report it's presence otherwise.
405 		 */
406 		if (flags_1_elt.dn_seen) {
407 			if (flags_1_elt.dn_dyn.d_un.d_val & DF_1_EDITED) {
408 				elfedit_msg(ELFEDIT_MSG_DEBUG,
409 				    MSG_INTL(MSG_DEBUG_SEEDYNFLG),
410 				    EC_WORD(obj_state->os_dynndx),
411 				    dynsec->sec_name,
412 				    EC_WORD(flags_1_elt.dn_ndx));
413 			} else {
414 				elfedit_msg(ELFEDIT_MSG_DEBUG,
415 				    MSG_INTL(MSG_DEBUG_ADDDYNFLG),
416 				    EC_WORD(obj_state->os_dynndx),
417 				    dynsec->sec_name,
418 				    EC_WORD(flags_1_elt.dn_ndx));
419 				flags_1_elt.dn_dyn.d_un.d_val |= DF_1_EDITED;
420 				dyn[flags_1_elt.dn_ndx] = flags_1_elt.dn_dyn;
421 				elfedit_modified_data(dynsec);
422 			}
423 		}
424 	}
425 
426 #ifdef _ELF64
427 	state.elf.obj_state.s64 = obj_state;
428 #else
429 	state.elf.obj_state.s32 = obj_state;
430 #endif
431 	return;
432 
433 libelf_failure:
434 	/*
435 	 * Control comes here if there is an error with LIBELF.
436 	 *
437 	 * entry:
438 	 *	libelf_fail_name - Name of failing libelf function
439 	 *	tstate.os_file - Name of ELF file being processed
440 	 *	tstate.os_fd - Descriptor of open ELF file
441 	 *
442 	 * exit:
443 	 *	- dynamic memory is released if necessary
444 	 *	- The error issued
445 	 */
446 	if (obj_state != NULL)
447 		free(obj_state);
448 	(void) close(tstate.os_fd);
449 	elfedit_elferr(tstate.os_file, libelf_fail_name);
450 #undef INITIAL_SYMTABNDX_ALLOC
451 #undef LIBELF_FAIL
452 #undef LIBELF
453 }
454