sym.c revision ba2be53024c0b999e74ba9adcd7d80fec5df8c57
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#define ELF_TARGET_AMD64 /* SHN_AMD64_LCOMMON */
#include <stdio.h>
#include <unistd.h>
#include <elfedit.h>
#include <strings.h>
#include <debug.h>
#include <conv.h>
#include <sym_msg.h>
#define MAXNDXSIZE 10
/*
* This module uses shared code for several of the commands.
* It is sometimes necessary to know which specific command
* is active.
*/
typedef enum {
SYM_CMD_T_DUMP = 0, /* sym:dump */
SYM_CMD_T_ST_BIND = 1, /* sym:st_bind */
SYM_CMD_T_ST_INFO = 2, /* sym:st_info */
SYM_CMD_T_ST_NAME = 3, /* sym:st_name */
SYM_CMD_T_ST_OTHER = 4, /* sym:st_other */
SYM_CMD_T_ST_SHNDX = 5, /* sym:st_shndx */
SYM_CMD_T_ST_SIZE = 6, /* sym:st_size */
SYM_CMD_T_ST_TYPE = 7, /* sym:st_type */
SYM_CMD_T_ST_VALUE = 8, /* sym:st_value */
SYM_CMD_T_ST_VISIBILITY = 9 /* sym:st_visibility */
} SYM_CMD_T;
/*
* ELFCLASS-specific definitions
*/
#ifdef _ELF64
#define MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_64
#else
#define MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_32
/*
* We supply this function for the msg module. Only one copy is needed.
*/
const char *
_sym_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 sym_opt_t enum specifies a bit value for every optional
* argument allowed by a command in this module.
*/
typedef enum {
SYM_OPT_F_XSHINDEX = 1, /* -e: Force shndx update to extended */
/* index section */
SYM_OPT_F_NAMOFFSET = 2, /* -name_offset: sym:st_name name arg */
/* is numeric offset */
/* rather than ASCII string */
SYM_OPT_F_SECSHNDX = 4, /* -secshndx: Section arg is */
/* section index, not name */
SYM_OPT_F_SECSHTYP = 8, /* -secshtyp: Section arg is */
/* section type, not name */
SYM_OPT_F_SHNAME = 16, /* -shnam name: section spec. by name */
SYM_OPT_F_SHNDX = 32, /* -shndx ndx: section spec. by index */
SYM_OPT_F_SHTYP = 64, /* -shtyp type: section spec. by type */
SYM_OPT_F_SYMNDX = 128 /* -symndx: Sym specified by index */
} sym_opt_t;
/*
* A variable of type ARGSTATE is used by each command to maintain
* the overall state for a given set of arguments and the symbol tables
* being managed.
*
* The state for each symbol table and the auxiliary sections that are
* related to it are kept in a SYMSTATE sub-struct.
*
* One benefit of ARGSTATE is that it helps us to ensure that we only
* fetch each section a single time:
* - More efficient
* - Prevents multiple ELFEDIT_MSG_DEBUG messages from
* being produced for a given section.
*
* note: The symstate array in ARGSTATE is defined as having one
* element, but in reality, we allocate enough room for
* the number of elements defined in the numsymstate field.
*/
typedef struct {
Word ndx; /* If argstate.argc > 0, this is the table index */
struct { /* Symbol table */
elfedit_section_t *sec;
Sym *data;
Word n;
} sym;
struct { /* String table */
elfedit_section_t *sec;
} str;
struct { /* Versym */
Word shndx;
elfedit_section_t *sec;
Versym *data;
Word n;
} versym;
struct { /* Extended section indices */
Word shndx;
elfedit_section_t *sec;
Word *data;
Word n;
} xshndx;
} SYMSTATE;
typedef struct {
elfedit_obj_state_t *obj_state;
sym_opt_t optmask; /* Mask of options used */
int argc; /* # of plain arguments */
const char **argv; /* Plain arguments */
int numsymstate; /* # of items in symstate[] */
SYMSTATE symstate[1]; /* Symbol tables to process */
} ARGSTATE;
/*
* We maintain the state of each symbol table and related associated
* sections in a SYMSTATE structure . We don't look those auxiliary
* things up unless we actually need them, both to be efficient,
* and to prevent duplicate ELFEDIT_MSG_DEBUG messages from being
* issued as they are located. Hence, process_args() is used to
* initialize the state block with just the symbol table, and then one
* of the argstate_add_XXX() functions is used as needed
* to fetch the additional sections.
*
* entry:
* argstate - Overall state block
* symstate - State block for current symbol table.
*
* exit:
* If the needed auxiliary section is not found, an error is
* issued and the argstate_add_XXX() routine does not return.
* Otherwise, the fields in argstate have been filled in, ready
* for use.
*
*/
static void
symstate_add_str(ARGSTATE *argstate, SYMSTATE *symstate)
{
if (symstate->str.sec != NULL)
return;
symstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
symstate->sym.sec->sec_shdr->sh_link);
}
static void
symstate_add_versym(ARGSTATE *argstate, SYMSTATE *symstate)
{
if (symstate->versym.sec != NULL)
return;
symstate->versym.sec = elfedit_sec_getversym(argstate->obj_state,
symstate->sym.sec, &symstate->versym.data, &symstate->versym.n);
}
static void
symstate_add_xshndx(ARGSTATE *argstate, SYMSTATE *symstate)
{
if (symstate->xshndx.sec != NULL)
return;
symstate->xshndx.sec = elfedit_sec_getxshndx(argstate->obj_state,
symstate->sym.sec, &symstate->xshndx.data, &symstate->xshndx.n);
}
/*
* Display symbol table entries in the style used by elfdump.
*
* entry:
* argstate - Overall state block
* symstate - State block for current symbol table.
* ndx - Index of first symbol to display
* cnt - Number of symbols to display
*/
static void
dump_symtab(ARGSTATE *argstate, SYMSTATE *symstate, Word ndx, Word cnt)
{
char index[MAXNDXSIZE];
Word shndx;
const char *shndx_name;
elfedit_section_t *symsec;
elfedit_section_t *strsec;
Sym *sym;
elfedit_obj_state_t *obj_state = argstate->obj_state;
Half mach = obj_state->os_ehdr->e_machine;
const char *symname;
Versym versym;
symsec = symstate->sym.sec;
sym = symstate->sym.data + ndx;
symstate_add_str(argstate, symstate);
strsec = symstate->str.sec;
/* If there is a versym index section, fetch it */
if (symstate->versym.shndx != SHN_UNDEF)
symstate_add_versym(argstate, symstate);
/* If there is an extended index section, fetch it */
if (symstate->xshndx.shndx != SHN_UNDEF)
symstate_add_xshndx(argstate, symstate);
elfedit_printf(MSG_INTL(MSG_FMT_SYMTAB), symsec->sec_name);
Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
for (; cnt-- > 0; ndx++, sym++) {
(void) snprintf(index, MAXNDXSIZE,
MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx));
versym = (symstate->versym.sec == NULL) ? 0 :
symstate->versym.data[ndx];
symname = elfedit_offset_to_str(strsec, sym->st_name,
ELFEDIT_MSG_DEBUG, 0);
shndx = sym->st_shndx;
if ((shndx == SHN_XINDEX) && (symstate->xshndx.sec != NULL))
shndx = symstate->xshndx.data[ndx];
shndx_name = elfedit_shndx_to_name(obj_state, shndx);
Elf_syms_table_entry(NULL, ELF_DBG_ELFDUMP, index, mach,
sym, versym, 0, shndx_name, symname);
}
}
/*
* Called by print_sym() to determine if a given symbol has the same
* display value for the current command in every symbol table.
*
* entry:
* cmd - SYM_CMD_T_* value giving identify of caller
* argstate - Overall state block
* outstyle - Output style to use
*/
static int
all_same(SYM_CMD_T cmd, ARGSTATE *argstate, elfedit_outstyle_t outstyle)
{
Word tblndx;
SYMSTATE *symstate1, *symstate2;
Sym *sym1, *sym2;
symstate1 = argstate->symstate;
for (tblndx = 0; tblndx < (argstate->numsymstate - 1);
tblndx++, symstate1++) {
symstate2 = symstate1 + 1;
sym1 = &symstate1->sym.data[symstate1->ndx];
sym2 = &symstate2->sym.data[symstate2->ndx];
switch (cmd) {
case SYM_CMD_T_DUMP:
/* sym:dump should always show everything */
return (0);
case SYM_CMD_T_ST_BIND:
if (ELF_ST_BIND(sym1->st_info) !=
ELF_ST_BIND(sym2->st_info))
return (0);
break;
case SYM_CMD_T_ST_INFO:
if (sym1->st_info != sym2->st_info)
return (0);
break;
case SYM_CMD_T_ST_NAME:
/*
* In simple output mode, we show the string. In
* numeric mode, we show the string table offset.
*/
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
const char *n1, *n2;
symstate_add_str(argstate, symstate1);
symstate_add_str(argstate, symstate2);
n1 = elfedit_offset_to_str(symstate1->str.sec,
sym1->st_name, ELFEDIT_MSG_DEBUG, 0);
n2 = elfedit_offset_to_str(symstate2->str.sec,
sym2->st_name, ELFEDIT_MSG_DEBUG, 0);
if (strcmp(n1, n2) != 0)
return (0);
} else {
if (sym1->st_name != sym2->st_name)
return (0);
}
break;
case SYM_CMD_T_ST_OTHER:
if (sym1->st_other != sym2->st_other)
return (0);
break;
case SYM_CMD_T_ST_SHNDX:
{
Word ndx1, ndx2;
ndx1 = sym1->st_shndx;
if ((ndx1 == SHN_XINDEX) &&
(symstate1->xshndx.shndx != SHN_UNDEF)) {
symstate_add_xshndx(argstate,
symstate1);
ndx1 = symstate1->xshndx.
data[symstate1->ndx];
}
ndx2 = sym2->st_shndx;
if ((ndx2 == SHN_XINDEX) &&
(symstate2->xshndx.shndx != SHN_UNDEF)) {
symstate_add_xshndx(argstate,
symstate2);
ndx2 = symstate2->xshndx.
data[symstate2->ndx];
}
if (ndx1 != ndx2)
return (0);
}
break;
case SYM_CMD_T_ST_SIZE:
if (sym1->st_size != sym2->st_size)
return (0);
break;
case SYM_CMD_T_ST_TYPE:
if (ELF_ST_TYPE(sym1->st_info) !=
ELF_ST_TYPE(sym2->st_info))
return (0);
break;
case SYM_CMD_T_ST_VALUE:
if (sym1->st_value != sym2->st_value)
return (0);
break;
case SYM_CMD_T_ST_VISIBILITY:
if (ELF_ST_VISIBILITY(sym1->st_info) !=
ELF_ST_VISIBILITY(sym2->st_info))
return (0);
break;
}
}
/* If we got here, there are no differences (or maybe only 1 table */
return (1);
}
/*
* Called by print_sym() to display values for a single symbol table.
*
* entry:
* autoprint - If True, output is only produced if the elfedit
* autoprint flag is set. If False, output is always produced.
* cmd - SYM_CMD_T_* value giving identify of caller
* argstate - Overall state block
* symstate - State block for current symbol table.
* ndx - Index of first symbol to display
* cnt - Number of symbols to display
*/
static void
print_symstate(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate,
elfedit_outstyle_t outstyle, Word ndx, Word cnt)
{
Word value;
Sym *sym;
/*
* If doing default output, use elfdump style where we
* show all symbol attributes. In this case, the command
* that called us doesn't matter
*/
if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
dump_symtab(argstate, symstate, ndx, cnt);
return;
}
sym = symstate->sym.data;
switch (cmd) {
case SYM_CMD_T_ST_BIND:
{
Conv_inv_buf_t inv_buf;
for (sym += ndx; cnt--; sym++) {
value = ELF_ST_BIND(sym->st_info);
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
conv_sym_info_bind(value,
CONV_FMT_ALT_FULLNAME, &inv_buf));
} else {
elfedit_printf(
MSG_ORIG(MSG_FMT_WORDVALNL),
EC_WORD(value));
}
}
}
return;
case SYM_CMD_T_ST_INFO:
for (sym += ndx; cnt-- > 0; sym++)
elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
EC_WORD(sym->st_info));
return;
case SYM_CMD_T_ST_NAME:
/*
* In simple output mode, we show the string. In numeric
* mode, we show the string table offset.
*/
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
symstate_add_str(argstate, symstate);
for (sym += ndx; cnt--; sym++) {
elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
elfedit_offset_to_str(symstate->str.sec,
sym->st_name, ELFEDIT_MSG_ERR, 0));
}
} else {
for (; cnt--; sym++)
elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
EC_WORD(sym->st_name));
}
return;
case SYM_CMD_T_ST_OTHER:
for (sym += ndx; cnt-- > 0; sym++)
elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
EC_WORD(sym->st_other));
return;
case SYM_CMD_T_ST_SHNDX:
/* If there is an extended index section, fetch it */
if (symstate->xshndx.shndx != SHN_UNDEF)
symstate_add_xshndx(argstate, symstate);
for (; cnt--; ndx++) {
value = sym[ndx].st_shndx;
if ((value == SHN_XINDEX) &&
(symstate->xshndx.sec != NULL))
value = symstate->xshndx.data[ndx];
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
elfedit_shndx_to_name(argstate->obj_state,
value));
} else {
elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
EC_WORD(value));
}
}
return;
case SYM_CMD_T_ST_SIZE:
/*
* machine word width integers displayed in fixed width
* 0-filled hex format.
*/
for (sym += ndx; cnt--; sym++)
elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL),
sym->st_size);
return;
case SYM_CMD_T_ST_TYPE:
{
Half mach = argstate->obj_state->os_ehdr->e_machine;
Conv_inv_buf_t inv_buf;
for (sym += ndx; cnt--; sym++) {
value = ELF_ST_TYPE(sym->st_info);
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
conv_sym_info_type(mach, value,
CONV_FMT_ALT_FULLNAME, &inv_buf));
} else {
elfedit_printf(
MSG_ORIG(MSG_FMT_WORDVALNL),
EC_WORD(value));
}
}
}
return;
case SYM_CMD_T_ST_VALUE:
/*
* machine word width integers displayed in fixed width
* 0-filled hex format.
*/
for (sym += ndx; cnt--; sym++)
elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL),
sym->st_value);
return;
case SYM_CMD_T_ST_VISIBILITY:
{
Conv_inv_buf_t inv_buf;
for (sym += ndx; cnt--; sym++) {
value = ELF_ST_VISIBILITY(sym->st_other);
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
conv_sym_other_vis(value,
CONV_FMT_ALT_FULLNAME, &inv_buf));
} else {
elfedit_printf(
MSG_ORIG(MSG_FMT_WORDVALNL),
EC_WORD(value));
}
}
}
return;
}
}
/*
* Print symbol 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 - SYM_CMD_T_* value giving identify of caller
* argstate - Overall state block
* symstate - State block for current symbol table.
* ndx - Index of first symbol to display
* cnt - Number of symbols to display
*/
static void
print_sym(SYM_CMD_T cmd, int autoprint, ARGSTATE *argstate)
{
Word ndx, tblndx;
Word cnt;
elfedit_outstyle_t outstyle;
SYMSTATE *symstate;
int only_one;
if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)))
return;
/*
* Pick an output style. sym:dump is required to use the default
* style. The other commands use the current output style.
*/
outstyle = (cmd == SYM_CMD_T_DUMP) ?
ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
/*
* This is a nicity: Force any needed auxiliary sections to be
* fetched here before any output is produced. This will put all
* of the debug messages right at the top in a single cluster.
*/
symstate = argstate->symstate;
for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) {
if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
symstate_add_str(argstate, symstate);
if (symstate->versym.shndx != SHN_UNDEF)
symstate_add_versym(argstate, symstate);
if (symstate->xshndx.shndx != SHN_UNDEF)
symstate_add_xshndx(argstate, symstate);
continue;
}
if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
switch (cmd) {
case SYM_CMD_T_ST_NAME:
symstate_add_str(argstate, symstate);
break;
case SYM_CMD_T_ST_SHNDX:
if (symstate->xshndx.shndx != SHN_UNDEF)
symstate_add_xshndx(argstate, symstate);
break;
}
}
}
/*
* If there is more than one table, we are displaying a single
* item, we are not using the default "elfdump" style, and all
* the symbols have the same value for the thing we intend to
* display, then we only want to display it once.
*/
only_one = (argstate->numsymstate > 1) && (argstate->argc > 0) &&
(outstyle != ELFEDIT_OUTSTYLE_DEFAULT) &&
all_same(cmd, argstate, outstyle);
/* Run through the tables and display from each one */
symstate = argstate->symstate;
for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) {
if (argstate->argc == 0) {
ndx = 0;
cnt = symstate->sym.n;
} else {
ndx = symstate->ndx;
cnt = 1;
}
if ((tblndx > 0) && ((argstate->argc == 0) ||
(outstyle == ELFEDIT_OUTSTYLE_DEFAULT)))
elfedit_printf(MSG_ORIG(MSG_STR_NL));
print_symstate(cmd, argstate, symstate, outstyle, ndx, cnt);
if (only_one)
break;
}
}
/*
* The cmd_body_set_st_XXX() functions are for use by cmd_body().
* They handle the case where the second plain argument is
* a value to be stored in the symbol.
*
* entry:
* argstate - Overall state block
* symstate - State block for current symbol table.
*/
static elfedit_cmdret_t
cmd_body_set_st_bind(ARGSTATE *argstate, SYMSTATE *symstate)
{
elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
Sym *sym = &symstate->sym.data[symstate->ndx];
Word gbl_ndx;
uchar_t bind, type, old_bind;
Word symndx;
Conv_inv_buf_t inv_buf1, inv_buf2;
/*
* Use the ELF_ST_BIND() macro to access the defined bits
* of the st_info field related to symbol binding.
* Accepts STB_ symbolic names as well as integers.
*/
bind = elfedit_atoconst_range(argstate->argv[1],
MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STB);
old_bind = ELF_ST_BIND(sym->st_info);
type = ELF_ST_TYPE(sym->st_info);
if (old_bind == bind) {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND),
conv_sym_info_bind(bind, CONV_FMT_ALT_FULLNAME, &inv_buf1));
} else {
/*
* The sh_info field of the symbol table section header
* gives the index of the first non-local symbol in
* the table. Issue warnings if the binding we set
* contradicts this.
*/
gbl_ndx = symstate->sym.sec->sec_shdr->sh_info;
symndx = symstate->sym.sec->sec_shndx;
if ((bind == STB_LOCAL) && (symstate->ndx >= gbl_ndx))
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_LBINDGSYM),
EC_WORD(symndx), symstate->sym.sec->sec_name,
symstate->ndx, EC_WORD(symndx), gbl_ndx);
if ((bind != STB_LOCAL) && (symstate->ndx < gbl_ndx))
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_GBINDLSYM),
EC_WORD(symndx), symstate->sym.sec->sec_name,
symstate->ndx, EC_WORD(symndx), gbl_ndx);
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND),
conv_sym_info_bind(old_bind, CONV_FMT_ALT_FULLNAME,
&inv_buf1),
conv_sym_info_bind(bind, CONV_FMT_ALT_FULLNAME, &inv_buf2));
ret = ELFEDIT_CMDRET_MOD;
sym->st_info = ELF_ST_INFO(bind, type);
}
return (ret);
}
static elfedit_cmdret_t
cmd_body_set_st_name(ARGSTATE *argstate, SYMSTATE *symstate)
{
elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
Sym *sym = &symstate->sym.data[symstate->ndx];
Word str_offset;
/*
* If -n was specified, this is an offset into the string
* table. Otherwise it is a string we need to turn into
* an offset
*/
symstate_add_str(argstate, symstate);
if (argstate->optmask & SYM_OPT_F_NAMOFFSET) {
str_offset = elfedit_atoui(argstate->argv[1], NULL);
/* Warn if the offset is out of range */
(void) elfedit_offset_to_str(symstate->str.sec,
str_offset, ELFEDIT_MSG_DEBUG, 1);
} else {
str_offset = elfedit_strtab_insert(argstate->obj_state,
symstate->str.sec, NULL, argstate->argv[1]);
}
if (sym->st_name == str_offset) {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_OK),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME),
EC_WORD(sym->st_name));
} else {
/*
* Warn the user: Changing the name of a symbol in the dynsym
* will break the hash table in this object.
*/
if (symstate->sym.sec->sec_shdr->sh_type == SHT_DYNSYM)
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_DYNSYMNAMCHG),
EC_WORD(symstate->sym.sec->sec_shndx),
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx));
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_CHG),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME),
EC_WORD(sym->st_name),
EC_WORD(str_offset));
ret = ELFEDIT_CMDRET_MOD;
sym->st_name = str_offset;
}
return (ret);
}
static elfedit_cmdret_t
cmd_body_set_st_shndx(ARGSTATE *argstate, SYMSTATE *symstate)
{
elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
Sym *sym = &symstate->sym.data[symstate->ndx];
Word shndx, st_shndx, xshndx;
int use_xshndx;
int shndx_chg, xshndx_chg;
/*
* By default, the sec argument is a section name. If -secshndx was
* specified, it is a section index, and if -secshtyp is specified,
* it is a section type.
*/
if (argstate->optmask & SYM_OPT_F_SECSHNDX)
shndx = elfedit_atoshndx(argstate->argv[1],
argstate->obj_state->os_shnum);
else if (argstate->optmask & SYM_OPT_F_SECSHTYP)
shndx = elfedit_type_to_shndx(argstate->obj_state,
elfedit_atoconst(argstate->argv[1], ELFEDIT_CONST_SHT));
else
shndx = elfedit_name_to_shndx(argstate->obj_state,
argstate->argv[1]);
/*
* We want to use an extended index section if the index is too
* large to be represented otherwise, or if the caller specified
* the -e option to make us do it anyway. However, we cannot
* do this if the index is in the special reserved range between
* SHN_LORESERVE and SHN_HIRESERVE.
*/
use_xshndx = (shndx > SHN_HIRESERVE) ||
((shndx < SHN_LORESERVE) &&
(argstate->optmask & SYM_OPT_F_XSHINDEX));
/*
* There are two cases where we have to touch the extended
* index section:
*
* 1) We have determined that we need to, as determined above.
* 2) We do not require it, but the file has an extended
* index section, in which case we should set the slot
* in that extended section to SHN_UNDEF (0).
*
* Fetch the extended section as required, and determine the values
* for st_shndx and the extended section slot.
*/
if (use_xshndx) {
/* We must have an extended index section, or error out */
symstate_add_xshndx(argstate, symstate);
/* Set symbol to SHN_XINDEX, put index in the extended sec. */
st_shndx = SHN_XINDEX;
xshndx = shndx;
} else {
st_shndx = shndx;
xshndx = SHN_UNDEF;
if (symstate->xshndx.shndx != SHN_UNDEF)
use_xshndx = 1;
}
if (use_xshndx)
symstate_add_xshndx(argstate, symstate);
shndx_chg = (sym->st_shndx != st_shndx);
xshndx_chg = use_xshndx &&
(symstate->xshndx.data[symstate->ndx] != xshndx);
/* If anything is going to change, issue appropiate warnings */
if (shndx_chg || xshndx_chg) {
/*
* Setting the first symbol to anything other than SHN_UNDEF
* produces a bad ELF file.
*/
if ((symstate->ndx == 0) && (shndx != SHN_UNDEF))
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_SHNDX_UNDEF0));
/*
* Setting SHN_XINDEX directly, instead of providing
* an extended index and letting us decide to use
* SHN_XINDEX to implement it, is probably a mistake.
* Issue a warning, but go ahead and follow the directions
* we've been given.
*/
if (shndx == SHN_XINDEX)
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_SHNDX_XINDEX));
/*
* If the section index can fit in the symbol, but
* -e is being used to force it into the extended
* index section, issue a warning.
*/
if (use_xshndx && (shndx < SHN_LORESERVE) &&
(st_shndx == SHN_XINDEX))
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_SHNDX_EFORCE),
EC_WORD(symstate->sym.sec->sec_shndx),
symstate->sym.sec->sec_name, EC_WORD(symstate->ndx),
EC_WORD(shndx));
}
if (shndx_chg) {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX),
elfedit_shndx_to_name(argstate->obj_state,
sym->st_shndx),
elfedit_shndx_to_name(argstate->obj_state, st_shndx));
ret = ELFEDIT_CMDRET_MOD;
sym->st_shndx = st_shndx;
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX),
elfedit_shndx_to_name(argstate->obj_state, st_shndx));
}
if (use_xshndx) {
if (xshndx_chg) {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_EXT_S_CHG),
symstate->xshndx.sec->sec_shndx,
symstate->xshndx.sec->sec_name,
EC_WORD(symstate->ndx),
elfedit_shndx_to_name(argstate->obj_state,
symstate->xshndx.data[symstate->ndx]),
elfedit_shndx_to_name(argstate->obj_state, xshndx));
ret = ELFEDIT_CMDRET_MOD;
symstate->xshndx.data[symstate->ndx] = xshndx;
elfedit_modified_data(symstate->xshndx.sec);
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_EXT_S_OK),
symstate->xshndx.sec->sec_shndx,
symstate->xshndx.sec->sec_name,
EC_WORD(symstate->ndx),
elfedit_shndx_to_name(argstate->obj_state, xshndx));
}
}
return (ret);
}
static elfedit_cmdret_t
cmd_body_set_st_type(ARGSTATE *argstate, SYMSTATE *symstate)
{
elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
Conv_inv_buf_t inv_buf1, inv_buf2;
Half mach = argstate->obj_state->os_ehdr->e_machine;
Sym *sym = &symstate->sym.data[symstate->ndx];
uchar_t bind, type, old_type;
/*
* Use the ELF_ST_TYPE() macro to access the defined bits
* of the st_info field related to symbol type.
* Accepts STT_ symbolic names as well as integers.
*/
bind = ELF_ST_BIND(sym->st_info);
type = elfedit_atoconst_range(argstate->argv[1],
MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STT);
old_type = ELF_ST_TYPE(sym->st_info);
if (old_type == type) {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE),
conv_sym_info_type(mach, type, CONV_FMT_ALT_FULLNAME,
&inv_buf1));
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE),
conv_sym_info_type(mach, old_type, CONV_FMT_ALT_FULLNAME,
&inv_buf1),
conv_sym_info_type(mach, type, CONV_FMT_ALT_FULLNAME,
&inv_buf2));
ret = ELFEDIT_CMDRET_MOD;
sym->st_info = ELF_ST_INFO(bind, type);
}
return (ret);
}
static elfedit_cmdret_t
cmd_body_set_st_visibility(ARGSTATE *argstate, SYMSTATE *symstate)
{
elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
Conv_inv_buf_t inv_buf1, inv_buf2;
Sym *sym = &symstate->sym.data[symstate->ndx];
uchar_t st_other = sym->st_other;
uchar_t vis, old_vis;
/*
* Use the ELF_ST_VISIBILITY() macro to access the
* defined bits of the st_other field related to symbol
* visibility. Accepts STV_ symbolic names as well as integers.
*/
vis = elfedit_atoconst_range(argstate->argv[1],
MSG_INTL(MSG_ARG_SYMVIS), 0, STV_ELIMINATE, ELFEDIT_CONST_STV);
old_vis = st_other & MSK_SYM_VISIBILITY;
if (old_vis == vis) {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY),
conv_sym_other_vis(old_vis, CONV_FMT_ALT_FULLNAME,
&inv_buf1));
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY),
conv_sym_other_vis(old_vis, CONV_FMT_ALT_FULLNAME,
&inv_buf1),
conv_sym_other_vis(vis, CONV_FMT_ALT_FULLNAME, &inv_buf2));
ret = ELFEDIT_CMDRET_MOD;
st_other = (st_other & ~MSK_SYM_VISIBILITY) |
ELF_ST_VISIBILITY(vis);
sym->st_other = st_other;
}
return (ret);
}
/*
* Standard argument processing for sym module
*
* entry
* obj_state, argc, argv - Standard command arguments
* optmask - Mask of allowed optional arguments.
* symstate - State block for current symbol table.
* 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.
*
* note:
* Only the basic symbol table is initially referenced by
* argstate. Use the argstate_add_XXX() routines below to
* access any auxiliary sections needed.
*/
static ARGSTATE *
process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
SYM_CMD_T cmd)
{
/*
* We reuse this same argstate, resizing it to the required
* number of symbol tables on the first call, and as necessary.
*/
static ARGSTATE *argstate;
static int argstate_size = 0;
elfedit_getopt_state_t getopt_state;
elfedit_getopt_ret_t *getopt_ret;
elfedit_symtab_t *symtab;
int explicit = 0;
int got_sym = 0;
Word index;
Word tblndx;
size_t size;
SYMSTATE *symstate;
/* If there are no symbol tables, we can't do a thing */
if (obj_state->os_symtabnum == 0)
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB));
/* Calulate required size of argstate and realloc as necessary */
size = sizeof (ARGSTATE) +
((obj_state->os_symtabnum - 1) * sizeof (SYMSTATE));
if (argstate_size != size) {
argstate = elfedit_realloc(MSG_INTL(MSG_ALLOC_ARGSTATE),
argstate, size);
argstate_size = size;
}
bzero(argstate, argstate_size);
argstate->obj_state = obj_state;
elfedit_getopt_init(&getopt_state, &argc, &argv);
while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
argstate->optmask |= getopt_ret->gor_idmask;
switch (getopt_ret->gor_idmask) {
case SYM_OPT_F_SHNAME: /* -shnam name */
index = elfedit_name_to_shndx(obj_state,
getopt_ret->gor_value);
explicit = 1;
break;
case SYM_OPT_F_SHNDX: /* -shndx index */
index = elfedit_atoui_range(getopt_ret->gor_value,
MSG_INTL(MSG_ARG_SECNDX), 1,
obj_state->os_shnum - 1, NULL);
explicit = 1;
break;
case SYM_OPT_F_SHTYP: /* -shtyp type */
index = elfedit_type_to_shndx(obj_state,
elfedit_atoconst(getopt_ret->gor_value,
ELFEDIT_CONST_SHT));
explicit = 1;
break;
}
}
/*
* Usage error if there are too many plain arguments. sym:dump accepts
* a single argument, while the others accept 2.
*/
if (((cmd == SYM_CMD_T_DUMP) && (argc > 1)) || (argc > 2))
elfedit_command_usage();
/*
* If the -symndx option was specified, the sym arg is an index
* into the symbol table. In this case, the symbol table must be
* explicitly specified (-shnam, -shndx, or -shtype).
*/
if ((argstate->optmask & SYM_OPT_F_SYMNDX) && !explicit)
elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NEEDEXPSYMTAB));
/*
* If a section was explicitly specified, it needs
* be a symbol table.
*/
if (explicit)
(void) elfedit_sec_issymtab(&obj_state->os_secarr[index],
1, NULL);
/* If there may be an arbitrary amount of output, use a pager */
if (argc == 0)
elfedit_pager_init();
/* Return the updated values of argc/argv */
argstate->argc = argc;
argstate->argv = argv;
/*
* Decide which symbol table(s) to use. Set up the symstate
* array to contain them:
* - If a symbol table was explicitly specified, we use
* it, and only it.
* - If no symbol table is explicitly specified, and the symbol
* is given by name, we use all symbol tables that
* contain a symbol with that name, throwing an error
* if there isn't at least 1 such table.
* - If no symbol table is specified, and no symbol is specified,
* we use all the tables.
*/
symtab = obj_state->os_symtab;
symstate = argstate->symstate;
for (tblndx = 0; tblndx < obj_state->os_symtabnum;
tblndx++, symtab++) {
/* If explicit table specified, only that table is considered */
if (explicit && (symtab->symt_shndx != index))
continue;
symstate->sym.sec = elfedit_sec_getsymtab(obj_state, 1,
symtab->symt_shndx, NULL, &symstate->sym.data,
&symstate->sym.n, &symtab);
symstate->versym.shndx = symtab->symt_versym;
symstate->xshndx.shndx = symtab->symt_xshndx;
if (argc > 0) {
if (argstate->optmask & SYM_OPT_F_SYMNDX) {
symstate->ndx = elfedit_atoui_range(
argstate->argv[0], MSG_INTL(MSG_ARG_SYM), 0,
symstate->sym.n - 1, NULL);
} else {
/*
* arg is a symbol name. Use the index of
* the first symbol that matches
*/
/*
* We will use debug messages for failure up
* until we run out of symbol tables. If we
* don't find a table with the desired symbol
* before the last table, we switch to error
* messages. Hence, we will jump with an error
* if no table will work.
*/
int err_type = (!got_sym &&
((tblndx + 1) == obj_state->os_symtabnum)) ?
ELFEDIT_MSG_ERR : ELFEDIT_MSG_DEBUG;
symstate_add_str(argstate, symstate);
/*
* If the symbol table doesn't have this
* symbol, then forget it.
*/
if (elfedit_name_to_symndx(symstate->sym.sec,
symstate->str.sec, argstate->argv[0],
err_type, &symstate->ndx) == 0) {
bzero(symstate, sizeof (*symstate));
continue;
}
}
}
argstate->numsymstate++;
symstate++;
/*
* If the symbol table was given explicitly, and
* we've just taken it, then there is no reason to
* continue searching.
*/
if (explicit)
break;
}
return (argstate);
}
/*
* Called by cmd_body() to handle the value change for a single
* symbol table.
*
* entry:
* cmd - One of the SYM_CMD_T_* constants listed above, specifying
* which command to implement.
* argstate - Overall state block
* symstate - State block for current symbol table.
*/
static elfedit_cmdret_t
symstate_cmd_body(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate)
{
elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
Sym *sym = &symstate->sym.data[symstate->ndx];
/* You're not supposed to change the value of symbol [0] */
if (symstate->ndx == 0)
elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMELT0),
EC_WORD(symstate->sym.sec->sec_shndx),
symstate->sym.sec->sec_name, EC_WORD(symstate->ndx));
/* The second value is an integer giving a new value */
switch (cmd) {
/*
* SYM_CMD_T_DUMP can't get here: It never has more than
* one argument, and is handled above.
*/
case SYM_CMD_T_ST_BIND:
ret = cmd_body_set_st_bind(argstate, symstate);
break;
case SYM_CMD_T_ST_INFO:
{
/* Treat st_info as a raw integer field */
uchar_t st_info =
elfedit_atoui(argstate->argv[1], NULL);
if (sym->st_info == st_info) {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_D_OK),
symstate->sym.sec->sec_shndx,
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx),
MSG_ORIG(MSG_CMD_ST_INFO),
EC_WORD(sym->st_info));
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_D_CHG),
symstate->sym.sec->sec_shndx,
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx),
MSG_ORIG(MSG_CMD_ST_INFO),
EC_WORD(sym->st_info), EC_WORD(st_info));
ret = ELFEDIT_CMDRET_MOD;
sym->st_info = st_info;
}
}
break;
case SYM_CMD_T_ST_NAME:
ret = cmd_body_set_st_name(argstate, symstate);
break;
case SYM_CMD_T_ST_OTHER:
{
/* Treat st_other as a raw integer field */
uchar_t st_other =
elfedit_atoui(argstate->argv[1], NULL);
if (sym->st_other == st_other) {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_D_OK),
symstate->sym.sec->sec_shndx,
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx),
MSG_ORIG(MSG_CMD_ST_OTHER),
EC_WORD(sym->st_other));
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_D_CHG),
symstate->sym.sec->sec_shndx,
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx),
MSG_ORIG(MSG_CMD_ST_OTHER),
EC_WORD(sym->st_other), EC_WORD(st_other));
ret = ELFEDIT_CMDRET_MOD;
sym->st_other = st_other;
}
}
break;
case SYM_CMD_T_ST_SHNDX:
ret = cmd_body_set_st_shndx(argstate, symstate);
break;
case SYM_CMD_T_ST_SIZE:
{
Xword st_size = elfedit_atoui(argstate->argv[1], NULL);
if (sym->st_size == st_size) {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_LLX_OK),
symstate->sym.sec->sec_shndx,
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx),
MSG_ORIG(MSG_CMD_ST_SIZE),
EC_XWORD(sym->st_size));
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_LLX_CHG),
symstate->sym.sec->sec_shndx,
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx),
MSG_ORIG(MSG_CMD_ST_SIZE),
EC_XWORD(sym->st_size), EC_XWORD(st_size));
ret = ELFEDIT_CMDRET_MOD;
sym->st_size = st_size;
}
}
break;
case SYM_CMD_T_ST_TYPE:
ret = cmd_body_set_st_type(argstate, symstate);
break;
case SYM_CMD_T_ST_VALUE:
{
Addr st_value = elfedit_atoui(argstate->argv[1], NULL);
if (sym->st_value == st_value) {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_LLX_OK),
symstate->sym.sec->sec_shndx,
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx),
MSG_ORIG(MSG_CMD_ST_VALUE),
EC_ADDR(sym->st_value));
} else {
elfedit_msg(ELFEDIT_MSG_DEBUG,
MSG_INTL(MSG_DEBUG_LLX_CHG),
symstate->sym.sec->sec_shndx,
symstate->sym.sec->sec_name,
EC_WORD(symstate->ndx),
MSG_ORIG(MSG_CMD_ST_VALUE),
EC_ADDR(sym->st_value),
EC_ADDR(st_value));
ret = ELFEDIT_CMDRET_MOD;
ret = ELFEDIT_CMDRET_MOD;
sym->st_value = st_value;
}
}
break;
case SYM_CMD_T_ST_VISIBILITY:
ret = cmd_body_set_st_visibility(argstate, symstate);
break;
}
/*
* If we modified the symbol table, tell libelf.
* Any other modified sections are the responsibility
* of the cmd_body_set_st_*() function that did it, but
* everyone modifies the table itself, so we handle that here.
*/
if (ret == ELFEDIT_CMDRET_MOD)
elfedit_modified_data(symstate->sym.sec);
return (ret);
}
/*
* Common body for the sym: 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 SYM_CMD_T_* constants listed above, specifying
* which command to implement.
* obj_state, argc, argv - Standard command arguments
*/
static elfedit_cmdret_t
cmd_body(SYM_CMD_T cmd, elfedit_obj_state_t *obj_state,
int argc, const char *argv[])
{
elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
ARGSTATE *argstate;
SYMSTATE *symstate;
Word tblndx;
argstate = process_args(obj_state, argc, argv, cmd);
/*
* If there are not 2 arguments, then this is a display request.
* If no arguments are present, the full table (or tables) is
* dumped. If there is one argument, then the specified item is shown.
*/
if (argstate->argc < 2) {
print_sym(cmd, 0, argstate);
return (ELFEDIT_CMDRET_NONE);
}
/*
* When processing multiple symbol tables, it is important that
* any failure happen before anything is changed. Otherwise, you
* can end up in a situation where things are left in an inconsistent
* half done state. sym:st_name has that issue when the -name_offset
* option is used, because the string may be insertable into some
* (dynstr) string tables, but not all of them. So, do the tests
* up front, and refuse to continue if any string insertions would
* fail.
*/
if ((cmd == SYM_CMD_T_ST_NAME) && (argstate->numsymstate > 1) &&
((argstate->optmask & SYM_OPT_F_NAMOFFSET) == 0)) {
symstate = argstate->symstate;
for (tblndx = 0; tblndx < argstate->numsymstate;
tblndx++, symstate++)
elfedit_strtab_insert_test(obj_state, symstate->str.sec,
NULL, argstate->argv[1]);
}
/* Loop over the table(s) and make the specified value change */
symstate = argstate->symstate;
for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++)
if (symstate_cmd_body(cmd, argstate, symstate) ==
ELFEDIT_CMDRET_MOD)
ret = ELFEDIT_CMDRET_MOD;
/* Do autoprint */
print_sym(cmd, 1, argstate);
return (ret);
}
/*
* Command completion functions for the various commands
*/
/*
* Handle filling in the values for -shnam, -shndx, and -shtyp options.
*/
/*ARGSUSED*/
static void
cpl_sh_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
const char *argv[], int num_opt)
{
enum { NAME, INDEX, TYPE } op;
elfedit_symtab_t *symtab;
Word tblndx;
if ((argc != num_opt) || (argc < 2))
return;
if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) {
op = NAME;
} else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) {
op = INDEX;
} else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) {
op = TYPE;
if (obj_state == NULL) /* No object available */
elfedit_cpl_atoconst(cpldata,
ELFEDIT_CONST_SHT_ALLSYMTAB);
} else {
return;
}
if (obj_state == NULL) /* No object available */
return;
/*
* Loop over the symbol tables and supply command completion
* for the items in the file.
*/
symtab = obj_state->os_symtab;
for (tblndx = 0; tblndx < obj_state->os_symtabnum;
tblndx++, symtab++) {
elfedit_section_t *sec =
&obj_state->os_secarr[symtab->symt_shndx];
switch (op) {
case NAME:
elfedit_cpl_match(cpldata, sec->sec_name, 0);
break;
case INDEX:
{
char index[MAXNDXSIZE];
(void) snprintf(index, sizeof (index),
MSG_ORIG(MSG_FMT_WORDVAL),
symtab->symt_shndx);
elfedit_cpl_match(cpldata, index, 1);
}
break;
case TYPE:
{
elfedit_atoui_sym_t *cpl_list;
(void) elfedit_sec_issymtab(sec, 1, &cpl_list);
elfedit_cpl_atoui(cpldata, cpl_list);
}
break;
}
}
}
/*ARGSUSED*/
static void
cpl_st_bind(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
const char *argv[], int num_opt)
{
/* Handle -shXXX options */
cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
/* The second argument can be an STB_ value */
if (argc == (num_opt + 2))
elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STB);
}
/*ARGSUSED*/
static void
cpl_st_shndx(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
const char *argv[], int num_opt)
{
elfedit_section_t *sec;
enum { NAME, INDEX, TYPE } op;
Word ndx;
/* Handle -shXXX options */
cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
/*
* The second argument can be a section name, a section
* index (-secshndx), or a section type (-secshtyp). We
* can do completions for each of these.
*/
if (argc != (num_opt + 2))
return;
op = NAME;
for (ndx = 0; ndx < num_opt; ndx++) {
if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SECSHNDX)) == 0)
op = INDEX;
else if (strcmp(argv[ndx],
MSG_ORIG(MSG_STR_MINUS_SECSHTYP)) == 0)
op = TYPE;
}
switch (op) {
case NAME:
if (obj_state == NULL)
break;
sec = obj_state->os_secarr;
for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++)
elfedit_cpl_match(cpldata, sec->sec_name, 0);
break;
case INDEX:
elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHN);
break;
case TYPE:
elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
break;
}
}
/*ARGSUSED*/
static void
cpl_st_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
const char *argv[], int num_opt)
{
/* Handle -shXXX options */
cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
/* The second argument can be an STT_ value */
if (argc == (num_opt + 2))
elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STT);
}
/*ARGSUSED*/
static void
cpl_st_visibility(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
const char *argv[], int num_opt)
{
/* Handle -shXXX options */
cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
/* The second argument can be an STV_ value */
if (argc == (num_opt + 2))
elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STV);
}
/*
* 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(SYM_CMD_T_DUMP, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_bind(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_BIND, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_info(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_INFO, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_name(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_NAME, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_other(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_OTHER, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_shndx(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_SHNDX, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_size(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_SIZE, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_TYPE, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_VALUE, obj_state, argc, argv));
}
static elfedit_cmdret_t
cmd_st_visibility(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
{
return (cmd_body(SYM_CMD_T_ST_VISIBILITY, obj_state, argc, argv));
}
/*ARGSUSED*/
elfedit_module_t *
elfedit_init(elfedit_module_version_t version)
{
/* Multiple commands accept only the standard set of options */
static elfedit_cmd_optarg_t opt_std[] = {
{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
/* MSG_INTL(MSG_OPTDESC_SHNAM) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
{ MSG_ORIG(MSG_STR_NAME), NULL, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
/* MSG_INTL(MSG_OPTDESC_SHNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
{ MSG_ORIG(MSG_STR_INDEX), NULL, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
/* MSG_INTL(MSG_OPTDESC_SHTYP) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
{ MSG_ORIG(MSG_STR_TYPE), NULL, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
/* MSG_INTL(MSG_OPTDESC_SYMNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX },
{ ELFEDIT_STDOA_OPT_O, NULL,
ELFEDIT_CMDOA_F_INHERIT, 0 },
{ NULL }
};
/* sym: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 opt_dump[] = {
{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
/* MSG_INTL(MSG_OPTDESC_SHNAM) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
{ MSG_ORIG(MSG_STR_NAME), NULL, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
/* MSG_INTL(MSG_OPTDESC_SHNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
{ MSG_ORIG(MSG_STR_INDEX), NULL, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
/* MSG_INTL(MSG_OPTDESC_SHTYP) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
{ MSG_ORIG(MSG_STR_TYPE), NULL, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
/* MSG_INTL(MSG_OPTDESC_SYMNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX },
{ NULL }
};
static elfedit_cmd_optarg_t arg_dump[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_bind */
static const char *name_st_bind[] = {
MSG_ORIG(MSG_CMD_ST_BIND), NULL };
static elfedit_cmd_optarg_t arg_st_bind[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_VALUE),
/* MSG_INTL(MSG_A2_DESC_ST_BIND) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_BIND),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_info */
static const char *name_st_info[] = {
MSG_ORIG(MSG_CMD_ST_INFO), NULL };
static elfedit_cmd_optarg_t arg_st_info[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_VALUE),
/* MSG_INTL(MSG_A2_DESC_ST_INFO) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_INFO),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_name */
static const char *name_st_name[] = {
MSG_ORIG(MSG_CMD_ST_NAME), NULL };
static elfedit_cmd_optarg_t opt_st_name[] = {
{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
/* MSG_INTL(MSG_OPTDESC_SHNAM) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
{ MSG_ORIG(MSG_STR_NAME), NULL, 0, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
/* MSG_INTL(MSG_OPTDESC_SHNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
{ MSG_ORIG(MSG_STR_INDEX), NULL, 0, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
/* MSG_INTL(MSG_OPTDESC_SHTYP) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
{ MSG_ORIG(MSG_STR_TYPE), NULL, 0, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
/* MSG_INTL(MSG_OPTDESC_SYMNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
SYM_OPT_F_SYMNDX, 0 },
{ MSG_ORIG(MSG_STR_MINUS_NAME_OFFSET),
/* MSG_INTL(MSG_OPTDESC_NAME_OFFSET) */
ELFEDIT_I18NHDL(MSG_OPTDESC_NAME_OFFSET), 0,
SYM_OPT_F_NAMOFFSET, 0 },
{ ELFEDIT_STDOA_OPT_O, NULL,
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
{ NULL }
};
static elfedit_cmd_optarg_t arg_st_name[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_NAME),
/* MSG_INTL(MSG_A2_DESC_ST_NAME) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_NAME),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_other */
static const char *name_st_other[] = {
MSG_ORIG(MSG_CMD_ST_OTHER), NULL };
static elfedit_cmd_optarg_t arg_st_other[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_VALUE),
/* MSG_INTL(MSG_A2_DESC_ST_OTHER) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_OTHER),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_shndx */
static const char *name_st_shndx[] = {
MSG_ORIG(MSG_CMD_ST_SHNDX), NULL };
static elfedit_cmd_optarg_t opt_st_shndx[] = {
{ MSG_ORIG(MSG_STR_MINUS_E),
/* MSG_INTL(MSG_OPTDESC_E) */
ELFEDIT_I18NHDL(MSG_OPTDESC_E), 0, SYM_OPT_F_XSHINDEX, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
/* MSG_INTL(MSG_OPTDESC_SHNAM) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
{ MSG_ORIG(MSG_STR_NAME), NULL, 0, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
/* MSG_INTL(MSG_OPTDESC_SHNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
{ MSG_ORIG(MSG_STR_INDEX), NULL, 0, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
/* MSG_INTL(MSG_OPTDESC_SHTYP) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
{ MSG_ORIG(MSG_STR_TYPE), NULL, 0, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
/* MSG_INTL(MSG_OPTDESC_SYMNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
SYM_OPT_F_SYMNDX, 0 },
{ ELFEDIT_STDOA_OPT_O, NULL,
ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
{ MSG_ORIG(MSG_STR_MINUS_SECSHNDX),
/* MSG_INTL(MSG_OPTDESC_SECSHNDX) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHNDX),
0, SYM_OPT_F_SECSHNDX, SYM_OPT_F_SECSHTYP },
{ MSG_ORIG(MSG_STR_MINUS_SECSHTYP),
/* MSG_INTL(MSG_OPTDESC_SECSHTYP) */
ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHTYP),
0, SYM_OPT_F_SECSHTYP, SYM_OPT_F_SECSHNDX },
{ NULL }
};
static elfedit_cmd_optarg_t arg_st_shndx[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_SEC),
/* MSG_INTL(MSG_A2_DESC_ST_SEC) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SEC),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_size */
static const char *name_st_size[] = {
MSG_ORIG(MSG_CMD_ST_SIZE), NULL };
static elfedit_cmd_optarg_t arg_st_size[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_VALUE),
/* MSG_INTL(MSG_A2_DESC_ST_SIZE) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SIZE),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_type */
static const char *name_st_type[] = {
MSG_ORIG(MSG_CMD_ST_TYPE), NULL };
static elfedit_cmd_optarg_t arg_st_type[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_VALUE),
/* MSG_INTL(MSG_A2_DESC_ST_TYPE) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_TYPE),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_value */
static const char *name_st_value[] = {
MSG_ORIG(MSG_CMD_ST_VALUE), NULL };
static elfedit_cmd_optarg_t arg_st_value[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_VALUE),
/* MSG_INTL(MSG_A2_DESC_ST_VALUE) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VALUE),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
/* sym:st_visibility */
static const char *name_st_visibility[] = {
MSG_ORIG(MSG_CMD_ST_VISIBILITY), NULL };
static elfedit_cmd_optarg_t arg_st_visibility[] = {
{ MSG_ORIG(MSG_STR_SYM),
/* MSG_INTL(MSG_A1_SYM) */
ELFEDIT_I18NHDL(MSG_A1_SYM),
ELFEDIT_CMDOA_F_OPT },
{ MSG_ORIG(MSG_STR_VALUE),
/* MSG_INTL(MSG_A2_DESC_ST_VISIBILITY) */
ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VISIBILITY),
ELFEDIT_CMDOA_F_OPT },
{ NULL }
};
static elfedit_cmd_t cmds[] = {
/* sym:dump */
{ cmd_dump, cpl_sh_opt, name_dump,
/* MSG_INTL(MSG_DESC_DUMP) */
ELFEDIT_I18NHDL(MSG_DESC_DUMP),
/* MSG_INTL(MSG_HELP_DUMP) */
ELFEDIT_I18NHDL(MSG_HELP_DUMP),
opt_dump, arg_dump },
/* sym:st_bind */
{ cmd_st_bind, cpl_st_bind, name_st_bind,
/* MSG_INTL(MSG_DESC_ST_BIND) */
ELFEDIT_I18NHDL(MSG_DESC_ST_BIND),
/* MSG_INTL(MSG_HELP_ST_BIND) */
ELFEDIT_I18NHDL(MSG_HELP_ST_BIND),
opt_std, arg_st_bind },
/* sym:st_info */
{ cmd_st_info, cpl_sh_opt, name_st_info,
/* MSG_INTL(MSG_DESC_ST_INFO) */
ELFEDIT_I18NHDL(MSG_DESC_ST_INFO),
/* MSG_INTL(MSG_HELP_ST_INFO) */
ELFEDIT_I18NHDL(MSG_HELP_ST_INFO),
opt_std, arg_st_info },
/* sym:st_name */
{ cmd_st_name, cpl_sh_opt, name_st_name,
/* MSG_INTL(MSG_DESC_ST_NAME) */
ELFEDIT_I18NHDL(MSG_DESC_ST_NAME),
/* MSG_INTL(MSG_HELP_ST_NAME) */
ELFEDIT_I18NHDL(MSG_HELP_ST_NAME),
opt_st_name, arg_st_name },
/* sym:st_other */
{ cmd_st_other, cpl_sh_opt, name_st_other,
/* MSG_INTL(MSG_DESC_ST_OTHER) */
ELFEDIT_I18NHDL(MSG_DESC_ST_OTHER),
/* MSG_INTL(MSG_HELP_ST_OTHER) */
ELFEDIT_I18NHDL(MSG_HELP_ST_OTHER),
opt_std, arg_st_other },
/* sym:st_shndx */
{ cmd_st_shndx, cpl_st_shndx, name_st_shndx,
/* MSG_INTL(MSG_DESC_ST_SHNDX) */
ELFEDIT_I18NHDL(MSG_DESC_ST_SHNDX),
/* MSG_INTL(MSG_HELP_ST_SHNDX) */
ELFEDIT_I18NHDL(MSG_HELP_ST_SHNDX),
opt_st_shndx, arg_st_shndx },
/* sym:st_size */
{ cmd_st_size, cpl_sh_opt, name_st_size,
/* MSG_INTL(MSG_DESC_ST_SIZE) */
ELFEDIT_I18NHDL(MSG_DESC_ST_SIZE),
/* MSG_INTL(MSG_HELP_ST_SIZE) */
ELFEDIT_I18NHDL(MSG_HELP_ST_SIZE),
opt_std, arg_st_size },
/* sym:st_type */
{ cmd_st_type, cpl_st_type, name_st_type,
/* MSG_INTL(MSG_DESC_ST_TYPE) */
ELFEDIT_I18NHDL(MSG_DESC_ST_TYPE),
/* MSG_INTL(MSG_HELP_ST_TYPE) */
ELFEDIT_I18NHDL(MSG_HELP_ST_TYPE),
opt_std, arg_st_type },
/* sym:st_value */
{ cmd_st_value, cpl_sh_opt, name_st_value,
/* MSG_INTL(MSG_DESC_ST_VALUE) */
ELFEDIT_I18NHDL(MSG_DESC_ST_VALUE),
/* MSG_INTL(MSG_HELP_ST_VALUE) */
ELFEDIT_I18NHDL(MSG_HELP_ST_VALUE),
opt_std, arg_st_value },
/* sym:st_visibility */
{ cmd_st_visibility, cpl_st_visibility, name_st_visibility,
/* MSG_INTL(MSG_DESC_ST_VISIBILITY) */
ELFEDIT_I18NHDL(MSG_DESC_ST_VISIBILITY),
/* MSG_INTL(MSG_HELP_ST_VISIBILITY) */
ELFEDIT_I18NHDL(MSG_HELP_ST_VISIBILITY),
opt_std, arg_st_visibility },
{ 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);
}