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	<stdio.h>
     28 #include	<unistd.h>
     29 #include	<elfedit.h>
     30 #include	<sys/elf_SPARC.h>
     31 #include	<sys/elf_amd64.h>
     32 #include	<strings.h>
     33 #include	<debug.h>
     34 #include	<conv.h>
     35 #include	<shdr_msg.h>
     36 
     37 
     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 	SHDR_CMD_T_DUMP =		0,	/* shdr:dump */
     47 
     48 	SHDR_CMD_T_SH_ADDR =		1,	/* shdr:sh_addr */
     49 	SHDR_CMD_T_SH_ADDRALIGN =	2,	/* shdr:sh_addralign */
     50 	SHDR_CMD_T_SH_ENTSIZE =		3,	/* shdr:sh_entsize */
     51 	SHDR_CMD_T_SH_FLAGS =		4,	/* shdr:sh_flags */
     52 	SHDR_CMD_T_SH_INFO =		5,	/* shdr:sh_info */
     53 	SHDR_CMD_T_SH_LINK =		6,	/* shdr:sh_link */
     54 	SHDR_CMD_T_SH_NAME =		7,	/* shdr:sh_name */
     55 	SHDR_CMD_T_SH_OFFSET =		8,	/* shdr:sh_offset */
     56 	SHDR_CMD_T_SH_SIZE =		9,	/* shdr:sh_size */
     57 	SHDR_CMD_T_SH_TYPE =		10	/* shdr:sh_type */
     58 } SHDR_CMD_T;
     59 
     60 
     61 
     62 #ifndef _ELF64
     63 /*
     64  * We supply this function for the msg module. Only one copy is needed.
     65  */
     66 const char *
     67 _shdr_msg(Msg mid)
     68 {
     69 	return (gettext(MSG_ORIG(mid)));
     70 }
     71 
     72 #endif
     73 
     74 
     75 
     76 /*
     77  * This function is supplied to elfedit through our elfedit_module_t
     78  * definition. It translates the opaque elfedit_i18nhdl_t handles
     79  * in our module interface into the actual strings for elfedit to
     80  * use.
     81  *
     82  * note:
     83  *	This module uses Msg codes for its i18n handle type.
     84  *	So the translation is simply to use MSG_INTL() to turn
     85  *	it into a string and return it.
     86  */
     87 static const char *
     88 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
     89 {
     90 	Msg msg = (Msg)hdl;
     91 
     92 	return (MSG_INTL(msg));
     93 }
     94 
     95 
     96 
     97 /*
     98  * The shdr_opt_t enum specifies a bit value for every optional
     99  * argument allowed by a command in this module.
    100  */
    101 typedef enum {
    102 	SHDR_OPT_F_AND =	1,	/* -and: AND (&) values to dest */
    103 	SHDR_OPT_F_CMP =	2,	/* -cmp: Complement (~) values */
    104 	SHDR_OPT_F_NAMOFFSET =	4,	/* -name_offset: Name arg is numeric */
    105 					/*	 ofset rather than string */
    106 	SHDR_OPT_F_OR =		8,	/* -or: OR (|) values to dest */
    107 	SHDR_OPT_F_SHNDX =	16,	/* -shndx: Section by index, not name */
    108 	SHDR_OPT_F_SHTYP =	32,	/* -shtyp: Section by type, not name */
    109 	SHDR_OPT_F_VALUE_SHNAM = 64,	/* -value_shnam: Value of sh_info or */
    110 					/*	sh_link given as section name */
    111 	SHDR_OPT_F_VALUE_SHTYP = 128	/* -value_shtyp: Value of sh_info or */
    112 					/*	sh_link given as section type */
    113 } shdr_opt_t;
    114 
    115 
    116 /*
    117  * A variable of type ARGSTATE is used by each command to maintain
    118  * information about the section headers and related things. It is
    119  * initialized by process_args(), and used by the other routines.
    120  */
    121 typedef struct {
    122 	elfedit_obj_state_t	*obj_state;
    123 	shdr_opt_t		optmask;   	/* Mask of options used */
    124 	int			argc;		/* # of plain arguments */
    125 	const char		**argv;		/* Plain arguments */
    126 } ARGSTATE;
    127 
    128 
    129 
    130 
    131 /*
    132  * Standard argument processing for shdr module
    133  *
    134  * entry
    135  *	obj_state, argc, argv - Standard command arguments
    136  *	optmask - Mask of allowed optional arguments.
    137  *	cmd - SHDR_CMD_T_* value giving identify of caller
    138  *	argstate - Address of ARGSTATE block to be initialized
    139  *
    140  * exit:
    141  *	On success, *argstate is initialized. On error,
    142  *	an error is issued and this routine does not return.
    143  */
    144 static void
    145 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
    146     SHDR_CMD_T cmd, ARGSTATE *argstate)
    147 {
    148 	elfedit_getopt_state_t	getopt_state;
    149 	elfedit_getopt_ret_t	*getopt_ret;
    150 
    151 	bzero(argstate, sizeof (*argstate));
    152 	argstate->obj_state = obj_state;
    153 
    154 	elfedit_getopt_init(&getopt_state, &argc, &argv);
    155 
    156 	/* Add each new option to the options mask */
    157 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
    158 		argstate->optmask |= getopt_ret->gor_idmask;
    159 
    160 	/* Are the right number of plain arguments present? */
    161 	switch (cmd) {
    162 	case SHDR_CMD_T_DUMP:
    163 		if (argc > 1)
    164 			elfedit_command_usage();
    165 		break;
    166 	case SHDR_CMD_T_SH_FLAGS:
    167 		/* shdr:sh_flags allows an arbitrary number of arguments */
    168 		break;
    169 	default:
    170 		/* The remaining commands accept 2 plain arguments */
    171 		if (argc > 2)
    172 			elfedit_command_usage();
    173 		break;
    174 	}
    175 
    176 	/* If there may be an arbitrary amount of output, use a pager */
    177 	if (argc == 0)
    178 		elfedit_pager_init();
    179 
    180 	/* Return the updated values of argc/argv */
    181 	argstate->argc = argc;
    182 	argstate->argv = argv;
    183 }
    184 
    185 
    186 
    187 /*
    188  * Options for deciding which items print_shdr() displays.
    189  */
    190 typedef enum {
    191 	PRINT_SHDR_ALL,		/* Print all shdr[ndx:ndx+cnt-1] */
    192 	PRINT_SHDR_TYPE,	/* Print all shdr[ndx:ndx+cnt-1] with type */
    193 				/*	 of shdr[ndx] */
    194 	PRINT_SHDR_NAME,	/* Print all shdr[ndx:ndx+cnt-1] with name */
    195 				/*	 of shdr[ndx] */
    196 } PRINT_SHDR_T;
    197 
    198 /*
    199  * Print section header values, taking the calling command, and output style
    200  * into account.
    201  *
    202  * entry:
    203  *	autoprint - If True, output is only produced if the elfedit
    204  *		autoprint flag is set. If False, output is always produced.
    205  *	cmd - SHDR_CMD_T_* value giving identify of caller
    206  *	argstate - State block for section header array
    207  *	ndx - Index of first section to display
    208  *	cnt - Number of sections to display
    209  *	print_type - Specifies which items are shown
    210  */
    211 static void
    212 print_shdr(SHDR_CMD_T cmd, int autoprint, ARGSTATE *argstate,
    213     Word ndx, Word cnt, PRINT_SHDR_T print_type)
    214 {
    215 	elfedit_outstyle_t	outstyle;
    216 	Ehdr			*ehdr = argstate->obj_state->os_ehdr;
    217 	uchar_t			osabi = ehdr->e_ident[EI_OSABI];
    218 	Half			mach = ehdr->e_machine;
    219 	elfedit_section_t 	*ref_sec = &argstate->obj_state->os_secarr[ndx];
    220 
    221 
    222 	if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) ||
    223 	    (cnt == 0))
    224 		return;
    225 
    226 	/*
    227 	 * Pick an output style. shdr:dump is required to use the default
    228 	 * style. The other commands use the current output style.
    229 	 */
    230 	outstyle = (cmd == SHDR_CMD_T_DUMP) ?
    231 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
    232 
    233 	for (; cnt--; ndx++) {
    234 		elfedit_section_t *sec = &argstate->obj_state->os_secarr[ndx];
    235 		Shdr *shdr = sec->sec_shdr;
    236 
    237 		switch (print_type) {
    238 		case PRINT_SHDR_TYPE:
    239 			if (shdr->sh_type != ref_sec->sec_shdr->sh_type)
    240 				continue;
    241 			break;
    242 
    243 		case PRINT_SHDR_NAME:
    244 			if (strcmp(sec->sec_name, ref_sec->sec_name) != 0)
    245 				continue;
    246 			break;
    247 		}
    248 
    249 		/*
    250 		 * If doing default output, use elfdump style where we
    251 		 * show all section header attributes. In this case, the
    252 		 * command that called us doesn't matter
    253 		 */
    254 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
    255 			elfedit_printf(MSG_ORIG(MSG_STR_NL));
    256 			elfedit_printf(MSG_INTL(MSG_ELF_SHDR), ndx,
    257 			    sec->sec_name);
    258 			Elf_shdr(NULL, osabi, mach, sec->sec_shdr);
    259 			continue;
    260 		}
    261 
    262 		/* Non-default output is handled case by case */
    263 		switch (cmd) {
    264 		case SHDR_CMD_T_SH_ADDR:
    265 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
    266 			    EC_XWORD(shdr->sh_addr));
    267 			break;
    268 
    269 		case SHDR_CMD_T_SH_ADDRALIGN:
    270 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
    271 			    EC_XWORD(shdr->sh_addralign));
    272 			break;
    273 
    274 		case SHDR_CMD_T_SH_ENTSIZE:
    275 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
    276 			    EC_XWORD(shdr->sh_entsize));
    277 			break;
    278 
    279 		case SHDR_CMD_T_SH_FLAGS:
    280 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    281 				Conv_sec_flags_buf_t sec_flags_buf;
    282 
    283 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    284 				    conv_sec_flags(osabi, mach, shdr->sh_flags,
    285 				    CONV_FMT_NOBKT, &sec_flags_buf));
    286 			} else {
    287 				elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
    288 				    EC_XWORD(shdr->sh_flags));
    289 			}
    290 			break;
    291 
    292 		case SHDR_CMD_T_SH_INFO:
    293 			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
    294 			    EC_WORD(shdr->sh_info));
    295 			break;
    296 
    297 		case SHDR_CMD_T_SH_LINK:
    298 			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
    299 			    EC_WORD(shdr->sh_link));
    300 			break;
    301 
    302 		case SHDR_CMD_T_SH_NAME:
    303 			/*
    304 			 * In simple output mode, we show the string. In
    305 			 * numeric mode, we show the string table offset.
    306 			 */
    307 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    308 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    309 				    sec->sec_name);
    310 			} else {
    311 				elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
    312 				    EC_WORD(shdr->sh_name));
    313 			}
    314 			break;
    315 
    316 		case SHDR_CMD_T_SH_OFFSET:
    317 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
    318 			    EC_XWORD(shdr->sh_offset));
    319 			break;
    320 
    321 		case SHDR_CMD_T_SH_SIZE:
    322 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
    323 			    EC_XWORD(shdr->sh_size));
    324 			break;
    325 
    326 		case SHDR_CMD_T_SH_TYPE:
    327 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    328 				Conv_inv_buf_t inv_buf;
    329 
    330 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    331 				    conv_sec_type(osabi, mach, shdr->sh_type, 0,
    332 				    &inv_buf));
    333 			} else {
    334 				elfedit_printf(MSG_ORIG(MSG_FMT_WORDHEXNL),
    335 				    EC_WORD(shdr->sh_type));
    336 			}
    337 			break;
    338 		}
    339 	}
    340 }
    341 
    342 
    343 /*
    344  * Common body for the shdr: module commands. These commands
    345  * share a large amount of common behavior, so it is convenient
    346  * to centralize things and use the cmd argument to handle the
    347  * small differences.
    348  *
    349  * entry:
    350  *	cmd - One of the SHDR_CMD_T_* constants listed above, specifying
    351  *		which command to implement.
    352  *	obj_state, argc, argv - Standard command arguments
    353  */
    354 static elfedit_cmdret_t
    355 cmd_body(SHDR_CMD_T cmd, elfedit_obj_state_t *obj_state,
    356     int argc, const char *argv[])
    357 {
    358 	Ehdr			*ehdr = obj_state->os_ehdr;
    359 	uchar_t			osabi = ehdr->e_ident[EI_OSABI];
    360 	Half			mach = ehdr->e_machine;
    361 	ARGSTATE		argstate;
    362 	Word			ndx;
    363 	elfedit_section_t	*shdr_sec;
    364 	Shdr			*shdr;
    365 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
    366 	PRINT_SHDR_T		print_type;
    367 
    368 	process_args(obj_state, argc, argv, cmd, &argstate);
    369 
    370 	/* If there are no arguments, dump the whole table and return */
    371 	if (argstate.argc == 0) {
    372 		print_shdr(cmd, 0, &argstate, 0, obj_state->os_shnum,
    373 		    PRINT_SHDR_ALL);
    374 		return (ELFEDIT_CMDRET_NONE);
    375 	}
    376 
    377 	/*
    378 	 * The first argument gives the section to use. This can be a
    379 	 * name (default), section index, or section type, depending on
    380 	 * the options used.
    381 	 */
    382 	if (argstate.optmask & SHDR_OPT_F_SHNDX) {
    383 		ndx = elfedit_atoshndx(argstate.argv[0], obj_state->os_shnum);
    384 		print_type = PRINT_SHDR_ALL;
    385 	} else if (argstate.optmask & SHDR_OPT_F_SHTYP) {
    386 		ndx = elfedit_type_to_shndx(obj_state,
    387 		    elfedit_atoconst(argstate.argv[0], ELFEDIT_CONST_SHT));
    388 		print_type = PRINT_SHDR_TYPE;
    389 	} else {
    390 		ndx = elfedit_name_to_shndx(obj_state, argstate.argv[0]);
    391 		print_type = PRINT_SHDR_NAME;
    392 	}
    393 
    394 	/* If there is a single argument, display that item and return */
    395 	if (argstate.argc == 1) {
    396 		Word	cnt;
    397 
    398 		cnt = (print_type == PRINT_SHDR_ALL) ?
    399 		    1 : obj_state->os_shnum - ndx;
    400 		print_shdr(cmd, 0, &argstate, ndx, cnt, print_type);
    401 		return (ELFEDIT_CMDRET_NONE);
    402 	}
    403 
    404 	/*
    405 	 * Section [0] is supposed to be all zero unless extended sections
    406 	 * are in force. Rather than setting extended values directly,
    407 	 * it is expected to be handled by libelf. So, a direct change here
    408 	 * is probably not what was intended.
    409 	 */
    410 	if (ndx == 0)
    411 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSHDR0));
    412 
    413 	/* The second value is an integer giving a new value */
    414 	shdr_sec = &obj_state->os_secarr[ndx];
    415 	shdr = shdr_sec->sec_shdr;
    416 	switch (cmd) {
    417 		/*
    418 		 * SHDR_CMD_T_DUMP can't get here: It never has more than
    419 		 * one argument, and is handled above.
    420 		 */
    421 
    422 	case SHDR_CMD_T_SH_ADDR:
    423 		{
    424 			Addr sh_addr = elfedit_atoui(argstate.argv[1], NULL);
    425 
    426 			if (shdr->sh_addr == sh_addr) {
    427 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    428 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    429 				    ndx, shdr_sec->sec_name,
    430 				    MSG_ORIG(MSG_CMD_SH_ADDR),
    431 				    EC_ADDR(shdr->sh_addr));
    432 			} else {
    433 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    434 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    435 				    ndx, shdr_sec->sec_name,
    436 				    MSG_ORIG(MSG_CMD_SH_ADDR),
    437 				    EC_ADDR(shdr->sh_addr), EC_ADDR(sh_addr));
    438 				ret = ELFEDIT_CMDRET_MOD;
    439 				shdr->sh_addr = sh_addr;
    440 			}
    441 		}
    442 		break;
    443 
    444 	case SHDR_CMD_T_SH_ADDRALIGN:
    445 		{
    446 			Xword	sh_addralign;
    447 
    448 			sh_addralign = elfedit_atoui(argstate.argv[1], NULL);
    449 			if (elfedit_bits_set(sh_addralign,
    450 			    sizeof (sh_addralign)) > 1)
    451 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    452 				    MSG_INTL(MSG_DEBUG_ADDRALIGN),
    453 				    argstate.argv[1]);
    454 			if (shdr->sh_addralign == sh_addralign) {
    455 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    456 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    457 				    ndx, shdr_sec->sec_name,
    458 				    MSG_ORIG(MSG_CMD_SH_ADDRALIGN),
    459 				    EC_XWORD(shdr->sh_addralign));
    460 			} else {
    461 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    462 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    463 				    ndx, shdr_sec->sec_name,
    464 				    MSG_ORIG(MSG_CMD_SH_ADDRALIGN),
    465 				    EC_XWORD(shdr->sh_addralign),
    466 				    EC_XWORD(sh_addralign));
    467 				ret = ELFEDIT_CMDRET_MOD;
    468 				shdr->sh_addralign = sh_addralign;
    469 			}
    470 		}
    471 		break;
    472 
    473 	case SHDR_CMD_T_SH_ENTSIZE:
    474 		{
    475 			Xword sh_entsize;
    476 
    477 			sh_entsize = elfedit_atoui(argstate.argv[1], NULL);
    478 			if (shdr->sh_entsize == sh_entsize) {
    479 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    480 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    481 				    ndx, shdr_sec->sec_name,
    482 				    MSG_ORIG(MSG_CMD_SH_ENTSIZE),
    483 				    EC_XWORD(shdr->sh_entsize));
    484 			} else {
    485 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    486 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    487 				    ndx, shdr_sec->sec_name,
    488 				    MSG_ORIG(MSG_CMD_SH_ENTSIZE),
    489 				    EC_XWORD(shdr->sh_entsize),
    490 				    EC_XWORD(sh_entsize));
    491 				ret = ELFEDIT_CMDRET_MOD;
    492 				shdr->sh_entsize = sh_entsize;
    493 			}
    494 		}
    495 		break;
    496 
    497 	case SHDR_CMD_T_SH_FLAGS:
    498 		{
    499 			Conv_sec_flags_buf_t buf1, buf2;
    500 			Word	sh_flags = 0;
    501 			int	i;
    502 
    503 						/* Collect the flag arguments */
    504 			for (i = 1; i < argstate.argc; i++)
    505 				sh_flags |=
    506 				    (Word) elfedit_atoconst(argstate.argv[i],
    507 				    ELFEDIT_CONST_SHF);
    508 
    509 			/* Complement the value? */
    510 			if (argstate.optmask & SHDR_OPT_F_CMP)
    511 				sh_flags = ~sh_flags;
    512 
    513 			/* Perform any requested bit operations */
    514 			if (argstate.optmask & SHDR_OPT_F_AND)
    515 				sh_flags &= shdr->sh_flags;
    516 			else if (argstate.optmask & SHDR_OPT_F_OR)
    517 				sh_flags |= shdr->sh_flags;
    518 
    519 			/* Set the value */
    520 			if (shdr->sh_flags == sh_flags) {
    521 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    522 				    MSG_INTL(MSG_DEBUG_S_OK),
    523 				    ndx, shdr_sec->sec_name,
    524 				    MSG_ORIG(MSG_CMD_SH_FLAGS),
    525 				    conv_sec_flags(osabi, mach,
    526 				    shdr->sh_flags, 0, &buf1));
    527 			} else {
    528 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    529 				    MSG_INTL(MSG_DEBUG_S_CHG),
    530 				    ndx, shdr_sec->sec_name,
    531 				    MSG_ORIG(MSG_CMD_SH_FLAGS),
    532 				    conv_sec_flags(osabi, mach,
    533 				    shdr->sh_flags, 0, &buf1),
    534 				    conv_sec_flags(osabi, mach,
    535 				    sh_flags, 0, &buf2));
    536 				ret = ELFEDIT_CMDRET_MOD;
    537 				shdr->sh_flags = sh_flags;
    538 			}
    539 		}
    540 		break;
    541 
    542 	case SHDR_CMD_T_SH_INFO:
    543 		{
    544 			Word sh_info;
    545 
    546 			if (argstate.optmask & SHDR_OPT_F_VALUE_SHNAM)
    547 				sh_info = elfedit_name_to_shndx(obj_state,
    548 				    argstate.argv[1]);
    549 			else if (argstate.optmask & SHDR_OPT_F_VALUE_SHTYP)
    550 				sh_info = elfedit_type_to_shndx(obj_state,
    551 				    elfedit_atoconst(argstate.argv[1],
    552 				    ELFEDIT_CONST_SHT));
    553 			else
    554 				sh_info = elfedit_atoui(argstate.argv[1], NULL);
    555 
    556 			if (shdr->sh_info == sh_info) {
    557 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    558 				    MSG_INTL(MSG_DEBUG_D_OK),
    559 				    ndx, shdr_sec->sec_name,
    560 				    MSG_ORIG(MSG_CMD_SH_INFO),
    561 				    EC_WORD(shdr->sh_info));
    562 			} else {
    563 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    564 				    MSG_INTL(MSG_DEBUG_D_CHG),
    565 				    ndx, shdr_sec->sec_name,
    566 				    MSG_ORIG(MSG_CMD_SH_INFO),
    567 				    EC_WORD(shdr->sh_info), EC_WORD(sh_info));
    568 				ret = ELFEDIT_CMDRET_MOD;
    569 				shdr->sh_info = sh_info;
    570 			}
    571 		}
    572 		break;
    573 
    574 	case SHDR_CMD_T_SH_LINK:
    575 		{
    576 			Word sh_link;
    577 
    578 			if (argstate.optmask & SHDR_OPT_F_VALUE_SHNAM)
    579 				sh_link = elfedit_name_to_shndx(obj_state,
    580 				    argstate.argv[1]);
    581 			else if (argstate.optmask & SHDR_OPT_F_VALUE_SHTYP)
    582 				sh_link = elfedit_type_to_shndx(obj_state,
    583 				    elfedit_atoconst(argstate.argv[1],
    584 				    ELFEDIT_CONST_SHT));
    585 			else
    586 				sh_link = elfedit_atoui(argstate.argv[1], NULL);
    587 
    588 			if (shdr->sh_link == sh_link) {
    589 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    590 				    MSG_INTL(MSG_DEBUG_D_OK),
    591 				    ndx, shdr_sec->sec_name,
    592 				    MSG_ORIG(MSG_CMD_SH_LINK),
    593 				    EC_WORD(shdr->sh_link));
    594 			} else {
    595 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    596 				    MSG_INTL(MSG_DEBUG_D_CHG),
    597 				    ndx, shdr_sec->sec_name,
    598 				    MSG_ORIG(MSG_CMD_SH_LINK),
    599 				    EC_WORD(shdr->sh_link), EC_WORD(sh_link));
    600 				ret = ELFEDIT_CMDRET_MOD;
    601 				shdr->sh_link = sh_link;
    602 			}
    603 		}
    604 		break;
    605 
    606 	case SHDR_CMD_T_SH_NAME:
    607 		{
    608 			elfedit_section_t *shstr_sec =
    609 			    &obj_state->os_secarr[obj_state->os_shstrndx];
    610 			Word sh_name;
    611 
    612 			/*
    613 			 * If -name_offset was specified, this is an offset
    614 			 * into the string table. Otherwise it is a string
    615 			 * we need to turn into an offset.
    616 			 */
    617 			sh_name = (argstate.optmask & SHDR_OPT_F_NAMOFFSET) ?
    618 			    elfedit_atoui(argstate.argv[1], NULL) :
    619 			    elfedit_strtab_insert(obj_state,
    620 			    shstr_sec, NULL, argstate.argv[1]);
    621 			if (shdr->sh_name == sh_name) {
    622 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    623 				    MSG_INTL(MSG_DEBUG_D_OK),
    624 				    ndx, shdr_sec->sec_name,
    625 				    MSG_ORIG(MSG_CMD_SH_NAME),
    626 				    EC_WORD(shdr->sh_name));
    627 			} else {
    628 				/*
    629 				 * The section name is cached, so we must
    630 				 * also update that value. This call will
    631 				 * warn if the offset is out of range, and
    632 				 * will supply a safe string in that case.
    633 				 */
    634 				shdr_sec->sec_name =
    635 				    elfedit_offset_to_str(shstr_sec,
    636 				    sh_name, ELFEDIT_MSG_DEBUG, 1);
    637 
    638 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    639 				    MSG_INTL(MSG_DEBUG_D_CHG),
    640 				    ndx, shdr_sec->sec_name,
    641 				    MSG_ORIG(MSG_CMD_SH_NAME),
    642 				    EC_WORD(shdr->sh_name), EC_WORD(sh_name));
    643 				ret = ELFEDIT_CMDRET_MOD;
    644 				shdr->sh_name = sh_name;
    645 			}
    646 		}
    647 		break;
    648 
    649 	case SHDR_CMD_T_SH_OFFSET:
    650 		{
    651 			Off sh_offset;
    652 
    653 			sh_offset = elfedit_atoui(argstate.argv[1], NULL);
    654 			if (shdr->sh_offset == sh_offset) {
    655 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    656 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    657 				    ndx, shdr_sec->sec_name,
    658 				    MSG_ORIG(MSG_CMD_SH_OFFSET),
    659 				    EC_XWORD(shdr->sh_offset));
    660 			} else {
    661 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    662 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    663 				    ndx, shdr_sec->sec_name,
    664 				    MSG_ORIG(MSG_CMD_SH_OFFSET),
    665 				    EC_XWORD(shdr->sh_offset),
    666 				    EC_XWORD(sh_offset));
    667 				ret = ELFEDIT_CMDRET_MOD;
    668 				shdr->sh_offset = sh_offset;
    669 			}
    670 		}
    671 		break;
    672 
    673 	case SHDR_CMD_T_SH_SIZE:
    674 		{
    675 			Xword sh_size;
    676 
    677 			sh_size = elfedit_atoui(argstate.argv[1], NULL);
    678 			if (shdr->sh_size == sh_size) {
    679 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    680 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    681 				    ndx, shdr_sec->sec_name,
    682 				    MSG_ORIG(MSG_CMD_SH_SIZE),
    683 				    EC_XWORD(shdr->sh_size));
    684 			} else {
    685 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    686 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    687 				    ndx, shdr_sec->sec_name,
    688 				    MSG_ORIG(MSG_CMD_SH_SIZE),
    689 				    EC_XWORD(shdr->sh_size),
    690 				    EC_XWORD(sh_size));
    691 				ret = ELFEDIT_CMDRET_MOD;
    692 				shdr->sh_size = sh_size;
    693 			}
    694 		}
    695 		break;
    696 
    697 	case SHDR_CMD_T_SH_TYPE:
    698 		{
    699 			Word sh_type = elfedit_atoconst(argstate.argv[1],
    700 			    ELFEDIT_CONST_SHT);
    701 			Conv_inv_buf_t inv_buf1, inv_buf2;
    702 
    703 			if (shdr->sh_type == sh_type) {
    704 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    705 				    MSG_INTL(MSG_DEBUG_S_OK),
    706 				    ndx, shdr_sec->sec_name,
    707 				    MSG_ORIG(MSG_CMD_SH_TYPE),
    708 				    conv_sec_type(osabi, mach, shdr->sh_type,
    709 				    0, &inv_buf1));
    710 			} else {
    711 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    712 				    MSG_INTL(MSG_DEBUG_S_CHG),
    713 				    ndx, shdr_sec->sec_name,
    714 				    MSG_ORIG(MSG_CMD_SH_TYPE),
    715 				    conv_sec_type(osabi, mach, shdr->sh_type,
    716 				    0, &inv_buf1),
    717 				    conv_sec_type(osabi, mach, sh_type,
    718 				    0, &inv_buf2));
    719 				ret = ELFEDIT_CMDRET_MOD;
    720 				shdr->sh_type = sh_type;
    721 			}
    722 		}
    723 		break;
    724 	}
    725 
    726 	/*
    727 	 * If we modified the section header array, tell libelf.
    728 	 */
    729 	if (ret == ELFEDIT_CMDRET_MOD)
    730 		elfedit_modified_shdr(shdr_sec);
    731 
    732 	/* Do autoprint */
    733 	print_shdr(cmd, 1, &argstate, ndx, 1, PRINT_SHDR_ALL);
    734 
    735 	return (ret);
    736 }
    737 
    738 
    739 
    740 
    741 /*
    742  * Command completion functions for the various commands
    743  */
    744 
    745 /*
    746  * All of the commands accept the same first argument (sec) that
    747  * specifies the section. This argument can be a section name
    748  * (default), section index, or section type, depending on the
    749  * options used. This routine determines which case is current,
    750  * and then supplies completion for the first argument.
    751  */
    752 static void
    753 cpl_1starg_sec(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    754     const char *argv[], int num_opt)
    755 {
    756 	elfedit_section_t *sec;
    757 	enum { NAME, INDEX, TYPE } op;
    758 	Word ndx;
    759 
    760 	if (argc != (num_opt + 1))
    761 		return;
    762 
    763 	op = NAME;
    764 	for (ndx = 0; ndx < num_opt; ndx++) {
    765 		if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0)
    766 			op = INDEX;
    767 		else if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0)
    768 			op = TYPE;
    769 	}
    770 
    771 	switch (op) {
    772 	case NAME:
    773 		if (obj_state == NULL)
    774 			break;
    775 		sec = obj_state->os_secarr;
    776 		for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++)
    777 			elfedit_cpl_match(cpldata, sec->sec_name, 0);
    778 		break;
    779 
    780 	case INDEX:
    781 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHN);
    782 		break;
    783 
    784 	case TYPE:
    785 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
    786 		break;
    787 	}
    788 }
    789 
    790 
    791 /*ARGSUSED*/
    792 static void
    793 cpl_sh_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    794     const char *argv[], int num_opt)
    795 {
    796 	/* Handle -shXXX options */
    797 	cpl_1starg_sec(obj_state, cpldata, argc, argv, num_opt);
    798 
    799 	/* The second and following arguments can be an SHF_ value */
    800 	if (argc >= (num_opt + 2))
    801 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHF);
    802 }
    803 
    804 /*
    805  * For shdr:sh_info and shdr:sh_link: The value argument can be an
    806  * integer, section name, or section type.
    807  */
    808 /*ARGSUSED*/
    809 static void
    810 cpl_sh_infolink(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    811     const char *argv[], int num_opt)
    812 {
    813 	elfedit_section_t *sec;
    814 	enum { NAME, INTVAL, TYPE } op;
    815 	Word ndx;
    816 
    817 	/* Handle -shXXX options */
    818 	cpl_1starg_sec(obj_state, cpldata, argc, argv, num_opt);
    819 
    820 	if (argc != (num_opt + 2))
    821 		return;
    822 
    823 	op = INTVAL;
    824 	for (ndx = 0; ndx < num_opt; ndx++) {
    825 		if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_VALUE_SHNAM)) == 0)
    826 			op = NAME;
    827 		else if (strcmp(argv[ndx],
    828 		    MSG_ORIG(MSG_STR_MINUS_VALUE_SHTYP)) == 0)
    829 			op = TYPE;
    830 	}
    831 
    832 	switch (op) {
    833 	case NAME:
    834 		if (obj_state == NULL)
    835 			break;
    836 		sec = obj_state->os_secarr;
    837 		for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++)
    838 			elfedit_cpl_match(cpldata, sec->sec_name, 0);
    839 		break;
    840 
    841 	case TYPE:
    842 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
    843 		break;
    844 	}
    845 }
    846 
    847 /*ARGSUSED*/
    848 static void
    849 cpl_sh_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    850     const char *argv[], int num_opt)
    851 {
    852 	/* Handle -shXXX options */
    853 	cpl_1starg_sec(obj_state, cpldata, argc, argv, num_opt);
    854 
    855 	/* The second argument can be an SHT_ value */
    856 	if (argc == (num_opt + 2))
    857 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
    858 }
    859 
    860 
    861 
    862 /*
    863  * Implementation functions for the commands
    864  */
    865 static elfedit_cmdret_t
    866 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    867 {
    868 	return (cmd_body(SHDR_CMD_T_DUMP, obj_state, argc, argv));
    869 }
    870 
    871 
    872 static elfedit_cmdret_t
    873 cmd_sh_addr(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    874 {
    875 	return (cmd_body(SHDR_CMD_T_SH_ADDR, obj_state, argc, argv));
    876 }
    877 
    878 
    879 static elfedit_cmdret_t
    880 cmd_sh_addralign(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    881 {
    882 	return (cmd_body(SHDR_CMD_T_SH_ADDRALIGN, obj_state, argc, argv));
    883 }
    884 
    885 
    886 static elfedit_cmdret_t
    887 cmd_sh_entsize(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    888 {
    889 	return (cmd_body(SHDR_CMD_T_SH_ENTSIZE, obj_state, argc, argv));
    890 }
    891 
    892 static elfedit_cmdret_t
    893 cmd_sh_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    894 {
    895 	return (cmd_body(SHDR_CMD_T_SH_FLAGS, obj_state, argc, argv));
    896 }
    897 
    898 static elfedit_cmdret_t
    899 cmd_sh_info(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    900 {
    901 	return (cmd_body(SHDR_CMD_T_SH_INFO, obj_state, argc, argv));
    902 }
    903 
    904 static elfedit_cmdret_t
    905 cmd_sh_link(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    906 {
    907 	return (cmd_body(SHDR_CMD_T_SH_LINK, obj_state, argc, argv));
    908 }
    909 
    910 static elfedit_cmdret_t
    911 cmd_sh_name(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    912 {
    913 	return (cmd_body(SHDR_CMD_T_SH_NAME, obj_state, argc, argv));
    914 }
    915 
    916 static elfedit_cmdret_t
    917 cmd_sh_offset(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    918 {
    919 	return (cmd_body(SHDR_CMD_T_SH_OFFSET, obj_state, argc, argv));
    920 }
    921 
    922 static elfedit_cmdret_t
    923 cmd_sh_size(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    924 {
    925 	return (cmd_body(SHDR_CMD_T_SH_SIZE, obj_state, argc, argv));
    926 }
    927 
    928 static elfedit_cmdret_t
    929 cmd_sh_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    930 {
    931 	return (cmd_body(SHDR_CMD_T_SH_TYPE, obj_state, argc, argv));
    932 }
    933 
    934 
    935 
    936 /*ARGSUSED*/
    937 elfedit_module_t *
    938 elfedit_init(elfedit_module_version_t version)
    939 {
    940 	/* Multiple commands accept only the standard set of options */
    941 	static elfedit_cmd_optarg_t opt_std[] = {
    942 		{ ELFEDIT_STDOA_OPT_O, NULL,
    943 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
    944 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
    945 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
    946 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
    947 		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
    948 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
    949 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
    950 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
    951 		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
    952 		{ NULL }
    953 	};
    954 
    955 	/*
    956 	 * sh_info and sh_link accept the standard options above,
    957 	 * plus -value_shnam and -value_shtyp.
    958 	 */
    959 	static elfedit_cmd_optarg_t opt_infolink[] = {
    960 		{ ELFEDIT_STDOA_OPT_O, NULL,
    961 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
    962 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
    963 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
    964 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
    965 		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
    966 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
    967 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
    968 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
    969 		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
    970 		{ MSG_ORIG(MSG_STR_MINUS_VALUE_SHNAM),
    971 		    /* MSG_INTL(MSG_OPTDESC_VALUE_SHNAM) */
    972 		    ELFEDIT_I18NHDL(MSG_OPTDESC_VALUE_SHNAM), 0,
    973 		    SHDR_OPT_F_VALUE_SHNAM, SHDR_OPT_F_VALUE_SHNAM },
    974 		{ MSG_ORIG(MSG_STR_MINUS_VALUE_SHTYP),
    975 		    /* MSG_INTL(MSG_OPTDESC_VALUE_SHTYP) */
    976 		    ELFEDIT_I18NHDL(MSG_OPTDESC_VALUE_SHTYP), 0,
    977 		    SHDR_OPT_F_VALUE_SHTYP, SHDR_OPT_F_VALUE_SHTYP },
    978 		{ NULL }
    979 	};
    980 
    981 	/* shdr:sh_addr */
    982 	static const char *name_sh_addr[] = {
    983 	    MSG_ORIG(MSG_CMD_SH_ADDR), NULL };
    984 	static elfedit_cmd_optarg_t arg_sh_addr[] = {
    985 		{ MSG_ORIG(MSG_STR_SEC),
    986 		    /* MSG_INTL(MSG_A1_SEC) */
    987 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
    988 		    ELFEDIT_CMDOA_F_OPT },
    989 		{ MSG_ORIG(MSG_STR_VALUE),
    990 		    /* MSG_INTL(MSG_A2_DESC_SH_ADDR) */
    991 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ADDR),
    992 		    ELFEDIT_CMDOA_F_OPT },
    993 		{ NULL }
    994 	};
    995 
    996 	/* shdr:dump */
    997 	static const char *name_dump[] = {
    998 	    MSG_ORIG(MSG_CMD_DUMP),
    999 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
   1000 	    NULL
   1001 	};
   1002 	static elfedit_cmd_optarg_t opt_dump[] = {
   1003 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
   1004 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
   1005 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
   1006 		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
   1007 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
   1008 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
   1009 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
   1010 		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
   1011 		{ NULL }
   1012 	};
   1013 	static elfedit_cmd_optarg_t arg_dump[] = {
   1014 		{ MSG_ORIG(MSG_STR_SEC),
   1015 		    /* MSG_INTL(MSG_A1_SEC) */
   1016 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1017 		    ELFEDIT_CMDOA_F_OPT },
   1018 		{ NULL }
   1019 	};
   1020 
   1021 	/* shdr:sh_addralign */
   1022 	static const char *name_sh_addralign[] = {
   1023 	    MSG_ORIG(MSG_CMD_SH_ADDRALIGN), NULL };
   1024 	static elfedit_cmd_optarg_t arg_sh_addralign[] = {
   1025 		{ MSG_ORIG(MSG_STR_SEC),
   1026 		    /* MSG_INTL(MSG_A1_SEC) */
   1027 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1028 		    ELFEDIT_CMDOA_F_OPT },
   1029 		{ MSG_ORIG(MSG_STR_VALUE),
   1030 		    /* MSG_INTL(MSG_A2_DESC_SH_ADDRALIGN) */
   1031 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ADDRALIGN),
   1032 		    ELFEDIT_CMDOA_F_OPT },
   1033 		{ NULL }
   1034 	};
   1035 
   1036 	/* shdr:sh_entsize */
   1037 	static const char *name_sh_entsize[] = {
   1038 	    MSG_ORIG(MSG_CMD_SH_ENTSIZE), NULL };
   1039 	static elfedit_cmd_optarg_t arg_sh_entsize[] = {
   1040 		{ MSG_ORIG(MSG_STR_SEC),
   1041 		    /* MSG_INTL(MSG_A1_SEC) */
   1042 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1043 		    ELFEDIT_CMDOA_F_OPT },
   1044 		{ MSG_ORIG(MSG_STR_VALUE),
   1045 		    /* MSG_INTL(MSG_A2_DESC_SH_ENTSIZE) */
   1046 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ENTSIZE),
   1047 		    ELFEDIT_CMDOA_F_OPT },
   1048 		{ NULL }
   1049 	};
   1050 
   1051 	/* shdr:sh_flags */
   1052 	static const char *name_sh_flags[] = {
   1053 	    MSG_ORIG(MSG_CMD_SH_FLAGS), NULL };
   1054 	static elfedit_cmd_optarg_t opt_sh_flags[] = {
   1055 		{ ELFEDIT_STDOA_OPT_AND, NULL,
   1056 		    ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_AND, SHDR_OPT_F_OR },
   1057 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
   1058 		    ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_CMP, 0 },
   1059 		{ ELFEDIT_STDOA_OPT_O, NULL,
   1060 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
   1061 		{ ELFEDIT_STDOA_OPT_OR, NULL,
   1062 		    ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_OR, SHDR_OPT_F_AND },
   1063 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
   1064 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
   1065 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
   1066 		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
   1067 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
   1068 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
   1069 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
   1070 		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
   1071 		{ NULL }
   1072 	};
   1073 	static elfedit_cmd_optarg_t arg_sh_flags[] = {
   1074 		{ MSG_ORIG(MSG_STR_SEC),
   1075 		    /* MSG_INTL(MSG_A1_SEC) */
   1076 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1077 		    ELFEDIT_CMDOA_F_OPT },
   1078 		{ MSG_ORIG(MSG_STR_VALUE),
   1079 		    /* MSG_INTL(MSG_A2_DESC_SH_FLAGS) */
   1080 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_FLAGS),
   1081 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
   1082 		{ NULL }
   1083 	};
   1084 
   1085 	/* shdr:sh_info */
   1086 	static const char *name_sh_info[] = {
   1087 	    MSG_ORIG(MSG_CMD_SH_INFO), NULL };
   1088 	static elfedit_cmd_optarg_t arg_sh_info[] = {
   1089 		{ MSG_ORIG(MSG_STR_SEC),
   1090 		    /* MSG_INTL(MSG_A1_SEC) */
   1091 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1092 		    ELFEDIT_CMDOA_F_OPT },
   1093 		{ MSG_ORIG(MSG_STR_VALUE),
   1094 		    /* MSG_INTL(MSG_A2_DESC_SH_INFO) */
   1095 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_INFO),
   1096 		    ELFEDIT_CMDOA_F_OPT },
   1097 		{ NULL }
   1098 	};
   1099 
   1100 	/* shdr:sh_link */
   1101 	static const char *name_sh_link[] = {
   1102 	    MSG_ORIG(MSG_CMD_SH_LINK), NULL };
   1103 	static elfedit_cmd_optarg_t arg_sh_link[] = {
   1104 		{ MSG_ORIG(MSG_STR_SEC),
   1105 		    /* MSG_INTL(MSG_A1_SEC) */
   1106 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1107 		    ELFEDIT_CMDOA_F_OPT },
   1108 		{ MSG_ORIG(MSG_STR_VALUE),
   1109 		    /* MSG_INTL(MSG_A2_DESC_SH_LINK) */
   1110 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_LINK),
   1111 		    ELFEDIT_CMDOA_F_OPT },
   1112 		{ NULL }
   1113 	};
   1114 
   1115 	/* shdr:sh_name */
   1116 	static const char *name_sh_name[] = {
   1117 	    MSG_ORIG(MSG_CMD_SH_NAME), NULL };
   1118 	static elfedit_cmd_optarg_t opt_sh_name[] = {
   1119 		{ MSG_ORIG(MSG_STR_MINUS_NAME_OFFSET),
   1120 		    /* MSG_INTL(MSG_OPTDESC_NAME_OFFSET) */
   1121 		    ELFEDIT_I18NHDL(MSG_OPTDESC_NAME_OFFSET), 0,
   1122 		    SHDR_OPT_F_NAMOFFSET, 0 },
   1123 		{ ELFEDIT_STDOA_OPT_O, NULL,
   1124 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
   1125 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
   1126 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
   1127 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
   1128 		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
   1129 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
   1130 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
   1131 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
   1132 		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
   1133 		{ NULL }
   1134 	};
   1135 	static elfedit_cmd_optarg_t arg_sh_name[] = {
   1136 		{ MSG_ORIG(MSG_STR_SEC),
   1137 		    /* MSG_INTL(MSG_A1_SEC) */
   1138 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1139 		    ELFEDIT_CMDOA_F_OPT },
   1140 		{ MSG_ORIG(MSG_STR_NAME),
   1141 		    /* MSG_INTL(MSG_A2_DESC_SH_NAME) */
   1142 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_NAME),
   1143 		    ELFEDIT_CMDOA_F_OPT },
   1144 		{ NULL }
   1145 	};
   1146 
   1147 	/* shdr:sh_offset */
   1148 	static const char *name_sh_offset[] = {
   1149 	    MSG_ORIG(MSG_CMD_SH_OFFSET), NULL };
   1150 	static elfedit_cmd_optarg_t arg_sh_offset[] = {
   1151 		{ MSG_ORIG(MSG_STR_SEC),
   1152 		    /* MSG_INTL(MSG_A1_SEC) */
   1153 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1154 		    ELFEDIT_CMDOA_F_OPT },
   1155 		{ MSG_ORIG(MSG_STR_VALUE),
   1156 		    /* MSG_INTL(MSG_A2_DESC_SH_OFFSET) */
   1157 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_OFFSET),
   1158 		    ELFEDIT_CMDOA_F_OPT },
   1159 		{ NULL }
   1160 	};
   1161 
   1162 	/* shdr:sh_size */
   1163 	static const char *name_sh_size[] = {
   1164 	    MSG_ORIG(MSG_CMD_SH_SIZE), NULL };
   1165 	static elfedit_cmd_optarg_t arg_sh_size[] = {
   1166 		{ MSG_ORIG(MSG_STR_SEC),
   1167 		    /* MSG_INTL(MSG_A1_SEC) */
   1168 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1169 		    ELFEDIT_CMDOA_F_OPT },
   1170 		{ MSG_ORIG(MSG_STR_VALUE),
   1171 		    /* MSG_INTL(MSG_A2_DESC_SH_SIZE) */
   1172 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_SIZE),
   1173 		    ELFEDIT_CMDOA_F_OPT },
   1174 		{ NULL }
   1175 	};
   1176 
   1177 	/* shdr:sh_type */
   1178 	static const char *name_sh_type[] = {
   1179 	    MSG_ORIG(MSG_CMD_SH_TYPE), NULL };
   1180 	static elfedit_cmd_optarg_t arg_sh_type[] = {
   1181 		{ MSG_ORIG(MSG_STR_SEC),
   1182 		    /* MSG_INTL(MSG_A1_SEC) */
   1183 		    ELFEDIT_I18NHDL(MSG_A1_SEC),
   1184 		    ELFEDIT_CMDOA_F_OPT },
   1185 		{ MSG_ORIG(MSG_STR_VALUE),
   1186 		    /* MSG_INTL(MSG_A2_DESC_SH_TYPE) */
   1187 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_TYPE),
   1188 		    ELFEDIT_CMDOA_F_OPT },
   1189 		{ NULL }
   1190 	};
   1191 
   1192 	static elfedit_cmd_t cmds[] = {
   1193 		/* shdr:dump */
   1194 		{ cmd_dump, cpl_1starg_sec, name_dump,
   1195 		    /* MSG_INTL(MSG_DESC_DUMP) */
   1196 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
   1197 		    /* MSG_INTL(MSG_HELP_DUMP) */
   1198 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
   1199 		    opt_dump, arg_dump },
   1200 
   1201 		/* shdr:sh_addr */
   1202 		{ cmd_sh_addr, cpl_1starg_sec, name_sh_addr,
   1203 		    /* MSG_INTL(MSG_DESC_SH_ADDR) */
   1204 		    ELFEDIT_I18NHDL(MSG_DESC_SH_ADDR),
   1205 		    /* MSG_INTL(MSG_HELP_SH_ADDR) */
   1206 		    ELFEDIT_I18NHDL(MSG_HELP_SH_ADDR),
   1207 		    opt_std, arg_sh_addr },
   1208 
   1209 		/* shdr:sh_addralign */
   1210 		{ cmd_sh_addralign, cpl_1starg_sec, name_sh_addralign,
   1211 		    /* MSG_INTL(MSG_DESC_SH_ADDRALIGN) */
   1212 		    ELFEDIT_I18NHDL(MSG_DESC_SH_ADDRALIGN),
   1213 		    /* MSG_INTL(MSG_HELP_SH_ADDRALIGN) */
   1214 		    ELFEDIT_I18NHDL(MSG_HELP_SH_ADDRALIGN),
   1215 		    opt_std, arg_sh_addralign },
   1216 
   1217 		/* shdr:sh_entsize */
   1218 		{ cmd_sh_entsize, cpl_1starg_sec, name_sh_entsize,
   1219 		    /* MSG_INTL(MSG_DESC_SH_ENTSIZE) */
   1220 		    ELFEDIT_I18NHDL(MSG_DESC_SH_ENTSIZE),
   1221 		    /* MSG_INTL(MSG_HELP_SH_ENTSIZE) */
   1222 		    ELFEDIT_I18NHDL(MSG_HELP_SH_ENTSIZE),
   1223 		    opt_std, arg_sh_entsize },
   1224 
   1225 		/* shdr:sh_flags */
   1226 		{ cmd_sh_flags, cpl_sh_flags, name_sh_flags,
   1227 		    /* MSG_INTL(MSG_DESC_SH_FLAGS) */
   1228 		    ELFEDIT_I18NHDL(MSG_DESC_SH_FLAGS),
   1229 		    /* MSG_INTL(MSG_HELP_SH_FLAGS) */
   1230 		    ELFEDIT_I18NHDL(MSG_HELP_SH_FLAGS),
   1231 		    opt_sh_flags, arg_sh_flags },
   1232 
   1233 		/* shdr:sh_info */
   1234 		{ cmd_sh_info, cpl_sh_infolink, name_sh_info,
   1235 		    /* MSG_INTL(MSG_DESC_SH_INFO) */
   1236 		    ELFEDIT_I18NHDL(MSG_DESC_SH_INFO),
   1237 		    /* MSG_INTL(MSG_HELP_SH_INFO) */
   1238 		    ELFEDIT_I18NHDL(MSG_HELP_SH_INFO),
   1239 		    opt_infolink, arg_sh_info },
   1240 
   1241 		/* shdr:sh_link */
   1242 		{ cmd_sh_link, cpl_sh_infolink, name_sh_link,
   1243 		    /* MSG_INTL(MSG_DESC_SH_LINK) */
   1244 		    ELFEDIT_I18NHDL(MSG_DESC_SH_LINK),
   1245 		    /* MSG_INTL(MSG_HELP_SH_LINK) */
   1246 		    ELFEDIT_I18NHDL(MSG_HELP_SH_LINK),
   1247 		    opt_infolink, arg_sh_link },
   1248 
   1249 		/* shdr:sh_name */
   1250 		{ cmd_sh_name, cpl_1starg_sec, name_sh_name,
   1251 		    /* MSG_INTL(MSG_DESC_SH_NAME) */
   1252 		    ELFEDIT_I18NHDL(MSG_DESC_SH_NAME),
   1253 		    /* MSG_INTL(MSG_HELP_SH_NAME) */
   1254 		    ELFEDIT_I18NHDL(MSG_HELP_SH_NAME),
   1255 		    opt_sh_name, arg_sh_name },
   1256 
   1257 		/* shdr:sh_offset */
   1258 		{ cmd_sh_offset, cpl_1starg_sec, name_sh_offset,
   1259 		    /* MSG_INTL(MSG_DESC_SH_OFFSET) */
   1260 		    ELFEDIT_I18NHDL(MSG_DESC_SH_OFFSET),
   1261 		    /* MSG_INTL(MSG_HELP_SH_OFFSET) */
   1262 		    ELFEDIT_I18NHDL(MSG_HELP_SH_OFFSET),
   1263 		    opt_std, arg_sh_offset },
   1264 
   1265 		/* shdr:sh_size */
   1266 		{ cmd_sh_size, cpl_1starg_sec, name_sh_size,
   1267 		    /* MSG_INTL(MSG_DESC_SH_SIZE) */
   1268 		    ELFEDIT_I18NHDL(MSG_DESC_SH_SIZE),
   1269 		    /* MSG_INTL(MSG_HELP_SH_SIZE) */
   1270 		    ELFEDIT_I18NHDL(MSG_HELP_SH_SIZE),
   1271 		    opt_std, arg_sh_size },
   1272 
   1273 		/* shdr:sh_type */
   1274 		{ cmd_sh_type, cpl_sh_type, name_sh_type,
   1275 		    /* MSG_INTL(MSG_DESC_SH_TYPE) */
   1276 		    ELFEDIT_I18NHDL(MSG_DESC_SH_TYPE),
   1277 		    /* MSG_INTL(MSG_HELP_SH_TYPE) */
   1278 		    ELFEDIT_I18NHDL(MSG_HELP_SH_TYPE),
   1279 		    opt_std, arg_sh_type },
   1280 
   1281 		{ NULL }
   1282 	};
   1283 
   1284 	static elfedit_module_t module = {
   1285 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
   1286 	    /* MSG_INTL(MSG_MOD_DESC) */
   1287 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
   1288 	    cmds, mod_i18nhdl_to_str };
   1289 
   1290 	return (&module);
   1291 }
   1292