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