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