xref: /illumos-gate/usr/src/cmd/sgs/elfedit/modules/common/phdr.c (revision b1e2e3fb17324e9ddf43db264a0c64da7756d9e6)
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, 0,
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, 0,
1207 		    ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_AND, PHDR_OPT_F_OR },
1208 		{ ELFEDIT_STDOA_OPT_CMP, 0,
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, 0,
1215 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1216 		{ ELFEDIT_STDOA_OPT_OR, 0,
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, 0,
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