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
* 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 */
/* Commands that do not correspond directly to a specific phdr tag */
} PHDR_CMD_T;
/*
* The following type is ued by locate_interp() to return
* information about the interpreter program header.
*/
typedef struct {
const char *str; /* Interpreter string */
} INTERP_STATE;
#ifndef _ELF64
/*
* We supply this function for the msg module
*/
const char *
{
}
#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 *
{
}
/*
* The phdr_opt_t enum specifies a bit value for every optional
* argument allowed by a command in this module.
*/
typedef enum {
/* not by name */
} 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 {
int argc; /* # of plain arguments */
const char **argv; /* Plain arguments */
int ndx_set; /* True if ndx is valid */
/* 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
{
/* Add each new option to the options mask */
/* Are the right number of plain arguments present? */
switch (cmd) {
case PHDR_CMD_T_DUMP:
if (argc > 1)
break;
case PHDR_CMD_T_P_FLAGS:
/* phdr:sh_flags allows an arbitrary number of arguments */
break;
case PHDR_CMD_T_INTERP:
if (argc > 1)
break;
case PHDR_CMD_T_DELETE:
break;
case PHDR_CMD_T_MOVE:
break;
default:
/* The remaining commands accept 2 plain arguments */
if (argc > 2)
break;
}
/*
* 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.
*/
} else {
Word i;
EC_WORD(i), conv_phdr_type(
break;
}
}
}
}
/* If there may be an arbitrary amount of output, use a pager */
if (argc == 0)
}
/*
* 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 *
{
int phndx; /* Index of PT_INTERP program header */
Word i;
interp = &local_interp;
/* Locate the PT_INTERP program header */
break;
}
}
/* If no PT_INTERP program header found, we cannot proceed */
/*
* 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.
*/
}
}
/*
* We don't expect to get here: If there is a PT_INTERP header,
* we fully expect the string to exist.
*/
/*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
{
return;
cnt = 1;
} else {
ndx = 0;
}
/*
* Pick an output style. phdr:dump is required to use the default
* style. The other commands use the current output style.
*/
/*
* 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)) {
}
return;
}
switch (cmd) {
case PHDR_CMD_T_P_TYPE:
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
} else {
}
}
return;
case PHDR_CMD_T_P_OFFSET:
return;
case PHDR_CMD_T_P_VADDR:
return;
case PHDR_CMD_T_P_PADDR:
return;
case PHDR_CMD_T_P_FILESZ:
return;
case PHDR_CMD_T_P_MEMSZ:
return;
case PHDR_CMD_T_P_FLAGS:
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
&phdr_flags_buf));
} else {
}
}
return;
case PHDR_CMD_T_P_ALIGN:
return;
case PHDR_CMD_T_INTERP:
{
switch (outstyle) {
case ELFEDIT_OUTSTYLE_DEFAULT:
break;
case ELFEDIT_OUTSTYLE_SIMPLE:
break;
case ELFEDIT_OUTSTYLE_NUM:
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
{
Word i, j;
int str_found = 0; /* True when we have new interp str */
/* Locate the PT_INTERP program header */
/*
* If the given string is the same as the existing interpreter
* string, say so and return.
*/
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.
*/
for (j = 0; j < phnum; j++) {
break;
}
}
if ((j == phnum) &&
/* .interp section found, and has room */
str_found = 1;
str_offset = 0;
/* Put new value in section */
/* Set libelf dirty bit so change is flushed */
break;
} else {
}
}
}
/*
* 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) {
/* Does string exist in the table already, or can we add it? */
}
/*
* 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.
*/
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
{
int do_autoprint = 1;
/* If this is a printing request, print and return */
return (ELFEDIT_CMDRET_NONE);
}
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:
{
0, &inv_buf1));
} else {
&inv_buf1),
}
}
break;
case PHDR_CMD_T_P_OFFSET:
{
} else {
}
}
break;
case PHDR_CMD_T_P_VADDR:
{
} else {
}
}
break;
case PHDR_CMD_T_P_PADDR:
{
} else {
}
}
break;
case PHDR_CMD_T_P_FILESZ:
{
} else {
}
}
break;
case PHDR_CMD_T_P_MEMSZ:
{
} else {
}
}
break;
case PHDR_CMD_T_P_FLAGS:
{
int i;
/* Collect the flag arguments */
p_flags |=
/* Complement the value? */
/* Perform any requested bit operations */
/* Set the value */
} else {
}
}
break;
case PHDR_CMD_T_P_ALIGN:
{
} else {
}
}
break;
case PHDR_CMD_T_INTERP:
break;
case PHDR_CMD_T_DELETE:
{
do_autoprint = 0;
}
break;
case PHDR_CMD_T_MOVE:
{
do_autoprint = 0;
cnt = 1;
} else {
}
}
break;
}
/*
* If we modified the section header array, tell libelf.
*/
if (ret == ELFEDIT_CMDRET_MOD)
/* Do autoprint */
if (do_autoprint)
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
{
int i;
for (i = 0; i < num_opt; i++)
return;
}
/*ARGSUSED*/
static void
{
/* The first argument follows the standard rules */
/* The second argument can be a PT_ value */
}
/*ARGSUSED*/
static void
{
/* The first argument follows the standard rules */
/* The second and following arguments can be an PF_ value */
}
/*
* Implementation functions for the commands
*/
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
static elfedit_cmdret_t
{
}
/*ARGSUSED*/
{
/* Multiple commands accept a standard set of options */
static elfedit_cmd_optarg_t opt_std[] = {
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
/* MSG_INTL(MSG_OPTDESC_PHNDX) */
PHDR_OPT_F_PHNDX, 0 },
{ NULL }
};
/* For commands that only accept -phndx */
static elfedit_cmd_optarg_t opt_minus_phndx[] = {
/* MSG_INTL(MSG_OPTDESC_PHNDX) */
PHDR_OPT_F_PHNDX, 0 },
{ NULL }
};
/* phdr:dump */
static const char *name_dump[] = {
};
static elfedit_cmd_optarg_t arg_dump[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
{ NULL }
};
/* phdr:p_type */
static elfedit_cmd_optarg_t arg_p_type[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
{ MSG_ORIG(MSG_STR_TYPE),
/* MSG_INTL(MSG_A2_P_TYPE_TYPE) */
{ NULL }
};
/* phdr:p_offset */
NULL };
static elfedit_cmd_optarg_t arg_p_offset[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
/* MSG_INTL(MSG_A2_P_OFFSET_VALUE) */
{ NULL }
};
/* phdr:p_vaddr */
NULL };
static elfedit_cmd_optarg_t arg_p_vaddr[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
{ MSG_ORIG(MSG_STR_ADDR),
/* MSG_INTL(MSG_A2_P_VADDR_ADDR) */
{ NULL }
};
/* phdr:p_paddr */
NULL };
static elfedit_cmd_optarg_t arg_p_paddr[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
{ MSG_ORIG(MSG_STR_ADDR),
/* MSG_INTL(MSG_A2_P_PADDR_ADDR) */
{ NULL }
};
/* phdr:p_filesz */
NULL };
static elfedit_cmd_optarg_t arg_p_filesz[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
{ MSG_ORIG(MSG_STR_SIZE),
/* MSG_INTL(MSG_A2_P_FILESZ_SIZE) */
{ NULL }
};
/* phdr:p_memsz */
NULL };
static elfedit_cmd_optarg_t arg_p_memsz[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
{ MSG_ORIG(MSG_STR_SIZE),
/* MSG_INTL(MSG_A2_P_MEMSZ_SIZE) */
{ NULL }
};
/* shdr:p_flags */
static const char *name_p_flags[] = {
static elfedit_cmd_optarg_t opt_p_flags[] = {
/* MSG_INTL(MSG_OPTDESC_PHNDX) */
PHDR_OPT_F_PHNDX, 0 },
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
{ NULL }
};
static elfedit_cmd_optarg_t arg_p_flags[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
/* MSG_INTL(MSG_A2_P_FLAGS_VALUE) */
{ NULL }
};
/* phdr:p_align */
NULL };
static elfedit_cmd_optarg_t arg_p_align[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
/* MSG_INTL(MSG_A2_P_ALIGN_ALIGN) */
{ NULL }
};
/* phdr:interp */
static elfedit_cmd_optarg_t opt_interp[] = {
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
{ NULL }
};
static elfedit_cmd_optarg_t arg_interp[] = {
/* MSG_INTL(MSG_A1_INTERP_NEWPATH) */
{ NULL }
};
/* phdr:delete */
static elfedit_cmd_optarg_t arg_delete[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
/* MSG_INTL(MSG_A2_DELETE_COUNT) */
{ NULL }
};
/* phdr:move */
static elfedit_cmd_optarg_t arg_move[] = {
/* MSG_INTL(MSG_A1_ELEMENT) */
/* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
0 },
/* MSG_INTL(MSG_A3_MOVE_COUNT) */
{ NULL }
};
static elfedit_cmd_t cmds[] = {
/* phdr:dump */
/* MSG_INTL(MSG_DESC_DUMP) */
/* MSG_INTL(MSG_HELP_DUMP) */
/* phdr:p_type */
/* MSG_INTL(MSG_DESC_P_TYPE) */
/* MSG_INTL(MSG_HELP_P_TYPE) */
opt_std, arg_p_type },
/* phdr:p_offset */
/* MSG_INTL(MSG_DESC_P_OFFSET) */
/* MSG_INTL(MSG_HELP_P_OFFSET) */
opt_std, arg_p_offset },
/* phdr:p_vaddr */
/* MSG_INTL(MSG_DESC_P_VADDR) */
/* MSG_INTL(MSG_HELP_P_VADDR) */
opt_std, arg_p_vaddr },
/* phdr:p_paddr */
/* MSG_INTL(MSG_DESC_P_PADDR) */
/* MSG_INTL(MSG_HELP_P_PADDR) */
opt_std, arg_p_paddr },
/* phdr:p_filesz */
/* MSG_INTL(MSG_DESC_P_FILESZ) */
/* MSG_INTL(MSG_HELP_P_FILESZ) */
opt_std, arg_p_filesz },
/* phdr:p_memsz */
/* MSG_INTL(MSG_DESC_P_MEMSZ) */
/* MSG_INTL(MSG_HELP_P_MEMSZ) */
opt_std, arg_p_memsz },
/* phdr:p_flags */
/* MSG_INTL(MSG_DESC_P_FLAGS) */
/* MSG_INTL(MSG_HELP_P_FLAGS) */
/* phdr:p_align */
/* MSG_INTL(MSG_DESC_P_ALIGN) */
/* MSG_INTL(MSG_HELP_P_ALIGN) */
opt_std, arg_p_align },
/* phdr:interp */
/* MSG_INTL(MSG_DESC_INTERP) */
/* MSG_INTL(MSG_HELP_INTERP) */
opt_interp, arg_interp },
/* phdr:delete */
/* MSG_INTL(MSG_DESC_DELETE) */
/* MSG_INTL(MSG_HELP_DELETE) */
/* phdr:move */
/* MSG_INTL(MSG_DESC_MOVE) */
/* MSG_INTL(MSG_HELP_MOVE) */
{ NULL }
};
static elfedit_module_t module = {
/* MSG_INTL(MSG_MOD_DESC) */
return (&module);
}