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	<elfedit.h>
     28 #include	<strings.h>
     29 #include	<conv.h>
     30 #include	<debug.h>
     31 #include	<phdr_msg.h>
     32 
     33 
     34 /*
     35  * Program headers
     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 	/* Dump command, used as module default to display dynamic section */
     47 	PHDR_CMD_T_DUMP =	0,	/* phdr:dump */
     48 
     49 	/* Commands that correspond directly to program header fields */
     50 	PHDR_CMD_T_P_TYPE =	1,	/* phdr:p_type */
     51 	PHDR_CMD_T_P_OFFSET =	2,	/* phdr:p_offset */
     52 	PHDR_CMD_T_P_VADDR =	3,	/* phdr:p_vaddr */
     53 	PHDR_CMD_T_P_PADDR =	4,	/* phdr:p_paddr */
     54 	PHDR_CMD_T_P_FILESZ =	5,	/* phdr:p_filesz */
     55 	PHDR_CMD_T_P_MEMSZ =	6,	/* phdr:p_memsz */
     56 	PHDR_CMD_T_P_FLAGS =	7,	/* phdr:p_flags */
     57 	PHDR_CMD_T_P_ALIGN =	8,	/* phdr:p_align */
     58 
     59 	/* Commands that do not correspond directly to a specific phdr tag */
     60 	PHDR_CMD_T_INTERP =	9,	/* phdr:interp */
     61 	PHDR_CMD_T_DELETE =	10,	/* phdr:delete */
     62 	PHDR_CMD_T_MOVE =	11	/* phdr:move */
     63 } PHDR_CMD_T;
     64 
     65 
     66 
     67 /*
     68  * The following type is ued by locate_interp() to return
     69  * information about the interpreter program header.
     70  */
     71 typedef struct {
     72 	Word			phndx;	/* Index of PT_INTERP header */
     73 	Phdr			*phdr;		/* PT_INTERP header */
     74 	elfedit_section_t	*sec;		/* Section containing string */
     75 	Word			stroff;		/* Offset into string section */
     76 	const char		*str;		/* Interpreter string */
     77 } INTERP_STATE;
     78 
     79 
     80 #ifndef _ELF64
     81 /*
     82  * We supply this function for the msg module
     83  */
     84 const char *
     85 _phdr_msg(Msg mid)
     86 {
     87 	return (gettext(MSG_ORIG(mid)));
     88 }
     89 #endif
     90 
     91 
     92 /*
     93  * This function is supplied to elfedit through our elfedit_module_t
     94  * definition. It translates the opaque elfedit_i18nhdl_t handles
     95  * in our module interface into the actual strings for elfedit to
     96  * use.
     97  *
     98  * note:
     99  *	This module uses Msg codes for its i18n handle type.
    100  *	So the translation is simply to use MSG_INTL() to turn
    101  *	it into a string and return it.
    102  */
    103 static const char *
    104 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
    105 {
    106 	Msg msg = (Msg)hdl;
    107 
    108 	return (MSG_INTL(msg));
    109 }
    110 
    111 
    112 
    113 /*
    114  * The phdr_opt_t enum specifies a bit value for every optional
    115  * argument allowed by a command in this module.
    116  */
    117 typedef enum {
    118 	PHDR_OPT_F_AND =	1,	/* -and: AND (&) values to dest */
    119 	PHDR_OPT_F_CMP =	2,	/* -cmp: Complement (~) values */
    120 	PHDR_OPT_F_PHNDX =	4,	/* -phndx: Program header by index, */
    121 					/*	not by name */
    122 	PHDR_OPT_F_OR =		8	/* -or: OR (|) values to dest */
    123 } phdr_opt_t;
    124 
    125 
    126 /*
    127  * A variable of type ARGSTATE is used by each command to maintain
    128  * information about the section headers and related things. It is
    129  * initialized by process_args(), and used by the other routines.
    130  */
    131 typedef struct {
    132 	elfedit_obj_state_t	*obj_state;
    133 	phdr_opt_t		optmask;   	/* Mask of options used */
    134 	int			argc;		/* # of plain arguments */
    135 	const char		**argv;		/* Plain arguments */
    136 	int			ndx_set;	/* True if ndx is valid */
    137 	Word			ndx;		/* Index of header if cmd */
    138 						/*	accepts it */
    139 	int			print_req;	/* Call is a print request */
    140 } ARGSTATE;
    141 
    142 
    143 /*
    144  * Standard argument processing for phdr module
    145  *
    146  * entry
    147  *	obj_state, argc, argv - Standard command arguments
    148  *	optmask - Mask of allowed optional arguments.
    149  *	cmd - PHDR_CMD_T_* value giving identify of caller
    150  *	argstate - Address of ARGSTATE block to be initialized
    151  *
    152  * exit:
    153  *	On success, *argstate is initialized. On error,
    154  *	an error is issued and this routine does not return.
    155  */
    156 static void
    157 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
    158     PHDR_CMD_T cmd, ARGSTATE *argstate)
    159 {
    160 	elfedit_getopt_state_t	getopt_state;
    161 	elfedit_getopt_ret_t	*getopt_ret;
    162 
    163 	bzero(argstate, sizeof (*argstate));
    164 	argstate->obj_state = obj_state;
    165 
    166 	elfedit_getopt_init(&getopt_state, &argc, &argv);
    167 
    168 	/* Add each new option to the options mask */
    169 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
    170 		argstate->optmask |= getopt_ret->gor_idmask;
    171 
    172 	/* Are the right number of plain arguments present? */
    173 	switch (cmd) {
    174 	case PHDR_CMD_T_DUMP:
    175 		if (argc > 1)
    176 			elfedit_command_usage();
    177 		argstate->print_req = 1;
    178 		break;
    179 	case PHDR_CMD_T_P_FLAGS:
    180 		/* phdr:sh_flags allows an arbitrary number of arguments */
    181 		argstate->print_req = (argc < 2);
    182 		break;
    183 	case PHDR_CMD_T_INTERP:
    184 		if (argc > 1)
    185 			elfedit_command_usage();
    186 		argstate->print_req = (argc == 0);
    187 		break;
    188 	case PHDR_CMD_T_DELETE:
    189 		if ((argc < 1) || (argc > 2))
    190 			elfedit_command_usage();
    191 		argstate->print_req = 0;
    192 		break;
    193 	case PHDR_CMD_T_MOVE:
    194 		if ((argc < 2) || (argc > 3))
    195 			elfedit_command_usage();
    196 		argstate->print_req = 0;
    197 		break;
    198 
    199 	default:
    200 		/* The remaining commands accept 2 plain arguments */
    201 		if (argc > 2)
    202 			elfedit_command_usage();
    203 		argstate->print_req = (argc < 2);
    204 		break;
    205 	}
    206 
    207 	/* Return the updated values of argc/argv */
    208 	argstate->argc = argc;
    209 	argstate->argv = argv;
    210 
    211 	argstate->ndx_set = 0;
    212 	if ((argc > 0) && (cmd != PHDR_CMD_T_INTERP)) {
    213 		/*
    214 		 * If the -phndx option is present, the first argument is
    215 		 * the index of the header to use. Otherwise, it is a
    216 		 * name corresponding to its type, similar to the way
    217 		 * elfdump works with its -N option.
    218 		 */
    219 		if (argstate->optmask & PHDR_OPT_F_PHNDX) {
    220 			argstate->ndx = (Word) elfedit_atoui_range(
    221 			    argstate->argv[0], MSG_ORIG(MSG_STR_ELEMENT), 0,
    222 			    argstate->obj_state->os_phnum - 1, NULL);
    223 			argstate->ndx_set = 1;
    224 		} else {
    225 			Conv_inv_buf_t inv_buf;
    226 			Ehdr		*ehdr = obj_state->os_ehdr;
    227 			Half		mach = ehdr->e_machine;
    228 			uchar_t		osabi = ehdr->e_ident[EI_OSABI];
    229 			Word		i;
    230 			Phdr		*phdr;
    231 
    232 			argstate->ndx = (Word) elfedit_atoconst(
    233 			    argstate->argv[0], ELFEDIT_CONST_PT);
    234 			phdr = obj_state->os_phdr;
    235 			for (i = 0; i < obj_state->os_phnum; i++, phdr++) {
    236 				if (phdr->p_type == argstate->ndx) {
    237 					argstate->ndx = i;
    238 					argstate->ndx_set = 1;
    239 					elfedit_msg(ELFEDIT_MSG_DEBUG,
    240 					    MSG_INTL(MSG_DEBUG_PHDR),
    241 					    EC_WORD(i), conv_phdr_type(osabi,
    242 					    mach, phdr->p_type, 0, &inv_buf));
    243 					break;
    244 				}
    245 			}
    246 			if (i == argstate->obj_state->os_phnum)
    247 				elfedit_msg(ELFEDIT_MSG_ERR,
    248 				    MSG_INTL(MSG_ERR_NOPHDR), conv_phdr_type(
    249 				    osabi, mach, argstate->ndx, 0, &inv_buf));
    250 		}
    251 	}
    252 
    253 	/* If there may be an arbitrary amount of output, use a pager */
    254 	if (argc == 0)
    255 		elfedit_pager_init();
    256 
    257 }
    258 
    259 
    260 
    261 /*
    262  * Locate the interpreter string for the object and related information
    263  *
    264  * entry:
    265  *	obj_state - Object state
    266  *	interp - NULL, or variable to be filled in with information
    267  *		about the interpteter string.
    268  */
    269 static const char *
    270 locate_interp(elfedit_obj_state_t *obj_state, INTERP_STATE *interp)
    271 {
    272 	INTERP_STATE		local_interp;
    273 	elfedit_section_t	*strsec;	/* String table */
    274 	size_t		phnum;		/* # of program headers */
    275 	int		phndx;		/* Index of PT_INTERP program header */
    276 	Phdr		*phdr;		/* Program header array */
    277 	Word		i;
    278 
    279 	if (interp == NULL)
    280 		interp = &local_interp;
    281 
    282 	/* Locate the PT_INTERP program header */
    283 	phnum = obj_state->os_phnum;
    284 	phdr = obj_state->os_phdr;
    285 
    286 	for (phndx = 0; phndx < phnum; phndx++) {
    287 		if (phdr[phndx].p_type  == PT_INTERP) {
    288 			interp->phndx = phndx;
    289 			interp->phdr = phdr + phndx;
    290 			break;
    291 		}
    292 	}
    293 	/* If no PT_INTERP program header found, we cannot proceed */
    294 	if (phndx == phnum)
    295 		elfedit_elferr(obj_state->os_file,
    296 		    MSG_INTL(MSG_ERR_NOINTERPPHDR));
    297 
    298 	/*
    299 	 * Locate the section containing the interpteter string as well
    300 	 * as the string itself.
    301 	 *
    302 	 * The program header contains a direct offset to the string, so
    303 	 * we find the section by walking through the them looking for
    304 	 * the one with a base and size that would contain the string.
    305 	 * Note that this target section cannot be in a NOBITS section.
    306 	 */
    307 	for (i = 1; i < obj_state->os_shnum; i++) {
    308 		strsec = &obj_state->os_secarr[i];
    309 
    310 		if ((strsec->sec_shdr->sh_type != SHT_NOBITS) &&
    311 		    (interp->phdr->p_offset >= strsec->sec_shdr->sh_offset) &&
    312 		    ((interp->phdr->p_offset + interp->phdr->p_filesz) <=
    313 		    (strsec->sec_shdr->sh_offset +
    314 		    strsec->sec_shdr->sh_size))) {
    315 			interp->sec = strsec;
    316 
    317 			interp->stroff = interp->phdr->p_offset -
    318 			    strsec->sec_shdr->sh_offset;
    319 			interp->str = ((char *)strsec->sec_data->d_buf) +
    320 			    interp->stroff;
    321 			return (interp->str);
    322 		}
    323 	}
    324 
    325 	/*
    326 	 * We don't expect to get here: If there is a PT_INTERP header,
    327 	 * we fully expect the string to exist.
    328 	 */
    329 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOINTERPSEC));
    330 	/*NOTREACHED*/
    331 
    332 	return (NULL);		/* For lint */
    333 }
    334 
    335 /*
    336  * Print program header values, taking the calling command, and output style
    337  * into account.
    338  *
    339  * entry:
    340  *	autoprint - If True, output is only produced if the elfedit
    341  *		autoprint flag is set. If False, output is always produced.
    342  *	cmd - PHDR_CMD_T_* value giving identify of caller
    343  *	argstate - State block for section header array. The following
    344  *		fields are examined in order to determine the form
    345  *		of output: ndx_set, ndx, print_req.
    346  */
    347 static void
    348 print_phdr(PHDR_CMD_T cmd, int autoprint, ARGSTATE *argstate)
    349 {
    350 	elfedit_outstyle_t	outstyle;
    351 	Ehdr			*ehdr = argstate->obj_state->os_ehdr;
    352 	uchar_t			osabi = ehdr->e_ident[EI_OSABI];
    353 	Half			mach = ehdr->e_machine;
    354 	Word			ndx, cnt, by_type, type;
    355 	Phdr			*phdr;
    356 
    357 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
    358 		return;
    359 
    360 	/*
    361 	 * Determine which indexes to display:
    362 	 *
    363 	 * -	If the user specified an index, the display starts
    364 	 *	with that item. If it was a print_request, and the
    365 	 *	index was specified by type, then all items of the
    366 	 *	same type are shown. If not a print request, or the index
    367 	 *	was given numerically, then just the single item is shown.
    368 	 *
    369 	 * -	If no index is specified, every program header is shown.
    370 	 */
    371 	by_type = 0;
    372 	if (argstate->ndx_set) {
    373 		ndx = argstate->ndx;
    374 		if (argstate->print_req &&
    375 		    ((argstate->optmask & PHDR_OPT_F_PHNDX) == 0)) {
    376 			by_type = 1;
    377 			type = argstate->obj_state->os_phdr[ndx].p_type;
    378 			cnt = argstate->obj_state->os_phnum - ndx;
    379 		} else {
    380 			cnt = 1;
    381 		}
    382 	} else {
    383 		ndx = 0;
    384 		cnt = argstate->obj_state->os_phnum;
    385 	}
    386 	phdr = argstate->obj_state->os_phdr + ndx;
    387 
    388 	/*
    389 	 * Pick an output style. phdr:dump is required to use the default
    390 	 * style. The other commands use the current output style.
    391 	 */
    392 	outstyle = (cmd == PHDR_CMD_T_DUMP) ?
    393 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
    394 
    395 	/*
    396 	 * If doing default output, use elfdump style where we
    397 	 * show all program header attributes. In this case, the
    398 	 * command that called us doesn't matter.
    399 	 *
    400 	 * Exclude PHDR_CMD_T_INTERP from this: It isn't per-phdr like
    401 	 * the other commands.
    402 	 */
    403 	if ((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) &&
    404 	    (cmd != PHDR_CMD_T_INTERP)) {
    405 		for (; cnt--; ndx++, phdr++) {
    406 			if (by_type && (type != phdr->p_type))
    407 				continue;
    408 
    409 			elfedit_printf(MSG_ORIG(MSG_STR_NL));
    410 			elfedit_printf(MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx));
    411 			Elf_phdr(0, osabi, mach, phdr);
    412 		}
    413 		return;
    414 	}
    415 
    416 	if (cmd == PHDR_CMD_T_INTERP) {
    417 		INTERP_STATE interp;
    418 
    419 		(void) locate_interp(argstate->obj_state, &interp);
    420 		switch (outstyle) {
    421 		case ELFEDIT_OUTSTYLE_DEFAULT:
    422 			elfedit_printf(MSG_INTL(MSG_FMT_ELF_INTERP),
    423 			    interp.sec->sec_name, interp.str);
    424 			break;
    425 		case ELFEDIT_OUTSTYLE_SIMPLE:
    426 			elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), interp.str);
    427 			break;
    428 		case ELFEDIT_OUTSTYLE_NUM:
    429 			elfedit_printf(MSG_ORIG(MSG_FMT_U_NL),
    430 			    EC_WORD(interp.stroff));
    431 			break;
    432 		}
    433 		return;
    434 	}
    435 
    436 	/* Handle the remaining commands */
    437 	for (; cnt--; ndx++, phdr++) {
    438 		if (by_type && (type != phdr->p_type))
    439 			continue;
    440 
    441 		switch (cmd) {
    442 		case PHDR_CMD_T_P_TYPE:
    443 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    444 				Conv_inv_buf_t inv_buf;
    445 
    446 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    447 				    conv_phdr_type(osabi,
    448 				    argstate->obj_state->os_ehdr->e_machine,
    449 				    phdr->p_type, 0, &inv_buf));
    450 			} else {
    451 				elfedit_printf(MSG_ORIG(MSG_FMT_X_NL),
    452 				    EC_WORD(phdr->p_type));
    453 			}
    454 			break;
    455 
    456 		case PHDR_CMD_T_P_OFFSET:
    457 			elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
    458 			    EC_OFF(phdr->p_offset));
    459 			break;
    460 
    461 		case PHDR_CMD_T_P_VADDR:
    462 			elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
    463 			    EC_ADDR(phdr->p_vaddr));
    464 			break;
    465 
    466 		case PHDR_CMD_T_P_PADDR:
    467 			elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
    468 			    EC_ADDR(phdr->p_paddr));
    469 			break;
    470 
    471 		case PHDR_CMD_T_P_FILESZ:
    472 			elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
    473 			    EC_XWORD(phdr->p_filesz));
    474 			break;
    475 
    476 		case PHDR_CMD_T_P_MEMSZ:
    477 			elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
    478 			    EC_XWORD(phdr->p_memsz));
    479 			break;
    480 
    481 		case PHDR_CMD_T_P_FLAGS:
    482 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    483 				Conv_phdr_flags_buf_t phdr_flags_buf;
    484 
    485 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    486 				    conv_phdr_flags(osabi, phdr->p_flags,
    487 				    CONV_FMT_NOBKT, &phdr_flags_buf));
    488 			} else {
    489 				elfedit_printf(MSG_ORIG(MSG_FMT_X_NL),
    490 				    EC_WORD(phdr->p_flags));
    491 			}
    492 			break;
    493 
    494 		case PHDR_CMD_T_P_ALIGN:
    495 			elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
    496 			    EC_XWORD(phdr->p_align));
    497 			break;
    498 		}
    499 	}
    500 }
    501 
    502 
    503 /*
    504  * Called from cmd_body() in the case where a plain argument
    505  * is given to phdr:interp to change the interpreter.
    506  */
    507 static elfedit_cmdret_t
    508 cmd_body_set_interp(ARGSTATE *argstate)
    509 {
    510 	elfedit_obj_state_t	*obj_state = argstate->obj_state;
    511 	elfedit_section_t	*strsec;	/* String table */
    512 	INTERP_STATE	interp;
    513 	Word		numdyn;		/* # of elements in dyn arr */
    514 	size_t		phnum;		/* # of program headers */
    515 	Phdr		*phdr;		/* Program header array */
    516 	Word		i, j;
    517 	Word		str_offset;	/* Offset in strsec to new interp str */
    518 	int		str_found = 0;	 /* True when we have new interp str */
    519 	Word		str_size;	/* Size of new interp string + NULL */
    520 
    521 	phnum = obj_state->os_phnum;
    522 	phdr = obj_state->os_phdr;
    523 
    524 	/* Locate the PT_INTERP program header */
    525 	(void) locate_interp(obj_state, &interp);
    526 	strsec = interp.sec;
    527 	str_offset = interp.stroff;
    528 
    529 	/*
    530 	 * If the given string is the same as the existing interpreter
    531 	 * string, say so and return.
    532 	 */
    533 	if (strcmp(interp.str, argstate->argv[0]) == 0) {
    534 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_OLDINTERPOK),
    535 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
    536 		    EC_WORD(str_offset), interp.str);
    537 		return (ELFEDIT_CMDRET_NONE);
    538 	}
    539 
    540 	/*
    541 	 * An ELF PT_INTERP usually references its own special section
    542 	 * instead of some other string table. The ELF ABI says that this
    543 	 * section must be named ".interp". Hence, this is a rare case
    544 	 * in which the name of a section can be taken as an indication
    545 	 * of its contents. .interp is typically sized to just fit
    546 	 * the original string, including its NULL termination. You can
    547 	 * treat it as a string table with one string.
    548 	 *
    549 	 * Thanks to 'elfedit', it may be that we encounter a file where
    550 	 * PT_INTERP does not reference the .interp section. This will happen
    551 	 * if elfedit is used to change the interpreter to a string that is
    552 	 * too big to fit in .interp, in which case we will use the
    553 	 * .dynstr string table (That code is below, in this function).
    554 	 *
    555 	 * Given the above facts, our next step is to locate the .interp
    556 	 * section and see if our new string will fit in it. Since we can't
    557 	 * depend on PT_INTERP, we search the section headers to find a
    558 	 * section whith the following characteristics:
    559 	 *	- The name is ".interp".
    560 	 *	- Section is allocable (SHF_ALLOC) and SHT_PROGBITS.
    561 	 *	- It is not part of a writable segment.
    562 	 * If we find such a section, and the new string fits, we will
    563 	 * write it there.
    564 	 */
    565 	str_size = strlen(argstate->argv[0]) + 1;
    566 	for (i = 1; i < obj_state->os_shnum; i++) {
    567 		strsec = &obj_state->os_secarr[i];
    568 		if ((strcmp(strsec->sec_name, MSG_ORIG(MSG_SEC_INTERP)) == 0) &&
    569 		    (strsec->sec_shdr->sh_flags & SHF_ALLOC) &&
    570 		    (strsec->sec_shdr->sh_type & SHT_PROGBITS)) {
    571 			for (j = 0; j < phnum; j++) {
    572 				Phdr *tphdr = &phdr[j];
    573 				if ((strsec->sec_shdr->sh_offset >=
    574 				    tphdr->p_offset) &&
    575 				    ((strsec->sec_shdr->sh_offset +
    576 				    strsec->sec_shdr->sh_size) <=
    577 				    (tphdr->p_offset + tphdr->p_filesz)) &&
    578 				    (tphdr->p_flags & PF_W)) {
    579 					break;
    580 				}
    581 			}
    582 			if ((j == phnum) &&
    583 			    (str_size <= strsec->sec_shdr->sh_size)) {
    584 				/* .interp section found, and has room */
    585 				str_found = 1;
    586 				str_offset = 0;
    587 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    588 				    MSG_INTL(MSG_DEBUG_NEWISTR), EC_WORD(j),
    589 				    strsec->sec_name, EC_WORD(str_offset),
    590 				    argstate->argv[0]);
    591 				/* Put new value in section */
    592 				(void) strncpy((char *)strsec->sec_data->d_buf,
    593 				    argstate->argv[0],
    594 				    strsec->sec_shdr->sh_size);
    595 				/* Set libelf dirty bit so change is flushed */
    596 				elfedit_modified_data(strsec);
    597 				break;
    598 			} else {
    599 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    600 				    MSG_INTL(MSG_DEBUG_LNGISTR), EC_WORD(j),
    601 				    strsec->sec_name, EC_WORD(str_offset),
    602 				    EC_WORD(str_size),
    603 				    EC_WORD(strsec->sec_shdr->sh_size),
    604 				    argstate->argv[0]);
    605 			}
    606 		}
    607 	}
    608 
    609 	/*
    610 	 * If the above did not find a string within the .interp section,
    611 	 * then we have a second option. If this ELF object has a dynamic
    612 	 * section, then we are willing to use strings from within the
    613 	 * associated .dynstr string table. And if there is reserved space
    614 	 * in .dynstr (as reported by the DT_SUNW_STRPAD dynamic entry),
    615 	 * then we are even willing to add a new string to .dynstr.
    616 	 */
    617 	if (!str_found) {
    618 		elfedit_section_t	*dynsec;
    619 		Dyn			*dyn;
    620 
    621 		dynsec = elfedit_sec_getdyn(obj_state, &dyn, &numdyn);
    622 		strsec = elfedit_sec_getstr(obj_state,
    623 		    dynsec->sec_shdr->sh_link, 0);
    624 
    625 		/* Does string exist in the table already, or can we add it? */
    626 		str_offset = elfedit_strtab_insert(obj_state, strsec,
    627 		    dynsec, argstate->argv[0]);
    628 	}
    629 
    630 
    631 	/*
    632 	 * If we are here, we know we have a replacement string, because
    633 	 * the errors from checking .dynamic/.dynstr will not allow
    634 	 * things to get here otherwise.
    635 	 *
    636 	 * The PT_INTERP program header references the string directly,
    637 	 * so we add the section offset to the string offset.
    638 	 */
    639 	interp.phdr->p_offset = strsec->sec_shdr->sh_offset + str_offset;
    640 	interp.phdr->p_filesz = str_size;
    641 	elfedit_modified_phdr(obj_state);
    642 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SETPHINTERP),
    643 	    EC_WORD(interp.phndx), EC_XWORD(interp.phdr->p_offset),
    644 	    EC_XWORD(interp.phdr->p_filesz));
    645 
    646 	return (ELFEDIT_CMDRET_MOD);
    647 }
    648 
    649 
    650 /*
    651  * Common body for the phdr: module commands. These commands
    652  * share a large amount of common behavior, so it is convenient
    653  * to centralize things and use the cmd argument to handle the
    654  * small differences.
    655  *
    656  * entry:
    657  *	cmd - One of the PHDR_CMD_T_* constants listed above, specifying
    658  *		which command to implement.
    659  *	obj_state, argc, argv - Standard command arguments
    660  */
    661 static elfedit_cmdret_t
    662 cmd_body(PHDR_CMD_T cmd, elfedit_obj_state_t *obj_state,
    663     int argc, const char *argv[])
    664 {
    665 	ARGSTATE		argstate;
    666 	Phdr			*phdr;
    667 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
    668 	int			do_autoprint = 1;
    669 
    670 	process_args(obj_state, argc, argv, cmd, &argstate);
    671 
    672 	/* If this is a printing request, print and return */
    673 	if (argstate.print_req) {
    674 		print_phdr(cmd, 0, &argstate);
    675 		return (ELFEDIT_CMDRET_NONE);
    676 	}
    677 
    678 
    679 	if (argstate.ndx_set)
    680 		phdr = &argstate.obj_state->os_phdr[argstate.ndx];
    681 
    682 	switch (cmd) {
    683 		/*
    684 		 * PHDR_CMD_T_DUMP can't get here: It never has more than
    685 		 * one argument, and is handled above.
    686 		 */
    687 
    688 	case PHDR_CMD_T_P_TYPE:
    689 		{
    690 			Ehdr	*ehdr = obj_state->os_ehdr;
    691 			uchar_t	osabi = ehdr->e_ident[EI_OSABI];
    692 			Half	mach = ehdr->e_machine;
    693 			Word p_type = elfedit_atoconst(argstate.argv[1],
    694 			    ELFEDIT_CONST_PT);
    695 			Conv_inv_buf_t inv_buf1, inv_buf2;
    696 
    697 			if (phdr->p_type == p_type) {
    698 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    699 				    MSG_INTL(MSG_DEBUG_S_OK),
    700 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_TYPE),
    701 				    conv_phdr_type(osabi, mach, phdr->p_type,
    702 				    0, &inv_buf1));
    703 			} else {
    704 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    705 				    MSG_INTL(MSG_DEBUG_S_CHG),
    706 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_TYPE),
    707 				    conv_phdr_type(osabi, mach,
    708 				    phdr->p_type, 0, &inv_buf1),
    709 				    conv_phdr_type(osabi, mach,
    710 				    p_type, 0, &inv_buf2));
    711 				ret = ELFEDIT_CMDRET_MOD;
    712 				phdr->p_type = p_type;
    713 			}
    714 		}
    715 		break;
    716 
    717 	case PHDR_CMD_T_P_OFFSET:
    718 		{
    719 			Off p_offset;
    720 
    721 			p_offset = elfedit_atoui(argstate.argv[1], NULL);
    722 			if (phdr->p_offset == p_offset) {
    723 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    724 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    725 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_OFFSET),
    726 				    EC_XWORD(phdr->p_offset));
    727 			} else {
    728 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    729 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    730 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_OFFSET),
    731 				    EC_XWORD(phdr->p_offset),
    732 				    EC_XWORD(p_offset));
    733 				ret = ELFEDIT_CMDRET_MOD;
    734 				phdr->p_offset = p_offset;
    735 			}
    736 		}
    737 		break;
    738 
    739 	case PHDR_CMD_T_P_VADDR:
    740 		{
    741 			Addr p_vaddr = elfedit_atoui(argstate.argv[1], NULL);
    742 
    743 			if (phdr->p_vaddr == p_vaddr) {
    744 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    745 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    746 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_VADDR),
    747 				    EC_ADDR(phdr->p_vaddr));
    748 			} else {
    749 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    750 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    751 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_VADDR),
    752 				    EC_ADDR(phdr->p_vaddr), EC_ADDR(p_vaddr));
    753 				ret = ELFEDIT_CMDRET_MOD;
    754 				phdr->p_vaddr = p_vaddr;
    755 			}
    756 		}
    757 		break;
    758 
    759 	case PHDR_CMD_T_P_PADDR:
    760 		{
    761 			Addr p_paddr = elfedit_atoui(argstate.argv[1], NULL);
    762 
    763 			if (phdr->p_paddr == p_paddr) {
    764 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    765 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    766 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_PADDR),
    767 				    EC_ADDR(phdr->p_paddr));
    768 			} else {
    769 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    770 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    771 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_PADDR),
    772 				    EC_ADDR(phdr->p_paddr), EC_ADDR(p_paddr));
    773 				ret = ELFEDIT_CMDRET_MOD;
    774 				phdr->p_paddr = p_paddr;
    775 			}
    776 		}
    777 		break;
    778 
    779 	case PHDR_CMD_T_P_FILESZ:
    780 		{
    781 			Xword p_filesz = elfedit_atoui(argstate.argv[1], NULL);
    782 
    783 			if (phdr->p_filesz == p_filesz) {
    784 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    785 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    786 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_FILESZ),
    787 				    EC_XWORD(phdr->p_filesz));
    788 			} else {
    789 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    790 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    791 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_FILESZ),
    792 				    EC_XWORD(phdr->p_filesz),
    793 				    EC_XWORD(p_filesz));
    794 				ret = ELFEDIT_CMDRET_MOD;
    795 				phdr->p_filesz = p_filesz;
    796 			}
    797 		}
    798 		break;
    799 
    800 	case PHDR_CMD_T_P_MEMSZ:
    801 		{
    802 			Xword p_memsz = elfedit_atoui(argstate.argv[1], NULL);
    803 
    804 			if (phdr->p_memsz == p_memsz) {
    805 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    806 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    807 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_MEMSZ),
    808 				    EC_XWORD(phdr->p_memsz));
    809 			} else {
    810 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    811 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    812 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_MEMSZ),
    813 				    EC_XWORD(phdr->p_memsz),
    814 				    EC_XWORD(p_memsz));
    815 				ret = ELFEDIT_CMDRET_MOD;
    816 				phdr->p_memsz = p_memsz;
    817 			}
    818 		}
    819 		break;
    820 
    821 	case PHDR_CMD_T_P_FLAGS:
    822 		{
    823 			Ehdr	*ehdr = obj_state->os_ehdr;
    824 			uchar_t	osabi = ehdr->e_ident[EI_OSABI];
    825 			Conv_phdr_flags_buf_t buf1, buf2;
    826 			Word	p_flags = 0;
    827 			int	i;
    828 
    829 						/* Collect the flag arguments */
    830 			for (i = 1; i < argstate.argc; i++)
    831 				p_flags |=
    832 				    (Word) elfedit_atoconst(argstate.argv[i],
    833 				    ELFEDIT_CONST_PF);
    834 
    835 			/* Complement the value? */
    836 			if (argstate.optmask & PHDR_OPT_F_CMP)
    837 				p_flags = ~p_flags;
    838 
    839 			/* Perform any requested bit operations */
    840 			if (argstate.optmask & PHDR_OPT_F_AND)
    841 				p_flags &= phdr->p_flags;
    842 			else if (argstate.optmask & PHDR_OPT_F_OR)
    843 				p_flags |= phdr->p_flags;
    844 
    845 			/* Set the value */
    846 			if (phdr->p_flags == p_flags) {
    847 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    848 				    MSG_INTL(MSG_DEBUG_S_OK),
    849 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_FLAGS),
    850 				    conv_phdr_flags(osabi, phdr->p_flags,
    851 				    0, &buf1));
    852 			} else {
    853 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    854 				    MSG_INTL(MSG_DEBUG_S_CHG),
    855 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_FLAGS),
    856 				    conv_phdr_flags(osabi, phdr->p_flags,
    857 				    0, &buf1),
    858 				    conv_phdr_flags(osabi, p_flags, 0, &buf2));
    859 				ret = ELFEDIT_CMDRET_MOD;
    860 				phdr->p_flags = p_flags;
    861 			}
    862 		}
    863 		break;
    864 
    865 	case PHDR_CMD_T_P_ALIGN:
    866 		{
    867 			Xword p_align = elfedit_atoui(argstate.argv[1], NULL);
    868 
    869 			if (phdr->p_align == p_align) {
    870 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    871 				    MSG_INTL(MSG_DEBUG_LLX_OK),
    872 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_ALIGN),
    873 				    EC_XWORD(phdr->p_align));
    874 			} else {
    875 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    876 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
    877 				    argstate.ndx, MSG_ORIG(MSG_CMD_P_ALIGN),
    878 				    EC_XWORD(phdr->p_align),
    879 				    EC_XWORD(p_align));
    880 				ret = ELFEDIT_CMDRET_MOD;
    881 				phdr->p_align = p_align;
    882 			}
    883 		}
    884 		break;
    885 
    886 	case PHDR_CMD_T_INTERP:
    887 		ret = cmd_body_set_interp(&argstate);
    888 		break;
    889 
    890 	case PHDR_CMD_T_DELETE:
    891 		{
    892 			Word cnt = (argstate.argc == 1) ? 1 :
    893 			    (Word) elfedit_atoui_range(argstate.argv[1],
    894 			    MSG_ORIG(MSG_STR_COUNT), 1,
    895 			    obj_state->os_phnum - argstate.ndx, NULL);
    896 
    897 			elfedit_array_elts_delete(MSG_ORIG(MSG_MOD_NAME),
    898 			    obj_state->os_phdr, sizeof (Phdr),
    899 			    obj_state->os_phnum, argstate.ndx, cnt);
    900 			do_autoprint = 0;
    901 			ret = ELFEDIT_CMDRET_MOD;
    902 		}
    903 		break;
    904 
    905 	case PHDR_CMD_T_MOVE:
    906 		{
    907 			Phdr	save;
    908 			Word	cnt;
    909 			Word	dstndx;
    910 
    911 			do_autoprint = 0;
    912 			dstndx = (Word)
    913 			    elfedit_atoui_range(argstate.argv[1],
    914 			    MSG_ORIG(MSG_STR_DST_INDEX), 0,
    915 			    obj_state->os_phnum - 1, NULL);
    916 			if (argstate.argc == 2) {
    917 				cnt = 1;
    918 			} else {
    919 				cnt = (Word) elfedit_atoui_range(
    920 				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
    921 				    1, obj_state->os_phnum, NULL);
    922 			}
    923 			elfedit_array_elts_move(MSG_ORIG(MSG_MOD_NAME),
    924 			    obj_state->os_phdr, sizeof (save),
    925 			    obj_state->os_phnum, argstate.ndx, dstndx,
    926 			    cnt, &save);
    927 			ret = ELFEDIT_CMDRET_MOD;
    928 		}
    929 		break;
    930 	}
    931 
    932 	/*
    933 	 * If we modified the section header array, tell libelf.
    934 	 */
    935 	if (ret == ELFEDIT_CMDRET_MOD)
    936 		elfedit_modified_phdr(obj_state);
    937 
    938 	/* Do autoprint */
    939 	if (do_autoprint)
    940 		print_phdr(cmd, 1, &argstate);
    941 
    942 	return (ret);
    943 }
    944 
    945 
    946 
    947 /*
    948  * Command completion functions for the various commands
    949  */
    950 
    951 /*
    952  * A number of the commands accept a PT_ constant as their first
    953  * argument as long as the -phndx option is not used.
    954  */
    955 /*ARGSUSED*/
    956 static void
    957 cpl_1starg_pt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    958     const char *argv[], int num_opt)
    959 {
    960 	int i;
    961 
    962 	for (i = 0; i < num_opt; i++)
    963 		if (strcmp(MSG_ORIG(MSG_STR_MINUS_PHNDX), argv[i]) == 0)
    964 			return;
    965 
    966 	if (argc == (num_opt + 1))
    967 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PT);
    968 }
    969 
    970 /*ARGSUSED*/
    971 static void
    972 cpl_p_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    973     const char *argv[], int num_opt)
    974 {
    975 	/* The first argument follows the standard rules */
    976 	cpl_1starg_pt(obj_state, cpldata, argc, argv, num_opt);
    977 
    978 	/* The second argument can be a PT_ value */
    979 	if (argc == (num_opt + 2))
    980 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PT);
    981 }
    982 
    983 
    984 /*ARGSUSED*/
    985 static void
    986 cpl_p_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    987     const char *argv[], int num_opt)
    988 {
    989 	/* The first argument follows the standard rules */
    990 	cpl_1starg_pt(obj_state, cpldata, argc, argv, num_opt);
    991 
    992 	/* The second and following arguments can be an PF_ value */
    993 	if (argc >= (num_opt + 2))
    994 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PF);
    995 }
    996 
    997 
    998 
    999 /*
   1000  * Implementation functions for the commands
   1001  */
   1002 static elfedit_cmdret_t
   1003 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1004 {
   1005 	return (cmd_body(PHDR_CMD_T_DUMP, obj_state, argc, argv));
   1006 }
   1007 
   1008 static elfedit_cmdret_t
   1009 cmd_p_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1010 {
   1011 	return (cmd_body(PHDR_CMD_T_P_TYPE, obj_state, argc, argv));
   1012 }
   1013 
   1014 static elfedit_cmdret_t
   1015 cmd_p_offset(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1016 {
   1017 	return (cmd_body(PHDR_CMD_T_P_OFFSET, obj_state, argc, argv));
   1018 }
   1019 
   1020 static elfedit_cmdret_t
   1021 cmd_p_vaddr(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1022 {
   1023 	return (cmd_body(PHDR_CMD_T_P_VADDR, obj_state, argc, argv));
   1024 }
   1025 
   1026 static elfedit_cmdret_t
   1027 cmd_p_paddr(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1028 {
   1029 	return (cmd_body(PHDR_CMD_T_P_PADDR, obj_state, argc, argv));
   1030 }
   1031 
   1032 static elfedit_cmdret_t
   1033 cmd_p_filesz(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1034 {
   1035 	return (cmd_body(PHDR_CMD_T_P_FILESZ, obj_state, argc, argv));
   1036 }
   1037 
   1038 static elfedit_cmdret_t
   1039 cmd_p_memsz(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1040 {
   1041 	return (cmd_body(PHDR_CMD_T_P_MEMSZ, obj_state, argc, argv));
   1042 }
   1043 
   1044 static elfedit_cmdret_t
   1045 cmd_p_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1046 {
   1047 	return (cmd_body(PHDR_CMD_T_P_FLAGS, obj_state, argc, argv));
   1048 }
   1049 
   1050 static elfedit_cmdret_t
   1051 cmd_p_align(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1052 {
   1053 	return (cmd_body(PHDR_CMD_T_P_ALIGN, obj_state, argc, argv));
   1054 }
   1055 
   1056 static elfedit_cmdret_t
   1057 cmd_interp(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1058 {
   1059 	return (cmd_body(PHDR_CMD_T_INTERP, obj_state, argc, argv));
   1060 }
   1061 
   1062 static elfedit_cmdret_t
   1063 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1064 {
   1065 	return (cmd_body(PHDR_CMD_T_DELETE, obj_state, argc, argv));
   1066 }
   1067 
   1068 static elfedit_cmdret_t
   1069 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1070 {
   1071 	return (cmd_body(PHDR_CMD_T_MOVE, obj_state, argc, argv));
   1072 }
   1073 
   1074 
   1075 /*ARGSUSED*/
   1076 elfedit_module_t *
   1077 elfedit_init(elfedit_module_version_t version)
   1078 {
   1079 	/* Multiple commands accept a standard set of options */
   1080 	static elfedit_cmd_optarg_t opt_std[] = {
   1081 		{ ELFEDIT_STDOA_OPT_O, NULL,
   1082 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
   1083 		{ MSG_ORIG(MSG_STR_MINUS_PHNDX),
   1084 		    /* MSG_INTL(MSG_OPTDESC_PHNDX) */
   1085 		    ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0,
   1086 		    PHDR_OPT_F_PHNDX, 0 },
   1087 		{ NULL }
   1088 	};
   1089 
   1090 	/* For commands that only accept -phndx */
   1091 	static elfedit_cmd_optarg_t opt_minus_phndx[] = {
   1092 		{ MSG_ORIG(MSG_STR_MINUS_PHNDX),
   1093 		    /* MSG_INTL(MSG_OPTDESC_PHNDX) */
   1094 		    ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0,
   1095 		    PHDR_OPT_F_PHNDX, 0 },
   1096 		{ NULL }
   1097 	};
   1098 
   1099 
   1100 	/* phdr:dump */
   1101 	static const char *name_dump[] = {
   1102 	    MSG_ORIG(MSG_CMD_DUMP),
   1103 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
   1104 	    NULL
   1105 	};
   1106 	static elfedit_cmd_optarg_t arg_dump[] = {
   1107 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1108 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1109 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1110 		    ELFEDIT_CMDOA_F_OPT },
   1111 		{ NULL }
   1112 	};
   1113 
   1114 	/* phdr:p_type */
   1115 	static const char *name_p_type[] = { MSG_ORIG(MSG_CMD_P_TYPE), NULL };
   1116 	static elfedit_cmd_optarg_t arg_p_type[] = {
   1117 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1118 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1119 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1120 		    ELFEDIT_CMDOA_F_OPT },
   1121 		{ MSG_ORIG(MSG_STR_TYPE),
   1122 		    /* MSG_INTL(MSG_A2_P_TYPE_TYPE) */
   1123 		    ELFEDIT_I18NHDL(MSG_A2_P_TYPE_TYPE),
   1124 		    ELFEDIT_CMDOA_F_OPT },
   1125 		{ NULL }
   1126 	};
   1127 
   1128 	/* phdr:p_offset */
   1129 	static const char *name_p_offset[] = { MSG_ORIG(MSG_CMD_P_OFFSET),
   1130 	    NULL };
   1131 	static elfedit_cmd_optarg_t arg_p_offset[] = {
   1132 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1133 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1134 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1135 		    ELFEDIT_CMDOA_F_OPT },
   1136 		{ MSG_ORIG(MSG_STR_VALUE),
   1137 		    /* MSG_INTL(MSG_A2_P_OFFSET_VALUE) */
   1138 		    ELFEDIT_I18NHDL(MSG_A2_P_OFFSET_VALUE),
   1139 		    ELFEDIT_CMDOA_F_OPT },
   1140 		{ NULL }
   1141 	};
   1142 
   1143 	/* phdr:p_vaddr */
   1144 	static const char *name_p_vaddr[] = { MSG_ORIG(MSG_CMD_P_VADDR),
   1145 	    NULL };
   1146 	static elfedit_cmd_optarg_t arg_p_vaddr[] = {
   1147 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1148 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1149 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1150 		    ELFEDIT_CMDOA_F_OPT },
   1151 		{ MSG_ORIG(MSG_STR_ADDR),
   1152 		    /* MSG_INTL(MSG_A2_P_VADDR_ADDR) */
   1153 		    ELFEDIT_I18NHDL(MSG_A2_P_VADDR_ADDR),
   1154 		    ELFEDIT_CMDOA_F_OPT },
   1155 		{ NULL }
   1156 	};
   1157 
   1158 	/* phdr:p_paddr */
   1159 	static const char *name_p_paddr[] = { MSG_ORIG(MSG_CMD_P_PADDR),
   1160 	    NULL };
   1161 	static elfedit_cmd_optarg_t arg_p_paddr[] = {
   1162 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1163 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1164 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1165 		    ELFEDIT_CMDOA_F_OPT },
   1166 		{ MSG_ORIG(MSG_STR_ADDR),
   1167 		    /* MSG_INTL(MSG_A2_P_PADDR_ADDR) */
   1168 		    ELFEDIT_I18NHDL(MSG_A2_P_PADDR_ADDR),
   1169 		    ELFEDIT_CMDOA_F_OPT },
   1170 		{ NULL }
   1171 	};
   1172 
   1173 	/* phdr:p_filesz */
   1174 	static const char *name_p_filesz[] = { MSG_ORIG(MSG_CMD_P_FILESZ),
   1175 	    NULL };
   1176 	static elfedit_cmd_optarg_t arg_p_filesz[] = {
   1177 	    /* MSG_INTL(MSG_A1_ELEMENT) */
   1178 		{ MSG_ORIG(MSG_STR_ELEMENT), ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1179 		    ELFEDIT_CMDOA_F_OPT },
   1180 		{ MSG_ORIG(MSG_STR_SIZE),
   1181 		    /* MSG_INTL(MSG_A2_P_FILESZ_SIZE) */
   1182 		    ELFEDIT_I18NHDL(MSG_A2_P_FILESZ_SIZE),
   1183 		    ELFEDIT_CMDOA_F_OPT },
   1184 		{ NULL }
   1185 	};
   1186 
   1187 	/* phdr:p_memsz */
   1188 	static const char *name_p_memsz[] = { MSG_ORIG(MSG_CMD_P_MEMSZ),
   1189 	    NULL };
   1190 	static elfedit_cmd_optarg_t arg_p_memsz[] = {
   1191 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1192 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1193 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1194 		    ELFEDIT_CMDOA_F_OPT },
   1195 		{ MSG_ORIG(MSG_STR_SIZE),
   1196 		    /* MSG_INTL(MSG_A2_P_MEMSZ_SIZE) */
   1197 		    ELFEDIT_I18NHDL(MSG_A2_P_MEMSZ_SIZE),
   1198 		    ELFEDIT_CMDOA_F_OPT },
   1199 		{ NULL }
   1200 	};
   1201 
   1202 	/* shdr:p_flags */
   1203 	static const char *name_p_flags[] = {
   1204 	    MSG_ORIG(MSG_CMD_P_FLAGS), NULL };
   1205 	static elfedit_cmd_optarg_t opt_p_flags[] = {
   1206 		{ ELFEDIT_STDOA_OPT_AND, NULL,
   1207 		    ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_AND, PHDR_OPT_F_OR },
   1208 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
   1209 		    ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_CMP, 0 },
   1210 		{ MSG_ORIG(MSG_STR_MINUS_PHNDX),
   1211 		    /* MSG_INTL(MSG_OPTDESC_PHNDX) */
   1212 		    ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0,
   1213 		    PHDR_OPT_F_PHNDX, 0 },
   1214 		{ ELFEDIT_STDOA_OPT_O, NULL,
   1215 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
   1216 		{ ELFEDIT_STDOA_OPT_OR, NULL,
   1217 		    ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_OR, PHDR_OPT_F_AND },
   1218 		{ NULL }
   1219 	};
   1220 	static elfedit_cmd_optarg_t arg_p_flags[] = {
   1221 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1222 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1223 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1224 		    ELFEDIT_CMDOA_F_OPT },
   1225 		{ MSG_ORIG(MSG_STR_VALUE),
   1226 		    /* MSG_INTL(MSG_A2_P_FLAGS_VALUE) */
   1227 		    ELFEDIT_I18NHDL(MSG_A2_P_FLAGS_VALUE),
   1228 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
   1229 		{ NULL }
   1230 	};
   1231 
   1232 	/* phdr:p_align */
   1233 	static const char *name_p_align[] = { MSG_ORIG(MSG_CMD_P_ALIGN),
   1234 	    NULL };
   1235 	static elfedit_cmd_optarg_t arg_p_align[] = {
   1236 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1237 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1238 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1239 		    ELFEDIT_CMDOA_F_OPT },
   1240 		{ MSG_ORIG(MSG_STR_ALIGN),
   1241 		    /* MSG_INTL(MSG_A2_P_ALIGN_ALIGN) */
   1242 		    ELFEDIT_I18NHDL(MSG_A2_P_ALIGN_ALIGN),
   1243 		    ELFEDIT_CMDOA_F_OPT },
   1244 		{ NULL }
   1245 	};
   1246 
   1247 	/* phdr:interp */
   1248 	static const char *name_interp[] = { MSG_ORIG(MSG_CMD_INTERP), NULL };
   1249 	static elfedit_cmd_optarg_t opt_interp[] = {
   1250 		{ ELFEDIT_STDOA_OPT_O, NULL,
   1251 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
   1252 		{ NULL }
   1253 	};
   1254 	static elfedit_cmd_optarg_t arg_interp[] = {
   1255 		{ MSG_ORIG(MSG_STR_NEWPATH),
   1256 		    /* MSG_INTL(MSG_A1_INTERP_NEWPATH) */
   1257 		    ELFEDIT_I18NHDL(MSG_A1_INTERP_NEWPATH),
   1258 		    ELFEDIT_CMDOA_F_OPT },
   1259 		{ NULL }
   1260 	};
   1261 
   1262 	/* phdr:delete */
   1263 	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
   1264 	static elfedit_cmd_optarg_t arg_delete[] = {
   1265 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1266 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1267 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1268 		    0 },
   1269 		{ MSG_ORIG(MSG_STR_COUNT),
   1270 		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
   1271 		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
   1272 		    ELFEDIT_CMDOA_F_OPT },
   1273 		{ NULL }
   1274 	};
   1275 
   1276 	/* phdr:move */
   1277 	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
   1278 	static elfedit_cmd_optarg_t arg_move[] = {
   1279 		{ MSG_ORIG(MSG_STR_ELEMENT),
   1280 		    /* MSG_INTL(MSG_A1_ELEMENT) */
   1281 		    ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
   1282 		    ELFEDIT_CMDOA_F_OPT },
   1283 		{ MSG_ORIG(MSG_STR_DST_INDEX),
   1284 		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
   1285 		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
   1286 		    0 },
   1287 		{ MSG_ORIG(MSG_STR_COUNT),
   1288 		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
   1289 		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
   1290 		    ELFEDIT_CMDOA_F_OPT },
   1291 		{ NULL }
   1292 	};
   1293 
   1294 	static elfedit_cmd_t cmds[] = {
   1295 		/* phdr:dump */
   1296 		{ cmd_dump, cpl_1starg_pt, name_dump,
   1297 		    /* MSG_INTL(MSG_DESC_DUMP) */
   1298 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
   1299 		    /* MSG_INTL(MSG_HELP_DUMP) */
   1300 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
   1301 		    opt_minus_phndx, arg_dump },
   1302 
   1303 		/* phdr:p_type */
   1304 		{ cmd_p_type, cpl_p_type, name_p_type,
   1305 		    /* MSG_INTL(MSG_DESC_P_TYPE) */
   1306 		    ELFEDIT_I18NHDL(MSG_DESC_P_TYPE),
   1307 		    /* MSG_INTL(MSG_HELP_P_TYPE) */
   1308 		    ELFEDIT_I18NHDL(MSG_HELP_P_TYPE),
   1309 		    opt_std, arg_p_type },
   1310 
   1311 		/* phdr:p_offset */
   1312 		{ cmd_p_offset, cpl_1starg_pt, name_p_offset,
   1313 		    /* MSG_INTL(MSG_DESC_P_OFFSET) */
   1314 		    ELFEDIT_I18NHDL(MSG_DESC_P_OFFSET),
   1315 		    /* MSG_INTL(MSG_HELP_P_OFFSET) */
   1316 		    ELFEDIT_I18NHDL(MSG_HELP_P_OFFSET),
   1317 		    opt_std, arg_p_offset },
   1318 
   1319 		/* phdr:p_vaddr */
   1320 		{ cmd_p_vaddr, cpl_1starg_pt, name_p_vaddr,
   1321 		    /* MSG_INTL(MSG_DESC_P_VADDR) */
   1322 		    ELFEDIT_I18NHDL(MSG_DESC_P_VADDR),
   1323 		    /* MSG_INTL(MSG_HELP_P_VADDR) */
   1324 		    ELFEDIT_I18NHDL(MSG_HELP_P_VADDR),
   1325 		    opt_std, arg_p_vaddr },
   1326 
   1327 		/* phdr:p_paddr */
   1328 		{ cmd_p_paddr, cpl_1starg_pt, name_p_paddr,
   1329 		    /* MSG_INTL(MSG_DESC_P_PADDR) */
   1330 		    ELFEDIT_I18NHDL(MSG_DESC_P_PADDR),
   1331 		    /* MSG_INTL(MSG_HELP_P_PADDR) */
   1332 		    ELFEDIT_I18NHDL(MSG_HELP_P_PADDR),
   1333 		    opt_std, arg_p_paddr },
   1334 
   1335 		/* phdr:p_filesz */
   1336 		{ cmd_p_filesz, cpl_1starg_pt, name_p_filesz,
   1337 		    /* MSG_INTL(MSG_DESC_P_FILESZ) */
   1338 		    ELFEDIT_I18NHDL(MSG_DESC_P_FILESZ),
   1339 		    /* MSG_INTL(MSG_HELP_P_FILESZ) */
   1340 		    ELFEDIT_I18NHDL(MSG_HELP_P_FILESZ),
   1341 		    opt_std, arg_p_filesz },
   1342 
   1343 		/* phdr:p_memsz */
   1344 		{ cmd_p_memsz, cpl_1starg_pt, name_p_memsz,
   1345 		    /* MSG_INTL(MSG_DESC_P_MEMSZ) */
   1346 		    ELFEDIT_I18NHDL(MSG_DESC_P_MEMSZ),
   1347 		    /* MSG_INTL(MSG_HELP_P_MEMSZ) */
   1348 		    ELFEDIT_I18NHDL(MSG_HELP_P_MEMSZ),
   1349 		    opt_std, arg_p_memsz },
   1350 
   1351 		/* phdr:p_flags */
   1352 		{ cmd_p_flags, cpl_p_flags, name_p_flags,
   1353 		    /* MSG_INTL(MSG_DESC_P_FLAGS) */
   1354 		    ELFEDIT_I18NHDL(MSG_DESC_P_FLAGS),
   1355 		    /* MSG_INTL(MSG_HELP_P_FLAGS) */
   1356 		    ELFEDIT_I18NHDL(MSG_HELP_P_FLAGS),
   1357 		    opt_p_flags, arg_p_flags },
   1358 
   1359 		/* phdr:p_align */
   1360 		{ cmd_p_align, cpl_1starg_pt, name_p_align,
   1361 		    /* MSG_INTL(MSG_DESC_P_ALIGN) */
   1362 		    ELFEDIT_I18NHDL(MSG_DESC_P_ALIGN),
   1363 		    /* MSG_INTL(MSG_HELP_P_ALIGN) */
   1364 		    ELFEDIT_I18NHDL(MSG_HELP_P_ALIGN),
   1365 		    opt_std, arg_p_align },
   1366 
   1367 		/* phdr:interp */
   1368 		{ cmd_interp, NULL, name_interp,
   1369 		    /* MSG_INTL(MSG_DESC_INTERP) */
   1370 		    ELFEDIT_I18NHDL(MSG_DESC_INTERP),
   1371 		    /* MSG_INTL(MSG_HELP_INTERP) */
   1372 		    ELFEDIT_I18NHDL(MSG_HELP_INTERP),
   1373 		    opt_interp, arg_interp },
   1374 
   1375 		/* phdr:delete */
   1376 		{ cmd_delete, cpl_1starg_pt, name_delete,
   1377 		    /* MSG_INTL(MSG_DESC_DELETE) */
   1378 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
   1379 		    /* MSG_INTL(MSG_HELP_DELETE) */
   1380 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
   1381 		    opt_minus_phndx, arg_delete },
   1382 
   1383 		/* phdr:move */
   1384 		{ cmd_move, cpl_1starg_pt, name_move,
   1385 		    /* MSG_INTL(MSG_DESC_MOVE) */
   1386 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
   1387 		    /* MSG_INTL(MSG_HELP_MOVE) */
   1388 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
   1389 		    opt_minus_phndx, arg_move },
   1390 
   1391 		{ NULL }
   1392 	};
   1393 
   1394 	static elfedit_module_t module = {
   1395 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
   1396 	    /* MSG_INTL(MSG_MOD_DESC) */
   1397 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
   1398 	    cmds, mod_i18nhdl_to_str };
   1399 
   1400 	return (&module);
   1401 }
   1402