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