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