Home | History | Annotate | Download | only in common
      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 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include	<ctype.h>
     28 #include	<elfedit.h>
     29 #include	<sys/elf_SPARC.h>
     30 #include	<strings.h>
     31 #include	<debug.h>
     32 #include	<conv.h>
     33 #include	<dyn_msg.h>
     34 
     35 
     36 /*
     37  * Dynamic section
     38  */
     39 
     40 /*
     41  * This module uses shared code for several of the commands.
     42  * It is sometimes necessary to know which specific command
     43  * is active.
     44  */
     45 typedef enum {
     46 	/* Dump command, used as module default to display dynamic section */
     47 	DYN_CMD_T_DUMP =	0,	/* dyn:dump */
     48 
     49 	/* Commands that do not correspond directly to a specific DT tag */
     50 	DYN_CMD_T_TAG =		1,	/* dyn:tag */
     51 	DYN_CMD_T_VALUE =	2,	/* dyn:value */
     52 	DYN_CMD_T_DELETE =	3,	/* dyn:delete */
     53 	DYN_CMD_T_MOVE =	4,	/* dyn:shift */
     54 
     55 	/* Commands that embody tag specific knowledge */
     56 	DYN_CMD_T_RUNPATH =	5,	/* dyn:runpath/rpath */
     57 	DYN_CMD_T_POSFLAG1 =	6,	/* dyn:posflag1 */
     58 	DYN_CMD_T_FLAGS =	7,	/* dyn:flags */
     59 	DYN_CMD_T_FLAGS1 =	8,	/* dyn:flags1 */
     60 	DYN_CMD_T_FEATURE1 =	9,	/* dyn:feature1 */
     61 	DYN_CMD_T_CHECKSUM =	10,	/* dyn:checksum */
     62 	DYN_CMD_T_SUNW_LDMACH =	11	/* dyn:sunw_ldmach */
     63 } DYN_CMD_T;
     64 
     65 
     66 
     67 #ifndef _ELF64
     68 /*
     69  * We supply this function for the msg module
     70  */
     71 const char *
     72 _dyn_msg(Msg mid)
     73 {
     74 	return (gettext(MSG_ORIG(mid)));
     75 }
     76 #endif
     77 
     78 
     79 /*
     80  * This function is supplied to elfedit through our elfedit_module_t
     81  * definition. It translates the opaque elfedit_i18nhdl_t handles
     82  * in our module interface into the actual strings for elfedit to
     83  * use.
     84  *
     85  * note:
     86  *	This module uses Msg codes for its i18n handle type.
     87  *	So the translation is simply to use MSG_INTL() to turn
     88  *	it into a string and return it.
     89  */
     90 static const char *
     91 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
     92 {
     93 	Msg msg = (Msg)hdl;
     94 
     95 	return (MSG_INTL(msg));
     96 }
     97 
     98 
     99 
    100 /*
    101  * The dyn_opt_t enum specifies a bit value for every optional
    102  * argument allowed by a command in this module.
    103  */
    104 typedef enum {
    105 	DYN_OPT_F_ADD =		1,	/* -add: Add new elt rather than */
    106 					/*	modifying an existing one */
    107 	DYN_OPT_F_AND =		2,	/* -and: AND (&) values to dest */
    108 	DYN_OPT_F_CMP =		4,	/* -cmp: Complement (~) values */
    109 	DYN_OPT_F_DYNNDX_ELT =	8,	/* -dynndx: 1st plain arg is tag */
    110 					/*	index, not name */
    111 	DYN_OPT_F_DYNNDX_VAL =	16,	/* -dynndx ndx: Index is value to */
    112 					/*	option rather than 1st plain */
    113 					/*	arg. Used for dyn:posflag1 */
    114 	DYN_OPT_F_NEEDED =	32,	/* -needed str: Locate DT_POSFLAG_1 */
    115 					/*	relative to DT_NEEDED element */
    116 	DYN_OPT_F_OR =		64,	/* -or: OR (|) values to dest */
    117 	DYN_OPT_F_STRVAL =	128	/* -s: value is string, not integer */
    118 } dyn_opt_t;
    119 
    120 
    121 /*
    122  * A variable of type ARGSTATE is used by each command to maintain
    123  * information about the arguments and related things. It is
    124  * initialized by process_args(), and used by the other routines.
    125  */
    126 typedef struct {
    127 	elfedit_obj_state_t	*obj_state;
    128 	elfedit_section_t	*strsec;	/* Dynamic string table ref */
    129 	struct {
    130 		elfedit_section_t *sec;		/* Dynamic section reference */
    131 		Dyn	*data;			/* Start dynamic section data */
    132 		Word	num;			/* # dynamic elts */
    133 		Word	null_ndx;		/* Index of first DT_NULL */
    134 		Word	num_null_ndx;		/* # of DT_NULL elements */
    135 	} dyn;
    136 	dyn_opt_t		optmask;   	/* Mask of options used */
    137 	int			argc;		/* # of plain arguments */
    138 	const char		**argv;		/* Plain arguments */
    139 	const char		*dyn_elt_str;	/* Value string for */
    140 						/*	DYN_OPT_F_DYNNDX_VAL */
    141 						/*	or DYN_OPT_F_NEEDED */
    142 } ARGSTATE;
    143 
    144 
    145 
    146 /*
    147  * Set argstate null_ndx field for current dynamic area
    148  */
    149 static void
    150 set_null_ndx(ARGSTATE *argstate)
    151 {
    152 	Word	num, null_ndx;
    153 
    154 	num = argstate->dyn.num;
    155 	argstate->dyn.num_null_ndx = 0;
    156 	for (null_ndx = 0; null_ndx < num; null_ndx++)
    157 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) {
    158 			argstate->dyn.num_null_ndx++;
    159 			break;
    160 		}
    161 	argstate->dyn.null_ndx = null_ndx;
    162 
    163 	/* Count the number of remaining DT_NULL items */
    164 	for (; null_ndx < num; null_ndx++)
    165 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL)
    166 			argstate->dyn.num_null_ndx++;
    167 }
    168 
    169 
    170 /*
    171  * Convert the first available DT_NULL slot in the dynamic section
    172  * into something else.
    173  *
    174  * entry:
    175  *	argstate - Argument state block
    176  *	d_tag, d_val - Values to be set in new element
    177  *
    178  * exit:
    179  *	If an extra DT_NULL slot is available, a debug message is
    180  *	issued, the slot is converted to its new use, and the argstate
    181  *	block state related to DT_NULL slots is updated.
    182  *
    183  *	if no extra DT_NULL slot is present, an error is issued and
    184  *	this routine does not return to the caller.
    185  */
    186 static Word
    187 convert_dt_null(ARGSTATE *argstate, Xword d_tag, Xword d_val)
    188 {
    189 	Conv_inv_buf_t inv_buf;
    190 	Word	ndx;
    191 	Dyn	*dyn;
    192 	Ehdr	*ehdr;
    193 
    194 	/* If we lack an extra element, we can't continue */
    195 	if (argstate->dyn.num_null_ndx <= 1)
    196 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
    197 		    EC_WORD(argstate->dyn.sec->sec_shndx),
    198 		    argstate->dyn.sec->sec_name);
    199 
    200 	ehdr = argstate->obj_state->os_ehdr;
    201 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
    202 	    EC_WORD(argstate->dyn.sec->sec_shndx), argstate->dyn.sec->sec_name,
    203 	    EC_WORD(argstate->dyn.null_ndx), conv_dyn_tag(d_tag,
    204 	    ehdr->e_ident[EI_OSABI], ehdr->e_machine, 0, &inv_buf));
    205 
    206 	ndx = argstate->dyn.null_ndx;
    207 	dyn = &argstate->dyn.data[ndx];
    208 	dyn->d_tag = d_tag;
    209 	dyn->d_un.d_val = d_val;
    210 
    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  */
    229 static void
    230 process_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  */
    283 typedef 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 
    292 static void
    293 print_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  */
    622 static Word
    623 arg_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  */
    763 static elfedit_cmdret_t
    764 cmd_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  */
    962 static elfedit_cmdret_t
    963 cmd_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  */
   1089 static Word
   1090 flag_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  */
   1125 static elfedit_cmdret_t
   1126 cmd_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*/
   1589 static void
   1590 cpl_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*/
   1646 static void
   1647 cpl_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*/
   1662 static void
   1663 cpl_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*/
   1723 static void
   1724 cpl_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*/
   1732 static void
   1733 cpl_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*/
   1741 static void
   1742 cpl_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*/
   1750 static void
   1751 cpl_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  */
   1769 static elfedit_cmdret_t
   1770 cmd_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 
   1775 static elfedit_cmdret_t
   1776 cmd_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 
   1781 static elfedit_cmdret_t
   1782 cmd_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 
   1787 static elfedit_cmdret_t
   1788 cmd_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 
   1793 static elfedit_cmdret_t
   1794 cmd_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 
   1799 static elfedit_cmdret_t
   1800 cmd_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 
   1805 static elfedit_cmdret_t
   1806 cmd_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 
   1811 static elfedit_cmdret_t
   1812 cmd_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 
   1817 static elfedit_cmdret_t
   1818 cmd_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 
   1823 static elfedit_cmdret_t
   1824 cmd_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 
   1829 static elfedit_cmdret_t
   1830 cmd_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 
   1835 static elfedit_cmdret_t
   1836 cmd_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*/
   1844 elfedit_module_t *
   1845 elfedit_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