phdr.c revision d29b2c4438482eb00488be49a1f5d6835f455546
/*
* 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);
}