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 /*
2308278a5eSRod Evans  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24d29b2c44Sab  * Use is subject to license terms.
25d29b2c44Sab  */
27d29b2c44Sab #include	<ctype.h>
28d29b2c44Sab #include	<elfedit.h>
29d29b2c44Sab #include	<sys/elf_SPARC.h>
30d29b2c44Sab #include	<strings.h>
31d29b2c44Sab #include	<debug.h>
32d29b2c44Sab #include	<conv.h>
33d29b2c44Sab #include	<dyn_msg.h>
36d29b2c44Sab /*
37d29b2c44Sab  * Dynamic section
38d29b2c44Sab  */
40d29b2c44Sab /*
41d29b2c44Sab  * This module uses shared code for several of the commands.
42d29b2c44Sab  * It is sometimes necessary to know which specific command
43d29b2c44Sab  * is active.
44d29b2c44Sab  */
45d29b2c44Sab typedef enum {
46d29b2c44Sab 	/* Dump command, used as module default to display dynamic section */
47d29b2c44Sab 	DYN_CMD_T_DUMP =	0,	/* dyn:dump */
49d29b2c44Sab 	/* Commands that do not correspond directly to a specific DT tag */
50d29b2c44Sab 	DYN_CMD_T_TAG =		1,	/* dyn:tag */
51d29b2c44Sab 	DYN_CMD_T_VALUE =	2,	/* dyn:value */
52d29b2c44Sab 	DYN_CMD_T_DELETE =	3,	/* dyn:delete */
53d29b2c44Sab 	DYN_CMD_T_MOVE =	4,	/* dyn:shift */
55d29b2c44Sab 	/* Commands that embody tag specific knowledge */
56d29b2c44Sab 	DYN_CMD_T_RUNPATH =	5,	/* dyn:runpath/rpath */
57d29b2c44Sab 	DYN_CMD_T_POSFLAG1 =	6,	/* dyn:posflag1 */
58d29b2c44Sab 	DYN_CMD_T_FLAGS =	7,	/* dyn:flags */
59d29b2c44Sab 	DYN_CMD_T_FLAGS1 =	8,	/* dyn:flags1 */
60d29b2c44Sab 	DYN_CMD_T_FEATURE1 =	9,	/* dyn:feature1 */
61ba2be530Sab 	DYN_CMD_T_CHECKSUM =	10,	/* dyn:checksum */
62ba2be530Sab 	DYN_CMD_T_SUNW_LDMACH =	11	/* dyn:sunw_ldmach */
63d29b2c44Sab } DYN_CMD_T;
67d29b2c44Sab #ifndef _ELF64
68d29b2c44Sab /*
69d29b2c44Sab  * We supply this function for the msg module
70d29b2c44Sab  */
71d29b2c44Sab const char *
_dyn_msg(Msg mid)72d29b2c44Sab _dyn_msg(Msg mid)
73d29b2c44Sab {
74d29b2c44Sab 	return (gettext(MSG_ORIG(mid)));
75d29b2c44Sab }
76d29b2c44Sab #endif
79d29b2c44Sab /*
80d29b2c44Sab  * This function is supplied to elfedit through our elfedit_module_t
81d29b2c44Sab  * definition. It translates the opaque elfedit_i18nhdl_t handles
82d29b2c44Sab  * in our module interface into the actual strings for elfedit to
83d29b2c44Sab  * use.
84d29b2c44Sab  *
85d29b2c44Sab  * note:
86d29b2c44Sab  *	This module uses Msg codes for its i18n handle type.
87d29b2c44Sab  *	So the translation is simply to use MSG_INTL() to turn
88d29b2c44Sab  *	it into a string and return it.
89d29b2c44Sab  */
90d29b2c44Sab static const char *
mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)91d29b2c44Sab mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
92d29b2c44Sab {
93d29b2c44Sab 	Msg msg = (Msg)hdl;
95d29b2c44Sab 	return (MSG_INTL(msg));
96d29b2c44Sab }
100d29b2c44Sab /*
101d29b2c44Sab  * The dyn_opt_t enum specifies a bit value for every optional
102d29b2c44Sab  * argument allowed by a command in this module.
103d29b2c44Sab  */
104d29b2c44Sab typedef enum {
105d29b2c44Sab 	DYN_OPT_F_ADD =		1,	/* -add: Add new elt rather than */
106d29b2c44Sab 					/*	modifying an existing one */
107d29b2c44Sab 	DYN_OPT_F_AND =		2,	/* -and: AND (&) values to dest */
108d29b2c44Sab 	DYN_OPT_F_CMP =		4,	/* -cmp: Complement (~) values */
10955ef6355Sab 	DYN_OPT_F_DYNNDX_ELT =	8,	/* -dynndx: 1st plain arg is tag */
11055ef6355Sab 					/*	index, not name */
11155ef6355Sab 	DYN_OPT_F_DYNNDX_VAL =	16,	/* -dynndx ndx: Index is value to */
11255ef6355Sab 					/*	option rather than 1st plain */
11355ef6355Sab 					/*	arg. Used for dyn:posflag1 */
11455ef6355Sab 	DYN_OPT_F_NEEDED =	32,	/* -needed str: Locate DT_POSFLAG_1 */
11555ef6355Sab 					/*	relative to DT_NEEDED element */
11655ef6355Sab 	DYN_OPT_F_OR =		64,	/* -or: OR (|) values to dest */
11755ef6355Sab 	DYN_OPT_F_STRVAL =	128	/* -s: value is string, not integer */
118d29b2c44Sab } dyn_opt_t;
121d29b2c44Sab /*
122d29b2c44Sab  * A variable of type ARGSTATE is used by each command to maintain
123d29b2c44Sab  * information about the arguments and related things. It is
124d29b2c44Sab  * initialized by process_args(), and used by the other routines.
125d29b2c44Sab  */
126d29b2c44Sab typedef struct {
127d29b2c44Sab 	elfedit_obj_state_t	*obj_state;
128d29b2c44Sab 	elfedit_section_t	*strsec;	/* Dynamic string table ref */
129d29b2c44Sab 	struct {
130d29b2c44Sab 		elfedit_section_t *sec;		/* Dynamic section reference */
131d29b2c44Sab 		Dyn	*data;			/* Start dynamic section data */
132d29b2c44Sab 		Word	num;			/* # dynamic elts */
133d29b2c44Sab 		Word	null_ndx;		/* Index of first DT_NULL */
134d29b2c44Sab 		Word	num_null_ndx;		/* # of DT_NULL elements */
135d29b2c44Sab 	} dyn;
136*9320f495SToomas Soome 	dyn_opt_t		optmask;	/* Mask of options used */
137d29b2c44Sab 	int			argc;		/* # of plain arguments */
138d29b2c44Sab 	const char		**argv;		/* Plain arguments */
13955ef6355Sab 	const char		*dyn_elt_str;	/* Value string for */
14055ef6355Sab 						/*	DYN_OPT_F_DYNNDX_VAL */
14155ef6355Sab 						/*	or DYN_OPT_F_NEEDED */
142d29b2c44Sab } ARGSTATE;
146d29b2c44Sab /*
147d29b2c44Sab  * Set argstate null_ndx field for current dynamic area
148d29b2c44Sab  */
149d29b2c44Sab static void
set_null_ndx(ARGSTATE * argstate)150d29b2c44Sab set_null_ndx(ARGSTATE *argstate)
151d29b2c44Sab {
152d29b2c44Sab 	Word	num, null_ndx;
154d29b2c44Sab 	num = argstate->dyn.num;
155d29b2c44Sab 	argstate->dyn.num_null_ndx = 0;
156d29b2c44Sab 	for (null_ndx = 0; null_ndx < num; null_ndx++)
157d29b2c44Sab 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) {
158d29b2c44Sab 			argstate->dyn.num_null_ndx++;
159d29b2c44Sab 			break;
160d29b2c44Sab 		}
161d29b2c44Sab 	argstate->dyn.null_ndx = null_ndx;
163d29b2c44Sab 	/* Count the number of remaining DT_NULL items */
164d29b2c44Sab 	for (; null_ndx < num; null_ndx++)
165d29b2c44Sab 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL)
166d29b2c44Sab 			argstate->dyn.num_null_ndx++;
167d29b2c44Sab }
170d29b2c44Sab /*
171d29b2c44Sab  * Convert the first available DT_NULL slot in the dynamic section
172d29b2c44Sab  * into something else.
173d29b2c44Sab  *
174d29b2c44Sab  * entry:
175d29b2c44Sab  *	argstate - Argument state block
176d29b2c44Sab  *	d_tag, d_val - Values to be set in new element
177d29b2c44Sab  *
178d29b2c44Sab  * exit:
179d29b2c44Sab  *	If an extra DT_NULL slot is available, a debug message is
180d29b2c44Sab  *	issued, the slot is converted to its new use, and the argstate
181d29b2c44Sab  *	block state related to DT_NULL slots is updated.
182d29b2c44Sab  *
183d29b2c44Sab  *	if no extra DT_NULL slot is present, an error is issued and
184d29b2c44Sab  *	this routine does not return to the caller.
185d29b2c44Sab  */
186d29b2c44Sab static Word
convert_dt_null(ARGSTATE * argstate,Xword d_tag,Xword d_val)1874f680cc6SAli Bahrami convert_dt_null(ARGSTATE *argstate, Xword d_tag, Xword d_val)
188d29b2c44Sab {
189d29b2c44Sab 	Conv_inv_buf_t inv_buf;
190d29b2c44Sab 	Word	ndx;
191d29b2c44Sab 	Dyn	*dyn;
1924f680cc6SAli Bahrami 	Ehdr	*ehdr;
194d29b2c44Sab 	/* If we lack an extra element, we can't continue */
195d29b2c44Sab 	if (argstate->dyn.num_null_ndx <= 1)
196d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
197d29b2c44Sab 		    EC_WORD(argstate->dyn.sec->sec_shndx),
198d29b2c44Sab 		    argstate->dyn.sec->sec_name);
2004f680cc6SAli Bahrami 	ehdr = argstate->obj_state->os_ehdr;
202d29b2c44Sab 	    EC_WORD(argstate->dyn.sec->sec_shndx), argstate->dyn.sec->sec_name,
203d29b2c44Sab 	    EC_WORD(argstate->dyn.null_ndx), conv_dyn_tag(d_tag,
2044f680cc6SAli Bahrami 	    ehdr->e_ident[EI_OSABI], ehdr->e_machine, 0, &inv_buf));
206d29b2c44Sab 	ndx = argstate->dyn.null_ndx;
207d29b2c44Sab 	dyn = &argstate->dyn.data[ndx];
208d29b2c44Sab 	dyn->d_tag = d_tag;
209d29b2c44Sab 	dyn->d_un.d_val = d_val;
211d29b2c44Sab 	/* Recompute the DT_NULL situation */
212d29b2c44Sab 	set_null_ndx(argstate);
214d29b2c44Sab 	return (ndx);
215d29b2c44Sab }
218d29b2c44Sab /*
219d29b2c44Sab  * Standard argument processing for dyn module
220d29b2c44Sab  *
221d29b2c44Sab  * entry
222d29b2c44Sab  *	obj_state, argc, argv - Standard command arguments
223d29b2c44Sab  *	argstate - Address of ARGSTATE block to be initialized
224d29b2c44Sab  *
225d29b2c44Sab  * exit:
226d29b2c44Sab  *	On success, *argstate is initialized. On error,
227d29b2c44Sab  *	an error is issued and this routine does not return.
228d29b2c44Sab  */
229d29b2c44Sab static void
process_args(elfedit_obj_state_t * obj_state,int argc,const char * argv[],ARGSTATE * argstate)230d29b2c44Sab process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
231d29b2c44Sab     ARGSTATE *argstate)
232d29b2c44Sab {
233d29b2c44Sab 	elfedit_getopt_state_t	getopt_state;
234d29b2c44Sab 	elfedit_getopt_ret_t	*getopt_ret;
236d29b2c44Sab 	bzero(argstate, sizeof (*argstate));
237d29b2c44Sab 	argstate->obj_state = obj_state;
239d29b2c44Sab 	elfedit_getopt_init(&getopt_state, &argc, &argv);
241d29b2c44Sab 	/* Add each new option to the options mask */
24255ef6355Sab 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
243d29b2c44Sab 		argstate->optmask |= getopt_ret->gor_idmask;
24455ef6355Sab 		switch (getopt_ret->gor_idmask) {
24555ef6355Sab 		case DYN_OPT_F_DYNNDX_VAL:
24655ef6355Sab 		case DYN_OPT_F_NEEDED:
24755ef6355Sab 			argstate->dyn_elt_str = getopt_ret->gor_value;
24855ef6355Sab 			break;
24955ef6355Sab 		}
25055ef6355Sab 	}
252d29b2c44Sab 	/* If there may be an arbitrary amount of output, use a pager */
253d29b2c44Sab 	if (argc == 0)
254d29b2c44Sab 		elfedit_pager_init();
256d29b2c44Sab 	/* Return the updated values of argc/argv */
257d29b2c44Sab 	argstate->argc = argc;
258d29b2c44Sab 	argstate->argv = argv;
260d29b2c44Sab 	/* Locate the dynamic section, and the assocated string table */
261d29b2c44Sab 	argstate->dyn.sec = elfedit_sec_getdyn(obj_state, &argstate->dyn.data,
262d29b2c44Sab 	    &argstate->dyn.num);
263d29b2c44Sab 	argstate->strsec = elfedit_sec_getstr(obj_state,
26455ef6355Sab 	    argstate->dyn.sec->sec_shdr->sh_link, 0);
266d29b2c44Sab 	/* Index of first DT_NULL */
267d29b2c44Sab 	set_null_ndx(argstate);
268d29b2c44Sab }
270d29b2c44Sab /*
271d29b2c44Sab  * Print ELF header values, taking the calling command, and output style
272d29b2c44Sab  * into account.
273d29b2c44Sab  *
274d29b2c44Sab  * entry:
275d29b2c44Sab  *	cmd - DYN_CMD_T_* value giving identify of caller
276d29b2c44Sab  *	autoprint - If True, output is only produced if the elfedit
277d29b2c44Sab  *		autoprint flag is set. If False, output is always produced.
278d29b2c44Sab  *	argstate - Argument state block
279d29b2c44Sab  *	print_type - Specifies which dynamic elements to display.
2804f680cc6SAli Bahrami  *	arg - If print_type is PRINT_DYN_T_NDX, displays the index specified.
281d29b2c44Sab  *		Otherwise ignored.
282d29b2c44Sab  */
283d29b2c44Sab typedef enum {
284d29b2c44Sab 	PRINT_DYN_T_ALL =	0,	/* Show all indexes */
285d29b2c44Sab 	PRINT_DYN_T_NDX =	1,	/* Show dynamic[arg] only */
286d29b2c44Sab 	PRINT_DYN_T_TAG =	2,	/* Show all elts with tag type */
287d29b2c44Sab 					/*	given by arg */
288d29b2c44Sab 	PRINT_DYN_T_RUNPATH =	3	/* Show all runpath/rpath elts */
290d29b2c44Sab } PRINT_DYN_T;
292d29b2c44Sab static void
print_dyn(DYN_CMD_T cmd,int autoprint,ARGSTATE * argstate,PRINT_DYN_T print_type,Word arg)293d29b2c44Sab print_dyn(DYN_CMD_T cmd, int autoprint, ARGSTATE *argstate,
294d29b2c44Sab     PRINT_DYN_T print_type, Word arg)
295d29b2c44Sab {
296d29b2c44Sab 	elfedit_outstyle_t	outstyle;
297d29b2c44Sab 	Conv_fmt_flags_t	flags_fmt_flags;
298c6c9aed4Sab 	Word	end_ndx, ndx, printed = 0;
299d29b2c44Sab 	Dyn	*dyn;
300d29b2c44Sab 	int	header_done = 0;
301d29b2c44Sab 	Xword	last_d_val;
30255ef6355Sab 	int	one_shot;
3034f680cc6SAli Bahrami 	int	osabi_solaris;
305d29b2c44Sab 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
306d29b2c44Sab 		return;
3084f680cc6SAli Bahrami 	osabi_solaris =
3094f680cc6SAli Bahrami 	    elfedit_test_osabi(argstate->obj_state, ELFOSABI_SOLARIS, 0);
3104f680cc6SAli Bahrami 
311d29b2c44Sab 	/*
312d29b2c44Sab 	 * Pick an output style. dyn:dump is required to use the default
313d29b2c44Sab 	 * style. The other commands use the current output style.
314d29b2c44Sab 	 */
315d29b2c44Sab 	outstyle = (cmd == DYN_CMD_T_DUMP) ?
316d29b2c44Sab 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
318d29b2c44Sab 	/*
319d29b2c44Sab 	 * When using the simple output style, omit the
320d29b2c44Sab 	 * brackets from around the values.
321d29b2c44Sab 	 */
322d29b2c44Sab 	flags_fmt_flags = (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) ?
323d29b2c44Sab 	    CONV_FMT_NOBKT : 0;
325c6c9aed4Sab 	/* Starting index */
326d29b2c44Sab 	if (print_type == PRINT_DYN_T_NDX) {
327d29b2c44Sab 		if (arg >= argstate->dyn.num)
328d29b2c44Sab 			return;		/* Out of range */
329d29b2c44Sab 		ndx = arg;
330d29b2c44Sab 	} else {
331d29b2c44Sab 		ndx = 0;
332d29b2c44Sab 	}
33455ef6355Sab 	/*
33555ef6355Sab 	 * one_shot is used by positional elements (e.g. DT_POSFLAG_1)
33655ef6355Sab 	 * to get the item following them to be shown even if they
33755ef6355Sab 	 * are not of the desired tag type or the count of elements
33855ef6355Sab 	 * to be displayed is only 1.
33955ef6355Sab 	 */
34055ef6355Sab 	one_shot = 0;
342d29b2c44Sab 	dyn = &argstate->dyn.data[ndx];
344c6c9aed4Sab 	/*
345c6c9aed4Sab 	 * Loop predicate explanation:
346c6c9aed4Sab 	 * Normally, we want to iterate from the starting index
347c6c9aed4Sab 	 * to the end. However, in the case of PRINT_DYN_T_NDX, we
348c6c9aed4Sab 	 * only want to display one item (ndx == arg) and then quit,
349c6c9aed4Sab 	 * with the exception that if we've been through the loop
350c6c9aed4Sab 	 * and encountered a one_shot situation, we want to continue
351c6c9aed4Sab 	 * iterating until the one-shot situation is cleared.
352c6c9aed4Sab 	 */
353c6c9aed4Sab 	for (; (ndx < argstate->dyn.num) &&
354c6c9aed4Sab 	    ((print_type != PRINT_DYN_T_NDX) || ((ndx == arg) || one_shot));
355c6c9aed4Sab 	    dyn++, ndx++) {
356d29b2c44Sab 		union {
357ba2be530Sab 			Conv_inv_buf_t		inv;
358d29b2c44Sab 			Conv_dyn_flag_buf_t	flag;
359d29b2c44Sab 			Conv_dyn_flag1_buf_t	flag1;
360d29b2c44Sab 			Conv_dyn_posflag1_buf_t	posflag1;
361d29b2c44Sab 			Conv_dyn_feature1_buf_t	feature1;
362d29b2c44Sab 		} c_buf;
363d29b2c44Sab 		const char	*name;
36555ef6355Sab 		if (one_shot) {
36655ef6355Sab 			one_shot = 0;
36755ef6355Sab 		} else {
36855ef6355Sab 			/*
36955ef6355Sab 			 * If we are only displaying certain tag types and
37055ef6355Sab 			 * this isn't one of those, move on to next element.
37155ef6355Sab 			 */
37255ef6355Sab 			switch (print_type) {
37355ef6355Sab 			case PRINT_DYN_T_TAG:
37455ef6355Sab 				if (dyn->d_tag != arg)
37555ef6355Sab 					continue;
37655ef6355Sab 				break;
37755ef6355Sab 			case PRINT_DYN_T_RUNPATH:
37855ef6355Sab 				if ((dyn->d_tag != DT_RPATH) &&
37955ef6355Sab 				    (dyn->d_tag != DT_RUNPATH))
38055ef6355Sab 					continue;
38155ef6355Sab 				break;
38255ef6355Sab 			}
383d29b2c44Sab 		}
385d29b2c44Sab 		/*
386d29b2c44Sab 		 * Print the information numerically, and if possible
387d29b2c44Sab 		 * as a string.
388d29b2c44Sab 		 */
389d29b2c44Sab 		name = NULL;
390d29b2c44Sab 		switch (dyn->d_tag) {
391d29b2c44Sab 		case DT_NULL:
392d29b2c44Sab 			if (!((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) &&
393d29b2c44Sab 			    (print_type == PRINT_DYN_T_ALL) &&
394d29b2c44Sab 			    (dyn->d_un.d_val == 0)))
395d29b2c44Sab 				break;
396d29b2c44Sab 			end_ndx = ndx;
397d29b2c44Sab 			/*
398d29b2c44Sab 			 * Special case: DT_NULLs can come in groups
399d29b2c44Sab 			 * that we prefer to reduce to a single line.
400d29b2c44Sab 			 */
401d29b2c44Sab 			while ((end_ndx < (argstate->dyn.num - 1)) &&
402d29b2c44Sab 			    ((dyn + 1)->d_tag == DT_NULL) &&
403d29b2c44Sab 			    ((dyn + 1)->d_un.d_val == 0)) {
404d29b2c44Sab 				dyn++;
405d29b2c44Sab 				end_ndx++;
406d29b2c44Sab 			}
407d29b2c44Sab 			if (header_done == 0) {
408d29b2c44Sab 				header_done = 1;
409d29b2c44Sab 				Elf_dyn_title(0);
410d29b2c44Sab 			}
411d29b2c44Sab 			Elf_dyn_null_entry(0, dyn, ndx, end_ndx);
412d29b2c44Sab 			ndx = end_ndx;
413d29b2c44Sab 			printed = 1;
414d29b2c44Sab 			last_d_val = dyn->d_un.d_val;
415d29b2c44Sab 			continue;
417d29b2c44Sab 		/*
418d29b2c44Sab 		 * Print the information numerically, and if possible
419d29b2c44Sab 		 * as a string.
420d29b2c44Sab 		 */
421d29b2c44Sab 		case DT_NEEDED:
422d29b2c44Sab 		case DT_SONAME:
423d29b2c44Sab 		case DT_FILTER:
424d29b2c44Sab 		case DT_AUXILIARY:
425d29b2c44Sab 		case DT_CONFIG:
426d29b2c44Sab 		case DT_RPATH:
427d29b2c44Sab 		case DT_RUNPATH:
428d29b2c44Sab 		case DT_USED:
429d29b2c44Sab 		case DT_DEPAUDIT:
430d29b2c44Sab 		case DT_AUDIT:
431d29b2c44Sab 			name = elfedit_offset_to_str(argstate->strsec,
432d29b2c44Sab 			    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
433d29b2c44Sab 			break;
4344f680cc6SAli Bahrami 		case DT_SUNW_AUXILIARY:
4354f680cc6SAli Bahrami 		case DT_SUNW_FILTER:
4364f680cc6SAli Bahrami 			if (osabi_solaris)
4374f680cc6SAli Bahrami 				name = elfedit_offset_to_str(argstate->strsec,
4384f680cc6SAli Bahrami 				    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
4394f680cc6SAli Bahrami 			break;
441d29b2c44Sab 		case DT_FLAGS:
442d29b2c44Sab 			name = conv_dyn_flag(dyn->d_un.d_val,
443d29b2c44Sab 			    flags_fmt_flags, &c_buf.flag);
444d29b2c44Sab 			break;
445d29b2c44Sab 		case DT_FLAGS_1:
446d29b2c44Sab 			name = conv_dyn_flag1(dyn->d_un.d_val,
447d29b2c44Sab 			    flags_fmt_flags, &c_buf.flag1);
448d29b2c44Sab 			break;
449d29b2c44Sab 		case DT_POSFLAG_1:
45055ef6355Sab 			/*
45155ef6355Sab 			 * If this is dyn:posflag1, and the print_type
45255ef6355Sab 			 * is PRINT_DYN_T_TAG, and the -needed option is
45355ef6355Sab 			 * used, then don't show any DT_POSFLAG_1 elements
45455ef6355Sab 			 * that are not followed by a DT_NEEDED element
45555ef6355Sab 			 * that matches the -needed string.
45655ef6355Sab 			 */
45755ef6355Sab 			if ((cmd == DYN_CMD_T_POSFLAG1) &&
45855ef6355Sab 			    (print_type == PRINT_DYN_T_TAG) &&
45955ef6355Sab 			    ((argstate->optmask & DYN_OPT_F_NEEDED) != 0) &&
46055ef6355Sab 			    ((ndx + 1) < argstate->dyn.num)) {
46155ef6355Sab 				Dyn *dyn1 = &argstate->dyn.data[ndx + 1];
46355ef6355Sab 				if (dyn1->d_tag != DT_NEEDED)
46455ef6355Sab 					continue;
46555ef6355Sab 				name = elfedit_offset_to_str(argstate->strsec,
46655ef6355Sab 				    dyn1->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
46755ef6355Sab 				if (strncmp(name, argstate->dyn_elt_str,
46855ef6355Sab 				    strlen(argstate->dyn_elt_str)) != 0)
46955ef6355Sab 					continue;
47055ef6355Sab 			}
472d29b2c44Sab 			name = conv_dyn_posflag1(dyn->d_un.d_val,
473d29b2c44Sab 			    flags_fmt_flags, &c_buf.posflag1);
47455ef6355Sab 			/*
47555ef6355Sab 			 * DT_POSFLAG_1 is a positional element that affects
47655ef6355Sab 			 * the following item. If using the default output
47755ef6355Sab 			 * style, then show the following item as well.
47855ef6355Sab 			 */
47955ef6355Sab 			one_shot = (outstyle == ELFEDIT_OUTSTYLE_DEFAULT);
480d29b2c44Sab 			break;
481d29b2c44Sab 		case DT_FEATURE_1:
482d29b2c44Sab 			name = conv_dyn_feature1(dyn->d_un.d_val,
483d29b2c44Sab 			    flags_fmt_flags, &c_buf.feature1);
484d29b2c44Sab 			break;
486d29b2c44Sab 			name = MSG_INTL(MSG_STR_DEPRECATED);
487d29b2c44Sab 			break;
488ba2be530Sab 		case DT_SUNW_LDMACH:
4894f680cc6SAli Bahrami 			if (osabi_solaris)
4904f680cc6SAli Bahrami 				name = conv_ehdr_mach((Half)dyn->d_un.d_val, 0,
4914f680cc6SAli Bahrami 				    &c_buf.inv);
492ba2be530Sab 			break;
493d29b2c44Sab 		}
495d29b2c44Sab 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
4964f680cc6SAli Bahrami 			Ehdr	*ehdr;
4974f680cc6SAli Bahrami 
498d29b2c44Sab 			if (header_done == 0) {
499d29b2c44Sab 				header_done = 1;
500d29b2c44Sab 				Elf_dyn_title(0);
501d29b2c44Sab 			}
502d29b2c44Sab 			if (name == NULL)
503d29b2c44Sab 				name = MSG_ORIG(MSG_STR_EMPTY);
5044f680cc6SAli Bahrami 			ehdr = argstate->obj_state->os_ehdr;
505d29b2c44Sab 			Elf_dyn_entry(0, dyn, ndx, name,
5064f680cc6SAli Bahrami 			    ehdr->e_ident[EI_OSABI], ehdr->e_machine);
507d29b2c44Sab 		} else {
508d29b2c44Sab 			/*
509d29b2c44Sab 			 * In simple or numeric mode under a print type
510d29b2c44Sab 			 * that is based on tag type rather than on index,
5115c02782fSAli Bahrami 			 * if there are more than one qualifying tag, we
5125c02782fSAli Bahrami 			 * want to skip printing redundant information.
513d29b2c44Sab 			 */
514d29b2c44Sab 			switch (print_type) {
515d29b2c44Sab 			case PRINT_DYN_T_TAG:
5165c02782fSAli Bahrami 				switch (dyn->d_tag) {
5175c02782fSAli Bahrami 				case DT_NEEDED:
5185c02782fSAli Bahrami 					/* Multiple NEEDED entries are normal */
5195c02782fSAli Bahrami 					break;
5205c02782fSAli Bahrami 				case DT_POSFLAG_1:
5215c02782fSAli Bahrami 					/*
5225c02782fSAli Bahrami 					 * Positional flags don't count,
5235c02782fSAli Bahrami 					 * because each one affects a different
5245c02782fSAli Bahrami 					 * item. Don't skip those even if they
5255c02782fSAli Bahrami 					 * have duplicate values.
5265c02782fSAli Bahrami 					 */
5275c02782fSAli Bahrami 					break;
5285c02782fSAli Bahrami 				default:
5295c02782fSAli Bahrami 					/*
5305c02782fSAli Bahrami 					 * Anything else: If we've already
5315c02782fSAli Bahrami 					 * printed this value, don't print
5325c02782fSAli Bahrami 					 * it again.
5335c02782fSAli Bahrami 					 */
5345c02782fSAli Bahrami 					if (printed &&
5355c02782fSAli Bahrami 					    (last_d_val == dyn->d_un.d_val))
5365c02782fSAli Bahrami 						continue;
5375c02782fSAli Bahrami 				}
53855ef6355Sab 				break;
539d29b2c44Sab 			case PRINT_DYN_T_RUNPATH:
5405c02782fSAli Bahrami 				/*
5415c02782fSAli Bahrami 				 * If we've already printed this value,
5425c02782fSAli Bahrami 				 * don't print it again. This commonly
5435c02782fSAli Bahrami 				 * happens when both DT_RPATH and DT_RUNPATH
5445c02782fSAli Bahrami 				 * are present with the same value.
5455c02782fSAli Bahrami 				 */
546d29b2c44Sab 				if (printed && (last_d_val == dyn->d_un.d_val))
547d29b2c44Sab 					continue;
54855ef6355Sab 				break;
549d29b2c44Sab 			}
551d29b2c44Sab 			if ((name != NULL) &&
552d29b2c44Sab 			    (outstyle == ELFEDIT_OUTSTYLE_SIMPLE)) {
553d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), name);
554d29b2c44Sab 			} else {
555d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
55608278a5eSRod Evans 				    EC_XWORD(dyn->d_un.d_val));
557d29b2c44Sab 			}
558d29b2c44Sab 		}
559d29b2c44Sab 		printed = 1;
560d29b2c44Sab 		last_d_val = dyn->d_un.d_val;
561d29b2c44Sab 	}
563d29b2c44Sab 	/*
564d29b2c44Sab 	 * If nothing was output under the print types that are
565d29b2c44Sab 	 * based on tag type, issue an error saying it doesn't exist.
566d29b2c44Sab 	 */
567d29b2c44Sab 	if (!printed) {
568d29b2c44Sab 		if (print_type == PRINT_DYN_T_TAG) {
5694f680cc6SAli Bahrami 			Conv_inv_buf_t	inv_buf;
5704f680cc6SAli Bahrami 			Ehdr		*ehdr = argstate->obj_state->os_ehdr;
572d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
573d29b2c44Sab 			    MSG_INTL(MSG_ERR_NODYNELT),
574d29b2c44Sab 			    EC_WORD(argstate->dyn.sec->sec_shndx),
575d29b2c44Sab 			    argstate->dyn.sec->sec_name, conv_dyn_tag(arg,
5764f680cc6SAli Bahrami 			    ehdr->e_ident[EI_OSABI], ehdr->e_machine,
577d29b2c44Sab 			    0, &inv_buf));
578d29b2c44Sab 		}
580d29b2c44Sab 		if (print_type == PRINT_DYN_T_RUNPATH)
581d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
582d29b2c44Sab 			    MSG_INTL(MSG_ERR_NORUNPATH),
583d29b2c44Sab 			    EC_WORD(argstate->dyn.sec->sec_shndx),
584d29b2c44Sab 			    argstate->dyn.sec->sec_name);
585d29b2c44Sab 	}
586d29b2c44Sab }
589d29b2c44Sab /*
59055ef6355Sab  * Determine the index(s) of the dynamic element(s) to be displayed and/or
59155ef6355Sab  * manipulated.
592d29b2c44Sab  *
593d29b2c44Sab  * entry:
594d29b2c44Sab  *	argstate - Argument state block
59555ef6355Sab  *	arg - If the command being called accepts a first plain argument
59655ef6355Sab  *		named 'elt' which is used to specify the dynamic element,
59755ef6355Sab  *		arg is the value of argv[0] for that command. If the
59855ef6355Sab  *		command does not accept an 'elt' argument and instead
59955ef6355Sab  *		implicitly assumes a tag type, arg is the constant string
60055ef6355Sab  *		for that type (e.g. "DT_POSFLAG_1").
601d29b2c44Sab  *	print_request - True if the command is to print the current
602d29b2c44Sab  *		value(s) and return without changing anything.
603d29b2c44Sab  *	print_type - Address of variable containing PRINT_DYN_T_
604d29b2c44Sab  *		code specifying how the elements will be displayed.
605d29b2c44Sab  *
606d29b2c44Sab  * exit:
60755ef6355Sab  *	If print_request is False: This routine always returns the index
60855ef6355Sab  *	of a single dynamic element. *print_type is set to PRINT_DYN_T_NDX.
60955ef6355Sab  *	The 'elt' argument as well as any modifier options (-dynndx, -needed)
61055ef6355Sab  *	are examined to determine this index. If there are no modifier options,
61155ef6355Sab  *	the dynamic section contains no element of the desired type, and there
61255ef6355Sab  *	is an extra DT_NULL element in the section, then a new element of
61355ef6355Sab  *	the desired type is created and its index returned. Otherwise an
61455ef6355Sab  *	error is issued.
615d29b2c44Sab  *
61655ef6355Sab  *	If print_request is True: If a modifier (-dynndx, -needed) was used,
61755ef6355Sab  *	*print_type is set to PRINT_DYN_T_NDX and the index of the
61855ef6355Sab  *	corresponding single dynamic element is returned. If no modifier
61955ef6355Sab  *	was used, *print_type is set to PRINT_DYN_T_TAG, and the tag
62055ef6355Sab  *	type code is returned.
621d29b2c44Sab  */
622d29b2c44Sab static Word
arg_to_index(ARGSTATE * argstate,const char * arg,int print_request,PRINT_DYN_T * print_type)62355ef6355Sab arg_to_index(ARGSTATE *argstate, const char *arg,
624d29b2c44Sab     int print_request, PRINT_DYN_T *print_type)
625d29b2c44Sab {
6264f680cc6SAli Bahrami 	Word	ndx;
6274f680cc6SAli Bahrami 	Xword	dt_value;
62855ef6355Sab 	Dyn	*dyn;
631d29b2c44Sab 	/* Assume we are returning an index, alter as needed below */
632d29b2c44Sab 	*print_type = PRINT_DYN_T_NDX;
63455ef6355Sab 	/*
63555ef6355Sab 	 * All the commands that accept the DYN_OPT_F_DYNNDX_ELT form
63655ef6355Sab 	 * of -dynndx require a plain argument named 'elt' as their first
63755ef6355Sab 	 * argument. -dynndx is a modifier that means that 'elt' is a
63855ef6355Sab 	 * simple numeric section index. Routines that accept this form
63955ef6355Sab 	 * of -dynndx are willing to handle any tag type, so all we need
64055ef6355Sab 	 * to check is that the value is in range.
64155ef6355Sab 	 */
64255ef6355Sab 	if ((argstate->optmask & DYN_OPT_F_DYNNDX_ELT) != 0)
64355ef6355Sab 		return ((Word) elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_ELT),
64455ef6355Sab 		    0, argstate->dyn.num - 1, NULL));
64655ef6355Sab 	/* arg is a DT_ tag type, not a numeric index */
647d29b2c44Sab 	dt_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_DT);
64955ef6355Sab 	/*
65055ef6355Sab 	 * Commands that accept the DYN_OPT_F_DYNNDX_VAL form  of
65155ef6355Sab 	 * dynndx do not accept the 'elt' argument. The index is a
65255ef6355Sab 	 * value that follows the option, and was saved in argstate by
65355ef6355Sab 	 * process_args(). Routines that accept this form of -dynndx
65455ef6355Sab 	 * require the specified element to have a specific tag type,
65555ef6355Sab 	 * so we test for this as well as for the index being in range.
65655ef6355Sab 	 */
65755ef6355Sab 	if ((argstate->optmask & DYN_OPT_F_DYNNDX_VAL) != 0) {
65855ef6355Sab 		ndx = ((Word) elfedit_atoui_range(argstate->dyn_elt_str,
65955ef6355Sab 		    MSG_ORIG(MSG_STR_INDEX), 0, argstate->dyn.num - 1, NULL));
66055ef6355Sab 		if (argstate->dyn.data[ndx].d_tag != dt_value) {
6614f680cc6SAli Bahrami 			Ehdr	*ehdr = argstate->obj_state->os_ehdr;
6624f680cc6SAli Bahrami 			uchar_t	osabi = ehdr->e_ident[EI_OSABI];
6634f680cc6SAli Bahrami 			Half	mach = ehdr->e_machine;
66455ef6355Sab 			Conv_inv_buf_t	is, want;
66655ef6355Sab 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_WRONGTAG),
66755ef6355Sab 			    EC_WORD(argstate->dyn.sec->sec_shndx),
66855ef6355Sab 			    argstate->dyn.sec->sec_name, ndx,
6694f680cc6SAli Bahrami 			    conv_dyn_tag(dt_value, osabi, mach, 0, &want),
6704f680cc6SAli Bahrami 			    conv_dyn_tag(argstate->dyn.data[ndx].d_tag,
6714f680cc6SAli Bahrami 			    osabi, mach, 0, &is));
67255ef6355Sab 		}
67355ef6355Sab 		return (ndx);
67455ef6355Sab 	}
676d29b2c44Sab 	/*
677d29b2c44Sab 	 * If this is a printing request, then we let print_dyn() show
678d29b2c44Sab 	 * all the items with this tag type.
679d29b2c44Sab 	 */
680d29b2c44Sab 	if (print_request) {
681d29b2c44Sab 		*print_type = PRINT_DYN_T_TAG;
682d29b2c44Sab 		return (dt_value);
683d29b2c44Sab 	}
68555ef6355Sab 	/*
68655ef6355Sab 	 * Commands that accept -needed are looking for the dt_value element
68755ef6355Sab 	 * (usually DT_POSFLAG_1) that immediately preceeds the DT_NEEDED
68855ef6355Sab 	 * element with the string given by argstate->dyn_elt_str.
68955ef6355Sab 	 */
69055ef6355Sab 	if ((argstate->optmask & DYN_OPT_F_NEEDED) != 0) {
69155ef6355Sab 		Word	retndx = argstate->dyn.num;	/* Out of range value */
69255ef6355Sab 		const char	*name;
69355ef6355Sab 		size_t		len;
69555ef6355Sab 		len = strlen(argstate->dyn_elt_str);
69655ef6355Sab 		for (ndx = 0, dyn = argstate->dyn.data;
69755ef6355Sab 		    ndx < argstate->dyn.num; dyn++, ndx++) {
69855ef6355Sab 			/*
69955ef6355Sab 			 * If the immediately preceeding item has the
70055ef6355Sab 			 * tag type we're looking for, and the current item
70155ef6355Sab 			 * is a DT_NEEDED with a string that matches,
70255ef6355Sab 			 * then the preceeding item is the one we want.
70355ef6355Sab 			 */
70455ef6355Sab 			if ((dyn->d_tag == DT_NEEDED) &&
70555ef6355Sab 			    (ndx > 0) && (retndx == (ndx - 1))) {
70655ef6355Sab 				name = elfedit_offset_to_str(argstate->strsec,
70755ef6355Sab 				    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
70955ef6355Sab 				if (strncmp(name,
71055ef6355Sab 				    argstate->dyn_elt_str, len) == 0)
71155ef6355Sab 					return (retndx);
71255ef6355Sab 				continue;
71355ef6355Sab 			}
71555ef6355Sab 			/*
71655ef6355Sab 			 * If the current item has the tag type we're
71755ef6355Sab 			 * looking for, make it our current candidate.
71855ef6355Sab 			 * If the next item is a DT_NEEDED with the right
71955ef6355Sab 			 * string value, we'll use it then.
72055ef6355Sab 			 */
72155ef6355Sab 			if (dyn->d_tag == dt_value)
72255ef6355Sab 				retndx = ndx;
72355ef6355Sab 		}
72555ef6355Sab 		/* If we get here, no matching DT_NEEDED was found */
72755ef6355Sab 		    EC_WORD(argstate->dyn.sec->sec_shndx),
72855ef6355Sab 		    argstate->dyn.sec->sec_name, argstate->dyn_elt_str);
72955ef6355Sab 	}
731d29b2c44Sab 	/* Locate the first entry with the given tag type */
732d29b2c44Sab 	for (ndx = 0; ndx < argstate->dyn.num; ndx++) {
733d29b2c44Sab 		if (argstate->dyn.data[ndx].d_tag == dt_value) {
734d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
735d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_DT2NDX),
736d29b2c44Sab 			    EC_WORD(argstate->dyn.sec->sec_shndx),
737d29b2c44Sab 			    argstate->dyn.sec->sec_name, EC_WORD(ndx), arg);
738d29b2c44Sab 			return (ndx);
739d29b2c44Sab 		}
740d29b2c44Sab 	}
742d29b2c44Sab 	/* Not found. Can we create one? */
743d29b2c44Sab 	if (argstate->dyn.num_null_ndx > 1)
744d29b2c44Sab 		return (convert_dt_null(argstate, dt_value, 0));
746d29b2c44Sab 	/* No room to create one, so we're out of options and must fail */
747d29b2c44Sab 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODTELT),
748d29b2c44Sab 	    EC_WORD(argstate->dyn.sec->sec_shndx),
749d29b2c44Sab 	    argstate->dyn.sec->sec_name, arg);
751d29b2c44Sab 	/*NOTREACHED*/
752d29b2c44Sab 	return (0);		/* For lint */
753d29b2c44Sab }
756d29b2c44Sab /*
757d29b2c44Sab  * Called by cmd_body() for dyn:value. Implements the core functionality
758d29b2c44Sab  * for that command.
759d29b2c44Sab  *
760d29b2c44Sab  * This routine expects that both the index and value arguments are
761d29b2c44Sab  * present.
762d29b2c44Sab  */
763d29b2c44Sab static elfedit_cmdret_t
cmd_body_value(ARGSTATE * argstate,Word * ret_ndx)764d29b2c44Sab cmd_body_value(ARGSTATE *argstate, Word *ret_ndx)
765d29b2c44Sab {
766d29b2c44Sab 	elfedit_section_t	*dynsec = argstate->dyn.sec;
767d29b2c44Sab 	elfedit_section_t	*strsec = argstate->strsec;
768d29b2c44Sab 	elfedit_dyn_elt_t	strpad_elt;
769d29b2c44Sab 	Word	i;
770d29b2c44Sab 	Dyn	*dyn = argstate->dyn.data;
771d29b2c44Sab 	Word	numdyn = argstate->dyn.num;
77255ef6355Sab 	int	minus_add, minus_s, minus_dynndx;
7734f680cc6SAli Bahrami 	Word	tmp_val;
7744f680cc6SAli Bahrami 	Xword	arg1, arg2;
775d29b2c44Sab 	int	arg2_known = 1;
77755ef6355Sab 	minus_add = ((argstate->optmask & DYN_OPT_F_ADD) != 0);
77855ef6355Sab 	minus_s = ((argstate->optmask & DYN_OPT_F_STRVAL) != 0);
77955ef6355Sab 	minus_dynndx = ((argstate->optmask & DYN_OPT_F_DYNNDX_ELT) != 0);
781d29b2c44Sab 	elfedit_dyn_elt_init(&strpad_elt);
783d29b2c44Sab 	/*
784d29b2c44Sab 	 * The first argument is an index if -dynndx is used, and is a
785d29b2c44Sab 	 * tag value otherwise.
786d29b2c44Sab 	 */
787d29b2c44Sab 	arg1 = minus_dynndx ?
788d29b2c44Sab 	    elfedit_atoui_range(argstate->argv[0], MSG_ORIG(MSG_STR_ELT),
789d29b2c44Sab 	    0, numdyn - 1, NULL) :
790d29b2c44Sab 	    elfedit_atoconst(argstate->argv[0], ELFEDIT_CONST_DT);
792d29b2c44Sab 	if (minus_s) {
793d29b2c44Sab 		/*
794d29b2c44Sab 		 * Don't allow the user to specify -s when manipulating a
795d29b2c44Sab 		 * DT_SUNW_STRPAD element. Since DT_SUNW_STRPAD is used to
796d29b2c44Sab 		 * manage the extra space used for strings, this would break
797d29b2c44Sab 		 * our ability to add the string.
798d29b2c44Sab 		 */
799d29b2c44Sab 		if ((!minus_dynndx && (arg1 == DT_SUNW_STRPAD)) ||
800d29b2c44Sab 		    (minus_dynndx && (dyn[arg1].d_tag == DT_SUNW_STRPAD)))
801d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
802d29b2c44Sab 			    MSG_INTL(MSG_ERR_STRPADSTRVAL),
803d29b2c44Sab 			    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
805d29b2c44Sab 		/* Locate DT_SUNW_STRPAD element if present */
806d29b2c44Sab 		strpad_elt.dn_dyn.d_un.d_val = 0;
8074f680cc6SAli Bahrami 		(void) elfedit_dynstr_getpad(argstate->obj_state,
8084f680cc6SAli Bahrami 		    argstate->dyn.sec, &strpad_elt);
810d29b2c44Sab 		/*
811d29b2c44Sab 		 * Look up the string: If the user specified the -dynndx
812d29b2c44Sab 		 * -option, then we will insert it if possible, and
813d29b2c44Sab 		 * fail with an error if not. However, if they did not
814d29b2c44Sab 		 * specify -dynndx, we want to look up the string if it is
815d29b2c44Sab 		 * already there, but defer the insertion. The reason for
816d29b2c44Sab 		 * this is that we may have to grab an unused DT_NULL element
817d29b2c44Sab 		 * below, and if there are none available, we won't want
818d29b2c44Sab 		 * to have modified the string table.
819d29b2c44Sab 		 *
820d29b2c44Sab 		 * This isn't a problem, because if the string isn't
821d29b2c44Sab 		 * in the string table, it can't be used by a dynamic element.
822d29b2c44Sab 		 * Hence, we don't need to insert it to know that there is
823d29b2c44Sab 		 * no match.
824d29b2c44Sab 		 */
825d29b2c44Sab 		if (minus_dynndx == 0) {
826d29b2c44Sab 			if (elfedit_sec_findstr(strsec,
827d29b2c44Sab 			    strpad_elt.dn_dyn.d_un.d_val, argstate->argv[1],
828d29b2c44Sab 			    &tmp_val) == 0) {
829d29b2c44Sab 				arg2_known = 0;
830d29b2c44Sab 			} else {
831d29b2c44Sab 				arg2 = tmp_val;
832d29b2c44Sab 			}
833d29b2c44Sab 		} else {
834d29b2c44Sab 			arg2 = elfedit_dynstr_insert(dynsec, strsec,
835d29b2c44Sab 			    &strpad_elt, argstate->argv[1]);
836d29b2c44Sab 		}
837d29b2c44Sab 	} else {		/* Argument 2 is an integer */
838d29b2c44Sab 		arg2 = elfedit_atoui(argstate->argv[1], NULL);
839d29b2c44Sab 	}
842d29b2c44Sab 	if (!minus_dynndx && !(minus_add && !arg2_known)) {
843d29b2c44Sab 		/*
844d29b2c44Sab 		 * Search the dynamic section and see if an item with the
845d29b2c44Sab 		 * specified tag value already exists. We can reduce this
846d29b2c44Sab 		 * to a simple update of an existing value if -add is not
847d29b2c44Sab 		 * specified or the existing d_un value matches the new one.
848d29b2c44Sab 		 *
849d29b2c44Sab 		 * In either of these cases, we will change arg1 to be the
850d29b2c44Sab 		 * index, and set minus_dynndx, causing the simple update to
851d29b2c44Sab 		 * happen immediately below.
852d29b2c44Sab 		 */
853d29b2c44Sab 		for (i = 0; i < numdyn; i++) {
854d29b2c44Sab 			if ((dyn[i].d_tag == arg1) &&
855d29b2c44Sab 			    (!minus_add || (dyn[i].d_un.d_val == arg2))) {
856d29b2c44Sab 				arg1 = i;
857d29b2c44Sab 				minus_dynndx = 1;
858d29b2c44Sab 				break;
859d29b2c44Sab 			}
860d29b2c44Sab 		}
861d29b2c44Sab 	}
863d29b2c44Sab 	/*
864d29b2c44Sab 	 * If -dynndx is used, then this is a relatively simple
865d29b2c44Sab 	 * operation, as we simply write over the specified index.
866d29b2c44Sab 	 */
867d29b2c44Sab 	if (minus_dynndx) {
868d29b2c44Sab 		/*
869d29b2c44Sab 		 * If we held back from inserting a new string into
870d29b2c44Sab 		 * the dynstr above, we insert it now, because we
871d29b2c44Sab 		 * have a slot in the dynamic section, and we need
872d29b2c44Sab 		 * the string offset ot finish.
873d29b2c44Sab 		 */
874d29b2c44Sab 		if (!arg2_known)
875d29b2c44Sab 			arg2 = elfedit_dynstr_insert(dynsec, strsec,
876d29b2c44Sab 			    &strpad_elt, argstate->argv[1]);
878d29b2c44Sab 		*ret_ndx = arg1;
879d29b2c44Sab 		if (dyn[arg1].d_un.d_val == arg2) {
880d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
881d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_X_OK),
882d29b2c44Sab 			    dynsec->sec_shndx, dynsec->sec_name,
883d29b2c44Sab 			    EC_WORD(arg1), EC_XWORD(arg2));
884d29b2c44Sab 			return (ELFEDIT_CMDRET_NONE);
885d29b2c44Sab 		} else {
886d29b2c44Sab 			/* Warn if setting DT_NULL value to non-zero */
887d29b2c44Sab 			if ((dyn[arg1].d_tag == DT_NULL) && (arg2 != 0))
888d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
889d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_DTNULLVALUE),
890d29b2c44Sab 				    dynsec->sec_shndx, dynsec->sec_name,
891d29b2c44Sab 				    EC_WORD(arg1), EC_XWORD(arg2));
893d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
894d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_X_CHG),
895d29b2c44Sab 			    dynsec->sec_shndx, dynsec->sec_name,
896d29b2c44Sab 			    EC_WORD(arg1), EC_XWORD(dyn[arg1].d_un.d_val),