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