phdr.c revision 5088:26c540f30cd3
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 */
47typedef 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 */
73typedef 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 */
86const 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 */
105static const char *
106mod_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 */
119typedef 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 */
133typedef 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 */
158static void
159process_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 */
270static const char *
271locate_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 */
348static void
349print_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 */
499static elfedit_cmdret_t
500cmd_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 */
653static elfedit_cmdret_t
654cmd_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*/
941static void
942cpl_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*/
956static void
957cpl_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*/
970static void
971cpl_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 */
987static elfedit_cmdret_t
988cmd_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
993static elfedit_cmdret_t
994cmd_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
999static elfedit_cmdret_t
1000cmd_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
1005static elfedit_cmdret_t
1006cmd_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
1011static elfedit_cmdret_t
1012cmd_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
1017static elfedit_cmdret_t
1018cmd_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
1023static elfedit_cmdret_t
1024cmd_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
1029static elfedit_cmdret_t
1030cmd_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
1035static elfedit_cmdret_t
1036cmd_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
1041static elfedit_cmdret_t
1042cmd_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
1047static elfedit_cmdret_t
1048cmd_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
1053static elfedit_cmdret_t
1054cmd_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*/
1061elfedit_module_t *
1062elfedit_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