15088Sab196087 /*
25088Sab196087 * CDDL HEADER START
35088Sab196087 *
45088Sab196087 * The contents of this file are subject to the terms of the
55088Sab196087 * Common Development and Distribution License (the "License").
65088Sab196087 * You may not use this file except in compliance with the License.
75088Sab196087 *
85088Sab196087 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95088Sab196087 * or http://www.opensolaris.org/os/licensing.
105088Sab196087 * See the License for the specific language governing permissions
115088Sab196087 * and limitations under the License.
125088Sab196087 *
135088Sab196087 * When distributing Covered Code, include this CDDL HEADER in each
145088Sab196087 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155088Sab196087 * If applicable, add the following below this CDDL HEADER, with the
165088Sab196087 * fields enclosed by brackets "[]" replaced with your own identifying
175088Sab196087 * information: Portions Copyright [yyyy] [name of copyright owner]
185088Sab196087 *
195088Sab196087 * CDDL HEADER END
205088Sab196087 */
215088Sab196087
225088Sab196087 /*
23*9273SAli.Bahrami@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
245088Sab196087 * Use is subject to license terms.
255088Sab196087 */
265088Sab196087
275088Sab196087 #include <stdio.h>
285088Sab196087 #include <unistd.h>
295088Sab196087 #include <elfedit.h>
305088Sab196087 #include <strings.h>
315088Sab196087 #include <debug.h>
325088Sab196087 #include <conv.h>
335088Sab196087 #include <syminfo_msg.h>
345088Sab196087
355088Sab196087
365088Sab196087
375088Sab196087 /*
385088Sab196087 * This module uses shared code for several of the commands.
395088Sab196087 * It is sometimes necessary to know which specific command
405088Sab196087 * is active.
415088Sab196087 */
425088Sab196087 typedef enum {
435088Sab196087 SYMINFO_CMD_T_DUMP = 0, /* syminfo:dump */
445088Sab196087
455088Sab196087 SYMINFO_CMD_T_SI_BOUNDTO = 1, /* syminfo:si_boundto */
465088Sab196087 SYMINFO_CMD_T_SI_FLAGS = 2 /* syminfo:si_boundto */
475088Sab196087 } SYMINFO_CMD_T;
485088Sab196087
495088Sab196087
505088Sab196087
515088Sab196087 #ifndef _ELF64
525088Sab196087 /*
535088Sab196087 * We supply this function for the msg module. Only one copy is needed.
545088Sab196087 */
555088Sab196087 const char *
_syminfo_msg(Msg mid)565088Sab196087 _syminfo_msg(Msg mid)
575088Sab196087 {
585088Sab196087 return (gettext(MSG_ORIG(mid)));
595088Sab196087 }
605088Sab196087
615088Sab196087 #endif
625088Sab196087
635088Sab196087
645088Sab196087
655088Sab196087 /*
665088Sab196087 * This function is supplied to elfedit through our elfedit_module_t
675088Sab196087 * definition. It translates the opaque elfedit_i18nhdl_t handles
685088Sab196087 * in our module interface into the actual strings for elfedit to
695088Sab196087 * use.
705088Sab196087 *
715088Sab196087 * note:
725088Sab196087 * This module uses Msg codes for its i18n handle type.
735088Sab196087 * So the translation is simply to use MSG_INTL() to turn
745088Sab196087 * it into a string and return it.
755088Sab196087 */
765088Sab196087 static const char *
mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)775088Sab196087 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
785088Sab196087 {
795088Sab196087 Msg msg = (Msg)hdl;
805088Sab196087
815088Sab196087 return (MSG_INTL(msg));
825088Sab196087 }
835088Sab196087
845088Sab196087
855088Sab196087
865088Sab196087 /*
875088Sab196087 * The sym_opt_t enum specifies a bit value for every optional
885088Sab196087 * argument allowed by a command in this module.
895088Sab196087 */
905088Sab196087 typedef enum {
915088Sab196087 SYMINFO_OPT_F_AND = 1, /* -and: AND (&) values to dest */
925088Sab196087 SYMINFO_OPT_F_CMP = 2, /* -cmp: Complement (~) values */
935088Sab196087 SYMINFO_OPT_F_NEEDED = 4, /* -needed: arg is name of object to */
945088Sab196087 /* be referenced via DT_NEEDED */
955088Sab196087 /* dynamic entry */
965088Sab196087 SYMINFO_OPT_F_OR = 8, /* -or: OR (|) values to dest */
975088Sab196087 SYMINFO_OPT_F_SYMNDX = 16 /* -symndx: Sym specified by index */
985088Sab196087 } syminfo_opt_t;
995088Sab196087
1005088Sab196087
1015088Sab196087 /*
1025088Sab196087 * A variable of type ARGSTATE is used by each command to maintain
1035088Sab196087 * information about the syminfo section being used, as and for any
1045088Sab196087 * auxiliary sections that are related to it. This helps us to ensure
1055088Sab196087 * that we only fetch each section a single time:
1065088Sab196087 * - More efficient
1075088Sab196087 * - Prevents multiple ELFEDIT_MSG_DEBUG messages from
1085088Sab196087 * being produced for a given section.
1095088Sab196087 */
1105088Sab196087 typedef struct {
1115088Sab196087 elfedit_obj_state_t *obj_state;
1125088Sab196087 syminfo_opt_t optmask; /* Mask of options used */
1135088Sab196087 int argc; /* # of plain arguments */
1145088Sab196087 const char **argv; /* Plain arguments */
1155088Sab196087 struct { /* Syminfo */
1165088Sab196087 elfedit_section_t *sec;
1175088Sab196087 Syminfo *data;
1185088Sab196087 Word n;
1195088Sab196087 } syminfo;
1205088Sab196087 struct { /* Symbol table */
1215088Sab196087 elfedit_section_t *sec;
1225088Sab196087 Sym *data;
1235088Sab196087 Word n;
1245088Sab196087 } sym;
1255088Sab196087 struct { /* String table */
1265088Sab196087 elfedit_section_t *sec;
1275088Sab196087 } str;
1285088Sab196087 struct { /* Dynamic section */
1295088Sab196087 elfedit_section_t *sec;
1305088Sab196087 Dyn *data;
1315088Sab196087 Word n;
1325088Sab196087 } dynamic;
1335088Sab196087 } ARGSTATE;
1345088Sab196087
1355088Sab196087
1365088Sab196087
1375088Sab196087 /*
1385088Sab196087 * Standard argument processing for syminfo module
1395088Sab196087 *
1405088Sab196087 * entry
1415088Sab196087 * obj_state, argc, argv - Standard command arguments
1425088Sab196087 * optmask - Mask of allowed optional arguments.
1435088Sab196087 * argstate - Address of ARGSTATE block to be initialized
1445088Sab196087 *
1455088Sab196087 * exit:
1465088Sab196087 * On success, *argstate is initialized. On error,
1475088Sab196087 * an error is issued and this routine does not return.
1485088Sab196087 *
1495088Sab196087 * note:
1505088Sab196087 * Only the syminfo section is initially referenced by
1515088Sab196087 * argstate. Use the argstate_add_XXX() routines below to
1525088Sab196087 * access any other sections needed.
1535088Sab196087 */
1545088Sab196087 static void
process_args(elfedit_obj_state_t * obj_state,int argc,const char * argv[],SYMINFO_CMD_T cmd,ARGSTATE * argstate)1555088Sab196087 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
1565088Sab196087 SYMINFO_CMD_T cmd, ARGSTATE *argstate)
1575088Sab196087 {
1585088Sab196087 elfedit_getopt_state_t getopt_state;
1595088Sab196087 elfedit_getopt_ret_t *getopt_ret;
1605088Sab196087
1615088Sab196087 bzero(argstate, sizeof (*argstate));
1625088Sab196087 argstate->obj_state = obj_state;
1635088Sab196087
1645088Sab196087 elfedit_getopt_init(&getopt_state, &argc, &argv);
1655088Sab196087
1665088Sab196087 /* Add each new option to the options mask */
1675088Sab196087 while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
1685088Sab196087 argstate->optmask |= getopt_ret->gor_idmask;
1695088Sab196087
1705088Sab196087 /*
1715088Sab196087 * Usage error if there are too many plain arguments.
1725088Sab196087 * - syminfo:dump accepts a single argument
1735088Sab196087 * - syminfo:si_boundto accepts 2 arguments
1745088Sab196087 * - syminfo:si_flags accepts an unbounded number
1755088Sab196087 */
1765088Sab196087 if (((cmd == SYMINFO_CMD_T_DUMP) && (argc > 1)) ||
1775088Sab196087 ((cmd == SYMINFO_CMD_T_SI_BOUNDTO) && (argc > 2)))
1785088Sab196087 elfedit_command_usage();
1795088Sab196087
1805088Sab196087 /* If there may be an arbitrary amount of output, use a pager */
1815088Sab196087 if (argc == 0)
1825088Sab196087 elfedit_pager_init();
1835088Sab196087
1845088Sab196087 /* Return the updated values of argc/argv */
1855088Sab196087 argstate->argc = argc;
1865088Sab196087 argstate->argv = argv;
1875088Sab196087
1885088Sab196087 /* Locate the syminfo section */
1895088Sab196087 argstate->syminfo.sec = elfedit_sec_getsyminfo(obj_state,
1905088Sab196087 &argstate->syminfo.data, &argstate->syminfo.n);
1915088Sab196087 }
1925088Sab196087
1935088Sab196087
1945088Sab196087
1955088Sab196087 /*
1965088Sab196087 * We maintain the state of the current syminfo table in a ARGSTATE
1975088Sab196087 * structure. A syminfo is related to the dynamic symbol table, and
1985088Sab196087 * can reference the dynamic section of the object. We don't look those
1995088Sab196087 * things up unless we actually need them, both to be efficient, and
2005088Sab196087 * to prevent duplicate ELFEDIT_MSG_DEBUG messages from being issued
2015088Sab196087 * as they are located. Hence, process_args() is used to initialze the
2025088Sab196087 * state block with just the syminfo section, and then one of the
2035088Sab196087 * argstate_add_XXX() functions is used as needed to fetch the
2045088Sab196087 * additional sections.
2055088Sab196087 *
2065088Sab196087 * entry:
2075088Sab196087 * argstate - State block for current symbol table.
2085088Sab196087 *
2095088Sab196087 * exit:
2105088Sab196087 * If the needed auxiliary section is not found, an error is
2115088Sab196087 * issued and the argstate_add_XXX() routine does not return.
2125088Sab196087 * Otherwise, the fields in argstate have been filled in, ready
2135088Sab196087 * for use.
2145088Sab196087 *
2155088Sab196087 */
2165088Sab196087 static void
argstate_add_sym(ARGSTATE * argstate)2175088Sab196087 argstate_add_sym(ARGSTATE *argstate)
2185088Sab196087 {
2195088Sab196087 if (argstate->sym.sec != NULL)
2205088Sab196087 return;
2215088Sab196087
2225088Sab196087 argstate->sym.sec = elfedit_sec_getsymtab(argstate->obj_state,
2235088Sab196087 1, argstate->syminfo.sec->sec_shdr->sh_link, NULL,
2245088Sab196087 &argstate->sym.data, &argstate->sym.n, NULL);
2255088Sab196087 }
2265088Sab196087 static void
argstate_add_str(ARGSTATE * argstate)2275088Sab196087 argstate_add_str(ARGSTATE *argstate)
2285088Sab196087 {
2295088Sab196087 if (argstate->str.sec != NULL)
2305088Sab196087 return;
2315088Sab196087
2325088Sab196087 argstate_add_sym(argstate);
2335088Sab196087 argstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
2346225Sab196087 argstate->sym.sec->sec_shdr->sh_link, 0);
2355088Sab196087 }
2365088Sab196087 static void
argstate_add_dynamic(ARGSTATE * argstate)2375088Sab196087 argstate_add_dynamic(ARGSTATE *argstate)
2385088Sab196087 {
2395088Sab196087 if (argstate->dynamic.sec != NULL)
2405088Sab196087 return;
2415088Sab196087
2425088Sab196087 argstate->dynamic.sec = elfedit_sec_getdyn(argstate->obj_state,
2435088Sab196087 &argstate->dynamic.data, &argstate->dynamic.n);
2445088Sab196087 }
2455088Sab196087
2465088Sab196087
2475088Sab196087
2485088Sab196087 /*
2495088Sab196087 * Display syminfo section entries in the style used by elfdump.
2505088Sab196087 *
2515088Sab196087 * entry:
2525088Sab196087 * argstate - State block for current symbol table.
2535088Sab196087 * ndx - Index of first symbol to display
2545088Sab196087 * cnt - Number of symbols to display
2555088Sab196087 */
2565088Sab196087 static void
dump_syminfo(ARGSTATE * argstate,Word ndx,Word cnt)2575088Sab196087 dump_syminfo(ARGSTATE *argstate, Word ndx, Word cnt)
2585088Sab196087 {
2595088Sab196087 Syminfo *syminfo;
2605088Sab196087 Sym *sym;
2615088Sab196087 Dyn *dyn;
2625088Sab196087
2635088Sab196087 syminfo = argstate->syminfo.data + ndx;
2645088Sab196087
2655088Sab196087 argstate_add_sym(argstate);
2665088Sab196087 sym = argstate->sym.data + ndx;
2675088Sab196087
2685088Sab196087 argstate_add_str(argstate);
2695088Sab196087
2705088Sab196087 argstate_add_dynamic(argstate);
2715088Sab196087 dyn = argstate->dynamic.data;
2725088Sab196087
2735088Sab196087 /*
2745088Sab196087 * Loop through the syminfo entries.
2755088Sab196087 */
2765088Sab196087 Elf_syminfo_title(0);
2775088Sab196087
2785088Sab196087 for (; cnt-- > 0; ndx++, syminfo++, sym++) {
2795088Sab196087 const char *needed = NULL, *name;
2805088Sab196087
2815088Sab196087 name = elfedit_offset_to_str(argstate->str.sec,
2825088Sab196087 sym->st_name, ELFEDIT_MSG_ERR, 0);
2835088Sab196087
2845088Sab196087 if ((syminfo->si_boundto < SYMINFO_BT_LOWRESERVE) &&
2855088Sab196087 (syminfo->si_boundto < argstate->dynamic.n) &&
2865088Sab196087 ((dyn[syminfo->si_boundto].d_tag == DT_NEEDED) ||
2875088Sab196087 (dyn[syminfo->si_boundto].d_tag == DT_USED)))
2885088Sab196087 needed = elfedit_offset_to_str(argstate->str.sec,
2895088Sab196087 dyn[syminfo->si_boundto].d_un.d_val,
2905088Sab196087 ELFEDIT_MSG_ERR, 0);
2915088Sab196087 else
2925088Sab196087 needed = MSG_ORIG(MSG_STR_EMPTY);
2935088Sab196087
2945088Sab196087 Elf_syminfo_entry(0, ndx, syminfo, name, needed);
2955088Sab196087 }
2965088Sab196087 }
2975088Sab196087
2985088Sab196087
2995088Sab196087
3005088Sab196087 /*
3015088Sab196087 * Print syminfo values, taking the calling command, and output style
3025088Sab196087 * into account.
3035088Sab196087 *
3045088Sab196087 * entry:
3055088Sab196087 * cmd - SYMINFO_CMD_T_* value giving identify of caller
3065088Sab196087 * autoprint - If True, output is only produced if the elfedit
3075088Sab196087 * autoprint flag is set. If False, output is always produced.
3085088Sab196087 * argstate - State block for current symbol table.
3095088Sab196087 * ndx - Index of first symbol to display
3105088Sab196087 * cnt - Number of symbols to display
3115088Sab196087 */
3125088Sab196087 static void
print_syminfo(SYMINFO_CMD_T cmd,int autoprint,ARGSTATE * argstate,Word ndx,Word cnt)3135088Sab196087 print_syminfo(SYMINFO_CMD_T cmd, int autoprint, ARGSTATE *argstate,
3145088Sab196087 Word ndx, Word cnt)
3155088Sab196087 {
3165088Sab196087 elfedit_outstyle_t outstyle;
3175088Sab196087 Syminfo *syminfo;
3185088Sab196087
3195088Sab196087 if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) ||
3205088Sab196087 (cnt == 0))
3215088Sab196087 return;
3225088Sab196087
3235088Sab196087 /*
3245088Sab196087 * Pick an output style. syminfo:dump is required to use the default
3255088Sab196087 * style. The other commands use the current output style.
3265088Sab196087 */
3275088Sab196087 outstyle = (cmd == SYMINFO_CMD_T_DUMP) ?
3285088Sab196087 ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
3295088Sab196087
3305088Sab196087 /*
3315088Sab196087 * If doing default output, use elfdump style where we
3325088Sab196087 * show all symbol attributes. In this case, the command
3335088Sab196087 * that called us doesn't matter
3345088Sab196087 */
3355088Sab196087 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
3365088Sab196087 dump_syminfo(argstate, ndx, cnt);
3375088Sab196087 return;
3385088Sab196087 }
3395088Sab196087
3405088Sab196087 syminfo = argstate->syminfo.data;
3415088Sab196087
3425088Sab196087 switch (cmd) {
3435088Sab196087 case SYMINFO_CMD_T_SI_BOUNDTO:
3445088Sab196087 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
3455088Sab196087 /* Find the dynamic section and string table */
3465088Sab196087 argstate_add_dynamic(argstate);
3475088Sab196087 argstate_add_str(argstate);
3485088Sab196087 }
3495088Sab196087
3505088Sab196087 for (syminfo += ndx; cnt--; syminfo++) {
3515088Sab196087 Half bndto = syminfo->si_boundto;
3525088Sab196087
3535088Sab196087 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
3545088Sab196087 const char *str = NULL;
3555088Sab196087
3565088Sab196087 switch (bndto) {
3575088Sab196087 case SYMINFO_BT_SELF:
3585088Sab196087 str = elfedit_atoconst_value_to_str(
3595088Sab196087 ELFEDIT_CONST_SYMINFO_BT,
3605088Sab196087 SYMINFO_BT_SELF, 1);
3615088Sab196087 break;
3625088Sab196087 case SYMINFO_BT_PARENT:
3635088Sab196087 str = elfedit_atoconst_value_to_str(
3645088Sab196087 ELFEDIT_CONST_SYMINFO_BT,
3655088Sab196087 SYMINFO_BT_PARENT, 1);
3665088Sab196087 break;
3675088Sab196087 case SYMINFO_BT_NONE:
3685088Sab196087 str = elfedit_atoconst_value_to_str(
3695088Sab196087 ELFEDIT_CONST_SYMINFO_BT,
3705088Sab196087 SYMINFO_BT_NONE, 1);
3715088Sab196087 break;
3725088Sab196087 }
3735088Sab196087 if ((str == NULL) &&
3745088Sab196087 (bndto < SYMINFO_BT_LOWRESERVE) &&
3755088Sab196087 (argstate->dynamic.sec != NULL) &&
3765088Sab196087 (bndto < argstate->dynamic.n) &&
3775088Sab196087 (argstate->dynamic.data[bndto].d_tag ==
3785088Sab196087 DT_NEEDED))
3795088Sab196087 str = elfedit_offset_to_str(
3805088Sab196087 argstate->str.sec,
3815088Sab196087 argstate->dynamic.data[bndto].
3825088Sab196087 d_un.d_val, ELFEDIT_MSG_ERR, 0);
3835088Sab196087
3845088Sab196087 if (str != NULL) {
3855088Sab196087 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
3865088Sab196087 str);
3875088Sab196087 continue;
3885088Sab196087 }
3895088Sab196087 }
3905088Sab196087
3915088Sab196087 /*
3925088Sab196087 * If we reach this point, we are either in numeric
3935088Sab196087 * mode, or we were unable to find a string above.
3945088Sab196087 * In either case, output as integer.
3955088Sab196087 */
3965088Sab196087 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
3975088Sab196087 EC_WORD(bndto));
3985088Sab196087 }
3995088Sab196087 break;
4005088Sab196087
4015088Sab196087 case SYMINFO_CMD_T_SI_FLAGS:
4025088Sab196087 for (syminfo += ndx; cnt--; syminfo++) {
4035088Sab196087 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
4045088Sab196087 Conv_syminfo_flags_buf_t buf;
4055088Sab196087
4065088Sab196087 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
4075088Sab196087 conv_syminfo_flags(syminfo->si_flags,
4085088Sab196087 CONV_FMT_NOBKT, &buf));
4095088Sab196087 } else {
4105088Sab196087 elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL),
4115088Sab196087 EC_WORD(syminfo->si_flags));
4125088Sab196087 }
4135088Sab196087 }
4145088Sab196087 break;
4155088Sab196087 }
4165088Sab196087 }
4175088Sab196087
4185088Sab196087
4195088Sab196087 /*
4205088Sab196087 * Convert the given argument string into a symbol table index.
4215088Sab196087 *
4225088Sab196087 * entry:
4235088Sab196087 * argstate - State block for current symbol table.
4245088Sab196087 * arg - String containing symbol index argument.
4255088Sab196087 *
4265088Sab196087 * exit:
4275088Sab196087 * On success, returns the symbol index. On failure, an error
4285088Sab196087 * is issued and this routine does not return.
4295088Sab196087 */
4305088Sab196087 static Word
arg_to_symndx(ARGSTATE * argstate,const char * arg)4315088Sab196087 arg_to_symndx(ARGSTATE *argstate, const char *arg)
4325088Sab196087 {
4335088Sab196087 Word symndx;
4345088Sab196087
4355088Sab196087 /*
4365088Sab196087 * If the -symndx option was specified, arg is an index
4375088Sab196087 * into the symbol table.
4385088Sab196087 */
4395088Sab196087 if (argstate->optmask & SYMINFO_OPT_F_SYMNDX)
4405088Sab196087 return (elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_SYM),
4415088Sab196087 0, argstate->syminfo.n - 1, NULL));
4425088Sab196087
4435088Sab196087 /*
4445088Sab196087 * arg is a symbol name. Return the index of the first symbol
4455088Sab196087 * that matches
4465088Sab196087 */
4475088Sab196087 argstate_add_sym(argstate);
4485088Sab196087 argstate_add_str(argstate);
4495088Sab196087
4505088Sab196087 (void) elfedit_name_to_symndx(argstate->sym.sec,
4515088Sab196087 argstate->str.sec, arg, ELFEDIT_MSG_ERR, &symndx);
4525088Sab196087
4535088Sab196087 return (symndx);
4545088Sab196087 }
4555088Sab196087
4565088Sab196087
4575088Sab196087 /*
4585088Sab196087 * Given a string argument representing an object, return the index of
4595088Sab196087 * the dynamic section that should be used for the si_boundto value.
4605088Sab196087 */
4615088Sab196087 static Half
needed_to_boundto(ARGSTATE * argstate,const char * arg)4625088Sab196087 needed_to_boundto(ARGSTATE *argstate, const char *arg)
4635088Sab196087 {
4645088Sab196087 Conv_inv_buf_t inv_buf;
4655088Sab196087 elfedit_dyn_elt_t strpad_elt;
4665088Sab196087 elfedit_dyn_elt_t null_elt;
4675088Sab196087 elfedit_section_t *dynsec;
4685088Sab196087 Word null_cnt;
4695088Sab196087 Dyn *dyn;
4705088Sab196087 Word str_offset, ndx, numdyn;
4715088Sab196087 int have_string;
4725088Sab196087
4735088Sab196087 argstate_add_str(argstate);
4745088Sab196087 argstate_add_dynamic(argstate);
4755088Sab196087 dynsec = argstate->dynamic.sec;
4765088Sab196087 numdyn = argstate->dynamic.n;
4775088Sab196087
4785088Sab196087 /* Locate DT_SUNW_STRPAD element if present and locate the DT_NULLs */
4795088Sab196087 elfedit_dyn_elt_init(&strpad_elt);
4805088Sab196087 elfedit_dyn_elt_init(&null_elt);
4815088Sab196087 null_cnt = 0;
4825088Sab196087 strpad_elt.dn_dyn.d_un.d_val = 0;
4835088Sab196087 dyn = argstate->dynamic.data;
4845088Sab196087 for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
4855088Sab196087 switch (dyn->d_tag) {
4865088Sab196087 case DT_NULL:
4875088Sab196087 /* Count all the nulls, remember the first one */
4885088Sab196087 null_cnt++;
4895088Sab196087 if (!null_elt.dn_seen)
4905088Sab196087 elfedit_dyn_elt_save(&null_elt, ndx, dyn);
4915088Sab196087 break;
4925088Sab196087
4935088Sab196087 case DT_SUNW_STRPAD:
494*9273SAli.Bahrami@Sun.COM if (elfedit_test_osabi(argstate->obj_state,
495*9273SAli.Bahrami@Sun.COM ELFOSABI_SOLARIS, 0))
496*9273SAli.Bahrami@Sun.COM elfedit_dyn_elt_save(&strpad_elt, ndx, dyn);
4975088Sab196087 break;
4985088Sab196087 }
4995088Sab196087 }
5005088Sab196087
5015088Sab196087 /*
5025088Sab196087 * Look up the string in the string table and get its offset. If
5035088Sab196087 * this succeeds, then it is possible that there is a DT_NEEDED
5045088Sab196087 * dynamic entry that references it.
5055088Sab196087 */
5065088Sab196087 have_string = elfedit_sec_findstr(argstate->str.sec,
5075088Sab196087 strpad_elt.dn_dyn.d_un.d_val, arg, &str_offset) != 0;
5085088Sab196087 if (have_string) {
5095088Sab196087 dyn = argstate->dynamic.data;
5105088Sab196087 for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
5115088Sab196087 if (((dyn->d_tag == DT_NEEDED) ||
5125088Sab196087 (dyn->d_tag == DT_USED)) &&
5135088Sab196087 (dyn->d_un.d_val == str_offset))
5145088Sab196087 goto done;
5155088Sab196087 }
5165088Sab196087 }
5175088Sab196087
5185088Sab196087 /*
5195088Sab196087 * It doesn't already exist. We might be able to add a DT_NEEDED
5205088Sab196087 * to the dynamic section if an extra DT_NULL is available.
5215088Sab196087 * Otherwise, we have to fail here.
5225088Sab196087 */
5235088Sab196087 if (null_cnt < 2)
5245088Sab196087 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
5255088Sab196087 EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
5265088Sab196087
5275088Sab196087 /*
5285088Sab196087 * If the string is not already in the string table, try to
5295088Sab196087 * insert it. If it succeeds, we will convert the DT_NULL.
5305088Sab196087 * Otherwise, an error will be issued and control will not
5315088Sab196087 * return here.
5325088Sab196087 */
5335088Sab196087 if (!have_string)
5345088Sab196087 str_offset = elfedit_dynstr_insert(dynsec,
5355088Sab196087 argstate->str.sec, &strpad_elt, arg);
5365088Sab196087
5375088Sab196087 /* Convert the extra DT_NULL */
5385088Sab196087 ndx = null_elt.dn_ndx;
5395088Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
5405088Sab196087 EC_WORD(dynsec->sec_shndx), dynsec->sec_name, EC_WORD(ndx),
541*9273SAli.Bahrami@Sun.COM conv_dyn_tag(DT_NEEDED,
542*9273SAli.Bahrami@Sun.COM argstate->obj_state->os_ehdr->e_ident[EI_OSABI],
543*9273SAli.Bahrami@Sun.COM argstate->obj_state->os_ehdr->e_machine,
5445088Sab196087 0, &inv_buf));
5455088Sab196087 dyn = argstate->dynamic.data + ndx;
5465088Sab196087 dyn->d_tag = DT_NEEDED;
5475088Sab196087 dyn->d_un.d_val = str_offset;
5485088Sab196087 elfedit_modified_data(dynsec);
5495088Sab196087
5505088Sab196087 done:
5515088Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDNEEDED),
5525088Sab196087 dynsec->sec_shndx, dynsec->sec_name, ndx, arg);
5535088Sab196087 return (ndx);
5545088Sab196087 }
5555088Sab196087
5565088Sab196087 /*
5575088Sab196087 * Common body for the syminfo: module commands. These commands
5585088Sab196087 * share a large amount of common behavior, so it is convenient
5595088Sab196087 * to centralize things and use the cmd argument to handle the
5605088Sab196087 * small differences.
5615088Sab196087 *
5625088Sab196087 * entry:
5635088Sab196087 * cmd - One of the SYMINFO_CMD_T_* constants listed above, specifying
5645088Sab196087 * which command to implement.
5655088Sab196087 * obj_state, argc, argv - Standard command arguments
5665088Sab196087 */
5675088Sab196087 static elfedit_cmdret_t
cmd_body(SYMINFO_CMD_T cmd,elfedit_obj_state_t * obj_state,int argc,const char * argv[])5685088Sab196087 cmd_body(SYMINFO_CMD_T cmd, elfedit_obj_state_t *obj_state,
5695088Sab196087 int argc, const char *argv[])
5705088Sab196087 {
5715088Sab196087 ARGSTATE argstate;
5725088Sab196087 Word ndx;
5735088Sab196087 Syminfo *syminfo;
5745088Sab196087 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE;
5755088Sab196087
5765088Sab196087 process_args(obj_state, argc, argv, cmd, &argstate);
5775088Sab196087
5785088Sab196087 /* If there are no arguments, dump the whole table and return */
5795088Sab196087 if (argstate.argc == 0) {
5805088Sab196087 print_syminfo(cmd, 0, &argstate, 0, argstate.syminfo.n);
5815088Sab196087 return (ELFEDIT_CMDRET_NONE);
5825088Sab196087 }
5835088Sab196087
5845088Sab196087 /* The first argument is the symbol name/index */
5855088Sab196087 ndx = arg_to_symndx(&argstate, argstate.argv[0]);
5865088Sab196087
5875088Sab196087 /* If there is a single argument, display that item and return */
5885088Sab196087 if (argstate.argc == 1) {
5895088Sab196087 print_syminfo(cmd, 0, &argstate, ndx, 1);
5905088Sab196087 return (ELFEDIT_CMDRET_NONE);
5915088Sab196087 }
5925088Sab196087
5935088Sab196087 syminfo = &argstate.syminfo.data[ndx];
5945088Sab196087
5955088Sab196087 /*
5965088Sab196087 * Syminfo [0] holds the value SYMINFO_CURRENT, as a versioning
5975088Sab196087 * technique. You're not supposed to mess with it.
5985088Sab196087 */
5995088Sab196087 if (ndx == 0)
6005088Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMINFO0),
6015088Sab196087 EC_WORD(argstate.syminfo.sec->sec_shndx),
6025088Sab196087 argstate.syminfo.sec->sec_name, EC_WORD(ndx));
6035088Sab196087
6045088Sab196087 /* The second value supplies a new value for the item */
6055088Sab196087 switch (cmd) {
6065088Sab196087 /*
6075088Sab196087 * SYMINFO_CMD_T_DUMP can't get here: It never has more than
6085088Sab196087 * one argument, and is handled above.
6095088Sab196087 */
6105088Sab196087
6115088Sab196087 case SYMINFO_CMD_T_SI_BOUNDTO:
6125088Sab196087 {
6135088Sab196087 const char *name = MSG_ORIG(MSG_CMD_SI_BOUNDTO);
6145088Sab196087 Half boundto;
6155088Sab196087
6165088Sab196087 if (argstate.optmask & SYMINFO_OPT_F_NEEDED)
6175088Sab196087 boundto = needed_to_boundto(&argstate,
6185088Sab196087 argstate.argv[1]);
6195088Sab196087 else
6205088Sab196087 boundto = elfedit_atoconst_range(
6215088Sab196087 argstate.argv[1], MSG_ORIG(MSG_STR_VALUE),
6225088Sab196087 0, 0xffff, ELFEDIT_CONST_SYMINFO_BT);
6235088Sab196087
6245088Sab196087 if (syminfo->si_boundto == boundto) {
6255088Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG,
6265088Sab196087 MSG_INTL(MSG_DEBUG_X_OK),
6275088Sab196087 argstate.syminfo.sec->sec_shndx,
6285088Sab196087 argstate.syminfo.sec->sec_name, ndx, name,
6295088Sab196087 syminfo->si_boundto);
6305088Sab196087 } else {
6315088Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG,
6325088Sab196087 MSG_INTL(MSG_DEBUG_X_CHG),
6335088Sab196087 argstate.syminfo.sec->sec_shndx,
6345088Sab196087 argstate.syminfo.sec->sec_name, ndx, name,
6355088Sab196087 syminfo->si_boundto, boundto);
6365088Sab196087 ret = ELFEDIT_CMDRET_MOD;
6375088Sab196087 syminfo->si_boundto = boundto;
6385088Sab196087 }
6395088Sab196087 }
6405088Sab196087 break;
6415088Sab196087
6425088Sab196087 case SYMINFO_CMD_T_SI_FLAGS:
6435088Sab196087 {
6445088Sab196087 Conv_syminfo_flags_buf_t flags_buf1, flags_buf2;
6455088Sab196087 const char *name = MSG_ORIG(MSG_CMD_SI_FLAGS);
6465088Sab196087 Half flags = 0;
6475088Sab196087 int i;
6485088Sab196087
6495088Sab196087 /* Collect the arguments */
6505088Sab196087 for (i = 1; i < argstate.argc; i++)
6515088Sab196087 flags |= (Word)
6525088Sab196087 elfedit_atoconst(argstate.argv[i],
6535088Sab196087 ELFEDIT_CONST_SYMINFO_FLG);
6545088Sab196087
6555088Sab196087 /* Complement the value? */
6565088Sab196087 if (argstate.optmask & SYMINFO_OPT_F_CMP)
6575088Sab196087 flags = ~flags;
6585088Sab196087
6595088Sab196087 /* Perform any requested bit operations */
6605088Sab196087 if (argstate.optmask & SYMINFO_OPT_F_AND)
6615088Sab196087 flags &= syminfo->si_flags;
6625088Sab196087 else if (argstate.optmask & SYMINFO_OPT_F_OR)
6635088Sab196087 flags |= syminfo->si_flags;
6645088Sab196087
6655088Sab196087 /* Set the value */
6665088Sab196087 if (syminfo->si_flags == flags) {
6675088Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG,
6685088Sab196087 MSG_INTL(MSG_DEBUG_S_OK),
6695088Sab196087 argstate.syminfo.sec->sec_shndx,
6705088Sab196087 argstate.syminfo.sec->sec_name, ndx, name,
6715088Sab196087 conv_syminfo_flags(syminfo->si_flags,
6725088Sab196087 0, &flags_buf1));
6735088Sab196087 } else {
6745088Sab196087 elfedit_msg(ELFEDIT_MSG_DEBUG,
6755088Sab196087 MSG_INTL(MSG_DEBUG_S_CHG),
6765088Sab196087 argstate.syminfo.sec->sec_shndx,
6775088Sab196087 argstate.syminfo.sec->sec_name, ndx, name,
6785088Sab196087 conv_syminfo_flags(syminfo->si_flags,
6795088Sab196087 0, &flags_buf1),
6805088Sab196087 conv_syminfo_flags(flags, 0, &flags_buf2));
6815088Sab196087 ret = ELFEDIT_CMDRET_MOD;
6825088Sab196087 syminfo->si_flags = flags;
6835088Sab196087 }
6845088Sab196087 }
6855088Sab196087 break;
6865088Sab196087 }
6875088Sab196087
6885088Sab196087 /*
6895088Sab196087 * If we modified the syminfo section, tell libelf.
6905088Sab196087 */
6915088Sab196087 if (ret == ELFEDIT_CMDRET_MOD)
6925088Sab196087 elfedit_modified_data(argstate.syminfo.sec);
6935088Sab196087
6945088Sab196087 /* Do autoprint */
6955088Sab196087 print_syminfo(cmd, 1, &argstate, ndx, 1);
6965088Sab196087
6975088Sab196087 return (ret);
6985088Sab196087 }
6995088Sab196087
7005088Sab196087
7015088Sab196087
7025088Sab196087
7035088Sab196087 /*
7045088Sab196087 * Command completion functions for the various commands
7055088Sab196087 */
7065088Sab196087 /*ARGSUSED*/
7075088Sab196087 static void
cpl_si_boundto(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)7085088Sab196087 cpl_si_boundto(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
7095088Sab196087 const char *argv[], int num_opt)
7105088Sab196087 {
7115088Sab196087 int i;
7125088Sab196087
7135088Sab196087 /*
7145088Sab196087 * If -needed option is not present, the second argument can be
7155088Sab196087 * an SYMINFO_BT_ value.
7165088Sab196087 */
7175088Sab196087 if (argc != (num_opt + 2))
7185088Sab196087 return;
7195088Sab196087
7205088Sab196087 /* Is -needed there? If so, no completion is possible so return */
7215088Sab196087 for (i = 0; i < num_opt; i++)
7225088Sab196087 if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0)
7235088Sab196087 return;
7245088Sab196087
7255088Sab196087 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_BT);
7265088Sab196087 }
7275088Sab196087
7285088Sab196087 /*ARGSUSED*/
7295088Sab196087 static void
cpl_si_flags(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)7305088Sab196087 cpl_si_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
7315088Sab196087 const char *argv[], int num_opt)
7325088Sab196087 {
7335088Sab196087 /* The second argument can be an SYMINFO_FLG_ value */
7345088Sab196087 if (argc == (num_opt + 2))
7355088Sab196087 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_FLG);
7365088Sab196087 }
7375088Sab196087
7385088Sab196087
7395088Sab196087
7405088Sab196087 /*
7415088Sab196087 * Implementation functions for the commands
7425088Sab196087 */
7435088Sab196087 static elfedit_cmdret_t
cmd_dump(elfedit_obj_state_t * obj_state,int argc,const char * argv[])7445088Sab196087 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
7455088Sab196087 {
7465088Sab196087 return (cmd_body(SYMINFO_CMD_T_DUMP, obj_state, argc, argv));
7475088Sab196087 }
7485088Sab196087
7495088Sab196087
7505088Sab196087 static elfedit_cmdret_t
cmd_si_boundto(elfedit_obj_state_t * obj_state,int argc,const char * argv[])7515088Sab196087 cmd_si_boundto(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
7525088Sab196087 {
7535088Sab196087 return (cmd_body(SYMINFO_CMD_T_SI_BOUNDTO, obj_state, argc, argv));
7545088Sab196087 }
7555088Sab196087
7565088Sab196087
7575088Sab196087 static elfedit_cmdret_t
cmd_si_flags(elfedit_obj_state_t * obj_state,int argc,const char * argv[])7585088Sab196087 cmd_si_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
7595088Sab196087 {
7605088Sab196087 return (cmd_body(SYMINFO_CMD_T_SI_FLAGS, obj_state, argc, argv));
7615088Sab196087 }
7625088Sab196087
7635088Sab196087
7645088Sab196087
7655088Sab196087
7665088Sab196087 /*ARGSUSED*/
7675088Sab196087 elfedit_module_t *
elfedit_init(elfedit_module_version_t version)7685088Sab196087 elfedit_init(elfedit_module_version_t version)
7695088Sab196087 {
7705088Sab196087 /* sym:dump */
7715088Sab196087 static const char *name_dump[] = {
7725088Sab196087 MSG_ORIG(MSG_CMD_DUMP),
7735088Sab196087 MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */
7745088Sab196087 NULL
7755088Sab196087 };
7765088Sab196087 static elfedit_cmd_optarg_t opt_dump[] = {
7775088Sab196087 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
7785088Sab196087 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
7795088Sab196087 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
7805088Sab196087 SYMINFO_OPT_F_SYMNDX, 0 },
7815088Sab196087 { NULL }
7825088Sab196087 };
7835088Sab196087 static elfedit_cmd_optarg_t arg_dump[] = {
7845088Sab196087 { MSG_ORIG(MSG_STR_SYM),
7855088Sab196087 /* MSG_INTL(MSG_A1_SYM) */
7865088Sab196087 ELFEDIT_I18NHDL(MSG_A1_SYM),
7875088Sab196087 ELFEDIT_CMDOA_F_OPT },
7885088Sab196087 { NULL }
7895088Sab196087 };
7905088Sab196087
7915088Sab196087 /* sym:si_boundto */
7925088Sab196087 static const char *name_si_boundto[] = {
7935088Sab196087 MSG_ORIG(MSG_CMD_SI_BOUNDTO), NULL };
7945088Sab196087 static elfedit_cmd_optarg_t opt_si_boundto[] = {
7955088Sab196087 { MSG_ORIG(MSG_STR_MINUS_NEEDED),
7965088Sab196087 /* MSG_INTL(MSG_OPTDESC_NEEDED) */
7975088Sab196087 ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED), 0,
7985088Sab196087 SYMINFO_OPT_F_NEEDED, 0 },
7995088Sab196087 { ELFEDIT_STDOA_OPT_O, NULL,
8005088Sab196087 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
8015088Sab196087 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
8025088Sab196087 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
8035088Sab196087 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
8045088Sab196087 SYMINFO_OPT_F_SYMNDX, 0 },
8055088Sab196087 { NULL }
8065088Sab196087 };
8075088Sab196087 static elfedit_cmd_optarg_t arg_si_boundto[] = {
8085088Sab196087 { MSG_ORIG(MSG_STR_SYM),
8095088Sab196087 /* MSG_INTL(MSG_A1_SYM) */
8105088Sab196087 ELFEDIT_I18NHDL(MSG_A1_SYM),
8115088Sab196087 ELFEDIT_CMDOA_F_OPT },
8125088Sab196087 { MSG_ORIG(MSG_STR_VALUE),
8135088Sab196087 /* MSG_INTL(MSG_A2_DESC_SI_BOUNDTO) */
8145088Sab196087 ELFEDIT_I18NHDL(MSG_A2_DESC_SI_BOUNDTO),
8155088Sab196087 ELFEDIT_CMDOA_F_OPT },
8165088Sab196087 { NULL }
8175088Sab196087 };
8185088Sab196087
8195088Sab196087 /* sym:si_flags */
8205088Sab196087 static const char *name_si_flags[] = {
8215088Sab196087 MSG_ORIG(MSG_CMD_SI_FLAGS), NULL };
8225088Sab196087 static elfedit_cmd_optarg_t opt_si_flags[] = {
8235088Sab196087 { ELFEDIT_STDOA_OPT_AND, NULL, ELFEDIT_CMDOA_F_INHERIT,
8245088Sab196087 SYMINFO_OPT_F_AND, SYMINFO_OPT_F_OR },
8255088Sab196087 { ELFEDIT_STDOA_OPT_CMP, NULL,
8265088Sab196087 ELFEDIT_CMDOA_F_INHERIT, SYMINFO_OPT_F_CMP, 0 },
8275088Sab196087 { ELFEDIT_STDOA_OPT_O, NULL,
8285088Sab196087 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
8295088Sab196087 { ELFEDIT_STDOA_OPT_OR, NULL, ELFEDIT_CMDOA_F_INHERIT,
8305088Sab196087 SYMINFO_OPT_F_OR, SYMINFO_OPT_F_AND },
8315088Sab196087 { MSG_ORIG(MSG_STR_MINUS_SYMNDX),
8325088Sab196087 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
8335088Sab196087 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
8345088Sab196087 SYMINFO_OPT_F_SYMNDX, 0 },
8355088Sab196087 { NULL }
8365088Sab196087 };
8375088Sab196087 static elfedit_cmd_optarg_t arg_si_flags[] = {
8385088Sab196087 { MSG_ORIG(MSG_STR_SYM),
8395088Sab196087 /* MSG_INTL(MSG_A1_SYM) */
8405088Sab196087 ELFEDIT_I18NHDL(MSG_A1_SYM),
8415088Sab196087 ELFEDIT_CMDOA_F_OPT },
8425088Sab196087 { MSG_ORIG(MSG_STR_VALUE),
8435088Sab196087 /* MSG_INTL(MSG_A2_DESC_SI_FLAGS) */
8445088Sab196087 ELFEDIT_I18NHDL(MSG_A2_DESC_SI_FLAGS),
8455088Sab196087 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
8465088Sab196087 { NULL }
8475088Sab196087 };
8485088Sab196087
8495088Sab196087 static elfedit_cmd_t cmds[] = {
8505088Sab196087 /* sym:dump */
8515088Sab196087 { cmd_dump, NULL, name_dump,
8525088Sab196087 /* MSG_INTL(MSG_DESC_DUMP) */
8535088Sab196087 ELFEDIT_I18NHDL(MSG_DESC_DUMP),
8545088Sab196087 /* MSG_INTL(MSG_HELP_DUMP) */
8555088Sab196087 ELFEDIT_I18NHDL(MSG_HELP_DUMP),
8565088Sab196087 opt_dump, arg_dump },
8575088Sab196087
8585088Sab196087 /* sym:si_boundto */
8595088Sab196087 { cmd_si_boundto, cpl_si_boundto, name_si_boundto,
8605088Sab196087 /* MSG_INTL(MSG_DESC_SI_BOUNDTO) */
8615088Sab196087 ELFEDIT_I18NHDL(MSG_DESC_SI_BOUNDTO),
8625088Sab196087 /* MSG_INTL(MSG_HELP_SI_BOUNDTO) */
8635088Sab196087 ELFEDIT_I18NHDL(MSG_HELP_SI_BOUNDTO),
8645088Sab196087 opt_si_boundto, arg_si_boundto },
8655088Sab196087
8665088Sab196087 /* sym:si_flags */
8675088Sab196087 { cmd_si_flags, cpl_si_flags, name_si_flags,
8685088Sab196087 /* MSG_INTL(MSG_DESC_SI_FLAGS) */
8695088Sab196087 ELFEDIT_I18NHDL(MSG_DESC_SI_FLAGS),
8705088Sab196087 /* MSG_INTL(MSG_HELP_SI_FLAGS) */
8715088Sab196087 ELFEDIT_I18NHDL(MSG_HELP_SI_FLAGS),
8725088Sab196087 opt_si_flags, arg_si_flags },
8735088Sab196087
8745088Sab196087 { NULL }
8755088Sab196087 };
8765088Sab196087
8775088Sab196087 static elfedit_module_t module = {
8785088Sab196087 ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
8795088Sab196087 /* MSG_INTL(MSG_MOD_DESC) */
8805088Sab196087 ELFEDIT_I18NHDL(MSG_MOD_DESC),
8815088Sab196087 cmds, mod_i18nhdl_to_str };
8825088Sab196087
8835088Sab196087 return (&module);
8845088Sab196087 }
885