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