summaryrefslogtreecommitdiff
path: root/usr/src/cmd/sgs/elfedit/modules/common/phdr.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/sgs/elfedit/modules/common/phdr.c')
-rw-r--r--usr/src/cmd/sgs/elfedit/modules/common/phdr.c1386
1 files changed, 1386 insertions, 0 deletions
diff --git a/usr/src/cmd/sgs/elfedit/modules/common/phdr.c b/usr/src/cmd/sgs/elfedit/modules/common/phdr.c
new file mode 100644
index 0000000000..1d40c14ecd
--- /dev/null
+++ b/usr/src/cmd/sgs/elfedit/modules/common/phdr.c
@@ -0,0 +1,1386 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+#include <machdep.h>
+#include <elfedit.h>
+#include <strings.h>
+#include <conv.h>
+#include <debug.h>
+#include <phdr_msg.h>
+
+
+/*
+ * Program headers
+ */
+
+
+
+/*
+ * This module uses shared code for several of the commands.
+ * It is sometimes necessary to know which specific command
+ * is active.
+ */
+typedef enum {
+ /* Dump command, used as module default to display dynamic section */
+ PHDR_CMD_T_DUMP = 0, /* phdr:dump */
+
+ /* Commands that correspond directly to program header fields */
+ PHDR_CMD_T_P_TYPE = 1, /* phdr:p_type */
+ PHDR_CMD_T_P_OFFSET = 2, /* phdr:p_offset */
+ PHDR_CMD_T_P_VADDR = 3, /* phdr:p_vaddr */
+ PHDR_CMD_T_P_PADDR = 4, /* phdr:p_paddr */
+ PHDR_CMD_T_P_FILESZ = 5, /* phdr:p_filesz */
+ PHDR_CMD_T_P_MEMSZ = 6, /* phdr:p_memsz */
+ PHDR_CMD_T_P_FLAGS = 7, /* phdr:p_flags */
+ PHDR_CMD_T_P_ALIGN = 8, /* phdr:p_align */
+
+ /* Commands that do not correspond directly to a specific phdr tag */
+ PHDR_CMD_T_INTERP = 9, /* phdr:interp */
+ PHDR_CMD_T_DELETE = 10, /* phdr:delete */
+ PHDR_CMD_T_MOVE = 11 /* phdr:move */
+} PHDR_CMD_T;
+
+
+
+/*
+ * The following type is ued by locate_interp() to return
+ * information about the interpreter program header.
+ */
+typedef struct {
+ Word phndx; /* Index of PT_INTERP header */
+ Phdr *phdr; /* PT_INTERP header */
+ elfedit_section_t *sec; /* Section containing string */
+ Word stroff; /* Offset into string section */
+ const char *str; /* Interpreter string */
+} INTERP_STATE;
+
+
+#ifndef _ELF64
+/*
+ * We supply this function for the msg module
+ */
+const char *
+_phdr_msg(Msg mid)
+{
+ return (gettext(MSG_ORIG(mid)));
+}
+#endif
+
+
+/*
+ * This function is supplied to elfedit through our elfedit_module_t
+ * definition. It translates the opaque elfedit_i18nhdl_t handles
+ * in our module interface into the actual strings for elfedit to
+ * use.
+ *
+ * note:
+ * This module uses Msg codes for its i18n handle type.
+ * So the translation is simply to use MSG_INTL() to turn
+ * it into a string and return it.
+ */
+static const char *
+mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
+{
+ Msg msg = (Msg)hdl;
+
+ return (MSG_INTL(msg));
+}
+
+
+
+/*
+ * The phdr_opt_t enum specifies a bit value for every optional
+ * argument allowed by a command in this module.
+ */
+typedef enum {
+ PHDR_OPT_F_AND = 1, /* -and: AND (&) values to dest */
+ PHDR_OPT_F_CMP = 2, /* -cmp: Complement (~) values */
+ PHDR_OPT_F_PHNDX = 4, /* -phndx: Program header by index, */
+ /* not by name */
+ PHDR_OPT_F_OR = 8 /* -or: OR (|) values to dest */
+} phdr_opt_t;
+
+
+/*
+ * A variable of type ARGSTATE is used by each command to maintain
+ * information about the section headers and related things. It is
+ * initialized by process_args(), and used by the other routines.
+ */
+typedef struct {
+ elfedit_obj_state_t *obj_state;
+ phdr_opt_t optmask; /* Mask of options used */
+ int argc; /* # of plain arguments */
+ const char **argv; /* Plain arguments */
+ int ndx_set; /* True if ndx is valid */
+ Word ndx; /* Index of header if cmd */
+ /* accepts it */
+ int print_req; /* Call is a print request */
+} ARGSTATE;
+
+
+/*
+ * Standard argument processing for phdr module
+ *
+ * entry
+ * obj_state, argc, argv - Standard command arguments
+ * optmask - Mask of allowed optional arguments.
+ * cmd - PHDR_CMD_T_* value giving identify of caller
+ * argstate - Address of ARGSTATE block to be initialized
+ *
+ * exit:
+ * On success, *argstate is initialized. On error,
+ * an error is issued and this routine does not return.
+ */
+static void
+process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
+ PHDR_CMD_T cmd, ARGSTATE *argstate)
+{
+ elfedit_getopt_state_t getopt_state;
+ elfedit_getopt_ret_t *getopt_ret;
+
+ bzero(argstate, sizeof (*argstate));
+ argstate->obj_state = obj_state;
+
+ elfedit_getopt_init(&getopt_state, &argc, &argv);
+
+ /* Add each new option to the options mask */
+ while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
+ argstate->optmask |= getopt_ret->gor_idmask;
+
+ /* Are the right number of plain arguments present? */
+ switch (cmd) {
+ case PHDR_CMD_T_DUMP:
+ if (argc > 1)
+ elfedit_command_usage();
+ argstate->print_req = 1;
+ break;
+ case PHDR_CMD_T_P_FLAGS:
+ /* phdr:sh_flags allows an arbitrary number of arguments */
+ argstate->print_req = (argc < 2);
+ break;
+ case PHDR_CMD_T_INTERP:
+ if (argc > 1)
+ elfedit_command_usage();
+ argstate->print_req = (argc == 0);
+ break;
+ case PHDR_CMD_T_DELETE:
+ if ((argc < 1) || (argc > 2))
+ elfedit_command_usage();
+ argstate->print_req = 0;
+ break;
+ case PHDR_CMD_T_MOVE:
+ if ((argc < 2) || (argc > 3))
+ elfedit_command_usage();
+ argstate->print_req = 0;
+ break;
+
+ default:
+ /* The remaining commands accept 2 plain arguments */
+ if (argc > 2)
+ elfedit_command_usage();
+ argstate->print_req = (argc < 2);
+ break;
+ }
+
+ /* Return the updated values of argc/argv */
+ argstate->argc = argc;
+ argstate->argv = argv;
+
+ argstate->ndx_set = 0;
+ if ((argc > 0) && (cmd != PHDR_CMD_T_INTERP)) {
+ /*
+ * If the -phndx option is present, the first argument is
+ * the index of the header to use. Otherwise, it is a
+ * name corresponding to its type, similar to the way
+ * elfdump works with its -N option.
+ */
+ if (argstate->optmask & PHDR_OPT_F_PHNDX) {
+ argstate->ndx = (Word) elfedit_atoui_range(
+ argstate->argv[0], MSG_ORIG(MSG_STR_ELEMENT), 0,
+ argstate->obj_state->os_phnum - 1, NULL);
+ argstate->ndx_set = 1;
+ } else {
+ Conv_inv_buf_t inv_buf;
+ Word i;
+ Phdr *phdr;
+
+ argstate->ndx = (Word) elfedit_atoconst(
+ argstate->argv[0], ELFEDIT_CONST_PT);
+ phdr = obj_state->os_phdr;
+ for (i = 0; i < obj_state->os_phnum; i++, phdr++) {
+ if (phdr->p_type == argstate->ndx) {
+ argstate->ndx = i;
+ argstate->ndx_set = 1;
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_PHDR),
+ EC_WORD(i), conv_phdr_type(
+ obj_state->os_ehdr->e_machine,
+ phdr->p_type, 0, &inv_buf));
+ break;
+ }
+ }
+ if (i == argstate->obj_state->os_phnum)
+ elfedit_msg(ELFEDIT_MSG_ERR,
+ MSG_INTL(MSG_ERR_NOPHDR), conv_phdr_type(
+ obj_state->os_ehdr->e_machine,
+ argstate->ndx, 0, &inv_buf));
+ }
+ }
+
+ /* If there may be an arbitrary amount of output, use a pager */
+ if (argc == 0)
+ elfedit_pager_init();
+
+}
+
+
+
+/*
+ * Locate the interpreter string for the object and related information
+ *
+ * entry:
+ * obj_state - Object state
+ * interp - NULL, or variable to be filled in with information
+ * about the interpteter string.
+ */
+static const char *
+locate_interp(elfedit_obj_state_t *obj_state, INTERP_STATE *interp)
+{
+ INTERP_STATE local_interp;
+ elfedit_section_t *strsec; /* String table */
+ size_t phnum; /* # of program headers */
+ int phndx; /* Index of PT_INTERP program header */
+ Phdr *phdr; /* Program header array */
+ Word i;
+
+ if (interp == NULL)
+ interp = &local_interp;
+
+ /* Locate the PT_INTERP program header */
+ phnum = obj_state->os_phnum;
+ phdr = obj_state->os_phdr;
+
+ for (phndx = 0; phndx < phnum; phndx++) {
+ if (phdr[phndx].p_type == PT_INTERP) {
+ interp->phndx = phndx;
+ interp->phdr = phdr + phndx;
+ break;
+ }
+ }
+ /* If no PT_INTERP program header found, we cannot proceed */
+ if (phndx == phnum)
+ elfedit_elferr(obj_state->os_file,
+ MSG_INTL(MSG_ERR_NOINTERPPHDR));
+
+ /*
+ * Locate the section containing the interpteter string as well
+ * as the string itself.
+ *
+ * The program header contains a direct offset to the string, so
+ * we find the section by walking through the them looking for
+ * the one with a base and size that would contain the string.
+ * Note that this target section cannot be in a NOBITS section.
+ */
+ for (i = 1; i < obj_state->os_shnum; i++) {
+ strsec = &obj_state->os_secarr[i];
+
+ if ((strsec->sec_shdr->sh_type != SHT_NOBITS) &&
+ (interp->phdr->p_offset >= strsec->sec_shdr->sh_offset) &&
+ ((interp->phdr->p_offset + interp->phdr->p_filesz) <=
+ (strsec->sec_shdr->sh_offset +
+ strsec->sec_shdr->sh_size))) {
+ interp->sec = strsec;
+
+ interp->stroff = interp->phdr->p_offset -
+ strsec->sec_shdr->sh_offset;
+ interp->str = ((char *)strsec->sec_data->d_buf) +
+ interp->stroff;
+ return (interp->str);
+ }
+ }
+
+ /*
+ * We don't expect to get here: If there is a PT_INTERP header,
+ * we fully expect the string to exist.
+ */
+ elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOINTERPSEC));
+ /*NOTREACHED*/
+
+ return (NULL); /* For lint */
+}
+
+/*
+ * Print program header values, taking the calling command, and output style
+ * into account.
+ *
+ * entry:
+ * autoprint - If True, output is only produced if the elfedit
+ * autoprint flag is set. If False, output is always produced.
+ * cmd - PHDR_CMD_T_* value giving identify of caller
+ * argstate - State block for section header array
+ * ndx - Index of first program header to display
+ * cnt - Number of program headers to display
+ */
+static void
+print_phdr(PHDR_CMD_T cmd, int autoprint, ARGSTATE *argstate)
+{
+ elfedit_outstyle_t outstyle;
+ Word ndx, cnt;
+
+ if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
+ return;
+
+ if (argstate->ndx_set) {
+ ndx = argstate->ndx;
+ cnt = 1;
+ } else {
+ ndx = 0;
+ cnt = argstate->obj_state->os_phnum;
+ }
+
+ /*
+ * Pick an output style. phdr:dump is required to use the default
+ * style. The other commands use the current output style.
+ */
+ outstyle = (cmd == PHDR_CMD_T_DUMP) ?
+ ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
+
+ /*
+ * If doing default output, use elfdump style where we
+ * show all program header attributes. In this case, the
+ * command that called us doesn't matter.
+ *
+ * Let PHDR_CMD_T_INTERP fall through: It isn't per-phdr like
+ * the other commands.
+ */
+ if ((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) &&
+ (cmd != PHDR_CMD_T_INTERP)) {
+ Half mach = argstate->obj_state->os_ehdr->e_machine;
+ Phdr *phdr = argstate->obj_state->os_phdr + ndx;
+
+ for (; cnt--; ndx++, phdr++) {
+ elfedit_printf(MSG_ORIG(MSG_STR_NL));
+ elfedit_printf(MSG_INTL(MSG_ELF_PHDR), EC_WORD(ndx));
+ Elf_phdr(0, mach, phdr);
+ }
+ return;
+ }
+
+ switch (cmd) {
+ case PHDR_CMD_T_P_TYPE:
+ for (; cnt--; ndx++) {
+ Word p_type = argstate->obj_state->os_phdr[ndx].p_type;
+ Conv_inv_buf_t inv_buf;
+
+ if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
+ Half mach =
+ argstate->obj_state->os_ehdr->e_machine;
+
+ elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+ conv_phdr_type(mach, p_type, 0, &inv_buf));
+ } else {
+ elfedit_printf(MSG_ORIG(MSG_FMT_X_NL),
+ EC_WORD(p_type));
+ }
+ }
+ return;
+
+ case PHDR_CMD_T_P_OFFSET:
+ for (; cnt--; ndx++)
+ elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
+ EC_OFF(argstate->obj_state->os_phdr[ndx].p_offset));
+ return;
+
+ case PHDR_CMD_T_P_VADDR:
+ for (; cnt--; ndx++)
+ elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
+ EC_ADDR(argstate->obj_state->os_phdr[ndx].p_vaddr));
+ return;
+
+ case PHDR_CMD_T_P_PADDR:
+ for (; cnt--; ndx++)
+ elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
+ EC_ADDR(argstate->obj_state->os_phdr[ndx].p_paddr));
+ return;
+
+ case PHDR_CMD_T_P_FILESZ:
+ for (; cnt--; ndx++)
+ elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
+ EC_XWORD(argstate->obj_state->
+ os_phdr[ndx].p_filesz));
+ return;
+
+ case PHDR_CMD_T_P_MEMSZ:
+ for (; cnt--; ndx++)
+ elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
+ EC_XWORD(argstate->obj_state->
+ os_phdr[ndx].p_memsz));
+ return;
+
+ case PHDR_CMD_T_P_FLAGS:
+ for (; cnt--; ndx++) {
+ Word p_flags =
+ argstate->obj_state->os_phdr[ndx].p_flags;
+
+ if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
+ Conv_phdr_flags_buf_t phdr_flags_buf;
+
+ elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+ conv_phdr_flags(p_flags, CONV_FMT_NOBKT,
+ &phdr_flags_buf));
+ } else {
+ elfedit_printf(MSG_ORIG(MSG_FMT_X_NL),
+ EC_WORD(p_flags));
+ }
+ }
+ return;
+
+ case PHDR_CMD_T_P_ALIGN:
+ for (; cnt--; ndx++)
+ elfedit_printf(MSG_ORIG(MSG_FMT_LLX_NL),
+ EC_XWORD(argstate->obj_state->
+ os_phdr[ndx].p_align));
+ return;
+
+ case PHDR_CMD_T_INTERP:
+ {
+ INTERP_STATE interp;
+
+ (void) locate_interp(argstate->obj_state, &interp);
+ switch (outstyle) {
+
+ case ELFEDIT_OUTSTYLE_DEFAULT:
+ elfedit_printf(MSG_INTL(MSG_FMT_ELF_INTERP),
+ interp.sec->sec_name, interp.str);
+ break;
+ case ELFEDIT_OUTSTYLE_SIMPLE:
+ elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
+ interp.str);
+ break;
+ case ELFEDIT_OUTSTYLE_NUM:
+ elfedit_printf(MSG_ORIG(MSG_FMT_U_NL),
+ EC_WORD(interp.stroff));
+ break;
+ }
+ }
+ return;
+ }
+}
+
+
+/*
+ * Called from cmd_body() in the case where a plain argument
+ * is given to phdr:interp to change the interpreter.
+ */
+static elfedit_cmdret_t
+cmd_body_set_interp(ARGSTATE *argstate)
+{
+ elfedit_obj_state_t *obj_state = argstate->obj_state;
+ elfedit_section_t *strsec; /* String table */
+ INTERP_STATE interp;
+ Word numdyn; /* # of elements in dyn arr */
+ size_t phnum; /* # of program headers */
+ Phdr *phdr; /* Program header array */
+ Word i, j;
+ Word str_offset; /* Offset in strsec to new interp str */
+ int str_found = 0; /* True when we have new interp str */
+ Word str_size; /* Size of new interp string + NULL */
+
+ phnum = obj_state->os_phnum;
+ phdr = obj_state->os_phdr;
+
+ /* Locate the PT_INTERP program header */
+ (void) locate_interp(obj_state, &interp);
+ strsec = interp.sec;
+ str_offset = interp.stroff;
+
+ /*
+ * If the given string is the same as the existing interpreter
+ * string, say so and return.
+ */
+ if (strcmp(interp.str, argstate->argv[0]) == 0) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_OLDINTERPOK),
+ EC_WORD(strsec->sec_shndx), strsec->sec_name,
+ EC_WORD(str_offset), interp.str);
+ return (ELFEDIT_CMDRET_NONE);
+ }
+
+ /*
+ * An ELF PT_INTERP usually references its own special section
+ * instead of some other string table. The ELF ABI says that this
+ * section must be named ".interp". Hence, this is a rare case
+ * in which the name of a section can be taken as an indication
+ * of its contents. .interp is typically sized to just fit
+ * the original string, including its NULL termination. You can
+ * treat it as a string table with one string.
+ *
+ * Thanks to 'elfedit', it may be that we encounter a file where
+ * PT_INTERP does not reference the .interp section. This will happen
+ * if elfedit is used to change the interpreter to a string that is
+ * too big to fit in .interp, in which case we will use the
+ * .dynstr string table (That code is below, in this function).
+ *
+ * Given the above facts, our next step is to locate the .interp
+ * section and see if our new string will fit in it. Since we can't
+ * depend on PT_INTERP, we search the section headers to find a
+ * section whith the following characteristics:
+ * - The name is ".interp".
+ * - Section is allocable (SHF_ALLOC) and SHT_PROGBITS.
+ * - It is not part of a writable segment.
+ * If we find such a section, and the new string fits, we will
+ * write it there.
+ */
+ str_size = strlen(argstate->argv[0]) + 1;
+ for (i = 1; i < obj_state->os_shnum; i++) {
+ strsec = &obj_state->os_secarr[i];
+ if ((strcmp(strsec->sec_name, MSG_ORIG(MSG_SEC_INTERP)) == 0) &&
+ (strsec->sec_shdr->sh_flags & SHF_ALLOC) &&
+ (strsec->sec_shdr->sh_type & SHT_PROGBITS)) {
+ for (j = 0; j < phnum; j++) {
+ Phdr *tphdr = &phdr[j];
+ if ((strsec->sec_shdr->sh_offset >=
+ tphdr->p_offset) &&
+ ((strsec->sec_shdr->sh_offset +
+ strsec->sec_shdr->sh_size) <=
+ (tphdr->p_offset + tphdr->p_filesz)) &&
+ (tphdr->p_flags & PF_W)) {
+ break;
+ }
+ }
+ if ((j == phnum) &&
+ (str_size <= strsec->sec_shdr->sh_size)) {
+ /* .interp section found, and has room */
+ str_found = 1;
+ str_offset = 0;
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_NEWISTR), EC_WORD(j),
+ strsec->sec_name, EC_WORD(str_offset),
+ argstate->argv[0]);
+ /* Put new value in section */
+ (void) strncpy((char *)strsec->sec_data->d_buf,
+ argstate->argv[0],
+ strsec->sec_shdr->sh_size);
+ /* Set libelf dirty bit so change is flushed */
+ elfedit_modified_data(strsec);
+ break;
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LNGISTR), EC_WORD(j),
+ strsec->sec_name, EC_WORD(str_offset),
+ EC_WORD(str_size),
+ EC_WORD(strsec->sec_shdr->sh_size),
+ argstate->argv[0]);
+ }
+ }
+ }
+
+ /*
+ * If the above did not find a string within the .interp section,
+ * then we have a second option. If this ELF object has a dynamic
+ * section, then we are willing to use strings from within the
+ * associated .dynstr string table. And if there is reserved space
+ * in .dynstr (as reported by the DT_SUNW_STRPAD dynamic entry),
+ * then we are even willing to add a new string to .dynstr.
+ */
+ if (!str_found) {
+ elfedit_section_t *dynsec;
+ Dyn *dyn;
+
+ dynsec = elfedit_sec_getdyn(obj_state, &dyn, &numdyn);
+ strsec = elfedit_sec_getstr(obj_state,
+ dynsec->sec_shdr->sh_link);
+
+ /* Does string exist in the table already, or can we add it? */
+ str_offset = elfedit_strtab_insert(obj_state, strsec,
+ dynsec, argstate->argv[0]);
+ }
+
+
+ /*
+ * If we are here, we know we have a replacement string, because
+ * the errors from checking .dynamic/.dynstr will not allow
+ * things to get here otherwise.
+ *
+ * The PT_INTERP program header references the string directly,
+ * so we add the section offset to the string offset.
+ */
+ interp.phdr->p_offset = strsec->sec_shdr->sh_offset + str_offset;
+ interp.phdr->p_filesz = str_size;
+ elfedit_modified_phdr(obj_state);
+ elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_SETPHINTERP),
+ EC_WORD(interp.phndx), EC_XWORD(interp.phdr->p_offset),
+ EC_XWORD(interp.phdr->p_filesz));
+
+ return (ELFEDIT_CMDRET_MOD);
+}
+
+
+/*
+ * Common body for the phdr: module commands. These commands
+ * share a large amount of common behavior, so it is convenient
+ * to centralize things and use the cmd argument to handle the
+ * small differences.
+ *
+ * entry:
+ * cmd - One of the PHDR_CMD_T_* constants listed above, specifying
+ * which command to implement.
+ * obj_state, argc, argv - Standard command arguments
+ */
+static elfedit_cmdret_t
+cmd_body(PHDR_CMD_T cmd, elfedit_obj_state_t *obj_state,
+ int argc, const char *argv[])
+{
+ ARGSTATE argstate;
+ Phdr *phdr;
+ elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
+ int do_autoprint = 1;
+
+ process_args(obj_state, argc, argv, cmd, &argstate);
+
+ /* If this is a printing request, print and return */
+ if (argstate.print_req) {
+ print_phdr(cmd, 0, &argstate);
+ return (ELFEDIT_CMDRET_NONE);
+ }
+
+
+ if (argstate.ndx_set)
+ phdr = &argstate.obj_state->os_phdr[argstate.ndx];
+
+ switch (cmd) {
+ /*
+ * PHDR_CMD_T_DUMP can't get here: It never has more than
+ * one argument, and is handled above.
+ */
+
+ case PHDR_CMD_T_P_TYPE:
+ {
+ Half mach = obj_state->os_ehdr->e_machine;
+ Word p_type = elfedit_atoconst(argstate.argv[1],
+ ELFEDIT_CONST_PT);
+ Conv_inv_buf_t inv_buf1, inv_buf2;
+
+ if (phdr->p_type == p_type) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_S_OK),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_TYPE),
+ conv_phdr_type(mach, phdr->p_type,
+ 0, &inv_buf1));
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_S_CHG),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_TYPE),
+ conv_phdr_type(mach, phdr->p_type, 0,
+ &inv_buf1),
+ conv_phdr_type(mach, p_type, 0, &inv_buf2));
+ ret = ELFEDIT_CMDRET_MOD;
+ phdr->p_type = p_type;
+ }
+ }
+ break;
+
+ case PHDR_CMD_T_P_OFFSET:
+ {
+ Off p_offset;
+
+ p_offset = elfedit_atoui(argstate.argv[1], NULL);
+ if (phdr->p_offset == p_offset) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_OK),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_OFFSET),
+ EC_XWORD(phdr->p_offset));
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_CHG),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_OFFSET),
+ EC_XWORD(phdr->p_offset),
+ EC_XWORD(p_offset));
+ ret = ELFEDIT_CMDRET_MOD;
+ phdr->p_offset = p_offset;
+ }
+ }
+ break;
+
+ case PHDR_CMD_T_P_VADDR:
+ {
+ Addr p_vaddr = elfedit_atoui(argstate.argv[1], NULL);
+
+ if (phdr->p_vaddr == p_vaddr) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_OK),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_VADDR),
+ EC_ADDR(phdr->p_vaddr));
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_CHG),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_VADDR),
+ EC_ADDR(phdr->p_vaddr), EC_ADDR(p_vaddr));
+ ret = ELFEDIT_CMDRET_MOD;
+ phdr->p_vaddr = p_vaddr;
+ }
+ }
+ break;
+
+ case PHDR_CMD_T_P_PADDR:
+ {
+ Addr p_paddr = elfedit_atoui(argstate.argv[1], NULL);
+
+ if (phdr->p_paddr == p_paddr) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_OK),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_PADDR),
+ EC_ADDR(phdr->p_paddr));
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_CHG),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_PADDR),
+ EC_ADDR(phdr->p_paddr), EC_ADDR(p_paddr));
+ ret = ELFEDIT_CMDRET_MOD;
+ phdr->p_paddr = p_paddr;
+ }
+ }
+ break;
+
+ case PHDR_CMD_T_P_FILESZ:
+ {
+ Xword p_filesz = elfedit_atoui(argstate.argv[1], NULL);
+
+ if (phdr->p_filesz == p_filesz) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_OK),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_FILESZ),
+ EC_XWORD(phdr->p_filesz));
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_CHG),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_FILESZ),
+ EC_XWORD(phdr->p_filesz),
+ EC_XWORD(p_filesz));
+ ret = ELFEDIT_CMDRET_MOD;
+ phdr->p_filesz = p_filesz;
+ }
+ }
+ break;
+
+ case PHDR_CMD_T_P_MEMSZ:
+ {
+ Xword p_memsz = elfedit_atoui(argstate.argv[1], NULL);
+
+ if (phdr->p_memsz == p_memsz) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_OK),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_MEMSZ),
+ EC_XWORD(phdr->p_memsz));
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_CHG),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_MEMSZ),
+ EC_XWORD(phdr->p_memsz),
+ EC_XWORD(p_memsz));
+ ret = ELFEDIT_CMDRET_MOD;
+ phdr->p_memsz = p_memsz;
+ }
+ }
+ break;
+
+ case PHDR_CMD_T_P_FLAGS:
+ {
+ Conv_phdr_flags_buf_t buf1, buf2;
+ Word p_flags = 0;
+ int i;
+
+ /* Collect the flag arguments */
+ for (i = 1; i < argstate.argc; i++)
+ p_flags |=
+ (Word) elfedit_atoconst(argstate.argv[i],
+ ELFEDIT_CONST_PF);
+
+ /* Complement the value? */
+ if (argstate.optmask & PHDR_OPT_F_CMP)
+ p_flags = ~p_flags;
+
+ /* Perform any requested bit operations */
+ if (argstate.optmask & PHDR_OPT_F_AND)
+ p_flags &= phdr->p_flags;
+ else if (argstate.optmask & PHDR_OPT_F_OR)
+ p_flags |= phdr->p_flags;
+
+ /* Set the value */
+ if (phdr->p_flags == p_flags) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_S_OK),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_FLAGS),
+ conv_phdr_flags(phdr->p_flags, 0, &buf1));
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_S_CHG),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_FLAGS),
+ conv_phdr_flags(phdr->p_flags, 0, &buf1),
+ conv_phdr_flags(p_flags, 0, &buf2));
+ ret = ELFEDIT_CMDRET_MOD;
+ phdr->p_flags = p_flags;
+ }
+ }
+ break;
+
+ case PHDR_CMD_T_P_ALIGN:
+ {
+ Xword p_align = elfedit_atoui(argstate.argv[1], NULL);
+
+ if (phdr->p_align == p_align) {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_OK),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_ALIGN),
+ EC_XWORD(phdr->p_align));
+ } else {
+ elfedit_msg(ELFEDIT_MSG_DEBUG,
+ MSG_INTL(MSG_DEBUG_LLX_CHG),
+ argstate.ndx, MSG_ORIG(MSG_CMD_P_ALIGN),
+ EC_XWORD(phdr->p_align),
+ EC_XWORD(p_align));
+ ret = ELFEDIT_CMDRET_MOD;
+ phdr->p_align = p_align;
+ }
+ }
+ break;
+
+ case PHDR_CMD_T_INTERP:
+ ret = cmd_body_set_interp(&argstate);
+ break;
+
+ case PHDR_CMD_T_DELETE:
+ {
+ Word cnt = (argstate.argc == 1) ? 1 :
+ (Word) elfedit_atoui_range(argstate.argv[1],
+ MSG_ORIG(MSG_STR_COUNT), 1,
+ obj_state->os_phnum - argstate.ndx, NULL);
+
+ elfedit_array_elts_delete(MSG_ORIG(MSG_MOD_NAME),
+ obj_state->os_phdr, sizeof (Phdr),
+ obj_state->os_phnum, argstate.ndx, cnt);
+ do_autoprint = 0;
+ ret = ELFEDIT_CMDRET_MOD;
+ }
+ break;
+
+ case PHDR_CMD_T_MOVE:
+ {
+ Phdr save;
+ Word cnt;
+ Word dstndx;
+
+ do_autoprint = 0;
+ dstndx = (Word)
+ elfedit_atoui_range(argstate.argv[1],
+ MSG_ORIG(MSG_STR_DST_INDEX), 0,
+ obj_state->os_phnum - 1, NULL);
+ if (argstate.argc == 2) {
+ cnt = 1;
+ } else {
+ cnt = (Word) elfedit_atoui_range(
+ argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
+ 1, obj_state->os_phnum, NULL);
+ }
+ elfedit_array_elts_move(MSG_ORIG(MSG_MOD_NAME),
+ obj_state->os_phdr, sizeof (save),
+ obj_state->os_phnum, argstate.ndx, dstndx,
+ cnt, &save);
+ ret = ELFEDIT_CMDRET_MOD;
+ }
+ break;
+ }
+
+ /*
+ * If we modified the section header array, tell libelf.
+ */
+ if (ret == ELFEDIT_CMDRET_MOD)
+ elfedit_modified_phdr(obj_state);
+
+ /* Do autoprint */
+ if (do_autoprint)
+ print_phdr(cmd, 1, &argstate);
+
+ return (ret);
+}
+
+
+
+/*
+ * Command completion functions for the various commands
+ */
+
+/*
+ * A number of the commands accept a PT_ constant as their first
+ * argument as long as the -phndx option is not used.
+ */
+/*ARGSUSED*/
+static void
+cpl_1starg_pt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
+ const char *argv[], int num_opt)
+{
+ int i;
+
+ for (i = 0; i < num_opt; i++)
+ if (strcmp(MSG_ORIG(MSG_STR_MINUS_PHNDX), argv[i]) == 0)
+ return;
+
+ if (argc == (num_opt + 1))
+ elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PT);
+}
+
+/*ARGSUSED*/
+static void
+cpl_p_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
+ const char *argv[], int num_opt)
+{
+ /* The first argument follows the standard rules */
+ cpl_1starg_pt(obj_state, cpldata, argc, argv, num_opt);
+
+ /* The second argument can be a PT_ value */
+ if (argc == (num_opt + 2))
+ elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PT);
+}
+
+
+/*ARGSUSED*/
+static void
+cpl_p_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
+ const char *argv[], int num_opt)
+{
+ /* The first argument follows the standard rules */
+ cpl_1starg_pt(obj_state, cpldata, argc, argv, num_opt);
+
+ /* The second and following arguments can be an PF_ value */
+ if (argc >= (num_opt + 2))
+ elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_PF);
+}
+
+
+
+/*
+ * Implementation functions for the commands
+ */
+static elfedit_cmdret_t
+cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_DUMP, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_p_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_P_TYPE, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_p_offset(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_P_OFFSET, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_p_vaddr(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_P_VADDR, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_p_paddr(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_P_PADDR, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_p_filesz(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_P_FILESZ, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_p_memsz(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_P_MEMSZ, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_p_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_P_FLAGS, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_p_align(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_P_ALIGN, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_interp(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_INTERP, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_DELETE, obj_state, argc, argv));
+}
+
+static elfedit_cmdret_t
+cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
+{
+ return (cmd_body(PHDR_CMD_T_MOVE, obj_state, argc, argv));
+}
+
+
+/*ARGSUSED*/
+elfedit_module_t *
+elfedit_init(elfedit_module_version_t version)
+{
+ /* Multiple commands accept a standard set of options */
+ static elfedit_cmd_optarg_t opt_std[] = {
+ { ELFEDIT_STDOA_OPT_O, NULL,
+ ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
+ { MSG_ORIG(MSG_STR_MINUS_PHNDX),
+ /* MSG_INTL(MSG_OPTDESC_PHNDX) */
+ ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0,
+ PHDR_OPT_F_PHNDX, 0 },
+ { NULL }
+ };
+
+ /* For commands that only accept -phndx */
+ static elfedit_cmd_optarg_t opt_minus_phndx[] = {
+ { MSG_ORIG(MSG_STR_MINUS_PHNDX),
+ /* MSG_INTL(MSG_OPTDESC_PHNDX) */
+ ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0,
+ PHDR_OPT_F_PHNDX, 0 },
+ { NULL }
+ };
+
+
+ /* phdr:dump */
+ static const char *name_dump[] = {
+ MSG_ORIG(MSG_CMD_DUMP),
+ MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */
+ NULL
+ };
+ static elfedit_cmd_optarg_t arg_dump[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:p_type */
+ static const char *name_p_type[] = { MSG_ORIG(MSG_CMD_P_TYPE), NULL };
+ static elfedit_cmd_optarg_t arg_p_type[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_TYPE),
+ /* MSG_INTL(MSG_A2_P_TYPE_TYPE) */
+ ELFEDIT_I18NHDL(MSG_A2_P_TYPE_TYPE),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:p_offset */
+ static const char *name_p_offset[] = { MSG_ORIG(MSG_CMD_P_OFFSET),
+ NULL };
+ static elfedit_cmd_optarg_t arg_p_offset[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_VALUE),
+ /* MSG_INTL(MSG_A2_P_OFFSET_VALUE) */
+ ELFEDIT_I18NHDL(MSG_A2_P_OFFSET_VALUE),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:p_vaddr */
+ static const char *name_p_vaddr[] = { MSG_ORIG(MSG_CMD_P_VADDR),
+ NULL };
+ static elfedit_cmd_optarg_t arg_p_vaddr[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_ADDR),
+ /* MSG_INTL(MSG_A2_P_VADDR_ADDR) */
+ ELFEDIT_I18NHDL(MSG_A2_P_VADDR_ADDR),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:p_paddr */
+ static const char *name_p_paddr[] = { MSG_ORIG(MSG_CMD_P_PADDR),
+ NULL };
+ static elfedit_cmd_optarg_t arg_p_paddr[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_ADDR),
+ /* MSG_INTL(MSG_A2_P_PADDR_ADDR) */
+ ELFEDIT_I18NHDL(MSG_A2_P_PADDR_ADDR),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:p_filesz */
+ static const char *name_p_filesz[] = { MSG_ORIG(MSG_CMD_P_FILESZ),
+ NULL };
+ static elfedit_cmd_optarg_t arg_p_filesz[] = {
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ { MSG_ORIG(MSG_STR_ELEMENT), ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_SIZE),
+ /* MSG_INTL(MSG_A2_P_FILESZ_SIZE) */
+ ELFEDIT_I18NHDL(MSG_A2_P_FILESZ_SIZE),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:p_memsz */
+ static const char *name_p_memsz[] = { MSG_ORIG(MSG_CMD_P_MEMSZ),
+ NULL };
+ static elfedit_cmd_optarg_t arg_p_memsz[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_SIZE),
+ /* MSG_INTL(MSG_A2_P_MEMSZ_SIZE) */
+ ELFEDIT_I18NHDL(MSG_A2_P_MEMSZ_SIZE),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* shdr:p_flags */
+ static const char *name_p_flags[] = {
+ MSG_ORIG(MSG_CMD_P_FLAGS), NULL };
+ static elfedit_cmd_optarg_t opt_p_flags[] = {
+ { ELFEDIT_STDOA_OPT_AND, NULL,
+ ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_AND, PHDR_OPT_F_OR },
+ { ELFEDIT_STDOA_OPT_CMP, NULL,
+ ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_CMP, 0 },
+ { MSG_ORIG(MSG_STR_MINUS_PHNDX),
+ /* MSG_INTL(MSG_OPTDESC_PHNDX) */
+ ELFEDIT_I18NHDL(MSG_OPTDESC_PHNDX), 0,
+ PHDR_OPT_F_PHNDX, 0 },
+ { ELFEDIT_STDOA_OPT_O, NULL,
+ ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
+ { ELFEDIT_STDOA_OPT_OR, NULL,
+ ELFEDIT_CMDOA_F_INHERIT, PHDR_OPT_F_OR, PHDR_OPT_F_AND },
+ { NULL }
+ };
+ static elfedit_cmd_optarg_t arg_p_flags[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_VALUE),
+ /* MSG_INTL(MSG_A2_P_FLAGS_VALUE) */
+ ELFEDIT_I18NHDL(MSG_A2_P_FLAGS_VALUE),
+ ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
+ { NULL }
+ };
+
+ /* phdr:p_align */
+ static const char *name_p_align[] = { MSG_ORIG(MSG_CMD_P_ALIGN),
+ NULL };
+ static elfedit_cmd_optarg_t arg_p_align[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_ALIGN),
+ /* MSG_INTL(MSG_A2_P_ALIGN_ALIGN) */
+ ELFEDIT_I18NHDL(MSG_A2_P_ALIGN_ALIGN),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:interp */
+ static const char *name_interp[] = { MSG_ORIG(MSG_CMD_INTERP), NULL };
+ static elfedit_cmd_optarg_t opt_interp[] = {
+ { ELFEDIT_STDOA_OPT_O, NULL,
+ ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
+ { NULL }
+ };
+ static elfedit_cmd_optarg_t arg_interp[] = {
+ { MSG_ORIG(MSG_STR_NEWPATH),
+ /* MSG_INTL(MSG_A1_INTERP_NEWPATH) */
+ ELFEDIT_I18NHDL(MSG_A1_INTERP_NEWPATH),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:delete */
+ static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
+ static elfedit_cmd_optarg_t arg_delete[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_COUNT),
+ /* MSG_INTL(MSG_A2_DELETE_COUNT) */
+ ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ /* phdr:move */
+ static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
+ static elfedit_cmd_optarg_t arg_move[] = {
+ { MSG_ORIG(MSG_STR_ELEMENT),
+ /* MSG_INTL(MSG_A1_ELEMENT) */
+ ELFEDIT_I18NHDL(MSG_A1_ELEMENT),
+ ELFEDIT_CMDOA_F_OPT },
+ { MSG_ORIG(MSG_STR_DST_INDEX),
+ /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
+ ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
+ 0 },
+ { MSG_ORIG(MSG_STR_COUNT),
+ /* MSG_INTL(MSG_A3_MOVE_COUNT) */
+ ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
+ ELFEDIT_CMDOA_F_OPT },
+ { NULL }
+ };
+
+ static elfedit_cmd_t cmds[] = {
+ /* phdr:dump */
+ { cmd_dump, cpl_1starg_pt, name_dump,
+ /* MSG_INTL(MSG_DESC_DUMP) */
+ ELFEDIT_I18NHDL(MSG_DESC_DUMP),
+ /* MSG_INTL(MSG_HELP_DUMP) */
+ ELFEDIT_I18NHDL(MSG_HELP_DUMP),
+ opt_minus_phndx, arg_dump },
+
+ /* phdr:p_type */
+ { cmd_p_type, cpl_p_type, name_p_type,
+ /* MSG_INTL(MSG_DESC_P_TYPE) */
+ ELFEDIT_I18NHDL(MSG_DESC_P_TYPE),
+ /* MSG_INTL(MSG_HELP_P_TYPE) */
+ ELFEDIT_I18NHDL(MSG_HELP_P_TYPE),
+ opt_std, arg_p_type },
+
+ /* phdr:p_offset */
+ { cmd_p_offset, cpl_1starg_pt, name_p_offset,
+ /* MSG_INTL(MSG_DESC_P_OFFSET) */
+ ELFEDIT_I18NHDL(MSG_DESC_P_OFFSET),
+ /* MSG_INTL(MSG_HELP_P_OFFSET) */
+ ELFEDIT_I18NHDL(MSG_HELP_P_OFFSET),
+ opt_std, arg_p_offset },
+
+ /* phdr:p_vaddr */
+ { cmd_p_vaddr, cpl_1starg_pt, name_p_vaddr,
+ /* MSG_INTL(MSG_DESC_P_VADDR) */
+ ELFEDIT_I18NHDL(MSG_DESC_P_VADDR),
+ /* MSG_INTL(MSG_HELP_P_VADDR) */
+ ELFEDIT_I18NHDL(MSG_HELP_P_VADDR),
+ opt_std, arg_p_vaddr },
+
+ /* phdr:p_paddr */
+ { cmd_p_paddr, cpl_1starg_pt, name_p_paddr,
+ /* MSG_INTL(MSG_DESC_P_PADDR) */
+ ELFEDIT_I18NHDL(MSG_DESC_P_PADDR),
+ /* MSG_INTL(MSG_HELP_P_PADDR) */
+ ELFEDIT_I18NHDL(MSG_HELP_P_PADDR),
+ opt_std, arg_p_paddr },
+
+ /* phdr:p_filesz */
+ { cmd_p_filesz, cpl_1starg_pt, name_p_filesz,
+ /* MSG_INTL(MSG_DESC_P_FILESZ) */
+ ELFEDIT_I18NHDL(MSG_DESC_P_FILESZ),
+ /* MSG_INTL(MSG_HELP_P_FILESZ) */
+ ELFEDIT_I18NHDL(MSG_HELP_P_FILESZ),
+ opt_std, arg_p_filesz },
+
+ /* phdr:p_memsz */
+ { cmd_p_memsz, cpl_1starg_pt, name_p_memsz,
+ /* MSG_INTL(MSG_DESC_P_MEMSZ) */
+ ELFEDIT_I18NHDL(MSG_DESC_P_MEMSZ),
+ /* MSG_INTL(MSG_HELP_P_MEMSZ) */
+ ELFEDIT_I18NHDL(MSG_HELP_P_MEMSZ),
+ opt_std, arg_p_memsz },
+
+ /* phdr:p_flags */
+ { cmd_p_flags, cpl_p_flags, name_p_flags,
+ /* MSG_INTL(MSG_DESC_P_FLAGS) */
+ ELFEDIT_I18NHDL(MSG_DESC_P_FLAGS),
+ /* MSG_INTL(MSG_HELP_P_FLAGS) */
+ ELFEDIT_I18NHDL(MSG_HELP_P_FLAGS),
+ opt_p_flags, arg_p_flags },
+
+ /* phdr:p_align */
+ { cmd_p_align, cpl_1starg_pt, name_p_align,
+ /* MSG_INTL(MSG_DESC_P_ALIGN) */
+ ELFEDIT_I18NHDL(MSG_DESC_P_ALIGN),
+ /* MSG_INTL(MSG_HELP_P_ALIGN) */
+ ELFEDIT_I18NHDL(MSG_HELP_P_ALIGN),
+ opt_std, arg_p_align },
+
+ /* phdr:interp */
+ { cmd_interp, NULL, name_interp,
+ /* MSG_INTL(MSG_DESC_INTERP) */
+ ELFEDIT_I18NHDL(MSG_DESC_INTERP),
+ /* MSG_INTL(MSG_HELP_INTERP) */
+ ELFEDIT_I18NHDL(MSG_HELP_INTERP),
+ opt_interp, arg_interp },
+
+ /* phdr:delete */
+ { cmd_delete, cpl_1starg_pt, name_delete,
+ /* MSG_INTL(MSG_DESC_DELETE) */
+ ELFEDIT_I18NHDL(MSG_DESC_DELETE),
+ /* MSG_INTL(MSG_HELP_DELETE) */
+ ELFEDIT_I18NHDL(MSG_HELP_DELETE),
+ opt_minus_phndx, arg_delete },
+
+ /* phdr:move */
+ { cmd_move, cpl_1starg_pt, name_move,
+ /* MSG_INTL(MSG_DESC_MOVE) */
+ ELFEDIT_I18NHDL(MSG_DESC_MOVE),
+ /* MSG_INTL(MSG_HELP_MOVE) */
+ ELFEDIT_I18NHDL(MSG_HELP_MOVE),
+ opt_minus_phndx, arg_move },
+
+ { NULL }
+ };
+
+ static elfedit_module_t module = {
+ ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
+ /* MSG_INTL(MSG_MOD_DESC) */
+ ELFEDIT_I18NHDL(MSG_MOD_DESC),
+ cmds, mod_i18nhdl_to_str };
+
+ return (&module);
+}