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