xref: /onnv-gate/usr/src/cmd/sgs/elfedit/modules/common/dyn.c (revision 5088:26c540f30cd3)
1*5088Sab196087 /*
2*5088Sab196087  * CDDL HEADER START
3*5088Sab196087  *
4*5088Sab196087  * The contents of this file are subject to the terms of the
5*5088Sab196087  * Common Development and Distribution License (the "License").
6*5088Sab196087  * You may not use this file except in compliance with the License.
7*5088Sab196087  *
8*5088Sab196087  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5088Sab196087  * or http://www.opensolaris.org/os/licensing.
10*5088Sab196087  * See the License for the specific language governing permissions
11*5088Sab196087  * and limitations under the License.
12*5088Sab196087  *
13*5088Sab196087  * When distributing Covered Code, include this CDDL HEADER in each
14*5088Sab196087  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5088Sab196087  * If applicable, add the following below this CDDL HEADER, with the
16*5088Sab196087  * fields enclosed by brackets "[]" replaced with your own identifying
17*5088Sab196087  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5088Sab196087  *
19*5088Sab196087  * CDDL HEADER END
20*5088Sab196087  */
21*5088Sab196087 
22*5088Sab196087 /*
23*5088Sab196087  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*5088Sab196087  * Use is subject to license terms.
25*5088Sab196087  */
26*5088Sab196087 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*5088Sab196087 
28*5088Sab196087 #include	<ctype.h>
29*5088Sab196087 #include	<machdep.h>
30*5088Sab196087 #include	<elfedit.h>
31*5088Sab196087 #include	<sys/elf_SPARC.h>
32*5088Sab196087 #include	<strings.h>
33*5088Sab196087 #include	<debug.h>
34*5088Sab196087 #include	<conv.h>
35*5088Sab196087 #include	<dyn_msg.h>
36*5088Sab196087 
37*5088Sab196087 
38*5088Sab196087 /*
39*5088Sab196087  * Dynamic section
40*5088Sab196087  */
41*5088Sab196087 
42*5088Sab196087 
43*5088Sab196087 
44*5088Sab196087 
45*5088Sab196087 /*
46*5088Sab196087  * This module uses shared code for several of the commands.
47*5088Sab196087  * It is sometimes necessary to know which specific command
48*5088Sab196087  * is active.
49*5088Sab196087  */
50*5088Sab196087 typedef enum {
51*5088Sab196087 	/* Dump command, used as module default to display dynamic section */
52*5088Sab196087 	DYN_CMD_T_DUMP =	0,	/* dyn:dump */
53*5088Sab196087 
54*5088Sab196087 	/* Commands that do not correspond directly to a specific DT tag */
55*5088Sab196087 	DYN_CMD_T_TAG =		1,	/* dyn:tag */
56*5088Sab196087 	DYN_CMD_T_VALUE =	2,	/* dyn:value */
57*5088Sab196087 	DYN_CMD_T_DELETE =	3,	/* dyn:delete */
58*5088Sab196087 	DYN_CMD_T_MOVE =	4,	/* dyn:shift */
59*5088Sab196087 
60*5088Sab196087 	/* Commands that embody tag specific knowledge */
61*5088Sab196087 	DYN_CMD_T_RUNPATH =	5,	/* dyn:runpath/rpath */
62*5088Sab196087 	DYN_CMD_T_POSFLAG1 =	6,	/* dyn:posflag1 */
63*5088Sab196087 	DYN_CMD_T_FLAGS =	7,	/* dyn:flags */
64*5088Sab196087 	DYN_CMD_T_FLAGS1 =	8,	/* dyn:flags1 */
65*5088Sab196087 	DYN_CMD_T_FEATURE1 =	9,	/* dyn:feature1 */
66*5088Sab196087 	DYN_CMD_T_CHECKSUM =	10	/* dyn:checksum */
67*5088Sab196087 } DYN_CMD_T;
68*5088Sab196087 
69*5088Sab196087 
70*5088Sab196087 
71*5088Sab196087 #ifndef _ELF64
72*5088Sab196087 /*
73*5088Sab196087  * We supply this function for the msg module
74*5088Sab196087  */
75*5088Sab196087 const char *
76*5088Sab196087 _dyn_msg(Msg mid)
77*5088Sab196087 {
78*5088Sab196087 	return (gettext(MSG_ORIG(mid)));
79*5088Sab196087 }
80*5088Sab196087 #endif
81*5088Sab196087 
82*5088Sab196087 
83*5088Sab196087 /*
84*5088Sab196087  * This function is supplied to elfedit through our elfedit_module_t
85*5088Sab196087  * definition. It translates the opaque elfedit_i18nhdl_t handles
86*5088Sab196087  * in our module interface into the actual strings for elfedit to
87*5088Sab196087  * use.
88*5088Sab196087  *
89*5088Sab196087  * note:
90*5088Sab196087  *	This module uses Msg codes for its i18n handle type.
91*5088Sab196087  *	So the translation is simply to use MSG_INTL() to turn
92*5088Sab196087  *	it into a string and return it.
93*5088Sab196087  */
94*5088Sab196087 static const char *
95*5088Sab196087 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
96*5088Sab196087 {
97*5088Sab196087 	Msg msg = (Msg)hdl;
98*5088Sab196087 
99*5088Sab196087 	return (MSG_INTL(msg));
100*5088Sab196087 }
101*5088Sab196087 
102*5088Sab196087 
103*5088Sab196087 
104*5088Sab196087 /*
105*5088Sab196087  * The dyn_opt_t enum specifies a bit value for every optional
106*5088Sab196087  * argument allowed by a command in this module.
107*5088Sab196087  */
108*5088Sab196087 typedef enum {
109*5088Sab196087 	DYN_OPT_F_ADD =		1,	/* -add: Add new elt rather than */
110*5088Sab196087 					/*	modifying an existing one */
111*5088Sab196087 	DYN_OPT_F_AND =		2,	/* -and: AND (&) values to dest */
112*5088Sab196087 	DYN_OPT_F_CMP =		4,	/* -cmp: Complement (~) values */
113*5088Sab196087 	DYN_OPT_F_DYNNDX =	8,	/* -dynndx: elt is tag index, */
114*5088Sab196087 					/*	not name */
115*5088Sab196087 	DYN_OPT_F_OR =		16,	/* -or: OR (|) values to dest */
116*5088Sab196087 	DYN_OPT_F_STRVAL =	32	/* -s: value is string, not integer */
117*5088Sab196087 } dyn_opt_t;
118*5088Sab196087 
119*5088Sab196087 
120*5088Sab196087 /*
121*5088Sab196087  * A variable of type ARGSTATE is used by each command to maintain
122*5088Sab196087  * information about the arguments and related things. It is
123*5088Sab196087  * initialized by process_args(), and used by the other routines.
124*5088Sab196087  */
125*5088Sab196087 typedef struct {
126*5088Sab196087 	elfedit_obj_state_t	*obj_state;
127*5088Sab196087 	elfedit_section_t	*strsec;	/* Dynamic string table ref */
128*5088Sab196087 	struct {
129*5088Sab196087 		elfedit_section_t *sec;		/* Dynamic section reference */
130*5088Sab196087 		Dyn	*data;			/* Start dynamic section data */
131*5088Sab196087 		Word	num;			/* # dynamic elts */
132*5088Sab196087 		Word	null_ndx;		/* Index of first DT_NULL */
133*5088Sab196087 		Word	num_null_ndx;		/* # of DT_NULL elements */
134*5088Sab196087 	} dyn;
135*5088Sab196087 	dyn_opt_t		optmask;   	/* Mask of options used */
136*5088Sab196087 	int			argc;		/* # of plain arguments */
137*5088Sab196087 	const char		**argv;		/* Plain arguments */
138*5088Sab196087 } ARGSTATE;
139*5088Sab196087 
140*5088Sab196087 
141*5088Sab196087 
142*5088Sab196087 /*
143*5088Sab196087  * Set argstate null_ndx field for current dynamic area
144*5088Sab196087  */
145*5088Sab196087 static void
146*5088Sab196087 set_null_ndx(ARGSTATE *argstate)
147*5088Sab196087 {
148*5088Sab196087 	Word	num, null_ndx;
149*5088Sab196087 
150*5088Sab196087 	num = argstate->dyn.num;
151*5088Sab196087 	argstate->dyn.num_null_ndx = 0;
152*5088Sab196087 	for (null_ndx = 0; null_ndx < num; null_ndx++)
153*5088Sab196087 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) {
154*5088Sab196087 			argstate->dyn.num_null_ndx++;
155*5088Sab196087 			break;
156*5088Sab196087 		}
157*5088Sab196087 	argstate->dyn.null_ndx = null_ndx;
158*5088Sab196087 
159*5088Sab196087 	/* Count the number of remaining DT_NULL items */
160*5088Sab196087 	for (; null_ndx < num; null_ndx++)
161*5088Sab196087 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL)
162*5088Sab196087 			argstate->dyn.num_null_ndx++;
163*5088Sab196087 }
164*5088Sab196087 
165*5088Sab196087 
166*5088Sab196087 /*
167*5088Sab196087  * Convert the first available DT_NULL slot in the dynamic section
168*5088Sab196087  * into something else.
169*5088Sab196087  *
170*5088Sab196087  * entry:
171*5088Sab196087  *	argstate - Argument state block
172*5088Sab196087  *	d_tag, d_val - Values to be set in new element
173*5088Sab196087  *
174*5088Sab196087  * exit:
175*5088Sab196087  *	If an extra DT_NULL slot is available, a debug message is
176*5088Sab196087  *	issued, the slot is converted to its new use, and the argstate
177*5088Sab196087  *	block state related to DT_NULL slots is updated.
178*5088Sab196087  *
179*5088Sab196087  *	if no extra DT_NULL slot is present, an error is issued and
180*5088Sab196087  *	this routine does not return to the caller.
181*5088Sab196087  */
182*5088Sab196087 static Word
183*5088Sab196087 convert_dt_null(ARGSTATE *argstate, Word d_tag, Xword d_val)
184*5088Sab196087 {
185*5088Sab196087 	Conv_inv_buf_t inv_buf;
186*5088Sab196087 	Word	ndx;
187*5088Sab196087 	Dyn	*dyn;
188*5088Sab196087 
189*5088Sab196087 	/* If we lack an extra element, we can't continue */
190*5088Sab196087 	if (argstate->dyn.num_null_ndx <= 1)
191*5088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
192*5088Sab196087 		    EC_WORD(argstate->dyn.sec->sec_shndx),
193*5088Sab196087 		    argstate->dyn.sec->sec_name);
194*5088Sab196087 
195*5088Sab196087 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
196*5088Sab196087 	    EC_WORD(argstate->dyn.sec->sec_shndx), argstate->dyn.sec->sec_name,
197*5088Sab196087 	    EC_WORD(argstate->dyn.null_ndx), conv_dyn_tag(d_tag,
198*5088Sab196087 	    argstate->obj_state->os_ehdr->e_machine, 0, &inv_buf));
199*5088Sab196087 
200*5088Sab196087 	ndx = argstate->dyn.null_ndx;
201*5088Sab196087 	dyn = &argstate->dyn.data[ndx];
202*5088Sab196087 	dyn->d_tag = d_tag;
203*5088Sab196087 	dyn->d_un.d_val = d_val;
204*5088Sab196087 
205*5088Sab196087 	/* Recompute the DT_NULL situation */
206*5088Sab196087 	set_null_ndx(argstate);
207*5088Sab196087 
208*5088Sab196087 	return (ndx);
209*5088Sab196087 }
210*5088Sab196087 
211*5088Sab196087 
212*5088Sab196087 /*
213*5088Sab196087  * Standard argument processing for dyn module
214*5088Sab196087  *
215*5088Sab196087  * entry
216*5088Sab196087  *	obj_state, argc, argv - Standard command arguments
217*5088Sab196087  *	argstate - Address of ARGSTATE block to be initialized
218*5088Sab196087  *
219*5088Sab196087  * exit:
220*5088Sab196087  *	On success, *argstate is initialized. On error,
221*5088Sab196087  *	an error is issued and this routine does not return.
222*5088Sab196087  */
223*5088Sab196087 static void
224*5088Sab196087 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
225*5088Sab196087     ARGSTATE *argstate)
226*5088Sab196087 {
227*5088Sab196087 	elfedit_getopt_state_t	getopt_state;
228*5088Sab196087 	elfedit_getopt_ret_t	*getopt_ret;
229*5088Sab196087 
230*5088Sab196087 	bzero(argstate, sizeof (*argstate));
231*5088Sab196087 	argstate->obj_state = obj_state;
232*5088Sab196087 
233*5088Sab196087 	elfedit_getopt_init(&getopt_state, &argc, &argv);
234*5088Sab196087 
235*5088Sab196087 	/* Add each new option to the options mask */
236*5088Sab196087 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
237*5088Sab196087 		argstate->optmask |= getopt_ret->gor_idmask;
238*5088Sab196087 
239*5088Sab196087 	/* If there may be an arbitrary amount of output, use a pager */
240*5088Sab196087 	if (argc == 0)
241*5088Sab196087 		elfedit_pager_init();
242*5088Sab196087 
243*5088Sab196087 	/* Return the updated values of argc/argv */
244*5088Sab196087 	argstate->argc = argc;
245*5088Sab196087 	argstate->argv = argv;
246*5088Sab196087 
247*5088Sab196087 	/* Locate the dynamic section, and the assocated string table */
248*5088Sab196087 	argstate->dyn.sec = elfedit_sec_getdyn(obj_state, &argstate->dyn.data,
249*5088Sab196087 	    &argstate->dyn.num);
250*5088Sab196087 	argstate->strsec = elfedit_sec_getstr(obj_state,
251*5088Sab196087 	    argstate->dyn.sec->sec_shdr->sh_link);
252*5088Sab196087 
253*5088Sab196087 	/* Index of first DT_NULL */
254*5088Sab196087 	set_null_ndx(argstate);
255*5088Sab196087 }
256*5088Sab196087 
257*5088Sab196087 
258*5088Sab196087 
259*5088Sab196087 /*
260*5088Sab196087  * Print ELF header values, taking the calling command, and output style
261*5088Sab196087  * into account.
262*5088Sab196087  *
263*5088Sab196087  * entry:
264*5088Sab196087  *	cmd - DYN_CMD_T_* value giving identify of caller
265*5088Sab196087  *	autoprint - If True, output is only produced if the elfedit
266*5088Sab196087  *		autoprint flag is set. If False, output is always produced.
267*5088Sab196087  *	argstate - Argument state block
268*5088Sab196087  *	print_type - Specifies which dynamic elements to display.
269*5088Sab196087  *	ndx = If print_type is PRINT_DYN_T_NDX, displays the index specified.
270*5088Sab196087  *		Otherwise ignored.
271*5088Sab196087  */
272*5088Sab196087 typedef enum {
273*5088Sab196087 	PRINT_DYN_T_ALL =	0,	/* Show all indexes */
274*5088Sab196087 	PRINT_DYN_T_NDX =	1,	/* Show dynamic[arg] only */
275*5088Sab196087 	PRINT_DYN_T_TAG =	2,	/* Show all elts with tag type */
276*5088Sab196087 					/*	given by arg */
277*5088Sab196087 	PRINT_DYN_T_RUNPATH =	3	/* Show all runpath/rpath elts */
278*5088Sab196087 
279*5088Sab196087 } PRINT_DYN_T;
280*5088Sab196087 
281*5088Sab196087 static void
282*5088Sab196087 print_dyn(DYN_CMD_T cmd, int autoprint, ARGSTATE *argstate,
283*5088Sab196087     PRINT_DYN_T print_type, Word arg)
284*5088Sab196087 {
285*5088Sab196087 	elfedit_outstyle_t	outstyle;
286*5088Sab196087 	Conv_fmt_flags_t	flags_fmt_flags;
287*5088Sab196087 	Word	end_ndx, cnt, ndx, printed = 0;
288*5088Sab196087 	Dyn	*dyn;
289*5088Sab196087 	int	header_done = 0;
290*5088Sab196087 	Xword	last_d_val;
291*5088Sab196087 
292*5088Sab196087 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
293*5088Sab196087 		return;
294*5088Sab196087 
295*5088Sab196087 	/*
296*5088Sab196087 	 * Pick an output style. dyn:dump is required to use the default
297*5088Sab196087 	 * style. The other commands use the current output style.
298*5088Sab196087 	 */
299*5088Sab196087 	outstyle = (cmd == DYN_CMD_T_DUMP) ?
300*5088Sab196087 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
301*5088Sab196087 
302*5088Sab196087 	/*
303*5088Sab196087 	 * When using the simple output style, omit the
304*5088Sab196087 	 * brackets from around the values.
305*5088Sab196087 	 */
306*5088Sab196087 	flags_fmt_flags = (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) ?
307*5088Sab196087 	    CONV_FMT_NOBKT : 0;
308*5088Sab196087 
309*5088Sab196087 	/* How many elements do we examine? */
310*5088Sab196087 	if (print_type == PRINT_DYN_T_NDX) {
311*5088Sab196087 		if (arg >= argstate->dyn.num)
312*5088Sab196087 			return;		/* Out of range */
313*5088Sab196087 		ndx = arg;
314*5088Sab196087 		cnt = 1;
315*5088Sab196087 	} else {
316*5088Sab196087 		ndx = 0;
317*5088Sab196087 		cnt = argstate->dyn.num;
318*5088Sab196087 	}
319*5088Sab196087 
320*5088Sab196087 	dyn = &argstate->dyn.data[ndx];
321*5088Sab196087 	for (; cnt--; dyn++, ndx++) {
322*5088Sab196087 		union {
323*5088Sab196087 			Conv_dyn_flag_buf_t	flag;
324*5088Sab196087 			Conv_dyn_flag1_buf_t	flag1;
325*5088Sab196087 			Conv_dyn_posflag1_buf_t	posflag1;
326*5088Sab196087 			Conv_dyn_feature1_buf_t	feature1;
327*5088Sab196087 		} c_buf;
328*5088Sab196087 		const char	*name;
329*5088Sab196087 
330*5088Sab196087 		/*
331*5088Sab196087 		 * If we are only displaying certain tag types and
332*5088Sab196087 		 * this isn't one of those, move on to next element.
333*5088Sab196087 		 */
334*5088Sab196087 		switch (print_type) {
335*5088Sab196087 		case PRINT_DYN_T_TAG:
336*5088Sab196087 			if (dyn->d_tag != arg)
337*5088Sab196087 				continue;
338*5088Sab196087 			break;
339*5088Sab196087 		case PRINT_DYN_T_RUNPATH:
340*5088Sab196087 			if ((dyn->d_tag != DT_RPATH) &&
341*5088Sab196087 			    (dyn->d_tag != DT_RUNPATH))
342*5088Sab196087 				continue;
343*5088Sab196087 			break;
344*5088Sab196087 		}
345*5088Sab196087 
346*5088Sab196087 		/*
347*5088Sab196087 		 * Print the information numerically, and if possible
348*5088Sab196087 		 * as a string.
349*5088Sab196087 		 */
350*5088Sab196087 		name = NULL;
351*5088Sab196087 		switch (dyn->d_tag) {
352*5088Sab196087 		case DT_NULL:
353*5088Sab196087 			if (!((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) &&
354*5088Sab196087 			    (print_type == PRINT_DYN_T_ALL) &&
355*5088Sab196087 			    (dyn->d_un.d_val == 0)))
356*5088Sab196087 				break;
357*5088Sab196087 			end_ndx = ndx;
358*5088Sab196087 			/*
359*5088Sab196087 			 * Special case: DT_NULLs can come in groups
360*5088Sab196087 			 * that we prefer to reduce to a single line.
361*5088Sab196087 			 */
362*5088Sab196087 			while ((end_ndx < (argstate->dyn.num - 1)) &&
363*5088Sab196087 			    ((dyn + 1)->d_tag == DT_NULL) &&
364*5088Sab196087 			    ((dyn + 1)->d_un.d_val == 0)) {
365*5088Sab196087 				dyn++;
366*5088Sab196087 				end_ndx++;
367*5088Sab196087 				cnt--;
368*5088Sab196087 			}
369*5088Sab196087 			if (header_done == 0) {
370*5088Sab196087 				header_done = 1;
371*5088Sab196087 				Elf_dyn_title(0);
372*5088Sab196087 			}
373*5088Sab196087 			Elf_dyn_null_entry(0, dyn, ndx, end_ndx);
374*5088Sab196087 			ndx = end_ndx;
375*5088Sab196087 			printed = 1;
376*5088Sab196087 			last_d_val = dyn->d_un.d_val;
377*5088Sab196087 			continue;
378*5088Sab196087 
379*5088Sab196087 		/*
380*5088Sab196087 		 * Print the information numerically, and if possible
381*5088Sab196087 		 * as a string.
382*5088Sab196087 		 */
383*5088Sab196087 		case DT_NEEDED:
384*5088Sab196087 		case DT_SONAME:
385*5088Sab196087 		case DT_FILTER:
386*5088Sab196087 		case DT_AUXILIARY:
387*5088Sab196087 		case DT_CONFIG:
388*5088Sab196087 		case DT_RPATH:
389*5088Sab196087 		case DT_RUNPATH:
390*5088Sab196087 		case DT_USED:
391*5088Sab196087 		case DT_DEPAUDIT:
392*5088Sab196087 		case DT_AUDIT:
393*5088Sab196087 		case DT_SUNW_AUXILIARY:
394*5088Sab196087 		case DT_SUNW_FILTER:
395*5088Sab196087 			name = elfedit_offset_to_str(argstate->strsec,
396*5088Sab196087 			    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
397*5088Sab196087 			break;
398*5088Sab196087 
399*5088Sab196087 		case DT_FLAGS:
400*5088Sab196087 			name = conv_dyn_flag(dyn->d_un.d_val,
401*5088Sab196087 			    flags_fmt_flags, &c_buf.flag);
402*5088Sab196087 			break;
403*5088Sab196087 		case DT_FLAGS_1:
404*5088Sab196087 			name = conv_dyn_flag1(dyn->d_un.d_val,
405*5088Sab196087 			    flags_fmt_flags, &c_buf.flag1);
406*5088Sab196087 			break;
407*5088Sab196087 		case DT_POSFLAG_1:
408*5088Sab196087 			name = conv_dyn_posflag1(dyn->d_un.d_val,
409*5088Sab196087 			    flags_fmt_flags, &c_buf.posflag1);
410*5088Sab196087 			break;
411*5088Sab196087 		case DT_FEATURE_1:
412*5088Sab196087 			name = conv_dyn_feature1(dyn->d_un.d_val,
413*5088Sab196087 			    flags_fmt_flags, &c_buf.feature1);
414*5088Sab196087 			break;
415*5088Sab196087 		case DT_DEPRECATED_SPARC_REGISTER:
416*5088Sab196087 			name = MSG_INTL(MSG_STR_DEPRECATED);
417*5088Sab196087 			break;
418*5088Sab196087 		}
419*5088Sab196087 
420*5088Sab196087 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
421*5088Sab196087 			if (header_done == 0) {
422*5088Sab196087 				header_done = 1;
423*5088Sab196087 				Elf_dyn_title(0);
424*5088Sab196087 			}
425*5088Sab196087 			if (name == NULL)
426*5088Sab196087 				name = MSG_ORIG(MSG_STR_EMPTY);
427*5088Sab196087 			Elf_dyn_entry(0, dyn, ndx, name,
428*5088Sab196087 			    argstate->obj_state->os_ehdr->e_machine);
429*5088Sab196087 		} else {
430*5088Sab196087 			/*
431*5088Sab196087 			 * In simple or numeric mode under a print type
432*5088Sab196087 			 * that is based on tag type rather than on index,
433*5088Sab196087 			 * quietly: If we've already printed this value,
434*5088Sab196087 			 * don't print it again. A common example of this
435*5088Sab196087 			 * is PRINT_DYN_T_RUNPATH when both DT_RPATH and
436*5088Sab196087 			 * DT_RUNPATH are present with the same value.
437*5088Sab196087 			 */
438*5088Sab196087 			switch (print_type) {
439*5088Sab196087 			case PRINT_DYN_T_TAG:
440*5088Sab196087 			case PRINT_DYN_T_RUNPATH:
441*5088Sab196087 				if (printed && (last_d_val == dyn->d_un.d_val))
442*5088Sab196087 					continue;
443*5088Sab196087 			}
444*5088Sab196087 
445*5088Sab196087 			if ((name != NULL) &&
446*5088Sab196087 			    (outstyle == ELFEDIT_OUTSTYLE_SIMPLE)) {
447*5088Sab196087 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), name);
448*5088Sab196087 			} else {
449*5088Sab196087 				elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
450*5088Sab196087 				    dyn->d_un.d_val);
451*5088Sab196087 			}
452*5088Sab196087 		}
453*5088Sab196087 		printed = 1;
454*5088Sab196087 		last_d_val = dyn->d_un.d_val;
455*5088Sab196087 	}
456*5088Sab196087 
457*5088Sab196087 	/*
458*5088Sab196087 	 * If nothing was output under the print types that are
459*5088Sab196087 	 * based on tag type, issue an error saying it doesn't exist.
460*5088Sab196087 	 */
461*5088Sab196087 	if (!printed) {
462*5088Sab196087 		if (print_type == PRINT_DYN_T_TAG) {
463*5088Sab196087 			Conv_inv_buf_t inv_buf;
464*5088Sab196087 
465*5088Sab196087 			elfedit_msg(ELFEDIT_MSG_ERR,
466*5088Sab196087 			    MSG_INTL(MSG_ERR_NODYNELT),
467*5088Sab196087 			    EC_WORD(argstate->dyn.sec->sec_shndx),
468*5088Sab196087 			    argstate->dyn.sec->sec_name, conv_dyn_tag(arg,
469*5088Sab196087 			    argstate->obj_state->os_ehdr->e_machine,
470*5088Sab196087 			    0, &inv_buf));
471*5088Sab196087 		}
472*5088Sab196087 
473*5088Sab196087 		if (print_type == PRINT_DYN_T_RUNPATH)
474*5088Sab196087 			elfedit_msg(ELFEDIT_MSG_ERR,
475*5088Sab196087 			    MSG_INTL(MSG_ERR_NORUNPATH),
476*5088Sab196087 			    EC_WORD(argstate->dyn.sec->sec_shndx),
477*5088Sab196087 			    argstate->dyn.sec->sec_name);
478*5088Sab196087 	}
479*5088Sab196087 }
480*5088Sab196087 
481*5088Sab196087 
482*5088Sab196087 /*
483*5088Sab196087  * Process the elt argument: This will be a tag type if -dynndx is
484*5088Sab196087  * not present and this is a print request. It will be an index otherwise.
485*5088Sab196087  *
486*5088Sab196087  * entry:
487*5088Sab196087  *	argstate - Argument state block
488*5088Sab196087  *	arg - Argument string to be converted into an index
489*5088Sab196087  *	argname - String giving the name by which the argument is
490*5088Sab196087  *		referred in the online help for the command.
491*5088Sab196087  *	print_request - True if the command is to print the current
492*5088Sab196087  *		value(s) and return without changing anything.
493*5088Sab196087  *	print_type - Address of variable containing PRINT_DYN_T_
494*5088Sab196087  *		code specifying how the elements will be displayed.
495*5088Sab196087  *
496*5088Sab196087  * exit:
497*5088Sab196087  *	If print_request is False: arg is converted into an integer value.
498*5088Sab196087  *	If -dynndx was used, we convert it into an integer. If it was not
499*5088Sab196087  *	used, then arg is a tag name --- we find the first dynamic entry
500*5088Sab196087  *	that matches. If no entry matches, and there is an extra DT_NULL,
501*5088Sab196087  *	it is added. Otherwise an error is issued. *print_type is set
502*5088Sab196087  *	to PRINT_DYN_T_NDX.
503*5088Sab196087  *
504*5088Sab196087  *	If print_request is True: If -dynndx was used, arg is converted into
505*5088Sab196087  *	an integer value, *print_type is set to PRINT_DYN_T_NDX, and
506*5088Sab196087  *	the value is returned. If -dynndx was not used, *print_type is set to
507*5088Sab196087  *	PRINT_DYN_T_TAG, and the tag value is returned.
508*5088Sab196087  */
509*5088Sab196087 static Word
510*5088Sab196087 arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname,
511*5088Sab196087     int print_request, PRINT_DYN_T *print_type)
512*5088Sab196087 {
513*5088Sab196087 	Word	ndx, dt_value;
514*5088Sab196087 
515*5088Sab196087 
516*5088Sab196087 	/* Assume we are returning an index, alter as needed below */
517*5088Sab196087 	*print_type = PRINT_DYN_T_NDX;
518*5088Sab196087 
519*5088Sab196087 	/* If -dynndx was used, this is a simple numeric index */
520*5088Sab196087 	if ((argstate->optmask & DYN_OPT_F_DYNNDX) != 0)
521*5088Sab196087 		return ((Word) elfedit_atoui_range(arg, argname, 0,
522*5088Sab196087 		    argstate->dyn.num - 1, NULL));
523*5088Sab196087 
524*5088Sab196087 	/* The argument is a DT_ tag type, not a numeric index */
525*5088Sab196087 	dt_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_DT);
526*5088Sab196087 
527*5088Sab196087 	/*
528*5088Sab196087 	 * If this is a printing request, then we let print_dyn() show
529*5088Sab196087 	 * all the items with this tag type.
530*5088Sab196087 	 */
531*5088Sab196087 	if (print_request) {
532*5088Sab196087 		*print_type = PRINT_DYN_T_TAG;
533*5088Sab196087 		return (dt_value);
534*5088Sab196087 	}
535*5088Sab196087 
536*5088Sab196087 	/* Locate the first entry with the given tag type */
537*5088Sab196087 	for (ndx = 0; ndx < argstate->dyn.num; ndx++) {
538*5088Sab196087 		if (argstate->dyn.data[ndx].d_tag == dt_value) {
539*5088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
540*5088Sab196087 			    MSG_INTL(MSG_DEBUG_DT2NDX),
541*5088Sab196087 			    EC_WORD(argstate->dyn.sec->sec_shndx),
542*5088Sab196087 			    argstate->dyn.sec->sec_name, EC_WORD(ndx), arg);
543*5088Sab196087 			return (ndx);
544*5088Sab196087 		}
545*5088Sab196087 	}
546*5088Sab196087 
547*5088Sab196087 	/* Not found. Can we create one? */
548*5088Sab196087 	if (argstate->dyn.num_null_ndx > 1)
549*5088Sab196087 		return (convert_dt_null(argstate, dt_value, 0));
550*5088Sab196087 
551*5088Sab196087 	/* No room to create one, so we're out of options and must fail */
552*5088Sab196087 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODTELT),
553*5088Sab196087 	    EC_WORD(argstate->dyn.sec->sec_shndx),
554*5088Sab196087 	    argstate->dyn.sec->sec_name, arg);
555*5088Sab196087 
556*5088Sab196087 	/*NOTREACHED*/
557*5088Sab196087 	return (0);		/* For lint */
558*5088Sab196087 }
559*5088Sab196087 
560*5088Sab196087 
561*5088Sab196087 /*
562*5088Sab196087  * Called by cmd_body() for dyn:value. Implements the core functionality
563*5088Sab196087  * for that command.
564*5088Sab196087  *
565*5088Sab196087  * This routine expects that both the index and value arguments are
566*5088Sab196087  * present.
567*5088Sab196087  */
568*5088Sab196087 static elfedit_cmdret_t
569*5088Sab196087 cmd_body_value(ARGSTATE *argstate, Word *ret_ndx)
570*5088Sab196087 {
571*5088Sab196087 	elfedit_section_t	*dynsec = argstate->dyn.sec;
572*5088Sab196087 	elfedit_section_t	*strsec = argstate->strsec;
573*5088Sab196087 	elfedit_dyn_elt_t	strpad_elt;
574*5088Sab196087 	Word	i;
575*5088Sab196087 	Dyn	*dyn = argstate->dyn.data;
576*5088Sab196087 	Word	numdyn = argstate->dyn.num;
577*5088Sab196087 	int	minus_add = ((argstate->optmask & DYN_OPT_F_ADD) != 0);
578*5088Sab196087 	int	minus_s = ((argstate->optmask & DYN_OPT_F_STRVAL) != 0);
579*5088Sab196087 	int	minus_dynndx = ((argstate->optmask & DYN_OPT_F_DYNNDX) != 0);
580*5088Sab196087 	Word	arg1, tmp_val;
581*5088Sab196087 	Xword	arg2;
582*5088Sab196087 	int	arg2_known = 1;
583*5088Sab196087 
584*5088Sab196087 
585*5088Sab196087 	elfedit_dyn_elt_init(&strpad_elt);
586*5088Sab196087 
587*5088Sab196087 	/*
588*5088Sab196087 	 * The first argument is an index if -dynndx is used, and is a
589*5088Sab196087 	 * tag value otherwise.
590*5088Sab196087 	 */
591*5088Sab196087 	arg1 = minus_dynndx ?
592*5088Sab196087 	    elfedit_atoui_range(argstate->argv[0], MSG_ORIG(MSG_STR_ELT),
593*5088Sab196087 	    0, numdyn - 1, NULL) :
594*5088Sab196087 	    elfedit_atoconst(argstate->argv[0], ELFEDIT_CONST_DT);
595*5088Sab196087 
596*5088Sab196087 	if (minus_s) {
597*5088Sab196087 		/*
598*5088Sab196087 		 * Don't allow the user to specify -s when manipulating a
599*5088Sab196087 		 * DT_SUNW_STRPAD element. Since DT_SUNW_STRPAD is used to
600*5088Sab196087 		 * manage the extra space used for strings, this would break
601*5088Sab196087 		 * our ability to add the string.
602*5088Sab196087 		 */
603*5088Sab196087 		if ((!minus_dynndx && (arg1 == DT_SUNW_STRPAD)) ||
604*5088Sab196087 		    (minus_dynndx && (dyn[arg1].d_tag == DT_SUNW_STRPAD)))
605*5088Sab196087 			elfedit_msg(ELFEDIT_MSG_ERR,
606*5088Sab196087 			    MSG_INTL(MSG_ERR_STRPADSTRVAL),
607*5088Sab196087 			    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
608*5088Sab196087 
609*5088Sab196087 		/* Locate DT_SUNW_STRPAD element if present */
610*5088Sab196087 		strpad_elt.dn_dyn.d_un.d_val = 0;
611*5088Sab196087 		(void) elfedit_dynstr_getpad(argstate->dyn.sec, &strpad_elt);
612*5088Sab196087 
613*5088Sab196087 		/*
614*5088Sab196087 		 * Look up the string: If the user specified the -dynndx
615*5088Sab196087 		 * -option, then we will insert it if possible, and
616*5088Sab196087 		 * fail with an error if not. However, if they did not
617*5088Sab196087 		 * specify -dynndx, we want to look up the string if it is
618*5088Sab196087 		 * already there, but defer the insertion. The reason for
619*5088Sab196087 		 * this is that we may have to grab an unused DT_NULL element
620*5088Sab196087 		 * below, and if there are none available, we won't want
621*5088Sab196087 		 * to have modified the string table.
622*5088Sab196087 		 *
623*5088Sab196087 		 * This isn't a problem, because if the string isn't
624*5088Sab196087 		 * in the string table, it can't be used by a dynamic element.
625*5088Sab196087 		 * Hence, we don't need to insert it to know that there is
626*5088Sab196087 		 * no match.
627*5088Sab196087 		 */
628*5088Sab196087 		if (minus_dynndx == 0) {
629*5088Sab196087 			if (elfedit_sec_findstr(strsec,
630*5088Sab196087 			    strpad_elt.dn_dyn.d_un.d_val, argstate->argv[1],
631*5088Sab196087 			    &tmp_val) == 0) {
632*5088Sab196087 				arg2_known = 0;
633*5088Sab196087 			} else {
634*5088Sab196087 				arg2 = tmp_val;
635*5088Sab196087 			}
636*5088Sab196087 		} else {
637*5088Sab196087 			arg2 = elfedit_dynstr_insert(dynsec, strsec,
638*5088Sab196087 			    &strpad_elt, argstate->argv[1]);
639*5088Sab196087 		}
640*5088Sab196087 	} else {		/* Argument 2 is an integer */
641*5088Sab196087 		arg2 = elfedit_atoui(argstate->argv[1], NULL);
642*5088Sab196087 	}
643*5088Sab196087 
644*5088Sab196087 
645*5088Sab196087 	if (!minus_dynndx && !(minus_add && !arg2_known)) {
646*5088Sab196087 		/*
647*5088Sab196087 		 * Search the dynamic section and see if an item with the
648*5088Sab196087 		 * specified tag value already exists. We can reduce this
649*5088Sab196087 		 * to a simple update of an existing value if -add is not
650*5088Sab196087 		 * specified or the existing d_un value matches the new one.
651*5088Sab196087 		 *
652*5088Sab196087 		 * In either of these cases, we will change arg1 to be the
653*5088Sab196087 		 * index, and set minus_dynndx, causing the simple update to
654*5088Sab196087 		 * happen immediately below.
655*5088Sab196087 		 */
656*5088Sab196087 		for (i = 0; i < numdyn; i++) {
657*5088Sab196087 			if ((dyn[i].d_tag == arg1) &&
658*5088Sab196087 			    (!minus_add || (dyn[i].d_un.d_val == arg2))) {
659*5088Sab196087 				arg1 = i;
660*5088Sab196087 				minus_dynndx = 1;
661*5088Sab196087 				break;
662*5088Sab196087 			}
663*5088Sab196087 		}
664*5088Sab196087 	}
665*5088Sab196087 
666*5088Sab196087 	/*
667*5088Sab196087 	 * If -dynndx is used, then this is a relatively simple
668*5088Sab196087 	 * operation, as we simply write over the specified index.
669*5088Sab196087 	 */
670*5088Sab196087 	if (minus_dynndx) {
671*5088Sab196087 		/*
672*5088Sab196087 		 * If we held back from inserting a new string into
673*5088Sab196087 		 * the dynstr above, we insert it now, because we
674*5088Sab196087 		 * have a slot in the dynamic section, and we need
675*5088Sab196087 		 * the string offset ot finish.
676*5088Sab196087 		 */
677*5088Sab196087 		if (!arg2_known)
678*5088Sab196087 			arg2 = elfedit_dynstr_insert(dynsec, strsec,
679*5088Sab196087 			    &strpad_elt, argstate->argv[1]);
680*5088Sab196087 
681*5088Sab196087 		*ret_ndx = arg1;
682*5088Sab196087 		if (dyn[arg1].d_un.d_val == arg2) {
683*5088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
684*5088Sab196087 			    MSG_INTL(MSG_DEBUG_X_OK),
685*5088Sab196087 			    dynsec->sec_shndx, dynsec->sec_name,
686*5088Sab196087 			    EC_WORD(arg1), EC_XWORD(arg2));
687*5088Sab196087 			return (ELFEDIT_CMDRET_NONE);
688*5088Sab196087 		} else {
689*5088Sab196087 			/* Warn if setting DT_NULL value to non-zero */
690*5088Sab196087 			if ((dyn[arg1].d_tag == DT_NULL) && (arg2 != 0))
691*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
692*5088Sab196087 				    MSG_INTL(MSG_DEBUG_DTNULLVALUE),
693*5088Sab196087 				    dynsec->sec_shndx, dynsec->sec_name,
694*5088Sab196087 				    EC_WORD(arg1), EC_XWORD(arg2));
695*5088Sab196087 
696*5088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
697*5088Sab196087 			    MSG_INTL(MSG_DEBUG_X_CHG),
698*5088Sab196087 			    dynsec->sec_shndx, dynsec->sec_name,
699*5088Sab196087 			    EC_WORD(arg1), EC_XWORD(dyn[arg1].d_un.d_val),
700*5088Sab196087 			    EC_XWORD(arg2));
701*5088Sab196087 			dyn[arg1].d_un.d_val = arg2;
702*5088Sab196087 			return (ELFEDIT_CMDRET_MOD);
703*5088Sab196087 		}
704*5088Sab196087 	}
705*5088Sab196087 
706*5088Sab196087 	/*
707*5088Sab196087 	 * We need a new slot in the dynamic section. If we can't have
708*5088Sab196087 	 * one, then we fail.
709*5088Sab196087 	 */
710*5088Sab196087 	if (argstate->dyn.num_null_ndx <= 1)
711*5088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
712*5088Sab196087 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
713*5088Sab196087 
714*5088Sab196087 	/*
715*5088Sab196087 	 * If we still need to insert a new string into the dynstr,
716*5088Sab196087 	 * then it is safe now, because if we succeed, we know that
717*5088Sab196087 	 * there is an available slot to receive it. If we fail, we
718*5088Sab196087 	 * haven't claimed the extra slot yet, and it will be unharmed.
719*5088Sab196087 	 */
720*5088Sab196087 	if (!arg2_known)
721*5088Sab196087 		arg2 = elfedit_dynstr_insert(dynsec, strsec,
722*5088Sab196087 		    &strpad_elt, argstate->argv[1]);
723*5088Sab196087 
724*5088Sab196087 	/* Use an extra DT_NULL slot and enter the new element */
725*5088Sab196087 	*ret_ndx = convert_dt_null(argstate, arg1, arg2);
726*5088Sab196087 	return (ELFEDIT_CMDRET_MOD);
727*5088Sab196087 }
728*5088Sab196087 
729*5088Sab196087 
730*5088Sab196087 
731*5088Sab196087 /*
732*5088Sab196087  * Called by cmd_body() for dyn:runpath. Implements the core functionality
733*5088Sab196087  * for that command.
734*5088Sab196087  *
735*5088Sab196087  * History Lesson And Strategy:
736*5088Sab196087  *
737*5088Sab196087  * This routine handles both DT_RPATH and DT_RUNPATH entries, altering
738*5088Sab196087  * either or both if they are present.
739*5088Sab196087  *
740*5088Sab196087  * The original SYSV ABI only had DT_RPATH, and the runtime loader used
741*5088Sab196087  * it to search for things in the following order:
742*5088Sab196087  *
743*5088Sab196087  *	DT_RPATH, LD_LIBRARY_PATH, defaults
744*5088Sab196087  *
745*5088Sab196087  * Solaris did not follow this rule, an extremely rare deviation from
746*5088Sab196087  * the ABI. Environment variables should supercede everything else,
747*5088Sab196087  * otherwise they are not very useful. This decision was made at the
748*5088Sab196087  * very beginning of the SunOS 5.x development, so we have always
749*5088Sab196087  * deviated from the ABI and and instead search in the order
750*5088Sab196087  *
751*5088Sab196087  *	LD_LIBRARY_PATH, DT_RPATH, defaults
752*5088Sab196087  *
753*5088Sab196087  * Other Unix variants initially followed the ABI, but in recent years
754*5088Sab196087  * have come to agree with the early Solaris folks that it was a mistake.
755*5088Sab196087  * Hence, DT_RUNPATH was invented, with the search order:
756*5088Sab196087  *
757*5088Sab196087  *	LD_LIBRARY_PATH, DT_RUNPATH, defaults
758*5088Sab196087  *
759*5088Sab196087  * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both
760*5088Sab196087  * are present (which does happen), we set them both to the new
761*5088Sab196087  * value. If either one is present, we set that one. If neither is
762*5088Sab196087  * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH, but
763*5088Sab196087  * not a DT_RPATH, to conserve available slots for other uses.
764*5088Sab196087  */
765*5088Sab196087 static elfedit_cmdret_t
766*5088Sab196087 cmd_body_runpath(ARGSTATE *argstate)
767*5088Sab196087 {
768*5088Sab196087 	elfedit_section_t	*dynsec = argstate->dyn.sec;
769*5088Sab196087 	elfedit_section_t	*strsec = argstate->strsec;
770*5088Sab196087 	elfedit_dyn_elt_t	rpath_elt;
771*5088Sab196087 	elfedit_dyn_elt_t	runpath_elt;
772*5088Sab196087 	elfedit_dyn_elt_t	strpad_elt;
773*5088Sab196087 	Word			i;
774*5088Sab196087 	Dyn			*dyn = argstate->dyn.data;
775*5088Sab196087 	Word			numdyn = argstate->dyn.num;
776*5088Sab196087 
777*5088Sab196087 	/* Go through the tags and gather what we need */
778*5088Sab196087 	elfedit_dyn_elt_init(&rpath_elt);
779*5088Sab196087 	elfedit_dyn_elt_init(&runpath_elt);
780*5088Sab196087 	elfedit_dyn_elt_init(&strpad_elt);
781*5088Sab196087 	for (i = 0; i < numdyn; i++) {
782*5088Sab196087 		switch (dyn[i].d_tag) {
783*5088Sab196087 		case DT_RPATH:
784*5088Sab196087 			elfedit_dyn_elt_save(&rpath_elt, i, &dyn[i]);
785*5088Sab196087 			break;
786*5088Sab196087 
787*5088Sab196087 		case DT_RUNPATH:
788*5088Sab196087 			elfedit_dyn_elt_save(&runpath_elt, i, &dyn[i]);
789*5088Sab196087 			break;
790*5088Sab196087 
791*5088Sab196087 		case DT_SUNW_STRPAD:
792*5088Sab196087 			elfedit_dyn_elt_save(&strpad_elt, i, &dyn[i]);
793*5088Sab196087 			break;
794*5088Sab196087 		}
795*5088Sab196087 	}
796*5088Sab196087 
797*5088Sab196087 	/*  Do we have an available dynamic section entry to use? */
798*5088Sab196087 	if (rpath_elt.dn_seen || runpath_elt.dn_seen) {
799*5088Sab196087 		/*
800*5088Sab196087 		 * We have seen a DT_RPATH, or a DT_RUNPATH, or both.
801*5088Sab196087 		 * If all of these have the same string as the desired
802*5088Sab196087 		 * new value, then we don't need to alter anything and can
803*5088Sab196087 		 * simply return. Otherwise, we'll modify them all to have
804*5088Sab196087 		 * the new string (below).
805*5088Sab196087 		 */
806*5088Sab196087 		if ((!rpath_elt.dn_seen ||
807*5088Sab196087 		    (strcmp(elfedit_dyn_offset_to_str(strsec, &rpath_elt),
808*5088Sab196087 		    argstate->argv[0]) == 0)) &&
809*5088Sab196087 		    (!runpath_elt.dn_seen ||
810*5088Sab196087 		    (strcmp(elfedit_dyn_offset_to_str(strsec, &runpath_elt),
811*5088Sab196087 		    argstate->argv[0]) == 0))) {
812*5088Sab196087 			if (rpath_elt.dn_seen)
813*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
814*5088Sab196087 				    MSG_INTL(MSG_DEBUG_OLDRPATHOK),
815*5088Sab196087 				    EC_WORD(dynsec->sec_shndx),
816*5088Sab196087 				    dynsec->sec_name, EC_WORD(rpath_elt.dn_ndx),
817*5088Sab196087 				    elfedit_atoconst_value_to_str(
818*5088Sab196087 				    ELFEDIT_CONST_DT, DT_RPATH, 1));
819*5088Sab196087 			if (runpath_elt.dn_seen)
820*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
821*5088Sab196087 				    MSG_INTL(MSG_DEBUG_OLDRPATHOK),
822*5088Sab196087 				    EC_WORD(dynsec->sec_shndx),
823*5088Sab196087 				    dynsec->sec_name,
824*5088Sab196087 				    EC_WORD(runpath_elt.dn_ndx),
825*5088Sab196087 				    elfedit_atoconst_value_to_str(
826*5088Sab196087 				    ELFEDIT_CONST_DT, DT_RUNPATH, 1));
827*5088Sab196087 			return (ELFEDIT_CMDRET_NONE);
828*5088Sab196087 		}
829*5088Sab196087 	} else if (argstate->dyn.num_null_ndx <= 1) {
830*5088Sab196087 		/*
831*5088Sab196087 		 * There is no DT_RPATH or DT_RUNPATH in the dynamic array,
832*5088Sab196087 		 * and there are no extra DT_NULL entries that we can
833*5088Sab196087 		 * convert into one. We cannot proceed.
834*5088Sab196087 		 */
835*5088Sab196087 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
836*5088Sab196087 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
837*5088Sab196087 	}
838*5088Sab196087 
839*5088Sab196087 	/* Does the string exist in the table already, or can we add it? */
840*5088Sab196087 	rpath_elt.dn_dyn.d_un.d_val = runpath_elt.dn_dyn.d_un.d_val =
841*5088Sab196087 	    elfedit_dynstr_insert(dynsec, strsec, &strpad_elt,
842*5088Sab196087 	    argstate->argv[0]);
843*5088Sab196087 
844*5088Sab196087 	/* Update DT_RPATH entry if present */
845*5088Sab196087 	if (rpath_elt.dn_seen) {
846*5088Sab196087 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_PREVRPATH),
847*5088Sab196087 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name,
848*5088Sab196087 		    EC_WORD(rpath_elt.dn_ndx),
849*5088Sab196087 		    elfedit_atoconst_value_to_str(
850*5088Sab196087 		    ELFEDIT_CONST_DT, DT_RPATH, 1),
851*5088Sab196087 		    elfedit_dyn_offset_to_str(strsec, &rpath_elt));
852*5088Sab196087 		dyn[rpath_elt.dn_ndx] = rpath_elt.dn_dyn;
853*5088Sab196087 	}
854*5088Sab196087 
855*5088Sab196087 	/*
856*5088Sab196087 	 * Update the DT_RUNPATH entry in the dynamic section, if present.
857*5088Sab196087 	 * If one is not present, and there is also no DT_RPATH, then
858*5088Sab196087 	 * we use a spare DT_NULL entry to create a new DT_RUNPATH.
859*5088Sab196087 	 */
860*5088Sab196087 	if (runpath_elt.dn_seen || !rpath_elt.dn_seen) {
861*5088Sab196087 		if (runpath_elt.dn_seen) {
862*5088Sab196087 			elfedit_msg(ELFEDIT_MSG_DEBUG,
863*5088Sab196087 			    MSG_INTL(MSG_DEBUG_PREVRPATH),
864*5088Sab196087 			    EC_WORD(dynsec->sec_shndx), dynsec->sec_name,
865*5088Sab196087 			    EC_WORD(runpath_elt.dn_ndx),
866*5088Sab196087 			    elfedit_atoconst_value_to_str(
867*5088Sab196087 			    ELFEDIT_CONST_DT, DT_RUNPATH, 1),
868*5088Sab196087 			    elfedit_dyn_offset_to_str(strsec, &runpath_elt));
869*5088Sab196087 			dyn[runpath_elt.dn_ndx] = runpath_elt.dn_dyn;
870*5088Sab196087 		} else {	/* Using a spare DT_NULL entry */
871*5088Sab196087 			(void) convert_dt_null(argstate, DT_RUNPATH,
872*5088Sab196087 			    runpath_elt.dn_dyn.d_un.d_val);
873*5088Sab196087 		}
874*5088Sab196087 	}
875*5088Sab196087 
876*5088Sab196087 	return (ELFEDIT_CMDRET_MOD);
877*5088Sab196087 }
878*5088Sab196087 
879*5088Sab196087 
880*5088Sab196087 
881*5088Sab196087 /*
882*5088Sab196087  * Argument processing for the bitmask commands. Convert the arguments
883*5088Sab196087  * to integer form, apply -and/-cmp/-or, and return the resulting value.
884*5088Sab196087  *
885*5088Sab196087  * entry:
886*5088Sab196087  *	argstate - Argument state block
887*5088Sab196087  *	orig - Value of original bitmask
888*5088Sab196087  *	const_type - ELFEDIT_CONST_* value for type of constants
889*5088Sab196087  */
890*5088Sab196087 static Word
891*5088Sab196087 flag_bitop(ARGSTATE *argstate, Word orig, elfedit_const_t const_type)
892*5088Sab196087 {
893*5088Sab196087 	Word flags = 0;
894*5088Sab196087 	int i;
895*5088Sab196087 
896*5088Sab196087 	/* Collect the arguments */
897*5088Sab196087 	for (i = 0; i < argstate->argc; i++)
898*5088Sab196087 		flags |= (Word) elfedit_atoconst(argstate->argv[i], const_type);
899*5088Sab196087 
900*5088Sab196087 	/* Complement the value? */
901*5088Sab196087 	if (argstate->optmask & DYN_OPT_F_CMP)
902*5088Sab196087 		flags = ~flags;
903*5088Sab196087 
904*5088Sab196087 	/* Perform any requested bit operations */
905*5088Sab196087 	if (argstate->optmask & DYN_OPT_F_AND)
906*5088Sab196087 		flags &= orig;
907*5088Sab196087 	else if (argstate->optmask & DYN_OPT_F_OR)
908*5088Sab196087 		flags |= orig;
909*5088Sab196087 
910*5088Sab196087 	return (flags);
911*5088Sab196087 }
912*5088Sab196087 
913*5088Sab196087 
914*5088Sab196087 
915*5088Sab196087 /*
916*5088Sab196087  * Common body for the dyn: module commands. These commands
917*5088Sab196087  * share a large amount of common behavior, so it is convenient
918*5088Sab196087  * to centralize things and use the cmd argument to handle the
919*5088Sab196087  * small differences.
920*5088Sab196087  *
921*5088Sab196087  * entry:
922*5088Sab196087  *	cmd - One of the DYN_CMD_T_* constants listed above, specifying
923*5088Sab196087  *		which command to implement.
924*5088Sab196087  *	obj_state, argc, argv - Standard command arguments
925*5088Sab196087  */
926*5088Sab196087 static elfedit_cmdret_t
927*5088Sab196087 cmd_body(DYN_CMD_T cmd, elfedit_obj_state_t *obj_state,
928*5088Sab196087     int argc, const char *argv[])
929*5088Sab196087 {
930*5088Sab196087 	ARGSTATE		argstate;
931*5088Sab196087 	Dyn			*dyn;
932*5088Sab196087 	const char		*dyn_name;
933*5088Sab196087 	Word			dyn_ndx, dyn_num, null_ndx;
934*5088Sab196087 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
935*5088Sab196087 	PRINT_DYN_T		print_type = PRINT_DYN_T_ALL;
936*5088Sab196087 	Word			ndx;
937*5088Sab196087 	int			print_only = 0;
938*5088Sab196087 	int			do_autoprint = 1;
939*5088Sab196087 
940*5088Sab196087 	/* Process the optional arguments */
941*5088Sab196087 	process_args(obj_state, argc, argv, &argstate);
942*5088Sab196087 
943*5088Sab196087 	dyn = argstate.dyn.data;
944*5088Sab196087 	dyn_num = argstate.dyn.num;
945*5088Sab196087 	dyn_name = argstate.dyn.sec->sec_name;
946*5088Sab196087 	dyn_ndx = argstate.dyn.sec->sec_shndx;
947*5088Sab196087 
948*5088Sab196087 	/* Check number of arguments, gather information */
949*5088Sab196087 	switch (cmd) {
950*5088Sab196087 	case DYN_CMD_T_DUMP:
951*5088Sab196087 		/* dyn:dump can accept an optional index argument */
952*5088Sab196087 		if (argstate.argc > 1)
953*5088Sab196087 			elfedit_command_usage();
954*5088Sab196087 		print_only = 1;
955*5088Sab196087 		if (argstate.argc == 1)
956*5088Sab196087 			ndx = arg_to_index(&argstate, argstate.argv[0],
957*5088Sab196087 			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
958*5088Sab196087 		break;
959*5088Sab196087 
960*5088Sab196087 	case DYN_CMD_T_TAG:
961*5088Sab196087 		print_only = (argstate.argc != 2);
962*5088Sab196087 		if (argstate.argc > 0) {
963*5088Sab196087 			if (argstate.argc > 2)
964*5088Sab196087 				elfedit_command_usage();
965*5088Sab196087 			ndx = arg_to_index(&argstate, argstate.argv[0],
966*5088Sab196087 			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
967*5088Sab196087 		}
968*5088Sab196087 		break;
969*5088Sab196087 
970*5088Sab196087 	case DYN_CMD_T_VALUE:
971*5088Sab196087 		print_only = (argstate.argc != 2);
972*5088Sab196087 		if (argstate.argc > 2)
973*5088Sab196087 			elfedit_command_usage();
974*5088Sab196087 		if (argstate.argc > 0) {
975*5088Sab196087 			if (print_only) {
976*5088Sab196087 				ndx = arg_to_index(&argstate, argstate.argv[0],
977*5088Sab196087 				    MSG_ORIG(MSG_STR_ELT),
978*5088Sab196087 				    print_only, &print_type);
979*5088Sab196087 			} else {
980*5088Sab196087 				print_type = PRINT_DYN_T_NDX;
981*5088Sab196087 			}
982*5088Sab196087 		}
983*5088Sab196087 		break;
984*5088Sab196087 
985*5088Sab196087 	case DYN_CMD_T_DELETE:
986*5088Sab196087 		if ((argstate.argc < 1) || (argstate.argc > 2))
987*5088Sab196087 			elfedit_command_usage();
988*5088Sab196087 		ndx = arg_to_index(&argstate, argstate.argv[0],
989*5088Sab196087 		    MSG_ORIG(MSG_STR_ELT),
990*5088Sab196087 		    0, &print_type);
991*5088Sab196087 		do_autoprint = 0;
992*5088Sab196087 		break;
993*5088Sab196087 
994*5088Sab196087 	case DYN_CMD_T_MOVE:
995*5088Sab196087 		if ((argstate.argc < 2) || (argstate.argc > 3))
996*5088Sab196087 			elfedit_command_usage();
997*5088Sab196087 		ndx = arg_to_index(&argstate, argstate.argv[0],
998*5088Sab196087 		    MSG_ORIG(MSG_STR_ELT), 0, &print_type);
999*5088Sab196087 		do_autoprint = 0;
1000*5088Sab196087 		break;
1001*5088Sab196087 
1002*5088Sab196087 	case DYN_CMD_T_RUNPATH:
1003*5088Sab196087 		if (argstate.argc > 1)
1004*5088Sab196087 			elfedit_command_usage();
1005*5088Sab196087 		/*
1006*5088Sab196087 		 * dyn:runpath does not accept an explicit index
1007*5088Sab196087 		 * argument, so we implicitly only show the DT_RPATH and
1008*5088Sab196087 		 * DT_RUNPATH elements.
1009*5088Sab196087 		 */
1010*5088Sab196087 		print_type = PRINT_DYN_T_RUNPATH;
1011*5088Sab196087 		print_only = (argstate.argc == 0);
1012*5088Sab196087 		break;
1013*5088Sab196087 
1014*5088Sab196087 	case DYN_CMD_T_POSFLAG1:
1015*5088Sab196087 		print_only = (argstate.argc == 0);
1016*5088Sab196087 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1017*5088Sab196087 		    ELFEDIT_CONST_DT, DT_POSFLAG_1, 1),
1018*5088Sab196087 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
1019*5088Sab196087 		break;
1020*5088Sab196087 
1021*5088Sab196087 	case DYN_CMD_T_FLAGS:
1022*5088Sab196087 		print_only = (argstate.argc == 0);
1023*5088Sab196087 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1024*5088Sab196087 		    ELFEDIT_CONST_DT, DT_FLAGS, 1),
1025*5088Sab196087 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
1026*5088Sab196087 		break;
1027*5088Sab196087 
1028*5088Sab196087 	case DYN_CMD_T_FLAGS1:
1029*5088Sab196087 		print_only = (argstate.argc == 0);
1030*5088Sab196087 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1031*5088Sab196087 		    ELFEDIT_CONST_DT, DT_FLAGS_1, 1),
1032*5088Sab196087 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
1033*5088Sab196087 		break;
1034*5088Sab196087 
1035*5088Sab196087 	case DYN_CMD_T_FEATURE1:
1036*5088Sab196087 		print_only = (argstate.argc == 0);
1037*5088Sab196087 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1038*5088Sab196087 		    ELFEDIT_CONST_DT, DT_FEATURE_1, 1),
1039*5088Sab196087 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
1040*5088Sab196087 		break;
1041*5088Sab196087 
1042*5088Sab196087 	case DYN_CMD_T_CHECKSUM:
1043*5088Sab196087 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1044*5088Sab196087 		    ELFEDIT_CONST_DT, DT_CHECKSUM, 1),
1045*5088Sab196087 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
1046*5088Sab196087 		break;
1047*5088Sab196087 
1048*5088Sab196087 	default:
1049*5088Sab196087 		/* Note expected: All commands should have been caught above */
1050*5088Sab196087 		elfedit_command_usage();
1051*5088Sab196087 		break;
1052*5088Sab196087 	}
1053*5088Sab196087 
1054*5088Sab196087 
1055*5088Sab196087 	/* If this is a request to print current values, do it and return */
1056*5088Sab196087 	if (print_only) {
1057*5088Sab196087 		print_dyn(cmd, 0, &argstate, print_type, ndx);
1058*5088Sab196087 		return (ELFEDIT_CMDRET_NONE);
1059*5088Sab196087 	}
1060*5088Sab196087 
1061*5088Sab196087 
1062*5088Sab196087 	switch (cmd) {
1063*5088Sab196087 		/*
1064*5088Sab196087 		 * DYN_CMD_T_DUMP can't get here: It is a print-only
1065*5088Sab196087 		 * command.
1066*5088Sab196087 		 */
1067*5088Sab196087 
1068*5088Sab196087 	case DYN_CMD_T_TAG:
1069*5088Sab196087 		{
1070*5088Sab196087 			Conv_inv_buf_t	inv_buf1, inv_buf2;
1071*5088Sab196087 			Half	mach = argstate.obj_state->os_ehdr->e_machine;
1072*5088Sab196087 			Word d_tag = (Word) elfedit_atoconst(argstate.argv[1],
1073*5088Sab196087 			    ELFEDIT_CONST_DT);
1074*5088Sab196087 
1075*5088Sab196087 			if (dyn[ndx].d_tag == d_tag) {
1076*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1077*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_OK),
1078*5088Sab196087 				    dyn_ndx,
1079*5088Sab196087 				    dyn_name, EC_WORD(ndx),
1080*5088Sab196087 				    conv_dyn_tag(d_tag, mach, 0, &inv_buf1));
1081*5088Sab196087 			} else {
1082*5088Sab196087 				Word orig_d_tag = dyn[ndx].d_tag;
1083*5088Sab196087 
1084*5088Sab196087 				ret = ELFEDIT_CMDRET_MOD;
1085*5088Sab196087 				dyn[ndx].d_tag = d_tag;
1086*5088Sab196087 
1087*5088Sab196087 				/*
1088*5088Sab196087 				 * Update null termination index. Warn if we
1089*5088Sab196087 				 * just clobbered the only DT_NULL termination
1090*5088Sab196087 				 * for the array.
1091*5088Sab196087 				 */
1092*5088Sab196087 				null_ndx = argstate.dyn.null_ndx;
1093*5088Sab196087 				set_null_ndx(&argstate);
1094*5088Sab196087 				if ((argstate.dyn.null_ndx >=
1095*5088Sab196087 				    argstate.dyn.num) &&
1096*5088Sab196087 				    (null_ndx != argstate.dyn.null_ndx))
1097*5088Sab196087 					elfedit_msg(ELFEDIT_MSG_DEBUG,
1098*5088Sab196087 					    MSG_INTL(MSG_DEBUG_NULLTERM),
1099*5088Sab196087 					    dyn_ndx, dyn_name,
1100*5088Sab196087 					    EC_WORD(ndx),
1101*5088Sab196087 					    conv_dyn_tag(d_tag, mach,
1102*5088Sab196087 					    0, &inv_buf1));
1103*5088Sab196087 
1104*5088Sab196087 				/*
1105*5088Sab196087 				 * Warning if
1106*5088Sab196087 				 *	- Inserting a DT_NULL cuts off following
1107*5088Sab196087 				 *		non-null elements.
1108*5088Sab196087 				 *	- Inserting a non-DT_NULL after the
1109*5088Sab196087 				 *		first null element, will be
1110*5088Sab196087 				 *		ignored by rtld.
1111*5088Sab196087 				 */
1112*5088Sab196087 				if (d_tag == DT_NULL) {
1113*5088Sab196087 					if ((ndx + 1) < null_ndx)
1114*5088Sab196087 						elfedit_msg(ELFEDIT_MSG_DEBUG,
1115*5088Sab196087 						    MSG_INTL(MSG_DEBUG_NULCLIP),
1116*5088Sab196087 						    dyn_ndx, dyn_name,
1117*5088Sab196087 						    EC_WORD(ndx),
1118*5088Sab196087 						    conv_dyn_tag(d_tag, mach,
1119*5088Sab196087 						    0, &inv_buf1));
1120*5088Sab196087 				} else {
1121*5088Sab196087 					if ((ndx + 1) > argstate.dyn.null_ndx)
1122*5088Sab196087 						elfedit_msg(ELFEDIT_MSG_DEBUG,
1123*5088Sab196087 						    MSG_INTL(MSG_DEBUG_NULHIDE),
1124*5088Sab196087 						    dyn_ndx, dyn_name,
1125*5088Sab196087 						    EC_WORD(ndx),
1126*5088Sab196087 						    conv_dyn_tag(d_tag, mach,
1127*5088Sab196087 						    0, &inv_buf1));
1128*5088Sab196087 				}
1129*5088Sab196087 
1130*5088Sab196087 				/* Debug message that we changed it */
1131*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1132*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_CHG),
1133*5088Sab196087 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1134*5088Sab196087 				    conv_dyn_tag(orig_d_tag, mach, 0,
1135*5088Sab196087 				    &inv_buf1),
1136*5088Sab196087 				    conv_dyn_tag(d_tag, mach, 0, &inv_buf2));
1137*5088Sab196087 			}
1138*5088Sab196087 		}
1139*5088Sab196087 		break;
1140*5088Sab196087 
1141*5088Sab196087 	case DYN_CMD_T_VALUE:
1142*5088Sab196087 		ret = cmd_body_value(&argstate, &ndx);
1143*5088Sab196087 		break;
1144*5088Sab196087 
1145*5088Sab196087 	case DYN_CMD_T_DELETE:
1146*5088Sab196087 		{
1147*5088Sab196087 			Word cnt = (argstate.argc == 1) ? 1 :
1148*5088Sab196087 			    (Word) elfedit_atoui_range(argstate.argv[1],
1149*5088Sab196087 			    MSG_ORIG(MSG_STR_COUNT), 1, dyn_num - ndx, NULL);
1150*5088Sab196087 			const char *msg_prefix =
1151*5088Sab196087 			    elfedit_sec_msgprefix(argstate.dyn.sec);
1152*5088Sab196087 
1153*5088Sab196087 			elfedit_array_elts_delete(msg_prefix, argstate.dyn.data,
1154*5088Sab196087 			    sizeof (Dyn), dyn_num, ndx, cnt);
1155*5088Sab196087 			ret = ELFEDIT_CMDRET_MOD;
1156*5088Sab196087 		}
1157*5088Sab196087 		break;
1158*5088Sab196087 
1159*5088Sab196087 	case DYN_CMD_T_MOVE:
1160*5088Sab196087 		{
1161*5088Sab196087 			Dyn	save;
1162*5088Sab196087 			Word	cnt;
1163*5088Sab196087 			Word	dstndx;
1164*5088Sab196087 			const char *msg_prefix =
1165*5088Sab196087 			    elfedit_sec_msgprefix(argstate.dyn.sec);
1166*5088Sab196087 
1167*5088Sab196087 			dstndx = (Word)
1168*5088Sab196087 			    elfedit_atoui_range(argstate.argv[1],
1169*5088Sab196087 			    MSG_ORIG(MSG_STR_DST_INDEX), 0, dyn_num - 1,
1170*5088Sab196087 			    NULL);
1171*5088Sab196087 			if (argstate.argc == 2) {
1172*5088Sab196087 				cnt = 1;
1173*5088Sab196087 			} else {
1174*5088Sab196087 				cnt = (Word) elfedit_atoui_range(
1175*5088Sab196087 				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
1176*5088Sab196087 				    1, dyn_num, NULL);
1177*5088Sab196087 			}
1178*5088Sab196087 			elfedit_array_elts_move(msg_prefix, argstate.dyn.data,
1179*5088Sab196087 			    sizeof (save), dyn_num, ndx, dstndx, cnt, &save);
1180*5088Sab196087 			ret = ELFEDIT_CMDRET_MOD;
1181*5088Sab196087 		}
1182*5088Sab196087 		break;
1183*5088Sab196087 
1184*5088Sab196087 
1185*5088Sab196087 	case DYN_CMD_T_RUNPATH:
1186*5088Sab196087 		ret = cmd_body_runpath(&argstate);
1187*5088Sab196087 		break;
1188*5088Sab196087 
1189*5088Sab196087 	case DYN_CMD_T_POSFLAG1:
1190*5088Sab196087 		{
1191*5088Sab196087 			Conv_dyn_posflag1_buf_t buf1, buf2;
1192*5088Sab196087 			Word flags;
1193*5088Sab196087 
1194*5088Sab196087 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1195*5088Sab196087 			    ELFEDIT_CONST_DF_P1);
1196*5088Sab196087 
1197*5088Sab196087 			/* Set the value */
1198*5088Sab196087 			if (dyn[ndx].d_un.d_val == flags) {
1199*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1200*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1201*5088Sab196087 				    dyn_name, EC_WORD(ndx),
1202*5088Sab196087 				    conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0,
1203*5088Sab196087 				    &buf1));
1204*5088Sab196087 			} else {
1205*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1206*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_CHG),
1207*5088Sab196087 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1208*5088Sab196087 				    conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0,
1209*5088Sab196087 				    &buf1),
1210*5088Sab196087 				    conv_dyn_posflag1(flags, 0, &buf2));
1211*5088Sab196087 				ret = ELFEDIT_CMDRET_MOD;
1212*5088Sab196087 				dyn[ndx].d_un.d_val = flags;
1213*5088Sab196087 			}
1214*5088Sab196087 		}
1215*5088Sab196087 		break;
1216*5088Sab196087 
1217*5088Sab196087 	case DYN_CMD_T_FLAGS:
1218*5088Sab196087 		{
1219*5088Sab196087 			Conv_dyn_flag_buf_t buf1, buf2;
1220*5088Sab196087 			Word flags;
1221*5088Sab196087 
1222*5088Sab196087 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1223*5088Sab196087 			    ELFEDIT_CONST_DF);
1224*5088Sab196087 
1225*5088Sab196087 			/* Set the value */
1226*5088Sab196087 			if (dyn[ndx].d_un.d_val == flags) {
1227*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1228*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1229*5088Sab196087 				    dyn_name, EC_WORD(ndx),
1230*5088Sab196087 				    conv_dyn_flag(dyn[ndx].d_un.d_val, 0,
1231*5088Sab196087 				    &buf1));
1232*5088Sab196087 			} else {
1233*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1234*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_CHG),
1235*5088Sab196087 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1236*5088Sab196087 				    conv_dyn_flag(dyn[ndx].d_un.d_val, 0,
1237*5088Sab196087 				    &buf1),
1238*5088Sab196087 				    conv_dyn_flag(flags, 0, &buf2));
1239*5088Sab196087 				ret = ELFEDIT_CMDRET_MOD;
1240*5088Sab196087 				dyn[ndx].d_un.d_val = flags;
1241*5088Sab196087 			}
1242*5088Sab196087 		}
1243*5088Sab196087 		break;
1244*5088Sab196087 
1245*5088Sab196087 	case DYN_CMD_T_FLAGS1:
1246*5088Sab196087 		{
1247*5088Sab196087 			Conv_dyn_flag1_buf_t buf1, buf2;
1248*5088Sab196087 			Word flags1;
1249*5088Sab196087 
1250*5088Sab196087 			flags1 = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1251*5088Sab196087 			    ELFEDIT_CONST_DF_1);
1252*5088Sab196087 
1253*5088Sab196087 			/* Set the value */
1254*5088Sab196087 			if (dyn[ndx].d_un.d_val == flags1) {
1255*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1256*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1257*5088Sab196087 				    dyn_name, EC_WORD(ndx),
1258*5088Sab196087 				    conv_dyn_flag1(dyn[ndx].d_un.d_val,
1259*5088Sab196087 				    0, &buf1));
1260*5088Sab196087 			} else {
1261*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1262*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_CHG),
1263*5088Sab196087 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1264*5088Sab196087 				    conv_dyn_flag1(dyn[ndx].d_un.d_val,
1265*5088Sab196087 				    0, &buf1),
1266*5088Sab196087 				    conv_dyn_flag1(flags1, 0, &buf2));
1267*5088Sab196087 				ret = ELFEDIT_CMDRET_MOD;
1268*5088Sab196087 				dyn[ndx].d_un.d_val = flags1;
1269*5088Sab196087 			}
1270*5088Sab196087 		}
1271*5088Sab196087 		break;
1272*5088Sab196087 
1273*5088Sab196087 	case DYN_CMD_T_FEATURE1:
1274*5088Sab196087 		{
1275*5088Sab196087 			Conv_dyn_feature1_buf_t buf1, buf2;
1276*5088Sab196087 			Word flags;
1277*5088Sab196087 
1278*5088Sab196087 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1279*5088Sab196087 			    ELFEDIT_CONST_DTF_1);
1280*5088Sab196087 
1281*5088Sab196087 			/* Set the value */
1282*5088Sab196087 			if (dyn[ndx].d_un.d_val == flags) {
1283*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1284*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1285*5088Sab196087 				    dyn_name, EC_WORD(ndx),
1286*5088Sab196087 				    conv_dyn_feature1(dyn[ndx].d_un.d_val, 0,
1287*5088Sab196087 				    &buf1));
1288*5088Sab196087 			} else {
1289*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1290*5088Sab196087 				    MSG_INTL(MSG_DEBUG_S_CHG),
1291*5088Sab196087 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1292*5088Sab196087 				    conv_dyn_feature1(dyn[ndx].d_un.d_val, 0,
1293*5088Sab196087 				    &buf1),
1294*5088Sab196087 				    conv_dyn_feature1(flags, 0, &buf2));
1295*5088Sab196087 				ret = ELFEDIT_CMDRET_MOD;
1296*5088Sab196087 				dyn[ndx].d_un.d_val = flags;
1297*5088Sab196087 			}
1298*5088Sab196087 		}
1299*5088Sab196087 		break;
1300*5088Sab196087 
1301*5088Sab196087 	case DYN_CMD_T_CHECKSUM:
1302*5088Sab196087 		{
1303*5088Sab196087 			long checksum = elf_checksum(obj_state->os_elf);
1304*5088Sab196087 
1305*5088Sab196087 			/* Set the value */
1306*5088Sab196087 			if (dyn[ndx].d_un.d_val == checksum) {
1307*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1308*5088Sab196087 				    MSG_INTL(MSG_DEBUG_X_OK), dyn_ndx,
1309*5088Sab196087 				    dyn_name, EC_WORD(ndx), EC_XWORD(checksum));
1310*5088Sab196087 			} else {
1311*5088Sab196087 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1312*5088Sab196087 				    MSG_INTL(MSG_DEBUG_X_CHG),
1313*5088Sab196087 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1314*5088Sab196087 				    EC_XWORD(dyn[ndx].d_un.d_val),
1315*5088Sab196087 				    EC_XWORD(checksum));
1316*5088Sab196087 				ret = ELFEDIT_CMDRET_MOD;
1317*5088Sab196087 				dyn[ndx].d_un.d_val = checksum;
1318*5088Sab196087 			}
1319*5088Sab196087 
1320*5088Sab196087 		}
1321*5088Sab196087 	}
1322*5088Sab196087 
1323*5088Sab196087 	/*
1324*5088Sab196087 	 * If we modified the dynamic section header, tell libelf.
1325*5088Sab196087 	 */
1326*5088Sab196087 	if (ret == ELFEDIT_CMDRET_MOD)
1327*5088Sab196087 		elfedit_modified_data(argstate.dyn.sec);
1328*5088Sab196087 
1329*5088Sab196087 	/* Do autoprint */
1330*5088Sab196087 	if (do_autoprint)
1331*5088Sab196087 		print_dyn(cmd, 1, &argstate, print_type, ndx);
1332*5088Sab196087 
1333*5088Sab196087 	return (ret);
1334*5088Sab196087 }
1335*5088Sab196087 
1336*5088Sab196087 
1337*5088Sab196087 
1338*5088Sab196087 /*
1339*5088Sab196087  * Command completion functions for the commands
1340*5088Sab196087  */
1341*5088Sab196087 
1342*5088Sab196087 /*
1343*5088Sab196087  * Command completion for the first argument, which specifies
1344*5088Sab196087  * the dynamic element to use. Examines the options to see if
1345*5088Sab196087  * -dynndx is present, and if not, supplies the completion
1346*5088Sab196087  * strings for argument 1.
1347*5088Sab196087  */
1348*5088Sab196087 /*ARGSUSED*/
1349*5088Sab196087 static void
1350*5088Sab196087 cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1351*5088Sab196087     const char *argv[], int num_opt)
1352*5088Sab196087 {
1353*5088Sab196087 	elfedit_section_t	*cache;
1354*5088Sab196087 	Dyn			*dyn;
1355*5088Sab196087 	Word			i;
1356*5088Sab196087 	const char		*s;
1357*5088Sab196087 	char			*s2;
1358*5088Sab196087 	char			buf[128];
1359*5088Sab196087 
1360*5088Sab196087 	/* Make sure it's the first argument */
1361*5088Sab196087 	if ((argc - num_opt) != 1)
1362*5088Sab196087 		return;
1363*5088Sab196087 
1364*5088Sab196087 	/* Is -dynndx present? If so, we don't complete tag types */
1365*5088Sab196087 	for (i = 0; i < num_opt; i++)
1366*5088Sab196087 		if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0)
1367*5088Sab196087 			return;
1368*5088Sab196087 
1369*5088Sab196087 	/*
1370*5088Sab196087 	 * If there is no object, or if there is no dynamic section,
1371*5088Sab196087 	 * then supply all possible names.
1372*5088Sab196087 	 */
1373*5088Sab196087 	if ((obj_state == NULL) || (obj_state->os_dynndx == SHN_UNDEF)) {
1374*5088Sab196087 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT);
1375*5088Sab196087 		return;
1376*5088Sab196087 	}
1377*5088Sab196087 
1378*5088Sab196087 	/* Supply completions for the tags present in the dynamic section */
1379*5088Sab196087 	cache = &obj_state->os_secarr[obj_state->os_dynndx];
1380*5088Sab196087 	dyn = (Dyn *) cache->sec_data->d_buf;
1381*5088Sab196087 	i = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize;
1382*5088Sab196087 	for (; i-- > 0; dyn++) {
1383*5088Sab196087 		s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_DT,
1384*5088Sab196087 		    dyn->d_tag, 0);
1385*5088Sab196087 		if (s == NULL)
1386*5088Sab196087 			continue;
1387*5088Sab196087 		elfedit_cpl_match(cpldata, s, 1);
1388*5088Sab196087 
1389*5088Sab196087 		/*
1390*5088Sab196087 		 * To get the informal tag names that are lowercase
1391*5088Sab196087 		 * and lack the leading DT_, we copy the string we
1392*5088Sab196087 		 * have into a buffer and process it.
1393*5088Sab196087 		 */
1394*5088Sab196087 		if (strlen(s) < 3)
1395*5088Sab196087 			continue;
1396*5088Sab196087 		(void) strlcpy(buf, s + 3, sizeof (buf));
1397*5088Sab196087 		for (s2 = buf; *s2 != '\0'; s2++)
1398*5088Sab196087 			if (isupper(*s2))
1399*5088Sab196087 				*s2 = tolower(*s2);
1400*5088Sab196087 		elfedit_cpl_match(cpldata, buf, 1);
1401*5088Sab196087 	}
1402*5088Sab196087 }
1403*5088Sab196087 
1404*5088Sab196087 
1405*5088Sab196087 /*ARGSUSED*/
1406*5088Sab196087 static void
1407*5088Sab196087 cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1408*5088Sab196087     const char *argv[], int num_opt)
1409*5088Sab196087 {
1410*5088Sab196087 	/* First argument */
1411*5088Sab196087 	if ((argc - num_opt) == 1) {
1412*5088Sab196087 		cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
1413*5088Sab196087 		return;
1414*5088Sab196087 	}
1415*5088Sab196087 
1416*5088Sab196087 	/* The second argument is always a tag value */
1417*5088Sab196087 	if ((argc - num_opt) == 2)
1418*5088Sab196087 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT);
1419*5088Sab196087 }
1420*5088Sab196087 
1421*5088Sab196087 /*ARGSUSED*/
1422*5088Sab196087 static void
1423*5088Sab196087 cpl_posflag1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1424*5088Sab196087     const char *argv[], int num_opt)
1425*5088Sab196087 {
1426*5088Sab196087 	/* This routine allows multiple flags to be specified */
1427*5088Sab196087 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_P1);
1428*5088Sab196087 }
1429*5088Sab196087 
1430*5088Sab196087 /*ARGSUSED*/
1431*5088Sab196087 static void
1432*5088Sab196087 cpl_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1433*5088Sab196087     const char *argv[], int num_opt)
1434*5088Sab196087 {
1435*5088Sab196087 	/* This routine allows multiple flags to be specified */
1436*5088Sab196087 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF);
1437*5088Sab196087 }
1438*5088Sab196087 
1439*5088Sab196087 /*ARGSUSED*/
1440*5088Sab196087 static void
1441*5088Sab196087 cpl_flags1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1442*5088Sab196087     const char *argv[], int num_opt)
1443*5088Sab196087 {
1444*5088Sab196087 	/* This routine allows multiple flags to be specified */
1445*5088Sab196087 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_1);
1446*5088Sab196087 }
1447*5088Sab196087 
1448*5088Sab196087 /*ARGSUSED*/
1449*5088Sab196087 static void
1450*5088Sab196087 cpl_feature1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1451*5088Sab196087     const char *argv[], int num_opt)
1452*5088Sab196087 {
1453*5088Sab196087 	/* This routine allows multiple flags to be specified */
1454*5088Sab196087 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DTF_1);
1455*5088Sab196087 }
1456*5088Sab196087 
1457*5088Sab196087 
1458*5088Sab196087 /*
1459*5088Sab196087  * Implementation functions for the commands
1460*5088Sab196087  */
1461*5088Sab196087 static elfedit_cmdret_t
1462*5088Sab196087 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1463*5088Sab196087 {
1464*5088Sab196087 	return (cmd_body(DYN_CMD_T_DUMP, obj_state, argc, argv));
1465*5088Sab196087 }
1466*5088Sab196087 
1467*5088Sab196087 static elfedit_cmdret_t
1468*5088Sab196087 cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1469*5088Sab196087 {
1470*5088Sab196087 	return (cmd_body(DYN_CMD_T_TAG, obj_state, argc, argv));
1471*5088Sab196087 }
1472*5088Sab196087 
1473*5088Sab196087 static elfedit_cmdret_t
1474*5088Sab196087 cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1475*5088Sab196087 {
1476*5088Sab196087 	return (cmd_body(DYN_CMD_T_VALUE, obj_state, argc, argv));
1477*5088Sab196087 }
1478*5088Sab196087 
1479*5088Sab196087 static elfedit_cmdret_t
1480*5088Sab196087 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1481*5088Sab196087 {
1482*5088Sab196087 	return (cmd_body(DYN_CMD_T_DELETE, obj_state, argc, argv));
1483*5088Sab196087 }
1484*5088Sab196087 
1485*5088Sab196087 static elfedit_cmdret_t
1486*5088Sab196087 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1487*5088Sab196087 {
1488*5088Sab196087 	return (cmd_body(DYN_CMD_T_MOVE, obj_state, argc, argv));
1489*5088Sab196087 }
1490*5088Sab196087 
1491*5088Sab196087 static elfedit_cmdret_t
1492*5088Sab196087 cmd_runpath(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1493*5088Sab196087 {
1494*5088Sab196087 	return (cmd_body(DYN_CMD_T_RUNPATH, obj_state, argc, argv));
1495*5088Sab196087 }
1496*5088Sab196087 
1497*5088Sab196087 static elfedit_cmdret_t
1498*5088Sab196087 cmd_posflag1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1499*5088Sab196087 {
1500*5088Sab196087 	return (cmd_body(DYN_CMD_T_POSFLAG1, obj_state, argc, argv));
1501*5088Sab196087 }
1502*5088Sab196087 
1503*5088Sab196087 static elfedit_cmdret_t
1504*5088Sab196087 cmd_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1505*5088Sab196087 {
1506*5088Sab196087 	return (cmd_body(DYN_CMD_T_FLAGS, obj_state, argc, argv));
1507*5088Sab196087 }
1508*5088Sab196087 
1509*5088Sab196087 static elfedit_cmdret_t
1510*5088Sab196087 cmd_flags1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1511*5088Sab196087 {
1512*5088Sab196087 	return (cmd_body(DYN_CMD_T_FLAGS1, obj_state, argc, argv));
1513*5088Sab196087 }
1514*5088Sab196087 
1515*5088Sab196087 static elfedit_cmdret_t
1516*5088Sab196087 cmd_feature1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1517*5088Sab196087 {
1518*5088Sab196087 	return (cmd_body(DYN_CMD_T_FEATURE1, obj_state, argc, argv));
1519*5088Sab196087 }
1520*5088Sab196087 
1521*5088Sab196087 static elfedit_cmdret_t
1522*5088Sab196087 cmd_checksum(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1523*5088Sab196087 {
1524*5088Sab196087 	return (cmd_body(DYN_CMD_T_CHECKSUM, obj_state, argc, argv));
1525*5088Sab196087 }
1526*5088Sab196087 
1527*5088Sab196087 
1528*5088Sab196087 
1529*5088Sab196087 /*ARGSUSED*/
1530*5088Sab196087 elfedit_module_t *
1531*5088Sab196087 elfedit_init(elfedit_module_version_t version)
1532*5088Sab196087 {
1533*5088Sab196087 	/* For commands that only accept -o */
1534*5088Sab196087 	static elfedit_cmd_optarg_t opt_ostyle[] = {
1535*5088Sab196087 		{ ELFEDIT_STDOA_OPT_O, NULL,
1536*5088Sab196087 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1537*5088Sab196087 		{ NULL }
1538*5088Sab196087 	};
1539*5088Sab196087 
1540*5088Sab196087 	/* For commands that only accept -and, -cmp, -o, -or */
1541*5088Sab196087 	static elfedit_cmd_optarg_t opt_ostyle_bitop[] = {
1542*5088Sab196087 		{ ELFEDIT_STDOA_OPT_AND, NULL,
1543*5088Sab196087 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR },
1544*5088Sab196087 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
1545*5088Sab196087 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 },
1546*5088Sab196087 		{ ELFEDIT_STDOA_OPT_O, NULL,
1547*5088Sab196087 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1548*5088Sab196087 		{ ELFEDIT_STDOA_OPT_OR, NULL,
1549*5088Sab196087 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND },
1550*5088Sab196087 		{ NULL }
1551*5088Sab196087 	};
1552*5088Sab196087 
1553*5088Sab196087 	/* For commands that only accept -dynndx */
1554*5088Sab196087 	static elfedit_cmd_optarg_t opt_minus_dynndx[] = {
1555*5088Sab196087 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1556*5088Sab196087 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX) */
1557*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0,
1558*5088Sab196087 		    DYN_OPT_F_DYNNDX, 0 },
1559*5088Sab196087 		{ NULL }
1560*5088Sab196087 	};
1561*5088Sab196087 
1562*5088Sab196087 	/* dyn:dump */
1563*5088Sab196087 	static const char *name_dump[] = {
1564*5088Sab196087 	    MSG_ORIG(MSG_CMD_DUMP),
1565*5088Sab196087 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
1566*5088Sab196087 	    NULL
1567*5088Sab196087 	};
1568*5088Sab196087 	static elfedit_cmd_optarg_t arg_dump[] = {
1569*5088Sab196087 		{ MSG_ORIG(MSG_STR_ELT),
1570*5088Sab196087 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1571*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1572*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT },
1573*5088Sab196087 		{ NULL }
1574*5088Sab196087 	};
1575*5088Sab196087 
1576*5088Sab196087 
1577*5088Sab196087 	/* dyn:tag */
1578*5088Sab196087 	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
1579*5088Sab196087 	static elfedit_cmd_optarg_t opt_tag[] = {
1580*5088Sab196087 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1581*5088Sab196087 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX) */
1582*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0,
1583*5088Sab196087 		    DYN_OPT_F_DYNNDX, 0 },
1584*5088Sab196087 		{ ELFEDIT_STDOA_OPT_O, NULL,
1585*5088Sab196087 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1586*5088Sab196087 		{ NULL }
1587*5088Sab196087 	};
1588*5088Sab196087 	static elfedit_cmd_optarg_t arg_tag[] = {
1589*5088Sab196087 		{ MSG_ORIG(MSG_STR_ELT),
1590*5088Sab196087 		    /* MSG_INTL(MSG_A1_TAG_ELT) */
1591*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
1592*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT },
1593*5088Sab196087 		{ MSG_ORIG(MSG_STR_VALUE),
1594*5088Sab196087 		    /* MSG_INTL(MSG_A2_TAG_VALUE) */
1595*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
1596*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT },
1597*5088Sab196087 		{ NULL }
1598*5088Sab196087 	};
1599*5088Sab196087 
1600*5088Sab196087 
1601*5088Sab196087 	/* dyn:value */
1602*5088Sab196087 	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
1603*5088Sab196087 	static elfedit_cmd_optarg_t opt_value[] = {
1604*5088Sab196087 		{ MSG_ORIG(MSG_STR_MINUS_ADD),
1605*5088Sab196087 		    /* MSG_INTL(MSG_OPTDESC_ADD) */
1606*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_OPTDESC_ADD), 0,
1607*5088Sab196087 		    DYN_OPT_F_ADD, DYN_OPT_F_DYNNDX },
1608*5088Sab196087 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1609*5088Sab196087 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX) */
1610*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0,
1611*5088Sab196087 		    DYN_OPT_F_DYNNDX, DYN_OPT_F_ADD },
1612*5088Sab196087 		{ ELFEDIT_STDOA_OPT_O, NULL,
1613*5088Sab196087 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1614*5088Sab196087 		{ MSG_ORIG(MSG_STR_MINUS_S),
1615*5088Sab196087 		    /* MSG_INTL(MSG_OPTDESC_S) */
1616*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0,
1617*5088Sab196087 		    DYN_OPT_F_STRVAL, 0 },
1618*5088Sab196087 		{ NULL }
1619*5088Sab196087 	};
1620*5088Sab196087 	static elfedit_cmd_optarg_t arg_value[] = {
1621*5088Sab196087 		{ MSG_ORIG(MSG_STR_ELT),
1622*5088Sab196087 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1623*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1624*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT },
1625*5088Sab196087 		{ MSG_ORIG(MSG_STR_VALUE),
1626*5088Sab196087 		    /* MSG_INTL(MSG_A2_VALUE_VALUE) */
1627*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
1628*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT },
1629*5088Sab196087 		{ NULL }
1630*5088Sab196087 	};
1631*5088Sab196087 
1632*5088Sab196087 	/* dyn:delete */
1633*5088Sab196087 	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
1634*5088Sab196087 	static elfedit_cmd_optarg_t arg_delete[] = {
1635*5088Sab196087 		{ MSG_ORIG(MSG_STR_ELT),
1636*5088Sab196087 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1637*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1638*5088Sab196087 		    0 },
1639*5088Sab196087 		{ MSG_ORIG(MSG_STR_COUNT),
1640*5088Sab196087 		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
1641*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
1642*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT },
1643*5088Sab196087 		{ NULL }
1644*5088Sab196087 	};
1645*5088Sab196087 
1646*5088Sab196087 	/* dyn:move */
1647*5088Sab196087 	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
1648*5088Sab196087 	static elfedit_cmd_optarg_t arg_move[] = {
1649*5088Sab196087 		{ MSG_ORIG(MSG_STR_ELT),
1650*5088Sab196087 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1651*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1652*5088Sab196087 		    0 },
1653*5088Sab196087 		{ MSG_ORIG(MSG_STR_DST_INDEX),
1654*5088Sab196087 		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
1655*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
1656*5088Sab196087 		    0 },
1657*5088Sab196087 		{ MSG_ORIG(MSG_STR_COUNT),
1658*5088Sab196087 		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
1659*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
1660*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT },
1661*5088Sab196087 		{ NULL }
1662*5088Sab196087 	};
1663*5088Sab196087 
1664*5088Sab196087 	/* dyn:runpath / dyn:rpath */
1665*5088Sab196087 	static const char *name_runpath[] = { MSG_ORIG(MSG_CMD_RUNPATH),
1666*5088Sab196087 	    MSG_ORIG(MSG_CMD_RUNPATH_A1), NULL };
1667*5088Sab196087 	static elfedit_cmd_optarg_t arg_runpath[] = {
1668*5088Sab196087 		{ MSG_ORIG(MSG_STR_NEWPATH),
1669*5088Sab196087 		    /* MSG_INTL(MSG_A1_RUNPATH_NEWPATH) */
1670*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A1_RUNPATH_NEWPATH),
1671*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT },
1672*5088Sab196087 		{ NULL }
1673*5088Sab196087 	};
1674*5088Sab196087 
1675*5088Sab196087 	/* dyn:posflag1 */
1676*5088Sab196087 	static const char *name_posflag1[] = { MSG_ORIG(MSG_CMD_POSFLAG1),
1677*5088Sab196087 	    NULL };
1678*5088Sab196087 	static elfedit_cmd_optarg_t arg_posflag1[] = {
1679*5088Sab196087 		{ MSG_ORIG(MSG_STR_VALUE),
1680*5088Sab196087 		    /* MSG_INTL(MSG_A1_POSFLAG1_VALUE) */
1681*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A1_POSFLAG1_VALUE),
1682*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1683*5088Sab196087 		{ NULL }
1684*5088Sab196087 	};
1685*5088Sab196087 
1686*5088Sab196087 	/* dyn:flags */
1687*5088Sab196087 	static const char *name_flags[] = { MSG_ORIG(MSG_CMD_FLAGS), NULL };
1688*5088Sab196087 	static elfedit_cmd_optarg_t arg_flags[] = {
1689*5088Sab196087 		{ MSG_ORIG(MSG_STR_VALUE),
1690*5088Sab196087 		    /* MSG_INTL(MSG_A1_FLAGS_VALUE) */
1691*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A1_FLAGS_VALUE),
1692*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1693*5088Sab196087 		{ NULL }
1694*5088Sab196087 	};
1695*5088Sab196087 
1696*5088Sab196087 	/* dyn:flags1 */
1697*5088Sab196087 	static const char *name_flags1[] = { MSG_ORIG(MSG_CMD_FLAGS1), NULL };
1698*5088Sab196087 	static elfedit_cmd_optarg_t arg_flags1[] = {
1699*5088Sab196087 		{ MSG_ORIG(MSG_STR_VALUE),
1700*5088Sab196087 		    /* MSG_INTL(MSG_A1_FLAGS1_VALUE) */
1701*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A1_FLAGS1_VALUE),
1702*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1703*5088Sab196087 		{ NULL }
1704*5088Sab196087 	};
1705*5088Sab196087 
1706*5088Sab196087 	/* dyn:feature1 */
1707*5088Sab196087 	static const char *name_feature1[] = { MSG_ORIG(MSG_CMD_FEATURE1),
1708*5088Sab196087 	    NULL };
1709*5088Sab196087 	static elfedit_cmd_optarg_t arg_feature1[] = {
1710*5088Sab196087 		{ MSG_ORIG(MSG_STR_VALUE),
1711*5088Sab196087 		    /* MSG_INTL(MSG_A1_FEATURE1_VALUE) */
1712*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_A1_FEATURE1_VALUE),
1713*5088Sab196087 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1714*5088Sab196087 		{ NULL }
1715*5088Sab196087 	};
1716*5088Sab196087 
1717*5088Sab196087 	/* dyn:checksum */
1718*5088Sab196087 	static const char *name_checksum[] = { MSG_ORIG(MSG_CMD_CHECKSUM),
1719*5088Sab196087 	    NULL };
1720*5088Sab196087 
1721*5088Sab196087 
1722*5088Sab196087 
1723*5088Sab196087 	static elfedit_cmd_t cmds[] = {
1724*5088Sab196087 		/* dyn:dump */
1725*5088Sab196087 		{ cmd_dump, cpl_eltarg, name_dump,
1726*5088Sab196087 		    /* MSG_INTL(MSG_DESC_DUMP) */
1727*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
1728*5088Sab196087 		    /* MSG_INTL(MSG_HELP_DUMP) */
1729*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
1730*5088Sab196087 		    opt_minus_dynndx, arg_dump },
1731*5088Sab196087 
1732*5088Sab196087 		/* dyn:tag */
1733*5088Sab196087 		{ cmd_tag, cpl_tag, name_tag,
1734*5088Sab196087 		    /* MSG_INTL(MSG_DESC_TAG) */
1735*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
1736*5088Sab196087 		    /* MSG_INTL(MSG_HELP_TAG) */
1737*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
1738*5088Sab196087 		    opt_tag, arg_tag },
1739*5088Sab196087 
1740*5088Sab196087 		/* dyn:value */
1741*5088Sab196087 		{ cmd_value, cpl_eltarg, name_value,
1742*5088Sab196087 		    /* MSG_INTL(MSG_DESC_VALUE) */
1743*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
1744*5088Sab196087 		    /* MSG_INTL(MSG_HELP_VALUE) */
1745*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
1746*5088Sab196087 		    opt_value, arg_value },
1747*5088Sab196087 
1748*5088Sab196087 		/* dyn:delete */
1749*5088Sab196087 		{ cmd_delete, cpl_eltarg, name_delete,
1750*5088Sab196087 		    /* MSG_INTL(MSG_DESC_DELETE) */
1751*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
1752*5088Sab196087 		    /* MSG_INTL(MSG_HELP_DELETE) */
1753*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
1754*5088Sab196087 		    opt_minus_dynndx, arg_delete },
1755*5088Sab196087 
1756*5088Sab196087 		/* dyn:move */
1757*5088Sab196087 		{ cmd_move, cpl_eltarg, name_move,
1758*5088Sab196087 		    /* MSG_INTL(MSG_DESC_MOVE) */
1759*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
1760*5088Sab196087 		    /* MSG_INTL(MSG_HELP_MOVE) */
1761*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
1762*5088Sab196087 		    opt_minus_dynndx, arg_move },
1763*5088Sab196087 
1764*5088Sab196087 		/* dyn:runpath */
1765*5088Sab196087 		{ cmd_runpath, NULL, name_runpath,
1766*5088Sab196087 		    /* MSG_INTL(MSG_DESC_RUNPATH) */
1767*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_RUNPATH),
1768*5088Sab196087 		    /* MSG_INTL(MSG_HELP_RUNPATH) */
1769*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_RUNPATH),
1770*5088Sab196087 		    opt_ostyle, arg_runpath },
1771*5088Sab196087 
1772*5088Sab196087 		/* dyn:posflag1 */
1773*5088Sab196087 		{ cmd_posflag1, cpl_posflag1, name_posflag1,
1774*5088Sab196087 		    /* MSG_INTL(MSG_DESC_POSFLAG1) */
1775*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_POSFLAG1),
1776*5088Sab196087 		    /* MSG_INTL(MSG_HELP_POSFLAG1) */
1777*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_POSFLAG1),
1778*5088Sab196087 		    opt_ostyle_bitop, arg_posflag1 },
1779*5088Sab196087 
1780*5088Sab196087 		/* dyn:flags */
1781*5088Sab196087 		{ cmd_flags, cpl_flags, name_flags,
1782*5088Sab196087 		    /* MSG_INTL(MSG_DESC_FLAGS) */
1783*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_FLAGS),
1784*5088Sab196087 		    /* MSG_INTL(MSG_HELP_FLAGS) */
1785*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_FLAGS),
1786*5088Sab196087 		    opt_ostyle_bitop, arg_flags },
1787*5088Sab196087 
1788*5088Sab196087 		/* dyn:flags1 */
1789*5088Sab196087 		{ cmd_flags1, cpl_flags1, name_flags1,
1790*5088Sab196087 		    /* MSG_INTL(MSG_DESC_FLAGS1) */
1791*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_FLAGS1),
1792*5088Sab196087 		    /* MSG_INTL(MSG_HELP_FLAGS1) */
1793*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_FLAGS1),
1794*5088Sab196087 		    opt_ostyle_bitop, arg_flags1 },
1795*5088Sab196087 
1796*5088Sab196087 		/* dyn:feature1 */
1797*5088Sab196087 		{ cmd_feature1, cpl_feature1, name_feature1,
1798*5088Sab196087 		    /* MSG_INTL(MSG_DESC_FEATURE1) */
1799*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_FEATURE1),
1800*5088Sab196087 		    /* MSG_INTL(MSG_HELP_FEATURE1) */
1801*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_FEATURE1),
1802*5088Sab196087 		    opt_ostyle_bitop, arg_feature1 },
1803*5088Sab196087 
1804*5088Sab196087 		/* dyn:checksum */
1805*5088Sab196087 		{ cmd_checksum, NULL, name_checksum,
1806*5088Sab196087 		    /* MSG_INTL(MSG_DESC_CHECKSUM) */
1807*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_DESC_CHECKSUM),
1808*5088Sab196087 		    /* MSG_INTL(MSG_HELP_CHECKSUM) */
1809*5088Sab196087 		    ELFEDIT_I18NHDL(MSG_HELP_CHECKSUM),
1810*5088Sab196087 		    NULL, NULL },
1811*5088Sab196087 
1812*5088Sab196087 		{ NULL }
1813*5088Sab196087 	};
1814*5088Sab196087 
1815*5088Sab196087 	static elfedit_module_t module = {
1816*5088Sab196087 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
1817*5088Sab196087 	    /* MSG_INTL(MSG_MOD_DESC) */
1818*5088Sab196087 	    ELFEDIT_I18NHDL(MSG_MOD_DESC), cmds, mod_i18nhdl_to_str };
1819*5088Sab196087 
1820*5088Sab196087 	return (&module);
1821*5088Sab196087 }
1822