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