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