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  */
21d29b2c44Sab 
22d29b2c44Sab /*
23ba2be530Sab  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24d29b2c44Sab  * Use is subject to license terms.
25d29b2c44Sab  */
26d29b2c44Sab 
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>
34d29b2c44Sab 
35d29b2c44Sab 
36d29b2c44Sab /*
37d29b2c44Sab  * Dynamic section
38d29b2c44Sab  */
39d29b2c44Sab 
40d29b2c44Sab 
41d29b2c44Sab 
42d29b2c44Sab 
43d29b2c44Sab /*
44d29b2c44Sab  * This module uses shared code for several of the commands.
45d29b2c44Sab  * It is sometimes necessary to know which specific command
46d29b2c44Sab  * is active.
47d29b2c44Sab  */
48d29b2c44Sab typedef enum {
49d29b2c44Sab 	/* Dump command, used as module default to display dynamic section */
50d29b2c44Sab 	DYN_CMD_T_DUMP =	0,	/* dyn:dump */
51d29b2c44Sab 
52d29b2c44Sab 	/* Commands that do not correspond directly to a specific DT tag */
53d29b2c44Sab 	DYN_CMD_T_TAG =		1,	/* dyn:tag */
54d29b2c44Sab 	DYN_CMD_T_VALUE =	2,	/* dyn:value */
55d29b2c44Sab 	DYN_CMD_T_DELETE =	3,	/* dyn:delete */
56d29b2c44Sab 	DYN_CMD_T_MOVE =	4,	/* dyn:shift */
57d29b2c44Sab 
58d29b2c44Sab 	/* Commands that embody tag specific knowledge */
59d29b2c44Sab 	DYN_CMD_T_RUNPATH =	5,	/* dyn:runpath/rpath */
60d29b2c44Sab 	DYN_CMD_T_POSFLAG1 =	6,	/* dyn:posflag1 */
61d29b2c44Sab 	DYN_CMD_T_FLAGS =	7,	/* dyn:flags */
62d29b2c44Sab 	DYN_CMD_T_FLAGS1 =	8,	/* dyn:flags1 */
63d29b2c44Sab 	DYN_CMD_T_FEATURE1 =	9,	/* dyn:feature1 */
64ba2be530Sab 	DYN_CMD_T_CHECKSUM =	10,	/* dyn:checksum */
65ba2be530Sab 	DYN_CMD_T_SUNW_LDMACH =	11	/* dyn:sunw_ldmach */
66d29b2c44Sab } DYN_CMD_T;
67d29b2c44Sab 
68d29b2c44Sab 
69d29b2c44Sab 
70d29b2c44Sab #ifndef _ELF64
71d29b2c44Sab /*
72d29b2c44Sab  * We supply this function for the msg module
73d29b2c44Sab  */
74d29b2c44Sab const char *
75d29b2c44Sab _dyn_msg(Msg mid)
76d29b2c44Sab {
77d29b2c44Sab 	return (gettext(MSG_ORIG(mid)));
78d29b2c44Sab }
79d29b2c44Sab #endif
80d29b2c44Sab 
81d29b2c44Sab 
82d29b2c44Sab /*
83d29b2c44Sab  * This function is supplied to elfedit through our elfedit_module_t
84d29b2c44Sab  * definition. It translates the opaque elfedit_i18nhdl_t handles
85d29b2c44Sab  * in our module interface into the actual strings for elfedit to
86d29b2c44Sab  * use.
87d29b2c44Sab  *
88d29b2c44Sab  * note:
89d29b2c44Sab  *	This module uses Msg codes for its i18n handle type.
90d29b2c44Sab  *	So the translation is simply to use MSG_INTL() to turn
91d29b2c44Sab  *	it into a string and return it.
92d29b2c44Sab  */
93d29b2c44Sab static const char *
94d29b2c44Sab mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
95d29b2c44Sab {
96d29b2c44Sab 	Msg msg = (Msg)hdl;
97d29b2c44Sab 
98d29b2c44Sab 	return (MSG_INTL(msg));
99d29b2c44Sab }
100d29b2c44Sab 
101d29b2c44Sab 
102d29b2c44Sab 
103d29b2c44Sab /*
104d29b2c44Sab  * The dyn_opt_t enum specifies a bit value for every optional
105d29b2c44Sab  * argument allowed by a command in this module.
106d29b2c44Sab  */
107d29b2c44Sab typedef enum {
108d29b2c44Sab 	DYN_OPT_F_ADD =		1,	/* -add: Add new elt rather than */
109d29b2c44Sab 					/*	modifying an existing one */
110d29b2c44Sab 	DYN_OPT_F_AND =		2,	/* -and: AND (&) values to dest */
111d29b2c44Sab 	DYN_OPT_F_CMP =		4,	/* -cmp: Complement (~) values */
11255ef6355Sab 	DYN_OPT_F_DYNNDX_ELT =	8,	/* -dynndx: 1st plain arg is tag */
11355ef6355Sab 					/*	index, not name */
11455ef6355Sab 	DYN_OPT_F_DYNNDX_VAL =	16,	/* -dynndx ndx: Index is value to */
11555ef6355Sab 					/*	option rather than 1st plain */
11655ef6355Sab 					/*	arg. Used for dyn:posflag1 */
11755ef6355Sab 	DYN_OPT_F_NEEDED =	32,	/* -needed str: Locate DT_POSFLAG_1 */
11855ef6355Sab 					/*	relative to DT_NEEDED element */
11955ef6355Sab 	DYN_OPT_F_OR =		64,	/* -or: OR (|) values to dest */
12055ef6355Sab 	DYN_OPT_F_STRVAL =	128	/* -s: value is string, not integer */
121d29b2c44Sab } dyn_opt_t;
122d29b2c44Sab 
123d29b2c44Sab 
124d29b2c44Sab /*
125d29b2c44Sab  * A variable of type ARGSTATE is used by each command to maintain
126d29b2c44Sab  * information about the arguments and related things. It is
127d29b2c44Sab  * initialized by process_args(), and used by the other routines.
128d29b2c44Sab  */
129d29b2c44Sab typedef struct {
130d29b2c44Sab 	elfedit_obj_state_t	*obj_state;
131d29b2c44Sab 	elfedit_section_t	*strsec;	/* Dynamic string table ref */
132d29b2c44Sab 	struct {
133d29b2c44Sab 		elfedit_section_t *sec;		/* Dynamic section reference */
134d29b2c44Sab 		Dyn	*data;			/* Start dynamic section data */
135d29b2c44Sab 		Word	num;			/* # dynamic elts */
136d29b2c44Sab 		Word	null_ndx;		/* Index of first DT_NULL */
137d29b2c44Sab 		Word	num_null_ndx;		/* # of DT_NULL elements */
138d29b2c44Sab 	} dyn;
139d29b2c44Sab 	dyn_opt_t		optmask;   	/* Mask of options used */
140d29b2c44Sab 	int			argc;		/* # of plain arguments */
141d29b2c44Sab 	const char		**argv;		/* Plain arguments */
14255ef6355Sab 	const char		*dyn_elt_str;	/* Value string for */
14355ef6355Sab 						/*	DYN_OPT_F_DYNNDX_VAL */
14455ef6355Sab 						/*	or DYN_OPT_F_NEEDED */
145d29b2c44Sab } ARGSTATE;
146d29b2c44Sab 
147d29b2c44Sab 
148d29b2c44Sab 
149d29b2c44Sab /*
150d29b2c44Sab  * Set argstate null_ndx field for current dynamic area
151d29b2c44Sab  */
152d29b2c44Sab static void
153d29b2c44Sab set_null_ndx(ARGSTATE *argstate)
154d29b2c44Sab {
155d29b2c44Sab 	Word	num, null_ndx;
156d29b2c44Sab 
157d29b2c44Sab 	num = argstate->dyn.num;
158d29b2c44Sab 	argstate->dyn.num_null_ndx = 0;
159d29b2c44Sab 	for (null_ndx = 0; null_ndx < num; null_ndx++)
160d29b2c44Sab 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) {
161d29b2c44Sab 			argstate->dyn.num_null_ndx++;
162d29b2c44Sab 			break;
163d29b2c44Sab 		}
164d29b2c44Sab 	argstate->dyn.null_ndx = null_ndx;
165d29b2c44Sab 
166d29b2c44Sab 	/* Count the number of remaining DT_NULL items */
167d29b2c44Sab 	for (; null_ndx < num; null_ndx++)
168d29b2c44Sab 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL)
169d29b2c44Sab 			argstate->dyn.num_null_ndx++;
170d29b2c44Sab }
171d29b2c44Sab 
172d29b2c44Sab 
173d29b2c44Sab /*
174d29b2c44Sab  * Convert the first available DT_NULL slot in the dynamic section
175d29b2c44Sab  * into something else.
176d29b2c44Sab  *
177d29b2c44Sab  * entry:
178d29b2c44Sab  *	argstate - Argument state block
179d29b2c44Sab  *	d_tag, d_val - Values to be set in new element
180d29b2c44Sab  *
181d29b2c44Sab  * exit:
182d29b2c44Sab  *	If an extra DT_NULL slot is available, a debug message is
183d29b2c44Sab  *	issued, the slot is converted to its new use, and the argstate
184d29b2c44Sab  *	block state related to DT_NULL slots is updated.
185d29b2c44Sab  *
186d29b2c44Sab  *	if no extra DT_NULL slot is present, an error is issued and
187d29b2c44Sab  *	this routine does not return to the caller.
188d29b2c44Sab  */
189d29b2c44Sab static Word
190d29b2c44Sab convert_dt_null(ARGSTATE *argstate, Word d_tag, Xword d_val)
191d29b2c44Sab {
192d29b2c44Sab 	Conv_inv_buf_t inv_buf;
193d29b2c44Sab 	Word	ndx;
194d29b2c44Sab 	Dyn	*dyn;
195d29b2c44Sab 
196d29b2c44Sab 	/* If we lack an extra element, we can't continue */
197d29b2c44Sab 	if (argstate->dyn.num_null_ndx <= 1)
198d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
199d29b2c44Sab 		    EC_WORD(argstate->dyn.sec->sec_shndx),
200d29b2c44Sab 		    argstate->dyn.sec->sec_name);
201d29b2c44Sab 
202d29b2c44Sab 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
203d29b2c44Sab 	    EC_WORD(argstate->dyn.sec->sec_shndx), argstate->dyn.sec->sec_name,
204d29b2c44Sab 	    EC_WORD(argstate->dyn.null_ndx), conv_dyn_tag(d_tag,
205d29b2c44Sab 	    argstate->obj_state->os_ehdr->e_machine, 0, &inv_buf));
206d29b2c44Sab 
207d29b2c44Sab 	ndx = argstate->dyn.null_ndx;
208d29b2c44Sab 	dyn = &argstate->dyn.data[ndx];
209d29b2c44Sab 	dyn->d_tag = d_tag;
210d29b2c44Sab 	dyn->d_un.d_val = d_val;
211d29b2c44Sab 
212d29b2c44Sab 	/* Recompute the DT_NULL situation */
213d29b2c44Sab 	set_null_ndx(argstate);
214d29b2c44Sab 
215d29b2c44Sab 	return (ndx);
216d29b2c44Sab }
217d29b2c44Sab 
218d29b2c44Sab 
219d29b2c44Sab /*
220d29b2c44Sab  * Standard argument processing for dyn module
221d29b2c44Sab  *
222d29b2c44Sab  * entry
223d29b2c44Sab  *	obj_state, argc, argv - Standard command arguments
224d29b2c44Sab  *	argstate - Address of ARGSTATE block to be initialized
225d29b2c44Sab  *
226d29b2c44Sab  * exit:
227d29b2c44Sab  *	On success, *argstate is initialized. On error,
228d29b2c44Sab  *	an error is issued and this routine does not return.
229d29b2c44Sab  */
230d29b2c44Sab static void
231d29b2c44Sab process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
232d29b2c44Sab     ARGSTATE *argstate)
233d29b2c44Sab {
234d29b2c44Sab 	elfedit_getopt_state_t	getopt_state;
235d29b2c44Sab 	elfedit_getopt_ret_t	*getopt_ret;
236d29b2c44Sab 
237d29b2c44Sab 	bzero(argstate, sizeof (*argstate));
238d29b2c44Sab 	argstate->obj_state = obj_state;
239d29b2c44Sab 
240d29b2c44Sab 	elfedit_getopt_init(&getopt_state, &argc, &argv);
241d29b2c44Sab 
242d29b2c44Sab 	/* Add each new option to the options mask */
24355ef6355Sab 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
244d29b2c44Sab 		argstate->optmask |= getopt_ret->gor_idmask;
24555ef6355Sab 		switch (getopt_ret->gor_idmask) {
24655ef6355Sab 		case DYN_OPT_F_DYNNDX_VAL:
24755ef6355Sab 		case DYN_OPT_F_NEEDED:
24855ef6355Sab 			argstate->dyn_elt_str = getopt_ret->gor_value;
24955ef6355Sab 			break;
25055ef6355Sab 		}
25155ef6355Sab 	}
252d29b2c44Sab 
253d29b2c44Sab 	/* If there may be an arbitrary amount of output, use a pager */
254d29b2c44Sab 	if (argc == 0)
255d29b2c44Sab 		elfedit_pager_init();
256d29b2c44Sab 
257d29b2c44Sab 	/* Return the updated values of argc/argv */
258d29b2c44Sab 	argstate->argc = argc;
259d29b2c44Sab 	argstate->argv = argv;
260d29b2c44Sab 
261d29b2c44Sab 	/* Locate the dynamic section, and the assocated string table */
262d29b2c44Sab 	argstate->dyn.sec = elfedit_sec_getdyn(obj_state, &argstate->dyn.data,
263d29b2c44Sab 	    &argstate->dyn.num);
264d29b2c44Sab 	argstate->strsec = elfedit_sec_getstr(obj_state,
26555ef6355Sab 	    argstate->dyn.sec->sec_shdr->sh_link, 0);
266d29b2c44Sab 
267d29b2c44Sab 	/* Index of first DT_NULL */
268d29b2c44Sab 	set_null_ndx(argstate);
269d29b2c44Sab }
270d29b2c44Sab 
271d29b2c44Sab 
272d29b2c44Sab 
273d29b2c44Sab /*
274d29b2c44Sab  * Print ELF header values, taking the calling command, and output style
275d29b2c44Sab  * into account.
276d29b2c44Sab  *
277d29b2c44Sab  * entry:
278d29b2c44Sab  *	cmd - DYN_CMD_T_* value giving identify of caller
279d29b2c44Sab  *	autoprint - If True, output is only produced if the elfedit
280d29b2c44Sab  *		autoprint flag is set. If False, output is always produced.
281d29b2c44Sab  *	argstate - Argument state block
282d29b2c44Sab  *	print_type - Specifies which dynamic elements to display.
283d29b2c44Sab  *	ndx = If print_type is PRINT_DYN_T_NDX, displays the index specified.
284d29b2c44Sab  *		Otherwise ignored.
285d29b2c44Sab  */
286d29b2c44Sab typedef enum {
287d29b2c44Sab 	PRINT_DYN_T_ALL =	0,	/* Show all indexes */
288d29b2c44Sab 	PRINT_DYN_T_NDX =	1,	/* Show dynamic[arg] only */
289d29b2c44Sab 	PRINT_DYN_T_TAG =	2,	/* Show all elts with tag type */
290d29b2c44Sab 					/*	given by arg */
291d29b2c44Sab 	PRINT_DYN_T_RUNPATH =	3	/* Show all runpath/rpath elts */
292d29b2c44Sab 
293d29b2c44Sab } PRINT_DYN_T;
294d29b2c44Sab 
295d29b2c44Sab static void
296d29b2c44Sab print_dyn(DYN_CMD_T cmd, int autoprint, ARGSTATE *argstate,
297d29b2c44Sab     PRINT_DYN_T print_type, Word arg)
298d29b2c44Sab {
299d29b2c44Sab 	elfedit_outstyle_t	outstyle;
300d29b2c44Sab 	Conv_fmt_flags_t	flags_fmt_flags;
301c6c9aed4Sab 	Word	end_ndx, ndx, printed = 0;
302d29b2c44Sab 	Dyn	*dyn;
303d29b2c44Sab 	int	header_done = 0;
304d29b2c44Sab 	Xword	last_d_val;
30555ef6355Sab 	int	one_shot;
306d29b2c44Sab 
307d29b2c44Sab 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
308d29b2c44Sab 		return;
309d29b2c44Sab 
310d29b2c44Sab 	/*
311d29b2c44Sab 	 * Pick an output style. dyn:dump is required to use the default
312d29b2c44Sab 	 * style. The other commands use the current output style.
313d29b2c44Sab 	 */
314d29b2c44Sab 	outstyle = (cmd == DYN_CMD_T_DUMP) ?
315d29b2c44Sab 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
316d29b2c44Sab 
317d29b2c44Sab 	/*
318d29b2c44Sab 	 * When using the simple output style, omit the
319d29b2c44Sab 	 * brackets from around the values.
320d29b2c44Sab 	 */
321d29b2c44Sab 	flags_fmt_flags = (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) ?
322d29b2c44Sab 	    CONV_FMT_NOBKT : 0;
323d29b2c44Sab 
324c6c9aed4Sab 	/* Starting index */
325d29b2c44Sab 	if (print_type == PRINT_DYN_T_NDX) {
326d29b2c44Sab 		if (arg >= argstate->dyn.num)
327d29b2c44Sab 			return;		/* Out of range */
328d29b2c44Sab 		ndx = arg;
329d29b2c44Sab 	} else {
330d29b2c44Sab 		ndx = 0;
331d29b2c44Sab 	}
332d29b2c44Sab 
33355ef6355Sab 	/*
33455ef6355Sab 	 * one_shot is used by positional elements (e.g. DT_POSFLAG_1)
33555ef6355Sab 	 * to get the item following them to be shown even if they
33655ef6355Sab 	 * are not of the desired tag type or the count of elements
33755ef6355Sab 	 * to be displayed is only 1.
33855ef6355Sab 	 */
33955ef6355Sab 	one_shot = 0;
34055ef6355Sab 
341d29b2c44Sab 	dyn = &argstate->dyn.data[ndx];
342c6c9aed4Sab 
343c6c9aed4Sab 	/*
344c6c9aed4Sab 	 * Loop predicate explanation:
345c6c9aed4Sab 	 * Normally, we want to iterate from the starting index
346c6c9aed4Sab 	 * to the end. However, in the case of PRINT_DYN_T_NDX, we
347c6c9aed4Sab 	 * only want to display one item (ndx == arg) and then quit,
348c6c9aed4Sab 	 * with the exception that if we've been through the loop
349c6c9aed4Sab 	 * and encountered a one_shot situation, we want to continue
350c6c9aed4Sab 	 * iterating until the one-shot situation is cleared.
351c6c9aed4Sab 	 */
352c6c9aed4Sab 	for (; (ndx < argstate->dyn.num) &&
353c6c9aed4Sab 	    ((print_type != PRINT_DYN_T_NDX) || ((ndx == arg) || one_shot));
354c6c9aed4Sab 	    dyn++, ndx++) {
355d29b2c44Sab 		union {
356ba2be530Sab 			Conv_inv_buf_t		inv;
357d29b2c44Sab 			Conv_dyn_flag_buf_t	flag;
358d29b2c44Sab 			Conv_dyn_flag1_buf_t	flag1;
359d29b2c44Sab 			Conv_dyn_posflag1_buf_t	posflag1;
360d29b2c44Sab 			Conv_dyn_feature1_buf_t	feature1;
361d29b2c44Sab 		} c_buf;
362d29b2c44Sab 		const char	*name;
363d29b2c44Sab 
36455ef6355Sab 		if (one_shot) {
36555ef6355Sab 			one_shot = 0;
36655ef6355Sab 		} else {
36755ef6355Sab 			/*
36855ef6355Sab 			 * If we are only displaying certain tag types and
36955ef6355Sab 			 * this isn't one of those, move on to next element.
37055ef6355Sab 			 */
37155ef6355Sab 			switch (print_type) {
37255ef6355Sab 			case PRINT_DYN_T_TAG:
37355ef6355Sab 				if (dyn->d_tag != arg)
37455ef6355Sab 					continue;
37555ef6355Sab 				break;
37655ef6355Sab 			case PRINT_DYN_T_RUNPATH:
37755ef6355Sab 				if ((dyn->d_tag != DT_RPATH) &&
37855ef6355Sab 				    (dyn->d_tag != DT_RUNPATH))
37955ef6355Sab 					continue;
38055ef6355Sab 				break;
38155ef6355Sab 			}
382d29b2c44Sab 		}
383d29b2c44Sab 
384d29b2c44Sab 		/*
385d29b2c44Sab 		 * Print the information numerically, and if possible
386d29b2c44Sab 		 * as a string.
387d29b2c44Sab 		 */
388d29b2c44Sab 		name = NULL;
389d29b2c44Sab 		switch (dyn->d_tag) {
390d29b2c44Sab 		case DT_NULL:
391d29b2c44Sab 			if (!((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) &&
392d29b2c44Sab 			    (print_type == PRINT_DYN_T_ALL) &&
393d29b2c44Sab 			    (dyn->d_un.d_val == 0)))
394d29b2c44Sab 				break;
395d29b2c44Sab 			end_ndx = ndx;
396d29b2c44Sab 			/*
397d29b2c44Sab 			 * Special case: DT_NULLs can come in groups
398d29b2c44Sab 			 * that we prefer to reduce to a single line.
399d29b2c44Sab 			 */
400d29b2c44Sab 			while ((end_ndx < (argstate->dyn.num - 1)) &&
401d29b2c44Sab 			    ((dyn + 1)->d_tag == DT_NULL) &&
402d29b2c44Sab 			    ((dyn + 1)->d_un.d_val == 0)) {
403d29b2c44Sab 				dyn++;
404d29b2c44Sab 				end_ndx++;
405d29b2c44Sab 			}
406d29b2c44Sab 			if (header_done == 0) {
407d29b2c44Sab 				header_done = 1;
408d29b2c44Sab 				Elf_dyn_title(0);
409d29b2c44Sab 			}
410d29b2c44Sab 			Elf_dyn_null_entry(0, dyn, ndx, end_ndx);
411d29b2c44Sab 			ndx = end_ndx;
412d29b2c44Sab 			printed = 1;
413d29b2c44Sab 			last_d_val = dyn->d_un.d_val;
414d29b2c44Sab 			continue;
415d29b2c44Sab 
416d29b2c44Sab 		/*
417d29b2c44Sab 		 * Print the information numerically, and if possible
418d29b2c44Sab 		 * as a string.
419d29b2c44Sab 		 */
420d29b2c44Sab 		case DT_NEEDED:
421d29b2c44Sab 		case DT_SONAME:
422d29b2c44Sab 		case DT_FILTER:
423d29b2c44Sab 		case DT_AUXILIARY:
424d29b2c44Sab 		case DT_CONFIG:
425d29b2c44Sab 		case DT_RPATH:
426d29b2c44Sab 		case DT_RUNPATH:
427d29b2c44Sab 		case DT_USED:
428d29b2c44Sab 		case DT_DEPAUDIT:
429d29b2c44Sab 		case DT_AUDIT:
430d29b2c44Sab 		case DT_SUNW_AUXILIARY:
431d29b2c44Sab 		case DT_SUNW_FILTER:
432d29b2c44Sab 			name = elfedit_offset_to_str(argstate->strsec,
433d29b2c44Sab 			    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
434d29b2c44Sab 			break;
435d29b2c44Sab 
436d29b2c44Sab 		case DT_FLAGS:
437d29b2c44Sab 			name = conv_dyn_flag(dyn->d_un.d_val,
438d29b2c44Sab 			    flags_fmt_flags, &c_buf.flag);
439d29b2c44Sab 			break;
440d29b2c44Sab 		case DT_FLAGS_1:
441d29b2c44Sab 			name = conv_dyn_flag1(dyn->d_un.d_val,
442d29b2c44Sab 			    flags_fmt_flags, &c_buf.flag1);
443d29b2c44Sab 			break;
444d29b2c44Sab 		case DT_POSFLAG_1:
44555ef6355Sab 			/*
44655ef6355Sab 			 * If this is dyn:posflag1, and the print_type
44755ef6355Sab 			 * is PRINT_DYN_T_TAG, and the -needed option is
44855ef6355Sab 			 * used, then don't show any DT_POSFLAG_1 elements
44955ef6355Sab 			 * that are not followed by a DT_NEEDED element
45055ef6355Sab 			 * that matches the -needed string.
45155ef6355Sab 			 */
45255ef6355Sab 			if ((cmd == DYN_CMD_T_POSFLAG1) &&
45355ef6355Sab 			    (print_type == PRINT_DYN_T_TAG) &&
45455ef6355Sab 			    ((argstate->optmask & DYN_OPT_F_NEEDED) != 0) &&
45555ef6355Sab 			    ((ndx + 1) < argstate->dyn.num)) {
45655ef6355Sab 				Dyn *dyn1 = &argstate->dyn.data[ndx + 1];
45755ef6355Sab 
45855ef6355Sab 				if (dyn1->d_tag != DT_NEEDED)
45955ef6355Sab 					continue;
46055ef6355Sab 				name = elfedit_offset_to_str(argstate->strsec,
46155ef6355Sab 				    dyn1->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
46255ef6355Sab 				if (strncmp(name, argstate->dyn_elt_str,
46355ef6355Sab 				    strlen(argstate->dyn_elt_str)) != 0)
46455ef6355Sab 					continue;
46555ef6355Sab 			}
46655ef6355Sab 
467d29b2c44Sab 			name = conv_dyn_posflag1(dyn->d_un.d_val,
468d29b2c44Sab 			    flags_fmt_flags, &c_buf.posflag1);
46955ef6355Sab 			/*
47055ef6355Sab 			 * DT_POSFLAG_1 is a positional element that affects
47155ef6355Sab 			 * the following item. If using the default output
47255ef6355Sab 			 * style, then show the following item as well.
47355ef6355Sab 			 */
47455ef6355Sab 			one_shot = (outstyle == ELFEDIT_OUTSTYLE_DEFAULT);
475d29b2c44Sab 			break;
476d29b2c44Sab 		case DT_FEATURE_1:
477d29b2c44Sab 			name = conv_dyn_feature1(dyn->d_un.d_val,
478d29b2c44Sab 			    flags_fmt_flags, &c_buf.feature1);
479d29b2c44Sab 			break;
480d29b2c44Sab 		case DT_DEPRECATED_SPARC_REGISTER:
481d29b2c44Sab 			name = MSG_INTL(MSG_STR_DEPRECATED);
482d29b2c44Sab 			break;
483ba2be530Sab 		case DT_SUNW_LDMACH:
484ba2be530Sab 			name = conv_ehdr_mach((Half)dyn->d_un.d_val, 0,
485ba2be530Sab 			    &c_buf.inv);
486ba2be530Sab 			break;
487d29b2c44Sab 		}
488d29b2c44Sab 
489d29b2c44Sab 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
490d29b2c44Sab 			if (header_done == 0) {
491d29b2c44Sab 				header_done = 1;
492d29b2c44Sab 				Elf_dyn_title(0);
493d29b2c44Sab 			}
494d29b2c44Sab 			if (name == NULL)
495d29b2c44Sab 				name = MSG_ORIG(MSG_STR_EMPTY);
496d29b2c44Sab 			Elf_dyn_entry(0, dyn, ndx, name,
497d29b2c44Sab 			    argstate->obj_state->os_ehdr->e_machine);
498d29b2c44Sab 		} else {
499d29b2c44Sab 			/*
500d29b2c44Sab 			 * In simple or numeric mode under a print type
501d29b2c44Sab 			 * that is based on tag type rather than on index,
502*5c02782fSAli Bahrami 			 * if there are more than one qualifying tag, we
503*5c02782fSAli Bahrami 			 * want to skip printing redundant information.
504d29b2c44Sab 			 */
505d29b2c44Sab 			switch (print_type) {
506d29b2c44Sab 			case PRINT_DYN_T_TAG:
507*5c02782fSAli Bahrami 				switch (dyn->d_tag) {
508*5c02782fSAli Bahrami 				case DT_NEEDED:
509*5c02782fSAli Bahrami 					/* Multiple NEEDED entries are normal */
510*5c02782fSAli Bahrami 					break;
511*5c02782fSAli Bahrami 				case DT_POSFLAG_1:
512*5c02782fSAli Bahrami 					/*
513*5c02782fSAli Bahrami 					 * Positional flags don't count,
514*5c02782fSAli Bahrami 					 * because each one affects a different
515*5c02782fSAli Bahrami 					 * item. Don't skip those even if they
516*5c02782fSAli Bahrami 					 * have duplicate values.
517*5c02782fSAli Bahrami 					 */
518*5c02782fSAli Bahrami 					break;
519*5c02782fSAli Bahrami 				default:
520*5c02782fSAli Bahrami 					/*
521*5c02782fSAli Bahrami 					 * Anything else: If we've already
522*5c02782fSAli Bahrami 					 * printed this value, don't print
523*5c02782fSAli Bahrami 					 * it again.
524*5c02782fSAli Bahrami 					 */
525*5c02782fSAli Bahrami 					if (printed &&
526*5c02782fSAli Bahrami 					    (last_d_val == dyn->d_un.d_val))
527*5c02782fSAli Bahrami 						continue;
528*5c02782fSAli Bahrami 				}
52955ef6355Sab 				break;
530d29b2c44Sab 			case PRINT_DYN_T_RUNPATH:
531*5c02782fSAli Bahrami 				/*
532*5c02782fSAli Bahrami 				 * If we've already printed this value,
533*5c02782fSAli Bahrami 				 * don't print it again. This commonly
534*5c02782fSAli Bahrami 				 * happens when both DT_RPATH and DT_RUNPATH
535*5c02782fSAli Bahrami 				 * are present with the same value.
536*5c02782fSAli Bahrami 				 */
537d29b2c44Sab 				if (printed && (last_d_val == dyn->d_un.d_val))
538d29b2c44Sab 					continue;
53955ef6355Sab 				break;
540d29b2c44Sab 			}
541d29b2c44Sab 
542d29b2c44Sab 			if ((name != NULL) &&
543d29b2c44Sab 			    (outstyle == ELFEDIT_OUTSTYLE_SIMPLE)) {
544d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), name);
545d29b2c44Sab 			} else {
546d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
547d29b2c44Sab 				    dyn->d_un.d_val);
548d29b2c44Sab 			}
549d29b2c44Sab 		}
550d29b2c44Sab 		printed = 1;
551d29b2c44Sab 		last_d_val = dyn->d_un.d_val;
552d29b2c44Sab 	}
553d29b2c44Sab 
554d29b2c44Sab 	/*
555d29b2c44Sab 	 * If nothing was output under the print types that are
556d29b2c44Sab 	 * based on tag type, issue an error saying it doesn't exist.
557d29b2c44Sab 	 */
558d29b2c44Sab 	if (!printed) {
559d29b2c44Sab 		if (print_type == PRINT_DYN_T_TAG) {
560d29b2c44Sab 			Conv_inv_buf_t inv_buf;
561d29b2c44Sab 
562d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
563d29b2c44Sab 			    MSG_INTL(MSG_ERR_NODYNELT),
564d29b2c44Sab 			    EC_WORD(argstate->dyn.sec->sec_shndx),
565d29b2c44Sab 			    argstate->dyn.sec->sec_name, conv_dyn_tag(arg,
566d29b2c44Sab 			    argstate->obj_state->os_ehdr->e_machine,
567d29b2c44Sab 			    0, &inv_buf));
568d29b2c44Sab 		}
569d29b2c44Sab 
570d29b2c44Sab 		if (print_type == PRINT_DYN_T_RUNPATH)
571d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
572d29b2c44Sab 			    MSG_INTL(MSG_ERR_NORUNPATH),
573d29b2c44Sab 			    EC_WORD(argstate->dyn.sec->sec_shndx),
574d29b2c44Sab 			    argstate->dyn.sec->sec_name);
575d29b2c44Sab 	}
576d29b2c44Sab }
577d29b2c44Sab 
578d29b2c44Sab 
579d29b2c44Sab /*
58055ef6355Sab  * Determine the index(s) of the dynamic element(s) to be displayed and/or
58155ef6355Sab  * manipulated.
582d29b2c44Sab  *
583d29b2c44Sab  * entry:
584d29b2c44Sab  *	argstate - Argument state block
58555ef6355Sab  *	arg - If the command being called accepts a first plain argument
58655ef6355Sab  *		named 'elt' which is used to specify the dynamic element,
58755ef6355Sab  *		arg is the value of argv[0] for that command. If the
58855ef6355Sab  *		command does not accept an 'elt' argument and instead
58955ef6355Sab  *		implicitly assumes a tag type, arg is the constant string
59055ef6355Sab  *		for that type (e.g. "DT_POSFLAG_1").
591d29b2c44Sab  *	print_request - True if the command is to print the current
592d29b2c44Sab  *		value(s) and return without changing anything.
593d29b2c44Sab  *	print_type - Address of variable containing PRINT_DYN_T_
594d29b2c44Sab  *		code specifying how the elements will be displayed.
595d29b2c44Sab  *
596d29b2c44Sab  * exit:
59755ef6355Sab  *	If print_request is False: This routine always returns the index
59855ef6355Sab  *	of a single dynamic element. *print_type is set to PRINT_DYN_T_NDX.
59955ef6355Sab  *	The 'elt' argument as well as any modifier options (-dynndx, -needed)
60055ef6355Sab  *	are examined to determine this index. If there are no modifier options,
60155ef6355Sab  *	the dynamic section contains no element of the desired type, and there
60255ef6355Sab  *	is an extra DT_NULL element in the section, then a new element of
60355ef6355Sab  *	the desired type is created and its index returned. Otherwise an
60455ef6355Sab  *	error is issued.
605d29b2c44Sab  *
60655ef6355Sab  *	If print_request is True: If a modifier (-dynndx, -needed) was used,
60755ef6355Sab  *	*print_type is set to PRINT_DYN_T_NDX and the index of the
60855ef6355Sab  *	corresponding single dynamic element is returned. If no modifier
60955ef6355Sab  *	was used, *print_type is set to PRINT_DYN_T_TAG, and the tag
61055ef6355Sab  *	type code is returned.
611d29b2c44Sab  */
612d29b2c44Sab static Word
61355ef6355Sab arg_to_index(ARGSTATE *argstate, const char *arg,
614d29b2c44Sab     int print_request, PRINT_DYN_T *print_type)
615d29b2c44Sab {
616d29b2c44Sab 	Word	ndx, dt_value;
61755ef6355Sab 	Dyn	*dyn;
618d29b2c44Sab 
619d29b2c44Sab 
620d29b2c44Sab 	/* Assume we are returning an index, alter as needed below */
621d29b2c44Sab 	*print_type = PRINT_DYN_T_NDX;
622d29b2c44Sab 
62355ef6355Sab 	/*
62455ef6355Sab 	 * All the commands that accept the DYN_OPT_F_DYNNDX_ELT form
62555ef6355Sab 	 * of -dynndx require a plain argument named 'elt' as their first
62655ef6355Sab 	 * argument. -dynndx is a modifier that means that 'elt' is a
62755ef6355Sab 	 * simple numeric section index. Routines that accept this form
62855ef6355Sab 	 * of -dynndx are willing to handle any tag type, so all we need
62955ef6355Sab 	 * to check is that the value is in range.
63055ef6355Sab 	 */
63155ef6355Sab 	if ((argstate->optmask & DYN_OPT_F_DYNNDX_ELT) != 0)
63255ef6355Sab 		return ((Word) elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_ELT),
63355ef6355Sab 		    0, argstate->dyn.num - 1, NULL));
634d29b2c44Sab 
63555ef6355Sab 	/* arg is a DT_ tag type, not a numeric index */
636d29b2c44Sab 	dt_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_DT);
637d29b2c44Sab 
63855ef6355Sab 	/*
63955ef6355Sab 	 * Commands that accept the DYN_OPT_F_DYNNDX_VAL form  of
64055ef6355Sab 	 * dynndx do not accept the 'elt' argument. The index is a
64155ef6355Sab 	 * value that follows the option, and was saved in argstate by
64255ef6355Sab 	 * process_args(). Routines that accept this form of -dynndx
64355ef6355Sab 	 * require the specified element to have a specific tag type,
64455ef6355Sab 	 * so we test for this as well as for the index being in range.
64555ef6355Sab 	 */
64655ef6355Sab 	if ((argstate->optmask & DYN_OPT_F_DYNNDX_VAL) != 0) {
64755ef6355Sab 		ndx = ((Word) elfedit_atoui_range(argstate->dyn_elt_str,
64855ef6355Sab 		    MSG_ORIG(MSG_STR_INDEX), 0, argstate->dyn.num - 1, NULL));
64955ef6355Sab 		if (argstate->dyn.data[ndx].d_tag != dt_value) {
65055ef6355Sab 			Half	mach = argstate->obj_state->os_ehdr->e_machine;
65155ef6355Sab 			Conv_inv_buf_t	is, want;
65255ef6355Sab 
65355ef6355Sab 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_WRONGTAG),
65455ef6355Sab 			    EC_WORD(argstate->dyn.sec->sec_shndx),
65555ef6355Sab 			    argstate->dyn.sec->sec_name, ndx,
65655ef6355Sab 			    conv_dyn_tag(dt_value, mach, 0, &want),
65755ef6355Sab 			    conv_dyn_tag(argstate->dyn.data[ndx].d_tag, mach,
65855ef6355Sab 			    0, &is));
65955ef6355Sab 		}
66055ef6355Sab 		return (ndx);
66155ef6355Sab 	}
66255ef6355Sab 
663d29b2c44Sab 	/*
664d29b2c44Sab 	 * If this is a printing request, then we let print_dyn() show
665d29b2c44Sab 	 * all the items with this tag type.
666d29b2c44Sab 	 */
667d29b2c44Sab 	if (print_request) {
668d29b2c44Sab 		*print_type = PRINT_DYN_T_TAG;
669d29b2c44Sab 		return (dt_value);
670d29b2c44Sab 	}
671d29b2c44Sab 
67255ef6355Sab 	/*
67355ef6355Sab 	 * Commands that accept -needed are looking for the dt_value element
67455ef6355Sab 	 * (usually DT_POSFLAG_1) that immediately preceeds the DT_NEEDED
67555ef6355Sab 	 * element with the string given by argstate->dyn_elt_str.
67655ef6355Sab 	 */
67755ef6355Sab 	if ((argstate->optmask & DYN_OPT_F_NEEDED) != 0) {
67855ef6355Sab 		Word	retndx = argstate->dyn.num;	/* Out of range value */
67955ef6355Sab 		const char	*name;
68055ef6355Sab 		size_t		len;
68155ef6355Sab 
68255ef6355Sab 		len = strlen(argstate->dyn_elt_str);
68355ef6355Sab 		for (ndx = 0, dyn = argstate->dyn.data;
68455ef6355Sab 		    ndx < argstate->dyn.num; dyn++, ndx++) {
68555ef6355Sab 			/*
68655ef6355Sab 			 * If the immediately preceeding item has the
68755ef6355Sab 			 * tag type we're looking for, and the current item
68855ef6355Sab 			 * is a DT_NEEDED with a string that matches,
68955ef6355Sab 			 * then the preceeding item is the one we want.
69055ef6355Sab 			 */
69155ef6355Sab 			if ((dyn->d_tag == DT_NEEDED) &&
69255ef6355Sab 			    (ndx > 0) && (retndx == (ndx - 1))) {
69355ef6355Sab 				name = elfedit_offset_to_str(argstate->strsec,
69455ef6355Sab 				    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
69555ef6355Sab 
69655ef6355Sab 				if (strncmp(name,
69755ef6355Sab 				    argstate->dyn_elt_str, len) == 0)
69855ef6355Sab 					return (retndx);
69955ef6355Sab 				continue;
70055ef6355Sab 			}
70155ef6355Sab 
70255ef6355Sab 			/*
70355ef6355Sab 			 * If the current item has the tag type we're
70455ef6355Sab 			 * looking for, make it our current candidate.
70555ef6355Sab 			 * If the next item is a DT_NEEDED with the right
70655ef6355Sab 			 * string value, we'll use it then.
70755ef6355Sab 			 */
70855ef6355Sab 			if (dyn->d_tag == dt_value)
70955ef6355Sab 				retndx = ndx;
71055ef6355Sab 		}
71155ef6355Sab 
71255ef6355Sab 		/* If we get here, no matching DT_NEEDED was found */
71355ef6355Sab 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NEEDEDNOMATCH),
71455ef6355Sab 		    EC_WORD(argstate->dyn.sec->sec_shndx),
71555ef6355Sab 		    argstate->dyn.sec->sec_name, argstate->dyn_elt_str);
71655ef6355Sab 	}
71755ef6355Sab 
718d29b2c44Sab 	/* Locate the first entry with the given tag type */
719d29b2c44Sab 	for (ndx = 0; ndx < argstate->dyn.num; ndx++) {
720d29b2c44Sab 		if (argstate->dyn.data[ndx].d_tag == dt_value) {
721d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
722d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_DT2NDX),
723d29b2c44Sab 			    EC_WORD(argstate->dyn.sec->sec_shndx),
724d29b2c44Sab 			    argstate->dyn.sec->sec_name, EC_WORD(ndx), arg);
725d29b2c44Sab 			return (ndx);
726d29b2c44Sab 		}
727d29b2c44Sab 	}
728d29b2c44Sab 
729d29b2c44Sab 	/* Not found. Can we create one? */
730d29b2c44Sab 	if (argstate->dyn.num_null_ndx > 1)
731d29b2c44Sab 		return (convert_dt_null(argstate, dt_value, 0));
732d29b2c44Sab 
733d29b2c44Sab 	/* No room to create one, so we're out of options and must fail */
734d29b2c44Sab 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODTELT),
735d29b2c44Sab 	    EC_WORD(argstate->dyn.sec->sec_shndx),
736d29b2c44Sab 	    argstate->dyn.sec->sec_name, arg);
737d29b2c44Sab 
738d29b2c44Sab 	/*NOTREACHED*/
739d29b2c44Sab 	return (0);		/* For lint */
740d29b2c44Sab }
741d29b2c44Sab 
742d29b2c44Sab 
743d29b2c44Sab /*
744d29b2c44Sab  * Called by cmd_body() for dyn:value. Implements the core functionality
745d29b2c44Sab  * for that command.
746d29b2c44Sab  *
747d29b2c44Sab  * This routine expects that both the index and value arguments are
748d29b2c44Sab  * present.
749d29b2c44Sab  */
750d29b2c44Sab static elfedit_cmdret_t
751d29b2c44Sab cmd_body_value(ARGSTATE *argstate, Word *ret_ndx)
752d29b2c44Sab {
753d29b2c44Sab 	elfedit_section_t	*dynsec = argstate->dyn.sec;
754d29b2c44Sab 	elfedit_section_t	*strsec = argstate->strsec;
755d29b2c44Sab 	elfedit_dyn_elt_t	strpad_elt;
756d29b2c44Sab 	Word	i;
757d29b2c44Sab 	Dyn	*dyn = argstate->dyn.data;
758d29b2c44Sab 	Word	numdyn = argstate->dyn.num;
75955ef6355Sab 	int	minus_add, minus_s, minus_dynndx;
760d29b2c44Sab 	Word	arg1, tmp_val;
761d29b2c44Sab 	Xword	arg2;
762d29b2c44Sab 	int	arg2_known = 1;
763d29b2c44Sab 
76455ef6355Sab 	minus_add = ((argstate->optmask & DYN_OPT_F_ADD) != 0);
76555ef6355Sab 	minus_s = ((argstate->optmask & DYN_OPT_F_STRVAL) != 0);
76655ef6355Sab 	minus_dynndx = ((argstate->optmask & DYN_OPT_F_DYNNDX_ELT) != 0);
767d29b2c44Sab 
768d29b2c44Sab 	elfedit_dyn_elt_init(&strpad_elt);
769d29b2c44Sab 
770d29b2c44Sab 	/*
771d29b2c44Sab 	 * The first argument is an index if -dynndx is used, and is a
772d29b2c44Sab 	 * tag value otherwise.
773d29b2c44Sab 	 */
774d29b2c44Sab 	arg1 = minus_dynndx ?
775d29b2c44Sab 	    elfedit_atoui_range(argstate->argv[0], MSG_ORIG(MSG_STR_ELT),
776d29b2c44Sab 	    0, numdyn - 1, NULL) :
777d29b2c44Sab 	    elfedit_atoconst(argstate->argv[0], ELFEDIT_CONST_DT);
778d29b2c44Sab 
779d29b2c44Sab 	if (minus_s) {
780d29b2c44Sab 		/*
781d29b2c44Sab 		 * Don't allow the user to specify -s when manipulating a
782d29b2c44Sab 		 * DT_SUNW_STRPAD element. Since DT_SUNW_STRPAD is used to
783d29b2c44Sab 		 * manage the extra space used for strings, this would break
784d29b2c44Sab 		 * our ability to add the string.
785d29b2c44Sab 		 */
786d29b2c44Sab 		if ((!minus_dynndx && (arg1 == DT_SUNW_STRPAD)) ||
787d29b2c44Sab 		    (minus_dynndx && (dyn[arg1].d_tag == DT_SUNW_STRPAD)))
788d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_ERR,
789d29b2c44Sab 			    MSG_INTL(MSG_ERR_STRPADSTRVAL),
790d29b2c44Sab 			    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
791d29b2c44Sab 
792d29b2c44Sab 		/* Locate DT_SUNW_STRPAD element if present */
793d29b2c44Sab 		strpad_elt.dn_dyn.d_un.d_val = 0;
794d29b2c44Sab 		(void) elfedit_dynstr_getpad(argstate->dyn.sec, &strpad_elt);
795d29b2c44Sab 
796d29b2c44Sab 		/*
797d29b2c44Sab 		 * Look up the string: If the user specified the -dynndx
798d29b2c44Sab 		 * -option, then we will insert it if possible, and
799d29b2c44Sab 		 * fail with an error if not. However, if they did not
800d29b2c44Sab 		 * specify -dynndx, we want to look up the string if it is
801d29b2c44Sab 		 * already there, but defer the insertion. The reason for
802d29b2c44Sab 		 * this is that we may have to grab an unused DT_NULL element
803d29b2c44Sab 		 * below, and if there are none available, we won't want
804d29b2c44Sab 		 * to have modified the string table.
805d29b2c44Sab 		 *
806d29b2c44Sab 		 * This isn't a problem, because if the string isn't
807d29b2c44Sab 		 * in the string table, it can't be used by a dynamic element.
808d29b2c44Sab 		 * Hence, we don't need to insert it to know that there is
809d29b2c44Sab 		 * no match.
810d29b2c44Sab 		 */
811d29b2c44Sab 		if (minus_dynndx == 0) {
812d29b2c44Sab 			if (elfedit_sec_findstr(strsec,
813d29b2c44Sab 			    strpad_elt.dn_dyn.d_un.d_val, argstate->argv[1],
814d29b2c44Sab 			    &tmp_val) == 0) {
815d29b2c44Sab 				arg2_known = 0;
816d29b2c44Sab 			} else {
817d29b2c44Sab 				arg2 = tmp_val;
818d29b2c44Sab 			}
819d29b2c44Sab 		} else {
820d29b2c44Sab 			arg2 = elfedit_dynstr_insert(dynsec, strsec,
821d29b2c44Sab 			    &strpad_elt, argstate->argv[1]);
822d29b2c44Sab 		}
823d29b2c44Sab 	} else {		/* Argument 2 is an integer */
824d29b2c44Sab 		arg2 = elfedit_atoui(argstate->argv[1], NULL);
825d29b2c44Sab 	}
826d29b2c44Sab 
827d29b2c44Sab 
828d29b2c44Sab 	if (!minus_dynndx && !(minus_add && !arg2_known)) {
829d29b2c44Sab 		/*
830d29b2c44Sab 		 * Search the dynamic section and see if an item with the
831d29b2c44Sab 		 * specified tag value already exists. We can reduce this
832d29b2c44Sab 		 * to a simple update of an existing value if -add is not
833d29b2c44Sab 		 * specified or the existing d_un value matches the new one.
834d29b2c44Sab 		 *
835d29b2c44Sab 		 * In either of these cases, we will change arg1 to be the
836d29b2c44Sab 		 * index, and set minus_dynndx, causing the simple update to
837d29b2c44Sab 		 * happen immediately below.
838d29b2c44Sab 		 */
839d29b2c44Sab 		for (i = 0; i < numdyn; i++) {
840d29b2c44Sab 			if ((dyn[i].d_tag == arg1) &&
841d29b2c44Sab 			    (!minus_add || (dyn[i].d_un.d_val == arg2))) {
842d29b2c44Sab 				arg1 = i;
843d29b2c44Sab 				minus_dynndx = 1;
844d29b2c44Sab 				break;
845d29b2c44Sab 			}
846d29b2c44Sab 		}
847d29b2c44Sab 	}
848d29b2c44Sab 
849d29b2c44Sab 	/*
850d29b2c44Sab 	 * If -dynndx is used, then this is a relatively simple
851d29b2c44Sab 	 * operation, as we simply write over the specified index.
852d29b2c44Sab 	 */
853d29b2c44Sab 	if (minus_dynndx) {
854d29b2c44Sab 		/*
855d29b2c44Sab 		 * If we held back from inserting a new string into
856d29b2c44Sab 		 * the dynstr above, we insert it now, because we
857d29b2c44Sab 		 * have a slot in the dynamic section, and we need
858d29b2c44Sab 		 * the string offset ot finish.
859d29b2c44Sab 		 */
860d29b2c44Sab 		if (!arg2_known)
861d29b2c44Sab 			arg2 = elfedit_dynstr_insert(dynsec, strsec,
862d29b2c44Sab 			    &strpad_elt, argstate->argv[1]);
863d29b2c44Sab 
864d29b2c44Sab 		*ret_ndx = arg1;
865d29b2c44Sab 		if (dyn[arg1].d_un.d_val == arg2) {
866d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
867d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_X_OK),
868d29b2c44Sab 			    dynsec->sec_shndx, dynsec->sec_name,
869d29b2c44Sab 			    EC_WORD(arg1), EC_XWORD(arg2));
870d29b2c44Sab 			return (ELFEDIT_CMDRET_NONE);
871d29b2c44Sab 		} else {
872d29b2c44Sab 			/* Warn if setting DT_NULL value to non-zero */
873d29b2c44Sab 			if ((dyn[arg1].d_tag == DT_NULL) && (arg2 != 0))
874d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
875d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_DTNULLVALUE),
876d29b2c44Sab 				    dynsec->sec_shndx, dynsec->sec_name,
877d29b2c44Sab 				    EC_WORD(arg1), EC_XWORD(arg2));
878d29b2c44Sab 
879d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
880d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_X_CHG),
881d29b2c44Sab 			    dynsec->sec_shndx, dynsec->sec_name,
882d29b2c44Sab 			    EC_WORD(arg1), EC_XWORD(dyn[arg1].d_un.d_val),
883d29b2c44Sab 			    EC_XWORD(arg2));
884d29b2c44Sab 			dyn[arg1].d_un.d_val = arg2;
885d29b2c44Sab 			return (ELFEDIT_CMDRET_MOD);
886d29b2c44Sab 		}
887d29b2c44Sab 	}
888d29b2c44Sab 
889d29b2c44Sab 	/*
890d29b2c44Sab 	 * We need a new slot in the dynamic section. If we can't have
891d29b2c44Sab 	 * one, then we fail.
892d29b2c44Sab 	 */
893d29b2c44Sab 	if (argstate->dyn.num_null_ndx <= 1)
894d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
895d29b2c44Sab 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
896d29b2c44Sab 
897d29b2c44Sab 	/*
898d29b2c44Sab 	 * If we still need to insert a new string into the dynstr,
899d29b2c44Sab 	 * then it is safe now, because if we succeed, we know that
900d29b2c44Sab 	 * there is an available slot to receive it. If we fail, we
901d29b2c44Sab 	 * haven't claimed the extra slot yet, and it will be unharmed.
902d29b2c44Sab 	 */
903d29b2c44Sab 	if (!arg2_known)
904d29b2c44Sab 		arg2 = elfedit_dynstr_insert(dynsec, strsec,
905d29b2c44Sab 		    &strpad_elt, argstate->argv[1]);
906d29b2c44Sab 
907d29b2c44Sab 	/* Use an extra DT_NULL slot and enter the new element */
908d29b2c44Sab 	*ret_ndx = convert_dt_null(argstate, arg1, arg2);
909d29b2c44Sab 	return (ELFEDIT_CMDRET_MOD);
910d29b2c44Sab }
911d29b2c44Sab 
912d29b2c44Sab 
913d29b2c44Sab 
914d29b2c44Sab /*
915d29b2c44Sab  * Called by cmd_body() for dyn:runpath. Implements the core functionality
916d29b2c44Sab  * for that command.
917d29b2c44Sab  *
918d29b2c44Sab  * History Lesson And Strategy:
919d29b2c44Sab  *
920d29b2c44Sab  * This routine handles both DT_RPATH and DT_RUNPATH entries, altering
921d29b2c44Sab  * either or both if they are present.
922d29b2c44Sab  *
923d29b2c44Sab  * The original SYSV ABI only had DT_RPATH, and the runtime loader used
924d29b2c44Sab  * it to search for things in the following order:
925d29b2c44Sab  *
926d29b2c44Sab  *	DT_RPATH, LD_LIBRARY_PATH, defaults
927d29b2c44Sab  *
928d29b2c44Sab  * Solaris did not follow this rule, an extremely rare deviation from
929d29b2c44Sab  * the ABI. Environment variables should supercede everything else,
930d29b2c44Sab  * otherwise they are not very useful. This decision was made at the
931d29b2c44Sab  * very beginning of the SunOS 5.x development, so we have always
932d29b2c44Sab  * deviated from the ABI and and instead search in the order
933d29b2c44Sab  *
934d29b2c44Sab  *	LD_LIBRARY_PATH, DT_RPATH, defaults
935d29b2c44Sab  *
936d29b2c44Sab  * Other Unix variants initially followed the ABI, but in recent years
937d29b2c44Sab  * have come to agree with the early Solaris folks that it was a mistake.
938d29b2c44Sab  * Hence, DT_RUNPATH was invented, with the search order:
939d29b2c44Sab  *
940d29b2c44Sab  *	LD_LIBRARY_PATH, DT_RUNPATH, defaults
941d29b2c44Sab  *
942d29b2c44Sab  * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both
943d29b2c44Sab  * are present (which does happen), we set them both to the new
944d29b2c44Sab  * value. If either one is present, we set that one. If neither is
945d29b2c44Sab  * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH, but
946d29b2c44Sab  * not a DT_RPATH, to conserve available slots for other uses.
947d29b2c44Sab  */
948d29b2c44Sab static elfedit_cmdret_t
949d29b2c44Sab cmd_body_runpath(ARGSTATE *argstate)
950d29b2c44Sab {
951d29b2c44Sab 	elfedit_section_t	*dynsec = argstate->dyn.sec;
952d29b2c44Sab 	elfedit_section_t	*strsec = argstate->strsec;
953d29b2c44Sab 	elfedit_dyn_elt_t	rpath_elt;
954d29b2c44Sab 	elfedit_dyn_elt_t	runpath_elt;
955d29b2c44Sab 	elfedit_dyn_elt_t	strpad_elt;
956d29b2c44Sab 	Word			i;
957d29b2c44Sab 	Dyn			*dyn = argstate->dyn.data;
958d29b2c44Sab 	Word			numdyn = argstate->dyn.num;
959d29b2c44Sab 
960d29b2c44Sab 	/* Go through the tags and gather what we need */
961d29b2c44Sab 	elfedit_dyn_elt_init(&rpath_elt);
962d29b2c44Sab 	elfedit_dyn_elt_init(&runpath_elt);
963d29b2c44Sab 	elfedit_dyn_elt_init(&strpad_elt);
964d29b2c44Sab 	for (i = 0; i < numdyn; i++) {
965d29b2c44Sab 		switch (dyn[i].d_tag) {
966d29b2c44Sab 		case DT_RPATH:
967d29b2c44Sab 			elfedit_dyn_elt_save(&rpath_elt, i, &dyn[i]);
968d29b2c44Sab 			break;
969d29b2c44Sab 
970d29b2c44Sab 		case DT_RUNPATH:
971d29b2c44Sab 			elfedit_dyn_elt_save(&runpath_elt, i, &dyn[i]);
972d29b2c44Sab 			break;
973d29b2c44Sab 
974d29b2c44Sab 		case DT_SUNW_STRPAD:
975d29b2c44Sab 			elfedit_dyn_elt_save(&strpad_elt, i, &dyn[i]);
976d29b2c44Sab 			break;
977d29b2c44Sab 		}
978d29b2c44Sab 	}
979d29b2c44Sab 
980d29b2c44Sab 	/*  Do we have an available dynamic section entry to use? */
981d29b2c44Sab 	if (rpath_elt.dn_seen || runpath_elt.dn_seen) {
982d29b2c44Sab 		/*
983d29b2c44Sab 		 * We have seen a DT_RPATH, or a DT_RUNPATH, or both.
984d29b2c44Sab 		 * If all of these have the same string as the desired
985d29b2c44Sab 		 * new value, then we don't need to alter anything and can
986d29b2c44Sab 		 * simply return. Otherwise, we'll modify them all to have
987d29b2c44Sab 		 * the new string (below).
988d29b2c44Sab 		 */
989d29b2c44Sab 		if ((!rpath_elt.dn_seen ||
990d29b2c44Sab 		    (strcmp(elfedit_dyn_offset_to_str(strsec, &rpath_elt),
991d29b2c44Sab 		    argstate->argv[0]) == 0)) &&
992d29b2c44Sab 		    (!runpath_elt.dn_seen ||
993d29b2c44Sab 		    (strcmp(elfedit_dyn_offset_to_str(strsec, &runpath_elt),
994d29b2c44Sab 		    argstate->argv[0]) == 0))) {
995d29b2c44Sab 			if (rpath_elt.dn_seen)
996d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
997d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_OLDRPATHOK),
998d29b2c44Sab 				    EC_WORD(dynsec->sec_shndx),
999d29b2c44Sab 				    dynsec->sec_name, EC_WORD(rpath_elt.dn_ndx),
1000d29b2c44Sab 				    elfedit_atoconst_value_to_str(
1001d29b2c44Sab 				    ELFEDIT_CONST_DT, DT_RPATH, 1));
1002d29b2c44Sab 			if (runpath_elt.dn_seen)
1003d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1004d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_OLDRPATHOK),
1005d29b2c44Sab 				    EC_WORD(dynsec->sec_shndx),
1006d29b2c44Sab 				    dynsec->sec_name,
1007d29b2c44Sab 				    EC_WORD(runpath_elt.dn_ndx),
1008d29b2c44Sab 				    elfedit_atoconst_value_to_str(
1009d29b2c44Sab 				    ELFEDIT_CONST_DT, DT_RUNPATH, 1));
1010d29b2c44Sab 			return (ELFEDIT_CMDRET_NONE);
1011d29b2c44Sab 		}
1012d29b2c44Sab 	} else if (argstate->dyn.num_null_ndx <= 1) {
1013d29b2c44Sab 		/*
1014d29b2c44Sab 		 * There is no DT_RPATH or DT_RUNPATH in the dynamic array,
1015d29b2c44Sab 		 * and there are no extra DT_NULL entries that we can
1016d29b2c44Sab 		 * convert into one. We cannot proceed.
1017d29b2c44Sab 		 */
1018d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
1019d29b2c44Sab 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
1020d29b2c44Sab 	}
1021d29b2c44Sab 
1022d29b2c44Sab 	/* Does the string exist in the table already, or can we add it? */
1023d29b2c44Sab 	rpath_elt.dn_dyn.d_un.d_val = runpath_elt.dn_dyn.d_un.d_val =
1024d29b2c44Sab 	    elfedit_dynstr_insert(dynsec, strsec, &strpad_elt,
1025d29b2c44Sab 	    argstate->argv[0]);
1026d29b2c44Sab 
1027d29b2c44Sab 	/* Update DT_RPATH entry if present */
1028d29b2c44Sab 	if (rpath_elt.dn_seen) {
1029d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_PREVRPATH),
1030d29b2c44Sab 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name,
1031d29b2c44Sab 		    EC_WORD(rpath_elt.dn_ndx),
1032d29b2c44Sab 		    elfedit_atoconst_value_to_str(
1033d29b2c44Sab 		    ELFEDIT_CONST_DT, DT_RPATH, 1),
1034d29b2c44Sab 		    elfedit_dyn_offset_to_str(strsec, &rpath_elt));
1035d29b2c44Sab 		dyn[rpath_elt.dn_ndx] = rpath_elt.dn_dyn;
1036d29b2c44Sab 	}
1037d29b2c44Sab 
1038d29b2c44Sab 	/*
1039d29b2c44Sab 	 * Update the DT_RUNPATH entry in the dynamic section, if present.
1040d29b2c44Sab 	 * If one is not present, and there is also no DT_RPATH, then
1041d29b2c44Sab 	 * we use a spare DT_NULL entry to create a new DT_RUNPATH.
1042d29b2c44Sab 	 */
1043d29b2c44Sab 	if (runpath_elt.dn_seen || !rpath_elt.dn_seen) {
1044d29b2c44Sab 		if (runpath_elt.dn_seen) {
1045d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
1046d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_PREVRPATH),
1047d29b2c44Sab 			    EC_WORD(dynsec->sec_shndx), dynsec->sec_name,
1048d29b2c44Sab 			    EC_WORD(runpath_elt.dn_ndx),
1049d29b2c44Sab 			    elfedit_atoconst_value_to_str(
1050d29b2c44Sab 			    ELFEDIT_CONST_DT, DT_RUNPATH, 1),
1051d29b2c44Sab 			    elfedit_dyn_offset_to_str(strsec, &runpath_elt));
1052d29b2c44Sab 			dyn[runpath_elt.dn_ndx] = runpath_elt.dn_dyn;
1053d29b2c44Sab 		} else {	/* Using a spare DT_NULL entry */
1054d29b2c44Sab 			(void) convert_dt_null(argstate, DT_RUNPATH,
1055d29b2c44Sab 			    runpath_elt.dn_dyn.d_un.d_val);
1056d29b2c44Sab 		}
1057d29b2c44Sab 	}
1058d29b2c44Sab 
1059d29b2c44Sab 	return (ELFEDIT_CMDRET_MOD);
1060d29b2c44Sab }
1061d29b2c44Sab 
1062d29b2c44Sab 
1063d29b2c44Sab 
1064d29b2c44Sab /*
1065d29b2c44Sab  * Argument processing for the bitmask commands. Convert the arguments
1066d29b2c44Sab  * to integer form, apply -and/-cmp/-or, and return the resulting value.
1067d29b2c44Sab  *
1068d29b2c44Sab  * entry:
1069d29b2c44Sab  *	argstate - Argument state block
1070d29b2c44Sab  *	orig - Value of original bitmask
1071d29b2c44Sab  *	const_type - ELFEDIT_CONST_* value for type of constants
1072d29b2c44Sab  */
1073d29b2c44Sab static Word
1074d29b2c44Sab flag_bitop(ARGSTATE *argstate, Word orig, elfedit_const_t const_type)
1075d29b2c44Sab {
1076d29b2c44Sab 	Word flags = 0;
1077d29b2c44Sab 	int i;
1078d29b2c44Sab 
1079d29b2c44Sab 	/* Collect the arguments */
1080d29b2c44Sab 	for (i = 0; i < argstate->argc; i++)
1081d29b2c44Sab 		flags |= (Word) elfedit_atoconst(argstate->argv[i], const_type);
1082d29b2c44Sab 
1083d29b2c44Sab 	/* Complement the value? */
1084d29b2c44Sab 	if (argstate->optmask & DYN_OPT_F_CMP)
1085d29b2c44Sab 		flags = ~flags;
1086d29b2c44Sab 
1087d29b2c44Sab 	/* Perform any requested bit operations */
1088d29b2c44Sab 	if (argstate->optmask & DYN_OPT_F_AND)
1089d29b2c44Sab 		flags &= orig;
1090d29b2c44Sab 	else if (argstate->optmask & DYN_OPT_F_OR)
1091d29b2c44Sab 		flags |= orig;
1092d29b2c44Sab 
1093d29b2c44Sab 	return (flags);
1094d29b2c44Sab }
1095d29b2c44Sab 
1096d29b2c44Sab 
1097d29b2c44Sab 
1098d29b2c44Sab /*
1099d29b2c44Sab  * Common body for the dyn: module commands. These commands
1100d29b2c44Sab  * share a large amount of common behavior, so it is convenient
1101d29b2c44Sab  * to centralize things and use the cmd argument to handle the
1102d29b2c44Sab  * small differences.
1103d29b2c44Sab  *
1104d29b2c44Sab  * entry:
1105d29b2c44Sab  *	cmd - One of the DYN_CMD_T_* constants listed above, specifying
1106d29b2c44Sab  *		which command to implement.
1107d29b2c44Sab  *	obj_state, argc, argv - Standard command arguments
1108d29b2c44Sab  */
1109d29b2c44Sab static elfedit_cmdret_t
1110d29b2c44Sab cmd_body(DYN_CMD_T cmd, elfedit_obj_state_t *obj_state,
1111d29b2c44Sab     int argc, const char *argv[])
1112d29b2c44Sab {
1113d29b2c44Sab 	ARGSTATE		argstate;
1114d29b2c44Sab 	Dyn			*dyn;
1115d29b2c44Sab 	const char		*dyn_name;
1116d29b2c44Sab 	Word			dyn_ndx, dyn_num, null_ndx;
1117d29b2c44Sab 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
1118d29b2c44Sab 	PRINT_DYN_T		print_type = PRINT_DYN_T_ALL;
1119d29b2c44Sab 	Word			ndx;
1120d29b2c44Sab 	int			print_only = 0;
1121d29b2c44Sab 	int			do_autoprint = 1;
1122d29b2c44Sab 
1123d29b2c44Sab 	/* Process the optional arguments */
1124d29b2c44Sab 	process_args(obj_state, argc, argv, &argstate);
1125d29b2c44Sab 
1126d29b2c44Sab 	dyn = argstate.dyn.data;
1127d29b2c44Sab 	dyn_num = argstate.dyn.num;
1128d29b2c44Sab 	dyn_name = argstate.dyn.sec->sec_name;
1129d29b2c44Sab 	dyn_ndx = argstate.dyn.sec->sec_shndx;
1130d29b2c44Sab 
1131d29b2c44Sab 	/* Check number of arguments, gather information */
1132d29b2c44Sab 	switch (cmd) {
1133d29b2c44Sab 	case DYN_CMD_T_DUMP:
1134d29b2c44Sab 		/* dyn:dump can accept an optional index argument */
1135d29b2c44Sab 		if (argstate.argc > 1)
1136d29b2c44Sab 			elfedit_command_usage();
1137d29b2c44Sab 		print_only = 1;
1138d29b2c44Sab 		if (argstate.argc == 1)
1139d29b2c44Sab 			ndx = arg_to_index(&argstate, argstate.argv[0],
114055ef6355Sab 			    print_only, &print_type);
1141d29b2c44Sab 		break;
1142d29b2c44Sab 
1143d29b2c44Sab 	case DYN_CMD_T_TAG:
1144d29b2c44Sab 		print_only = (argstate.argc != 2);
1145d29b2c44Sab 		if (argstate.argc > 0) {
1146d29b2c44Sab 			if (argstate.argc > 2)
1147d29b2c44Sab 				elfedit_command_usage();
1148d29b2c44Sab 			ndx = arg_to_index(&argstate, argstate.argv[0],
114955ef6355Sab 			    print_only, &print_type);
1150d29b2c44Sab 		}
1151d29b2c44Sab 		break;
1152d29b2c44Sab 
1153d29b2c44Sab 	case DYN_CMD_T_VALUE:
1154d29b2c44Sab 		print_only = (argstate.argc != 2);
1155d29b2c44Sab 		if (argstate.argc > 2)
1156d29b2c44Sab 			elfedit_command_usage();
1157d29b2c44Sab 		if (argstate.argc > 0) {
1158d29b2c44Sab 			if (print_only) {
1159d29b2c44Sab 				ndx = arg_to_index(&argstate, argstate.argv[0],
1160d29b2c44Sab 				    print_only, &print_type);
1161d29b2c44Sab 			} else {
1162d29b2c44Sab 				print_type = PRINT_DYN_T_NDX;
1163d29b2c44Sab 			}
1164d29b2c44Sab 		}
1165d29b2c44Sab 		break;
1166d29b2c44Sab 
1167d29b2c44Sab 	case DYN_CMD_T_DELETE:
1168d29b2c44Sab 		if ((argstate.argc < 1) || (argstate.argc > 2))
1169d29b2c44Sab 			elfedit_command_usage();
1170d29b2c44Sab 		ndx = arg_to_index(&argstate, argstate.argv[0],
1171d29b2c44Sab 		    0, &print_type);
1172d29b2c44Sab 		do_autoprint = 0;
1173d29b2c44Sab 		break;
1174d29b2c44Sab 
1175d29b2c44Sab 	case DYN_CMD_T_MOVE:
1176d29b2c44Sab 		if ((argstate.argc < 2) || (argstate.argc > 3))
1177d29b2c44Sab 			elfedit_command_usage();
1178d29b2c44Sab 		ndx = arg_to_index(&argstate, argstate.argv[0],
117955ef6355Sab 		    0, &print_type);
1180d29b2c44Sab 		do_autoprint = 0;
1181d29b2c44Sab 		break;
1182d29b2c44Sab 
1183d29b2c44Sab 	case DYN_CMD_T_RUNPATH:
1184d29b2c44Sab 		if (argstate.argc > 1)
1185d29b2c44Sab 			elfedit_command_usage();
1186d29b2c44Sab 		/*
1187d29b2c44Sab 		 * dyn:runpath does not accept an explicit index
1188d29b2c44Sab 		 * argument, so we implicitly only show the DT_RPATH and
1189d29b2c44Sab 		 * DT_RUNPATH elements.
1190d29b2c44Sab 		 */
1191d29b2c44Sab 		print_type = PRINT_DYN_T_RUNPATH;
1192d29b2c44Sab 		print_only = (argstate.argc == 0);
1193d29b2c44Sab 		break;
1194d29b2c44Sab 
1195d29b2c44Sab 	case DYN_CMD_T_POSFLAG1:
1196d29b2c44Sab 		print_only = (argstate.argc == 0);
1197d29b2c44Sab 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1198d29b2c44Sab 		    ELFEDIT_CONST_DT, DT_POSFLAG_1, 1),
119955ef6355Sab 		    print_only, &print_type);
1200d29b2c44Sab 		break;
1201d29b2c44Sab 
1202d29b2c44Sab 	case DYN_CMD_T_FLAGS:
1203d29b2c44Sab 		print_only = (argstate.argc == 0);
1204d29b2c44Sab 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1205d29b2c44Sab 		    ELFEDIT_CONST_DT, DT_FLAGS, 1),
120655ef6355Sab 		    print_only, &print_type);
1207d29b2c44Sab 		break;
1208d29b2c44Sab 
1209d29b2c44Sab 	case DYN_CMD_T_FLAGS1:
1210d29b2c44Sab 		print_only = (argstate.argc == 0);
1211d29b2c44Sab 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1212d29b2c44Sab 		    ELFEDIT_CONST_DT, DT_FLAGS_1, 1),
121355ef6355Sab 		    print_only, &print_type);
1214d29b2c44Sab 		break;
1215d29b2c44Sab 
1216d29b2c44Sab 	case DYN_CMD_T_FEATURE1:
1217d29b2c44Sab 		print_only = (argstate.argc == 0);
1218d29b2c44Sab 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1219d29b2c44Sab 		    ELFEDIT_CONST_DT, DT_FEATURE_1, 1),
122055ef6355Sab 		    print_only, &print_type);
1221d29b2c44Sab 		break;
1222d29b2c44Sab 
1223d29b2c44Sab 	case DYN_CMD_T_CHECKSUM:
1224d29b2c44Sab 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1225d29b2c44Sab 		    ELFEDIT_CONST_DT, DT_CHECKSUM, 1),
122655ef6355Sab 		    print_only, &print_type);
1227d29b2c44Sab 		break;
1228d29b2c44Sab 
1229ba2be530Sab 	case DYN_CMD_T_SUNW_LDMACH:
1230ba2be530Sab 		if (argstate.argc > 1)
1231ba2be530Sab 			elfedit_command_usage();
1232ba2be530Sab 		print_only = (argstate.argc == 0);
1233ba2be530Sab 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1234ba2be530Sab 		    ELFEDIT_CONST_DT, DT_SUNW_LDMACH, 1),
123555ef6355Sab 		    print_only, &print_type);
1236ba2be530Sab 		break;
1237ba2be530Sab 
1238d29b2c44Sab 	default:
1239d29b2c44Sab 		/* Note expected: All commands should have been caught above */
1240d29b2c44Sab 		elfedit_command_usage();
1241d29b2c44Sab 		break;
1242d29b2c44Sab 	}
1243d29b2c44Sab 
1244d29b2c44Sab 
1245d29b2c44Sab 	/* If this is a request to print current values, do it and return */
1246d29b2c44Sab 	if (print_only) {
1247d29b2c44Sab 		print_dyn(cmd, 0, &argstate, print_type, ndx);
1248d29b2c44Sab 		return (ELFEDIT_CMDRET_NONE);
1249d29b2c44Sab 	}
1250d29b2c44Sab 
1251d29b2c44Sab 
1252d29b2c44Sab 	switch (cmd) {
1253d29b2c44Sab 		/*
1254d29b2c44Sab 		 * DYN_CMD_T_DUMP can't get here: It is a print-only
1255d29b2c44Sab 		 * command.
1256d29b2c44Sab 		 */
1257d29b2c44Sab 
1258d29b2c44Sab 	case DYN_CMD_T_TAG:
1259d29b2c44Sab 		{
1260d29b2c44Sab 			Conv_inv_buf_t	inv_buf1, inv_buf2;
1261d29b2c44Sab 			Half	mach = argstate.obj_state->os_ehdr->e_machine;
1262d29b2c44Sab 			Word d_tag = (Word) elfedit_atoconst(argstate.argv[1],
1263d29b2c44Sab 			    ELFEDIT_CONST_DT);
1264d29b2c44Sab 
1265d29b2c44Sab 			if (dyn[ndx].d_tag == d_tag) {
1266d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1267d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_OK),
1268d29b2c44Sab 				    dyn_ndx,
1269d29b2c44Sab 				    dyn_name, EC_WORD(ndx),
1270d29b2c44Sab 				    conv_dyn_tag(d_tag, mach, 0, &inv_buf1));
1271d29b2c44Sab 			} else {
1272d29b2c44Sab 				Word orig_d_tag = dyn[ndx].d_tag;
1273d29b2c44Sab 
1274d29b2c44Sab 				ret = ELFEDIT_CMDRET_MOD;
1275d29b2c44Sab 				dyn[ndx].d_tag = d_tag;
1276d29b2c44Sab 
1277d29b2c44Sab 				/*
1278d29b2c44Sab 				 * Update null termination index. Warn if we
1279d29b2c44Sab 				 * just clobbered the only DT_NULL termination
1280d29b2c44Sab 				 * for the array.
1281d29b2c44Sab 				 */
1282d29b2c44Sab 				null_ndx = argstate.dyn.null_ndx;
1283d29b2c44Sab 				set_null_ndx(&argstate);
1284d29b2c44Sab 				if ((argstate.dyn.null_ndx >=
1285d29b2c44Sab 				    argstate.dyn.num) &&
1286d29b2c44Sab 				    (null_ndx != argstate.dyn.null_ndx))
1287d29b2c44Sab 					elfedit_msg(ELFEDIT_MSG_DEBUG,
1288d29b2c44Sab 					    MSG_INTL(MSG_DEBUG_NULLTERM),
1289d29b2c44Sab 					    dyn_ndx, dyn_name,
1290d29b2c44Sab 					    EC_WORD(ndx),
1291d29b2c44Sab 					    conv_dyn_tag(d_tag, mach,
1292d29b2c44Sab 					    0, &inv_buf1));
1293d29b2c44Sab 
1294d29b2c44Sab 				/*
1295d29b2c44Sab 				 * Warning if
1296d29b2c44Sab 				 *	- Inserting a DT_NULL cuts off following
1297d29b2c44Sab 				 *		non-null elements.
1298d29b2c44Sab 				 *	- Inserting a non-DT_NULL after the
1299d29b2c44Sab 				 *		first null element, will be
1300d29b2c44Sab 				 *		ignored by rtld.
1301d29b2c44Sab 				 */
1302d29b2c44Sab 				if (d_tag == DT_NULL) {
1303d29b2c44Sab 					if ((ndx + 1) < null_ndx)
1304d29b2c44Sab 						elfedit_msg(ELFEDIT_MSG_DEBUG,
1305d29b2c44Sab 						    MSG_INTL(MSG_DEBUG_NULCLIP),
1306d29b2c44Sab 						    dyn_ndx, dyn_name,
1307d29b2c44Sab 						    EC_WORD(ndx),
1308d29b2c44Sab 						    conv_dyn_tag(d_tag, mach,
1309d29b2c44Sab 						    0, &inv_buf1));
1310d29b2c44Sab 				} else {
1311d29b2c44Sab 					if ((ndx + 1) > argstate.dyn.null_ndx)
1312d29b2c44Sab 						elfedit_msg(ELFEDIT_MSG_DEBUG,
1313d29b2c44Sab 						    MSG_INTL(MSG_DEBUG_NULHIDE),
1314d29b2c44Sab 						    dyn_ndx, dyn_name,
1315d29b2c44Sab 						    EC_WORD(ndx),
1316d29b2c44Sab 						    conv_dyn_tag(d_tag, mach,
1317d29b2c44Sab 						    0, &inv_buf1));
1318d29b2c44Sab 				}
1319d29b2c44Sab 
1320d29b2c44Sab 				/* Debug message that we changed it */
1321d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1322d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_CHG),
1323d29b2c44Sab 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1324d29b2c44Sab 				    conv_dyn_tag(orig_d_tag, mach, 0,
1325d29b2c44Sab 				    &inv_buf1),
1326d29b2c44Sab 				    conv_dyn_tag(d_tag, mach, 0, &inv_buf2));
1327d29b2c44Sab 			}
1328d29b2c44Sab 		}
1329d29b2c44Sab 		break;
1330d29b2c44Sab 
1331d29b2c44Sab 	case DYN_CMD_T_VALUE:
1332d29b2c44Sab 		ret = cmd_body_value(&argstate, &ndx);
1333d29b2c44Sab 		break;
1334d29b2c44Sab 
1335d29b2c44Sab 	case DYN_CMD_T_DELETE:
1336d29b2c44Sab 		{
1337d29b2c44Sab 			Word cnt = (argstate.argc == 1) ? 1 :
1338d29b2c44Sab 			    (Word) elfedit_atoui_range(argstate.argv[1],
1339d29b2c44Sab 			    MSG_ORIG(MSG_STR_COUNT), 1, dyn_num - ndx, NULL);
1340d29b2c44Sab 			const char *msg_prefix =
1341d29b2c44Sab 			    elfedit_sec_msgprefix(argstate.dyn.sec);
1342d29b2c44Sab 
1343d29b2c44Sab 			elfedit_array_elts_delete(msg_prefix, argstate.dyn.data,
1344d29b2c44Sab 			    sizeof (Dyn), dyn_num, ndx, cnt);
1345d29b2c44Sab 			ret = ELFEDIT_CMDRET_MOD;
1346d29b2c44Sab 		}
1347d29b2c44Sab 		break;
1348d29b2c44Sab 
1349d29b2c44Sab 	case DYN_CMD_T_MOVE:
1350d29b2c44Sab 		{
1351d29b2c44Sab 			Dyn	save;
1352d29b2c44Sab 			Word	cnt;
1353d29b2c44Sab 			Word	dstndx;
1354d29b2c44Sab 			const char *msg_prefix =
1355d29b2c44Sab 			    elfedit_sec_msgprefix(argstate.dyn.sec);
1356d29b2c44Sab 
1357d29b2c44Sab 			dstndx = (Word)
1358d29b2c44Sab 			    elfedit_atoui_range(argstate.argv[1],
1359d29b2c44Sab 			    MSG_ORIG(MSG_STR_DST_INDEX), 0, dyn_num - 1,
1360d29b2c44Sab 			    NULL);
1361d29b2c44Sab 			if (argstate.argc == 2) {
1362d29b2c44Sab 				cnt = 1;
1363d29b2c44Sab 			} else {
1364d29b2c44Sab 				cnt = (Word) elfedit_atoui_range(
1365d29b2c44Sab 				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
1366d29b2c44Sab 				    1, dyn_num, NULL);
1367d29b2c44Sab 			}
1368d29b2c44Sab 			elfedit_array_elts_move(msg_prefix, argstate.dyn.data,
1369d29b2c44Sab 			    sizeof (save), dyn_num, ndx, dstndx, cnt, &save);
1370d29b2c44Sab 			ret = ELFEDIT_CMDRET_MOD;
1371d29b2c44Sab 		}
1372d29b2c44Sab 		break;
1373d29b2c44Sab 
1374d29b2c44Sab 
1375d29b2c44Sab 	case DYN_CMD_T_RUNPATH:
1376d29b2c44Sab 		ret = cmd_body_runpath(&argstate);
1377d29b2c44Sab 		break;
1378d29b2c44Sab 
1379d29b2c44Sab 	case DYN_CMD_T_POSFLAG1:
1380d29b2c44Sab 		{
1381d29b2c44Sab 			Conv_dyn_posflag1_buf_t buf1, buf2;
1382d29b2c44Sab 			Word flags;
1383d29b2c44Sab 
1384d29b2c44Sab 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1385d29b2c44Sab 			    ELFEDIT_CONST_DF_P1);
1386d29b2c44Sab 
1387d29b2c44Sab 			/* Set the value */
1388d29b2c44Sab 			if (dyn[ndx].d_un.d_val == flags) {
1389d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1390d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1391d29b2c44Sab 				    dyn_name, EC_WORD(ndx),
1392d29b2c44Sab 				    conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0,
1393d29b2c44Sab 				    &buf1));
1394d29b2c44Sab 			} else {
1395d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1396d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_CHG),
1397d29b2c44Sab 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1398d29b2c44Sab 				    conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0,
1399d29b2c44Sab 				    &buf1),
1400d29b2c44Sab 				    conv_dyn_posflag1(flags, 0, &buf2));
1401d29b2c44Sab 				ret = ELFEDIT_CMDRET_MOD;
1402d29b2c44Sab 				dyn[ndx].d_un.d_val = flags;
1403d29b2c44Sab 			}
1404d29b2c44Sab 		}
1405d29b2c44Sab 		break;
1406d29b2c44Sab 
1407d29b2c44Sab 	case DYN_CMD_T_FLAGS:
1408d29b2c44Sab 		{
1409d29b2c44Sab 			Conv_dyn_flag_buf_t buf1, buf2;
1410d29b2c44Sab 			Word flags;
1411d29b2c44Sab 
1412d29b2c44Sab 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1413d29b2c44Sab 			    ELFEDIT_CONST_DF);
1414d29b2c44Sab 
1415d29b2c44Sab 			/* Set the value */
1416d29b2c44Sab 			if (dyn[ndx].d_un.d_val == flags) {
1417d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1418d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1419d29b2c44Sab 				    dyn_name, EC_WORD(ndx),
1420d29b2c44Sab 				    conv_dyn_flag(dyn[ndx].d_un.d_val, 0,
1421d29b2c44Sab 				    &buf1));
1422d29b2c44Sab 			} else {
1423d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1424d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_CHG),
1425d29b2c44Sab 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1426d29b2c44Sab 				    conv_dyn_flag(dyn[ndx].d_un.d_val, 0,
1427d29b2c44Sab 				    &buf1),
1428d29b2c44Sab 				    conv_dyn_flag(flags, 0, &buf2));
1429d29b2c44Sab 				ret = ELFEDIT_CMDRET_MOD;
1430d29b2c44Sab 				dyn[ndx].d_un.d_val = flags;
1431d29b2c44Sab 			}
1432d29b2c44Sab 		}
1433d29b2c44Sab 		break;
1434d29b2c44Sab 
1435d29b2c44Sab 	case DYN_CMD_T_FLAGS1:
1436d29b2c44Sab 		{
1437d29b2c44Sab 			Conv_dyn_flag1_buf_t buf1, buf2;
1438d29b2c44Sab 			Word flags1;
1439d29b2c44Sab 
1440d29b2c44Sab 			flags1 = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1441d29b2c44Sab 			    ELFEDIT_CONST_DF_1);
1442d29b2c44Sab 
1443d29b2c44Sab 			/* Set the value */
1444d29b2c44Sab 			if (dyn[ndx].d_un.d_val == flags1) {
1445d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1446d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1447d29b2c44Sab 				    dyn_name, EC_WORD(ndx),
1448d29b2c44Sab 				    conv_dyn_flag1(dyn[ndx].d_un.d_val,
1449d29b2c44Sab 				    0, &buf1));
1450d29b2c44Sab 			} else {
1451d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1452d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_CHG),
1453d29b2c44Sab 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1454d29b2c44Sab 				    conv_dyn_flag1(dyn[ndx].d_un.d_val,
1455d29b2c44Sab 				    0, &buf1),
1456d29b2c44Sab 				    conv_dyn_flag1(flags1, 0, &buf2));
1457d29b2c44Sab 				ret = ELFEDIT_CMDRET_MOD;
1458d29b2c44Sab 				dyn[ndx].d_un.d_val = flags1;
1459d29b2c44Sab 			}
1460d29b2c44Sab 		}
1461d29b2c44Sab 		break;
1462d29b2c44Sab 
1463d29b2c44Sab 	case DYN_CMD_T_FEATURE1:
1464d29b2c44Sab 		{
1465d29b2c44Sab 			Conv_dyn_feature1_buf_t buf1, buf2;
1466d29b2c44Sab 			Word flags;
1467d29b2c44Sab 
1468d29b2c44Sab 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1469d29b2c44Sab 			    ELFEDIT_CONST_DTF_1);
1470d29b2c44Sab 
1471d29b2c44Sab 			/* Set the value */
1472d29b2c44Sab 			if (dyn[ndx].d_un.d_val == flags) {
1473d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1474d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1475d29b2c44Sab 				    dyn_name, EC_WORD(ndx),
1476d29b2c44Sab 				    conv_dyn_feature1(dyn[ndx].d_un.d_val, 0,
1477d29b2c44Sab 				    &buf1));
1478d29b2c44Sab 			} else {
1479d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1480d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_S_CHG),
1481d29b2c44Sab 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1482d29b2c44Sab 				    conv_dyn_feature1(dyn[ndx].d_un.d_val, 0,
1483d29b2c44Sab 				    &buf1),
1484d29b2c44Sab 				    conv_dyn_feature1(flags, 0, &buf2));
1485d29b2c44Sab 				ret = ELFEDIT_CMDRET_MOD;
1486d29b2c44Sab 				dyn[ndx].d_un.d_val = flags;
1487d29b2c44Sab 			}
1488d29b2c44Sab 		}
1489d29b2c44Sab 		break;
1490d29b2c44Sab 
1491d29b2c44Sab 	case DYN_CMD_T_CHECKSUM:
1492d29b2c44Sab 		{
1493d29b2c44Sab 			long checksum = elf_checksum(obj_state->os_elf);
1494d29b2c44Sab 
1495d29b2c44Sab 			/* Set the value */
1496d29b2c44Sab 			if (dyn[ndx].d_un.d_val == checksum) {
1497d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1498d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_X_OK), dyn_ndx,
1499d29b2c44Sab 				    dyn_name, EC_WORD(ndx), EC_XWORD(checksum));
1500d29b2c44Sab 			} else {
1501d29b2c44Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1502d29b2c44Sab 				    MSG_INTL(MSG_DEBUG_X_CHG),
1503d29b2c44Sab 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1504d29b2c44Sab 				    EC_XWORD(dyn[ndx].d_un.d_val),
1505d29b2c44Sab 				    EC_XWORD(checksum));
1506d29b2c44Sab 				ret = ELFEDIT_CMDRET_MOD;
1507d29b2c44Sab 				dyn[ndx].d_un.d_val = checksum;
1508d29b2c44Sab 			}
1509d29b2c44Sab 
1510d29b2c44Sab 		}
1511ba2be530Sab 		break;
1512ba2be530Sab 
1513ba2be530Sab 	case DYN_CMD_T_SUNW_LDMACH:
1514ba2be530Sab 		{
1515ba2be530Sab 			Conv_inv_buf_t buf1, buf2;
1516ba2be530Sab 			Half ldmach;
1517ba2be530Sab 
1518ba2be530Sab 			ldmach = (Half) elfedit_atoconst(argstate.argv[0],
1519ba2be530Sab 			    ELFEDIT_CONST_EM);
1520ba2be530Sab 
1521ba2be530Sab 			/* Set the value */
1522ba2be530Sab 			if (dyn[ndx].d_un.d_val == ldmach) {
1523ba2be530Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1524ba2be530Sab 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1525ba2be530Sab 				    dyn_name, EC_WORD(ndx),
1526ba2be530Sab 				    conv_ehdr_mach(dyn[ndx].d_un.d_val, 0,
1527ba2be530Sab 				    &buf1));
1528ba2be530Sab 			} else {
1529ba2be530Sab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1530ba2be530Sab 				    MSG_INTL(MSG_DEBUG_S_CHG),
1531ba2be530Sab 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1532ba2be530Sab 				    conv_ehdr_mach(dyn[ndx].d_un.d_val, 0,
1533ba2be530Sab 				    &buf1),
1534ba2be530Sab 				    conv_ehdr_mach(ldmach, 0, &buf2));
1535ba2be530Sab 				ret = ELFEDIT_CMDRET_MOD;
1536ba2be530Sab 				dyn[ndx].d_un.d_val = ldmach;
1537ba2be530Sab 			}
1538ba2be530Sab 		}
1539ba2be530Sab 		break;
1540ba2be530Sab 
1541d29b2c44Sab 	}
1542d29b2c44Sab 
1543d29b2c44Sab 	/*
1544d29b2c44Sab 	 * If we modified the dynamic section header, tell libelf.
1545d29b2c44Sab 	 */
1546d29b2c44Sab 	if (ret == ELFEDIT_CMDRET_MOD)
1547d29b2c44Sab 		elfedit_modified_data(argstate.dyn.sec);
1548d29b2c44Sab 
1549d29b2c44Sab 	/* Do autoprint */
1550d29b2c44Sab 	if (do_autoprint)
1551d29b2c44Sab 		print_dyn(cmd, 1, &argstate, print_type, ndx);
1552d29b2c44Sab 
1553d29b2c44Sab 	return (ret);
1554d29b2c44Sab }
1555d29b2c44Sab 
1556d29b2c44Sab 
1557d29b2c44Sab 
1558d29b2c44Sab /*
1559d29b2c44Sab  * Command completion functions for the commands
1560d29b2c44Sab  */
1561d29b2c44Sab 
1562d29b2c44Sab /*
1563d29b2c44Sab  * Command completion for the first argument, which specifies
1564d29b2c44Sab  * the dynamic element to use. Examines the options to see if
1565d29b2c44Sab  * -dynndx is present, and if not, supplies the completion
1566d29b2c44Sab  * strings for argument 1.
1567d29b2c44Sab  */
1568d29b2c44Sab /*ARGSUSED*/
1569d29b2c44Sab static void
1570d29b2c44Sab cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1571d29b2c44Sab     const char *argv[], int num_opt)
1572d29b2c44Sab {
1573d29b2c44Sab 	elfedit_section_t	*cache;
1574d29b2c44Sab 	Dyn			*dyn;
1575d29b2c44Sab 	Word			i;
1576d29b2c44Sab 	const char		*s;
1577d29b2c44Sab 	char			*s2;
1578d29b2c44Sab 	char			buf[128];
1579d29b2c44Sab 
1580d29b2c44Sab 	/* Make sure it's the first argument */
1581d29b2c44Sab 	if ((argc - num_opt) != 1)
1582d29b2c44Sab 		return;
1583d29b2c44Sab 
1584d29b2c44Sab 	/* Is -dynndx present? If so, we don't complete tag types */
1585d29b2c44Sab 	for (i = 0; i < num_opt; i++)
1586d29b2c44Sab 		if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0)
1587d29b2c44Sab 			return;
1588d29b2c44Sab 
1589d29b2c44Sab 	/*
1590d29b2c44Sab 	 * If there is no object, or if there is no dynamic section,
1591d29b2c44Sab 	 * then supply all possible names.
1592d29b2c44Sab 	 */
1593d29b2c44Sab 	if ((obj_state == NULL) || (obj_state->os_dynndx == SHN_UNDEF)) {
1594d29b2c44Sab 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT);
1595d29b2c44Sab 		return;
1596d29b2c44Sab 	}
1597d29b2c44Sab 
1598d29b2c44Sab 	/* Supply completions for the tags present in the dynamic section */
1599d29b2c44Sab 	cache = &obj_state->os_secarr[obj_state->os_dynndx];
1600d29b2c44Sab 	dyn = (Dyn *) cache->sec_data->d_buf;
1601d29b2c44Sab 	i = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize;
1602d29b2c44Sab 	for (; i-- > 0; dyn++) {
1603d29b2c44Sab 		s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_DT,
1604d29b2c44Sab 		    dyn->d_tag, 0);
1605d29b2c44Sab 		if (s == NULL)
1606d29b2c44Sab 			continue;
1607d29b2c44Sab 		elfedit_cpl_match(cpldata, s, 1);
1608d29b2c44Sab 
1609d29b2c44Sab 		/*
1610d29b2c44Sab 		 * To get the informal tag names that are lowercase
1611d29b2c44Sab 		 * and lack the leading DT_, we copy the string we
1612d29b2c44Sab 		 * have into a buffer and process it.
1613d29b2c44Sab 		 */
1614d29b2c44Sab 		if (strlen(s) < 3)
1615d29b2c44Sab 			continue;
1616d29b2c44Sab 		(void) strlcpy(buf, s + 3, sizeof (buf));
1617d29b2c44Sab 		for (s2 = buf; *s2 != '\0'; s2++)
1618d29b2c44Sab 			if (isupper(*s2))
1619d29b2c44Sab 				*s2 = tolower(*s2);
1620d29b2c44Sab 		elfedit_cpl_match(cpldata, buf, 1);
1621d29b2c44Sab 	}
1622d29b2c44Sab }
1623d29b2c44Sab 
1624d29b2c44Sab 
1625d29b2c44Sab /*ARGSUSED*/
1626d29b2c44Sab static void
1627d29b2c44Sab cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1628d29b2c44Sab     const char *argv[], int num_opt)
1629d29b2c44Sab {
1630d29b2c44Sab 	/* First argument */
1631d29b2c44Sab 	if ((argc - num_opt) == 1) {
1632d29b2c44Sab 		cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
1633d29b2c44Sab 		return;
1634d29b2c44Sab 	}
1635d29b2c44Sab 
1636d29b2c44Sab 	/* The second argument is always a tag value */
1637d29b2c44Sab 	if ((argc - num_opt) == 2)
1638d29b2c44Sab 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT);
1639d29b2c44Sab }
1640d29b2c44Sab 
1641d29b2c44Sab /*ARGSUSED*/
1642d29b2c44Sab static void
1643d29b2c44Sab cpl_posflag1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1644d29b2c44Sab     const char *argv[], int num_opt)
1645d29b2c44Sab {
164655ef6355Sab 	/*
164755ef6355Sab 	 * dyn:posflag1 accepts two mutually exclusive options that have
164855ef6355Sab 	 * a corresponding value argument: -dynndx and -needed. If we
164955ef6355Sab 	 * are being called to supply options for the value, handle that here.
165055ef6355Sab 	 */
165155ef6355Sab 	if ((num_opt > 1) && (argc == num_opt)) {
165255ef6355Sab 		elfedit_section_t	*dynsec, *strsec;
165355ef6355Sab 		const char		*opt = argv[num_opt - 2];
165455ef6355Sab 		dyn_opt_t		type;
165555ef6355Sab 		Dyn			*dyn;
165655ef6355Sab 		Word			i, num;
165755ef6355Sab 
165855ef6355Sab 		/*
165955ef6355Sab 		 * If there is no object available, or if the object has no
166055ef6355Sab 		 * dynamic section, then there is nothing to report.
166155ef6355Sab 		 */
166255ef6355Sab 		if ((obj_state == NULL) || obj_state->os_dynndx == SHN_UNDEF)
166355ef6355Sab 			return;
166455ef6355Sab 
166555ef6355Sab 		/*
166655ef6355Sab 		 * Determine which option it is, bail if it isn't one of
166755ef6355Sab 		 * the ones we are concerned with.
166855ef6355Sab 		 */
166955ef6355Sab 		if ((strcmp(opt, MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0))
167055ef6355Sab 			type = DYN_OPT_F_NEEDED;
167155ef6355Sab 		else if ((strcmp(opt, MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0))
167255ef6355Sab 			type = DYN_OPT_F_DYNNDX_VAL;
167355ef6355Sab 		else
167455ef6355Sab 			return;
167555ef6355Sab 
167655ef6355Sab 		dynsec = elfedit_sec_getdyn(obj_state, &dyn, &num);
167755ef6355Sab 		switch (type) {
167855ef6355Sab 		case DYN_OPT_F_NEEDED:
167955ef6355Sab 			strsec = elfedit_sec_getstr(obj_state,
168055ef6355Sab 			    dynsec->sec_shdr->sh_link, 0);
168155ef6355Sab 			for (; num-- > 0; dyn++)
168255ef6355Sab 				if (dyn->d_tag == DT_NEEDED)
168355ef6355Sab 					elfedit_cpl_match(cpldata,
168455ef6355Sab 					    elfedit_offset_to_str(strsec,
168555ef6355Sab 					    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG,
168655ef6355Sab 					    0), 0);
168755ef6355Sab 			break;
168855ef6355Sab 
168955ef6355Sab 		case DYN_OPT_F_DYNNDX_VAL:
169055ef6355Sab 			for (i = 0; i < num; i++, dyn++)
169155ef6355Sab 				if (dyn->d_tag == DT_POSFLAG_1)
169255ef6355Sab 					elfedit_cpl_ndx(cpldata, i);
169355ef6355Sab 			break;
169455ef6355Sab 		}
169555ef6355Sab 		return;
169655ef6355Sab 	}
169755ef6355Sab 
1698d29b2c44Sab 	/* This routine allows multiple flags to be specified */
1699d29b2c44Sab 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_P1);
1700d29b2c44Sab }
1701d29b2c44Sab 
1702d29b2c44Sab /*ARGSUSED*/
1703d29b2c44Sab static void
1704d29b2c44Sab cpl_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1705d29b2c44Sab     const char *argv[], int num_opt)
1706d29b2c44Sab {
1707d29b2c44Sab 	/* This routine allows multiple flags to be specified */
1708d29b2c44Sab 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF);
1709d29b2c44Sab }
1710d29b2c44Sab 
1711d29b2c44Sab /*ARGSUSED*/
1712d29b2c44Sab static void
1713d29b2c44Sab cpl_flags1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1714d29b2c44Sab     const char *argv[], int num_opt)
1715d29b2c44Sab {
1716d29b2c44Sab 	/* This routine allows multiple flags to be specified */
1717d29b2c44Sab 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_1);
1718d29b2c44Sab }
1719d29b2c44Sab 
1720d29b2c44Sab /*ARGSUSED*/
1721d29b2c44Sab static void
1722d29b2c44Sab cpl_feature1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1723d29b2c44Sab     const char *argv[], int num_opt)
1724d29b2c44Sab {
1725d29b2c44Sab 	/* This routine allows multiple flags to be specified */
1726d29b2c44Sab 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DTF_1);
1727d29b2c44Sab }
1728d29b2c44Sab 
1729ba2be530Sab /*ARGSUSED*/
1730ba2be530Sab static void
1731ba2be530Sab cpl_sunw_ldmach(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1732ba2be530Sab     const char *argv[], int num_opt)
1733ba2be530Sab {
1734ba2be530Sab 	/*
1735ba2be530Sab 	 * This command doesn't accept options, so num_opt should be
1736ba2be530Sab 	 * 0. This is a defensive measure, in case that should change.
1737ba2be530Sab 	 */
1738ba2be530Sab 	argc -= num_opt;
1739ba2be530Sab 	argv += num_opt;
1740ba2be530Sab 
1741ba2be530Sab 	if (argc == 1)
1742ba2be530Sab 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_EM);
1743ba2be530Sab }
1744ba2be530Sab 
1745d29b2c44Sab 
1746d29b2c44Sab /*
1747d29b2c44Sab  * Implementation functions for the commands
1748d29b2c44Sab  */
1749d29b2c44Sab static elfedit_cmdret_t
1750d29b2c44Sab cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1751d29b2c44Sab {
1752d29b2c44Sab 	return (cmd_body(DYN_CMD_T_DUMP, obj_state, argc, argv));
1753d29b2c44Sab }
1754d29b2c44Sab 
1755d29b2c44Sab static elfedit_cmdret_t
1756d29b2c44Sab cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1757d29b2c44Sab {
1758d29b2c44Sab 	return (cmd_body(DYN_CMD_T_TAG, obj_state, argc, argv));
1759d29b2c44Sab }
1760d29b2c44Sab 
1761d29b2c44Sab static elfedit_cmdret_t
1762d29b2c44Sab cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1763d29b2c44Sab {
1764d29b2c44Sab 	return (cmd_body(DYN_CMD_T_VALUE, obj_state, argc, argv));
1765d29b2c44Sab }
1766d29b2c44Sab 
1767d29b2c44Sab static elfedit_cmdret_t
1768d29b2c44Sab cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1769d29b2c44Sab {
1770d29b2c44Sab 	return (cmd_body(DYN_CMD_T_DELETE, obj_state, argc, argv));
1771d29b2c44Sab }
1772d29b2c44Sab 
1773d29b2c44Sab static elfedit_cmdret_t
1774d29b2c44Sab cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1775d29b2c44Sab {
1776d29b2c44Sab 	return (cmd_body(DYN_CMD_T_MOVE, obj_state, argc, argv));
1777d29b2c44Sab }
1778d29b2c44Sab 
1779d29b2c44Sab static elfedit_cmdret_t
1780d29b2c44Sab cmd_runpath(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1781d29b2c44Sab {
1782d29b2c44Sab 	return (cmd_body(DYN_CMD_T_RUNPATH, obj_state, argc, argv));
1783d29b2c44Sab }
1784d29b2c44Sab 
1785d29b2c44Sab static elfedit_cmdret_t
1786d29b2c44Sab cmd_posflag1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1787d29b2c44Sab {
1788d29b2c44Sab 	return (cmd_body(DYN_CMD_T_POSFLAG1, obj_state, argc, argv));
1789d29b2c44Sab }
1790d29b2c44Sab 
1791d29b2c44Sab static elfedit_cmdret_t
1792d29b2c44Sab cmd_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1793d29b2c44Sab {
1794d29b2c44Sab 	return (cmd_body(DYN_CMD_T_FLAGS, obj_state, argc, argv));
1795d29b2c44Sab }
1796d29b2c44Sab 
1797d29b2c44Sab static elfedit_cmdret_t
1798d29b2c44Sab cmd_flags1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1799d29b2c44Sab {
1800d29b2c44Sab 	return (cmd_body(DYN_CMD_T_FLAGS1, obj_state, argc, argv));
1801d29b2c44Sab }
1802d29b2c44Sab 
1803d29b2c44Sab static elfedit_cmdret_t
1804d29b2c44Sab cmd_feature1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1805d29b2c44Sab {
1806d29b2c44Sab 	return (cmd_body(DYN_CMD_T_FEATURE1, obj_state, argc, argv));
1807d29b2c44Sab }
1808d29b2c44Sab 
1809d29b2c44Sab static elfedit_cmdret_t
1810d29b2c44Sab cmd_checksum(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1811d29b2c44Sab {
1812d29b2c44Sab 	return (cmd_body(DYN_CMD_T_CHECKSUM, obj_state, argc, argv));
1813d29b2c44Sab }
1814d29b2c44Sab 
1815ba2be530Sab static elfedit_cmdret_t
1816ba2be530Sab cmd_sunw_ldmach(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1817ba2be530Sab {
1818ba2be530Sab 	return (cmd_body(DYN_CMD_T_SUNW_LDMACH, obj_state, argc, argv));
1819ba2be530Sab }
1820ba2be530Sab 
1821d29b2c44Sab 
1822d29b2c44Sab 
1823d29b2c44Sab /*ARGSUSED*/
1824d29b2c44Sab elfedit_module_t *
1825d29b2c44Sab elfedit_init(elfedit_module_version_t version)
1826d29b2c44Sab {
1827d29b2c44Sab 	/* For commands that only accept -o */
1828d29b2c44Sab 	static elfedit_cmd_optarg_t opt_ostyle[] = {
1829d29b2c44Sab 		{ ELFEDIT_STDOA_OPT_O, NULL,
1830d29b2c44Sab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1831d29b2c44Sab 		{ NULL }
1832d29b2c44Sab 	};
1833d29b2c44Sab 
1834d29b2c44Sab 	/* For commands that only accept -and, -cmp, -o, -or */
1835d29b2c44Sab 	static elfedit_cmd_optarg_t opt_ostyle_bitop[] = {
1836d29b2c44Sab 		{ ELFEDIT_STDOA_OPT_AND, NULL,
1837d29b2c44Sab 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR },
1838d29b2c44Sab 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
1839d29b2c44Sab 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 },
1840d29b2c44Sab 		{ ELFEDIT_STDOA_OPT_O, NULL,
1841d29b2c44Sab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1842d29b2c44Sab 		{ ELFEDIT_STDOA_OPT_OR, NULL,
1843d29b2c44Sab 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND },
1844d29b2c44Sab 		{ NULL }
1845d29b2c44Sab 	};
1846d29b2c44Sab 
1847d29b2c44Sab 	/* For commands that only accept -dynndx */
1848d29b2c44Sab 	static elfedit_cmd_optarg_t opt_minus_dynndx[] = {
1849d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
185055ef6355Sab 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
185155ef6355Sab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
185255ef6355Sab 		    DYN_OPT_F_DYNNDX_ELT, 0 },
1853d29b2c44Sab 		{ NULL }
1854d29b2c44Sab 	};
1855d29b2c44Sab 
1856d29b2c44Sab 	/* dyn:dump */
1857d29b2c44Sab 	static const char *name_dump[] = {
1858d29b2c44Sab 	    MSG_ORIG(MSG_CMD_DUMP),
1859d29b2c44Sab 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
1860d29b2c44Sab 	    NULL
1861d29b2c44Sab 	};
1862d29b2c44Sab 	static elfedit_cmd_optarg_t arg_dump[] = {
1863d29b2c44Sab 		{ MSG_ORIG(MSG_STR_ELT),
1864d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1865d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1866d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT },
1867d29b2c44Sab 		{ NULL }
1868d29b2c44Sab 	};
1869d29b2c44Sab 
1870d29b2c44Sab 
1871d29b2c44Sab 	/* dyn:tag */
1872d29b2c44Sab 	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
1873d29b2c44Sab 	static elfedit_cmd_optarg_t opt_tag[] = {
1874d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
187555ef6355Sab 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
187655ef6355Sab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
187755ef6355Sab 		    DYN_OPT_F_DYNNDX_ELT, 0 },
1878d29b2c44Sab 		{ ELFEDIT_STDOA_OPT_O, NULL,
1879d29b2c44Sab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1880d29b2c44Sab 		{ NULL }
1881d29b2c44Sab 	};
1882d29b2c44Sab 	static elfedit_cmd_optarg_t arg_tag[] = {
1883d29b2c44Sab 		{ MSG_ORIG(MSG_STR_ELT),
1884d29b2c44Sab 		    /* MSG_INTL(MSG_A1_TAG_ELT) */
1885d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
1886d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT },
1887d29b2c44Sab 		{ MSG_ORIG(MSG_STR_VALUE),
1888d29b2c44Sab 		    /* MSG_INTL(MSG_A2_TAG_VALUE) */
1889d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
1890d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT },
1891d29b2c44Sab 		{ NULL }
1892d29b2c44Sab 	};
1893d29b2c44Sab 
1894d29b2c44Sab 
1895d29b2c44Sab 	/* dyn:value */
1896d29b2c44Sab 	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
1897d29b2c44Sab 	static elfedit_cmd_optarg_t opt_value[] = {
1898d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_ADD),
1899d29b2c44Sab 		    /* MSG_INTL(MSG_OPTDESC_ADD) */
1900d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_ADD), 0,
190155ef6355Sab 		    DYN_OPT_F_ADD, DYN_OPT_F_DYNNDX_ELT },
1902d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
190355ef6355Sab 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
190455ef6355Sab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
190555ef6355Sab 		    DYN_OPT_F_DYNNDX_ELT, DYN_OPT_F_ADD },
1906d29b2c44Sab 		{ ELFEDIT_STDOA_OPT_O, NULL,
1907d29b2c44Sab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1908d29b2c44Sab 		{ MSG_ORIG(MSG_STR_MINUS_S),
1909d29b2c44Sab 		    /* MSG_INTL(MSG_OPTDESC_S) */
1910d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0,
1911d29b2c44Sab 		    DYN_OPT_F_STRVAL, 0 },
1912d29b2c44Sab 		{ NULL }
1913d29b2c44Sab 	};
1914d29b2c44Sab 	static elfedit_cmd_optarg_t arg_value[] = {
1915d29b2c44Sab 		{ MSG_ORIG(MSG_STR_ELT),
1916d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1917d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1918d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT },
1919d29b2c44Sab 		{ MSG_ORIG(MSG_STR_VALUE),
1920d29b2c44Sab 		    /* MSG_INTL(MSG_A2_VALUE_VALUE) */
1921d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
1922d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT },
1923d29b2c44Sab 		{ NULL }
1924d29b2c44Sab 	};
1925d29b2c44Sab 
1926d29b2c44Sab 	/* dyn:delete */
1927d29b2c44Sab 	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
1928d29b2c44Sab 	static elfedit_cmd_optarg_t arg_delete[] = {
1929d29b2c44Sab 		{ MSG_ORIG(MSG_STR_ELT),
1930d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1931d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1932d29b2c44Sab 		    0 },
1933d29b2c44Sab 		{ MSG_ORIG(MSG_STR_COUNT),
1934d29b2c44Sab 		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
1935d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
1936d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT },
1937d29b2c44Sab 		{ NULL }
1938d29b2c44Sab 	};
1939d29b2c44Sab 
1940d29b2c44Sab 	/* dyn:move */
1941d29b2c44Sab 	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
1942d29b2c44Sab 	static elfedit_cmd_optarg_t arg_move[] = {
1943d29b2c44Sab 		{ MSG_ORIG(MSG_STR_ELT),
1944d29b2c44Sab 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1945d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1946d29b2c44Sab 		    0 },
1947d29b2c44Sab 		{ MSG_ORIG(MSG_STR_DST_INDEX),
1948d29b2c44Sab 		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
1949d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
1950d29b2c44Sab 		    0 },
1951d29b2c44Sab 		{ MSG_ORIG(MSG_STR_COUNT),
1952d29b2c44Sab 		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
1953d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
1954d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT },
1955d29b2c44Sab 		{ NULL }
1956d29b2c44Sab 	};
1957d29b2c44Sab 
1958d29b2c44Sab 	/* dyn:runpath / dyn:rpath */
1959d29b2c44Sab 	static const char *name_runpath[] = { MSG_ORIG(MSG_CMD_RUNPATH),
1960d29b2c44Sab 	    MSG_ORIG(MSG_CMD_RUNPATH_A1), NULL };
1961d29b2c44Sab 	static elfedit_cmd_optarg_t arg_runpath[] = {
1962d29b2c44Sab 		{ MSG_ORIG(MSG_STR_NEWPATH),
1963d29b2c44Sab 		    /* MSG_INTL(MSG_A1_RUNPATH_NEWPATH) */
1964d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A1_RUNPATH_NEWPATH),
1965d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT },
1966d29b2c44Sab 		{ NULL }
1967d29b2c44Sab 	};
1968d29b2c44Sab 
1969d29b2c44Sab 	/* dyn:posflag1 */
1970d29b2c44Sab 	static const char *name_posflag1[] = { MSG_ORIG(MSG_CMD_POSFLAG1),
1971d29b2c44Sab 	    NULL };
197255ef6355Sab 	static elfedit_cmd_optarg_t opt_posflag1[] = {
197355ef6355Sab 		{ ELFEDIT_STDOA_OPT_AND, NULL,
197455ef6355Sab 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR },
197555ef6355Sab 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
197655ef6355Sab 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 },
197755ef6355Sab 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
197855ef6355Sab 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX_VAL) */
197955ef6355Sab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_VAL),
198055ef6355Sab 		    ELFEDIT_CMDOA_F_VALUE,
198155ef6355Sab 		    DYN_OPT_F_DYNNDX_VAL, DYN_OPT_F_NEEDED },
198255ef6355Sab 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0, 0 },
198355ef6355Sab 		{ MSG_ORIG(MSG_STR_MINUS_NEEDED),
198455ef6355Sab 		    /* MSG_INTL(MSG_OPTDESC_NEEDED) */
198555ef6355Sab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED),
198655ef6355Sab 		    ELFEDIT_CMDOA_F_VALUE,
198755ef6355Sab 		    DYN_OPT_F_NEEDED, DYN_OPT_F_DYNNDX_VAL },
198855ef6355Sab 		{ MSG_ORIG(MSG_STR_PREFIX), NULL, 0, 0 },
198955ef6355Sab 		{ ELFEDIT_STDOA_OPT_O, NULL,
199055ef6355Sab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
199155ef6355Sab 		{ ELFEDIT_STDOA_OPT_OR, NULL,
199255ef6355Sab 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND },
199355ef6355Sab 		{ NULL }
199455ef6355Sab 	};
1995d29b2c44Sab 	static elfedit_cmd_optarg_t arg_posflag1[] = {
1996d29b2c44Sab 		{ MSG_ORIG(MSG_STR_VALUE),
1997d29b2c44Sab 		    /* MSG_INTL(MSG_A1_POSFLAG1_VALUE) */
1998d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A1_POSFLAG1_VALUE),
1999d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2000d29b2c44Sab 		{ NULL }
2001d29b2c44Sab 	};
2002d29b2c44Sab 
2003d29b2c44Sab 	/* dyn:flags */
2004d29b2c44Sab 	static const char *name_flags[] = { MSG_ORIG(MSG_CMD_FLAGS), NULL };
2005d29b2c44Sab 	static elfedit_cmd_optarg_t arg_flags[] = {
2006d29b2c44Sab 		{ MSG_ORIG(MSG_STR_VALUE),
2007d29b2c44Sab 		    /* MSG_INTL(MSG_A1_FLAGS_VALUE) */
2008d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A1_FLAGS_VALUE),
2009d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2010d29b2c44Sab 		{ NULL }
2011d29b2c44Sab 	};
2012d29b2c44Sab 
2013d29b2c44Sab 	/* dyn:flags1 */
2014d29b2c44Sab 	static const char *name_flags1[] = { MSG_ORIG(MSG_CMD_FLAGS1), NULL };
2015d29b2c44Sab 	static elfedit_cmd_optarg_t arg_flags1[] = {
2016d29b2c44Sab 		{ MSG_ORIG(MSG_STR_VALUE),
2017d29b2c44Sab 		    /* MSG_INTL(MSG_A1_FLAGS1_VALUE) */
2018d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A1_FLAGS1_VALUE),
2019d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2020d29b2c44Sab 		{ NULL }
2021d29b2c44Sab 	};
2022d29b2c44Sab 
2023d29b2c44Sab 	/* dyn:feature1 */
2024d29b2c44Sab 	static const char *name_feature1[] = { MSG_ORIG(MSG_CMD_FEATURE1),
2025d29b2c44Sab 	    NULL };
2026d29b2c44Sab 	static elfedit_cmd_optarg_t arg_feature1[] = {
2027d29b2c44Sab 		{ MSG_ORIG(MSG_STR_VALUE),
2028d29b2c44Sab 		    /* MSG_INTL(MSG_A1_FEATURE1_VALUE) */
2029d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_A1_FEATURE1_VALUE),
2030d29b2c44Sab 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2031d29b2c44Sab 		{ NULL }
2032d29b2c44Sab 	};
2033d29b2c44Sab 
2034d29b2c44Sab 	/* dyn:checksum */
2035d29b2c44Sab 	static const char *name_checksum[] = { MSG_ORIG(MSG_CMD_CHECKSUM),
2036d29b2c44Sab 	    NULL };
2037d29b2c44Sab 
2038ba2be530Sab 	/* dyn:sunw_ldmach */
2039ba2be530Sab 	static const char *name_sunw_ldmach[] = { MSG_ORIG(MSG_CMD_SUNW_LDMACH),
2040ba2be530Sab 	    NULL };
2041ba2be530Sab 	static elfedit_cmd_optarg_t arg_sunw_ldmach[] = {
2042ba2be530Sab 		{ MSG_ORIG(MSG_STR_VALUE),
2043ba2be530Sab 		    /* MSG_INTL(MSG_A1_SUNW_LDMACH_VALUE) */
2044ba2be530Sab 		    ELFEDIT_I18NHDL(MSG_A1_SUNW_LDMACH_VALUE),
2045ba2be530Sab 		    ELFEDIT_CMDOA_F_OPT },
2046ba2be530Sab 		{ NULL }
2047ba2be530Sab 	};
2048ba2be530Sab 
2049d29b2c44Sab 
2050d29b2c44Sab 
2051d29b2c44Sab 	static elfedit_cmd_t cmds[] = {
2052d29b2c44Sab 		/* dyn:dump */
2053d29b2c44Sab 		{ cmd_dump, cpl_eltarg, name_dump,
2054d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_DUMP) */
2055d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
2056d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_DUMP) */
2057d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
2058d29b2c44Sab 		    opt_minus_dynndx, arg_dump },
2059d29b2c44Sab 
2060d29b2c44Sab 		/* dyn:tag */
2061d29b2c44Sab 		{ cmd_tag, cpl_tag, name_tag,
2062d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_TAG) */
2063d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
2064d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_TAG) */
2065d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
2066d29b2c44Sab 		    opt_tag, arg_tag },
2067d29b2c44Sab 
2068d29b2c44Sab 		/* dyn:value */
2069d29b2c44Sab 		{ cmd_value, cpl_eltarg, name_value,
2070d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_VALUE) */
2071d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
2072d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_VALUE) */
2073d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
2074d29b2c44Sab 		    opt_value, arg_value },
2075d29b2c44Sab 
2076d29b2c44Sab 		/* dyn:delete */
2077d29b2c44Sab 		{ cmd_delete, cpl_eltarg, name_delete,
2078d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_DELETE) */
2079d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
2080d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_DELETE) */
2081d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
2082d29b2c44Sab 		    opt_minus_dynndx, arg_delete },
2083d29b2c44Sab 
2084d29b2c44Sab 		/* dyn:move */
2085d29b2c44Sab 		{ cmd_move, cpl_eltarg, name_move,
2086d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_MOVE) */
2087d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
2088d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_MOVE) */
2089d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
2090d29b2c44Sab 		    opt_minus_dynndx, arg_move },
2091d29b2c44Sab 
2092d29b2c44Sab 		/* dyn:runpath */
2093d29b2c44Sab 		{ cmd_runpath, NULL, name_runpath,
2094d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_RUNPATH) */
2095d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_RUNPATH),
2096d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_RUNPATH) */
2097d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_RUNPATH),
2098d29b2c44Sab 		    opt_ostyle, arg_runpath },
2099d29b2c44Sab 
2100d29b2c44Sab 		/* dyn:posflag1 */
2101d29b2c44Sab 		{ cmd_posflag1, cpl_posflag1, name_posflag1,
2102d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_POSFLAG1) */
2103d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_POSFLAG1),
2104d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_POSFLAG1) */
2105d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_POSFLAG1),
210655ef6355Sab 		    opt_posflag1, arg_posflag1 },
2107d29b2c44Sab 
2108d29b2c44Sab 		/* dyn:flags */
2109d29b2c44Sab 		{ cmd_flags, cpl_flags, name_flags,
2110d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_FLAGS) */
2111d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_FLAGS),
2112d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_FLAGS) */
2113d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_FLAGS),
2114d29b2c44Sab 		    opt_ostyle_bitop, arg_flags },
2115d29b2c44Sab 
2116d29b2c44Sab 		/* dyn:flags1 */
2117d29b2c44Sab 		{ cmd_flags1, cpl_flags1, name_flags1,
2118d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_FLAGS1) */
2119d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_FLAGS1),
2120d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_FLAGS1) */
2121d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_FLAGS1),
2122d29b2c44Sab 		    opt_ostyle_bitop, arg_flags1 },
2123d29b2c44Sab 
2124d29b2c44Sab 		/* dyn:feature1 */
2125d29b2c44Sab 		{ cmd_feature1, cpl_feature1, name_feature1,
2126d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_FEATURE1) */
2127d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_FEATURE1),
2128d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_FEATURE1) */
2129d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_FEATURE1),
2130d29b2c44Sab 		    opt_ostyle_bitop, arg_feature1 },
2131d29b2c44Sab 
2132d29b2c44Sab 		/* dyn:checksum */
2133d29b2c44Sab 		{ cmd_checksum, NULL, name_checksum,
2134d29b2c44Sab 		    /* MSG_INTL(MSG_DESC_CHECKSUM) */
2135d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_DESC_CHECKSUM),
2136d29b2c44Sab 		    /* MSG_INTL(MSG_HELP_CHECKSUM) */
2137d29b2c44Sab 		    ELFEDIT_I18NHDL(MSG_HELP_CHECKSUM),
2138d29b2c44Sab 		    NULL, NULL },
2139d29b2c44Sab 
2140ba2be530Sab 		/* dyn:sunw_ldmach */
2141ba2be530Sab 		{ cmd_sunw_ldmach, cpl_sunw_ldmach, name_sunw_ldmach,
2142ba2be530Sab 		    /* MSG_INTL(MSG_DESC_SUNW_LDMACH) */
2143ba2be530Sab 		    ELFEDIT_I18NHDL(MSG_DESC_SUNW_LDMACH),
2144ba2be530Sab 		    /* MSG_INTL(MSG_HELP_SUNW_LDMACH) */
2145ba2be530Sab 		    ELFEDIT_I18NHDL(MSG_HELP_SUNW_LDMACH),
2146ba2be530Sab 		    opt_ostyle, arg_sunw_ldmach },
2147ba2be530Sab 
2148d29b2c44Sab 		{ NULL }
2149d29b2c44Sab 	};
2150d29b2c44Sab 
2151d29b2c44Sab 	static elfedit_module_t module = {
2152d29b2c44Sab 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
2153d29b2c44Sab 	    /* MSG_INTL(MSG_MOD_DESC) */
2154d29b2c44Sab 	    ELFEDIT_I18NHDL(MSG_MOD_DESC), cmds, mod_i18nhdl_to_str };
2155d29b2c44Sab 
2156d29b2c44Sab 	return (&module);
2157d29b2c44Sab }
2158