Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #define	ELF_TARGET_AMD64	/* SHN_AMD64_LCOMMON */
     28 
     29 #include	<stdio.h>
     30 #include	<unistd.h>
     31 #include	<elfedit.h>
     32 #include	<strings.h>
     33 #include	<debug.h>
     34 #include	<conv.h>
     35 #include	<sym_msg.h>
     36 
     37 
     38 
     39 
     40 #define	MAXNDXSIZE	10
     41 
     42 
     43 
     44 /*
     45  * This module uses shared code for several of the commands.
     46  * It is sometimes necessary to know which specific command
     47  * is active.
     48  */
     49 typedef enum {
     50 	SYM_CMD_T_DUMP =		0,	/* sym:dump */
     51 
     52 	SYM_CMD_T_ST_BIND =		1,	/* sym:st_bind */
     53 	SYM_CMD_T_ST_INFO =		2,	/* sym:st_info */
     54 	SYM_CMD_T_ST_NAME =		3,	/* sym:st_name */
     55 	SYM_CMD_T_ST_OTHER =		4,	/* sym:st_other */
     56 	SYM_CMD_T_ST_SHNDX =		5,	/* sym:st_shndx */
     57 	SYM_CMD_T_ST_SIZE =		6,	/* sym:st_size */
     58 	SYM_CMD_T_ST_TYPE =		7,	/* sym:st_type */
     59 	SYM_CMD_T_ST_VALUE =		8,	/* sym:st_value */
     60 	SYM_CMD_T_ST_VISIBILITY =	9	/* sym:st_visibility */
     61 } SYM_CMD_T;
     62 
     63 
     64 
     65 /*
     66  * ELFCLASS-specific definitions
     67  */
     68 #ifdef _ELF64
     69 
     70 #define	MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_64
     71 
     72 #else
     73 
     74 #define	MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_32
     75 
     76 /*
     77  * We supply this function for the msg module. Only one copy is needed.
     78  */
     79 const char *
     80 _sym_msg(Msg mid)
     81 {
     82 	return (gettext(MSG_ORIG(mid)));
     83 }
     84 
     85 #endif
     86 
     87 
     88 
     89 /*
     90  * This function is supplied to elfedit through our elfedit_module_t
     91  * definition. It translates the opaque elfedit_i18nhdl_t handles
     92  * in our module interface into the actual strings for elfedit to
     93  * use.
     94  *
     95  * note:
     96  *	This module uses Msg codes for its i18n handle type.
     97  *	So the translation is simply to use MSG_INTL() to turn
     98  *	it into a string and return it.
     99  */
    100 static const char *
    101 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
    102 {
    103 	Msg msg = (Msg)hdl;
    104 
    105 	return (MSG_INTL(msg));
    106 }
    107 
    108 
    109 
    110 /*
    111  * The sym_opt_t enum specifies a bit value for every optional
    112  * argument allowed by a command in this module.
    113  */
    114 typedef enum {
    115 	SYM_OPT_F_XSHINDEX =	1,	/* -e: Force shndx update to extended */
    116 					/*	 index section */
    117 	SYM_OPT_F_NAMOFFSET =	2,	/* -name_offset: sym:st_name name arg */
    118 					/*	is numeric offset */
    119 					/* 	rather than ASCII string */
    120 	SYM_OPT_F_SECSHNDX =	4,	/* -secshndx: Section arg is */
    121 					/*	section index, not name */
    122 	SYM_OPT_F_SECSHTYP =	8,	/* -secshtyp: Section arg is */
    123 					/*	section type, not name */
    124 	SYM_OPT_F_SHNAME =	16,	/* -shnam name: section spec. by name */
    125 	SYM_OPT_F_SHNDX =	32,	/* -shndx ndx: section spec. by index */
    126 	SYM_OPT_F_SHTYP =	64,	/* -shtyp type: section spec. by type */
    127 	SYM_OPT_F_SYMNDX =	128	/* -symndx: Sym specified by index */
    128 } sym_opt_t;
    129 
    130 
    131 /*
    132  * A variable of type ARGSTATE is used by each command to maintain
    133  * the overall state for a given set of arguments and the symbol tables
    134  * being managed.
    135  *
    136  * The state for each symbol table and the auxiliary sections that are
    137  * related to it are kept in a SYMSTATE sub-struct.
    138  *
    139  * One benefit of ARGSTATE is that it helps us to ensure that we only
    140  * fetch each section a single time:
    141  *	- More efficient
    142  *	- Prevents multiple ELFEDIT_MSG_DEBUG messages from
    143  *	  being produced for a given section.
    144  *
    145  * note: The symstate array in ARGSTATE is defined as having one
    146  *	element, but in reality, we allocate enough room for
    147  *	the number of elements defined in the numsymstate field.
    148  */
    149 typedef struct {
    150 	Word ndx;	/* If argstate.argc > 0, this is the table index */
    151 	struct {				/* Symbol table */
    152 		elfedit_section_t	*sec;
    153 		Sym			*data;
    154 		Word			n;
    155 	} sym;
    156 	struct {				/* String table */
    157 		elfedit_section_t	*sec;
    158 	} str;
    159 	struct {				/* Versym */
    160 		Word			shndx;
    161 		elfedit_section_t	*sec;
    162 		Versym			*data;
    163 		Word			n;
    164 	} versym;
    165 	struct {				/* Extended section indices */
    166 		Word			shndx;
    167 		elfedit_section_t	*sec;
    168 		Word			*data;
    169 		Word			n;
    170 	} xshndx;
    171 } SYMSTATE;
    172 typedef struct {
    173 	elfedit_obj_state_t	*obj_state;
    174 	sym_opt_t		optmask;   	/* Mask of options used */
    175 	int			argc;		/* # of plain arguments */
    176 	const char		**argv;		/* Plain arguments */
    177 	int			numsymstate;	/* # of items in symstate[] */
    178 	SYMSTATE		symstate[1];	/* Symbol tables to process */
    179 } ARGSTATE;
    180 
    181 
    182 /*
    183  * We maintain the state of each symbol table and related associated
    184  * sections in a SYMSTATE structure . We don't look those auxiliary
    185  * things up unless we actually need them, both to be efficient,
    186  * and to prevent duplicate ELFEDIT_MSG_DEBUG messages from being
    187  * issued as they are located. Hence, process_args() is used to
    188  * initialize the state block with just the symbol table, and then one
    189  * of the argstate_add_XXX() functions is used as needed
    190  * to fetch the additional sections.
    191  *
    192  * entry:
    193  *	argstate - Overall state block
    194  *	symstate - State block for current symbol table.
    195  *
    196  * exit:
    197  *	If the needed auxiliary section is not found, an error is
    198  *	issued and the argstate_add_XXX() routine does not return.
    199  *	Otherwise, the fields in argstate have been filled in, ready
    200  *	for use.
    201  *
    202  */
    203 static void
    204 symstate_add_str(ARGSTATE *argstate, SYMSTATE *symstate)
    205 {
    206 	if (symstate->str.sec != NULL)
    207 		return;
    208 
    209 	symstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
    210 	    symstate->sym.sec->sec_shdr->sh_link, 0);
    211 }
    212 static void
    213 symstate_add_versym(ARGSTATE *argstate, SYMSTATE *symstate)
    214 {
    215 	if (symstate->versym.sec != NULL)
    216 		return;
    217 
    218 	symstate->versym.sec = elfedit_sec_getversym(argstate->obj_state,
    219 	    symstate->sym.sec, &symstate->versym.data, &symstate->versym.n);
    220 }
    221 static void
    222 symstate_add_xshndx(ARGSTATE *argstate, SYMSTATE *symstate)
    223 {
    224 	if (symstate->xshndx.sec != NULL)
    225 		return;
    226 
    227 	symstate->xshndx.sec = elfedit_sec_getxshndx(argstate->obj_state,
    228 	    symstate->sym.sec, &symstate->xshndx.data, &symstate->xshndx.n);
    229 }
    230 
    231 
    232 
    233 /*
    234  * Display symbol table entries in the style used by elfdump.
    235  *
    236  * entry:
    237  *	argstate - Overall state block
    238  *	symstate - State block for current symbol table.
    239  *	ndx - Index of first symbol to display
    240  *	cnt - Number of symbols to display
    241  */
    242 static void
    243 dump_symtab(ARGSTATE *argstate, SYMSTATE *symstate, Word ndx, Word cnt)
    244 {
    245 	char			index[MAXNDXSIZE];
    246 	Word			shndx;
    247 	const char		*shndx_name;
    248 	elfedit_section_t	*symsec;
    249 	elfedit_section_t	*strsec;
    250 	Sym			*sym;
    251 	elfedit_obj_state_t	*obj_state = argstate->obj_state;
    252 	uchar_t			osabi = obj_state->os_ehdr->e_ident[EI_OSABI];
    253 	Half			mach = obj_state->os_ehdr->e_machine;
    254 	const char		*symname;
    255 	Versym			versym;
    256 
    257 	symsec = symstate->sym.sec;
    258 	sym = symstate->sym.data + ndx;
    259 
    260 	symstate_add_str(argstate, symstate);
    261 	strsec = symstate->str.sec;
    262 
    263 	/* If there is a versym index section, fetch it */
    264 	if (symstate->versym.shndx != SHN_UNDEF)
    265 		symstate_add_versym(argstate, symstate);
    266 
    267 	/* If there is an extended index section, fetch it */
    268 	if (symstate->xshndx.shndx != SHN_UNDEF)
    269 		symstate_add_xshndx(argstate, symstate);
    270 
    271 	elfedit_printf(MSG_INTL(MSG_FMT_SYMTAB), symsec->sec_name);
    272 	Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
    273 	for (; cnt-- > 0; ndx++, sym++) {
    274 		(void) snprintf(index, MAXNDXSIZE,
    275 		    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx));
    276 		versym = (symstate->versym.sec == NULL) ? 0 :
    277 		    symstate->versym.data[ndx];
    278 		symname = elfedit_offset_to_str(strsec, sym->st_name,
    279 		    ELFEDIT_MSG_DEBUG, 0);
    280 		shndx = sym->st_shndx;
    281 		if ((shndx == SHN_XINDEX) && (symstate->xshndx.sec != NULL))
    282 			shndx = symstate->xshndx.data[ndx];
    283 		shndx_name = elfedit_shndx_to_name(obj_state, shndx);
    284 		Elf_syms_table_entry(NULL, ELF_DBG_ELFDUMP, index, osabi, mach,
    285 		    sym, versym, 0, shndx_name, symname);
    286 	}
    287 }
    288 
    289 
    290 
    291 /*
    292  * Called by print_sym() to determine if a given symbol has the same
    293  * display value for the current command in every symbol table.
    294  *
    295  * entry:
    296  *	cmd - SYM_CMD_T_* value giving identify of caller
    297  *	argstate - Overall state block
    298  *	outstyle - Output style to use
    299  */
    300 static int
    301 all_same(SYM_CMD_T cmd, ARGSTATE *argstate, elfedit_outstyle_t outstyle)
    302 {
    303 	Word			tblndx;
    304 	SYMSTATE		*symstate1, *symstate2;
    305 	Sym			*sym1, *sym2;
    306 
    307 	symstate1 = argstate->symstate;
    308 	for (tblndx = 0; tblndx < (argstate->numsymstate - 1);
    309 	    tblndx++, symstate1++) {
    310 		symstate2 = symstate1 + 1;
    311 		sym1 = &symstate1->sym.data[symstate1->ndx];
    312 		sym2 = &symstate2->sym.data[symstate2->ndx];
    313 
    314 		switch (cmd) {
    315 		case SYM_CMD_T_DUMP:
    316 			/* sym:dump should always show everything */
    317 			return (0);
    318 
    319 		case SYM_CMD_T_ST_BIND:
    320 			if (ELF_ST_BIND(sym1->st_info) !=
    321 			    ELF_ST_BIND(sym2->st_info))
    322 				return (0);
    323 			break;
    324 
    325 		case SYM_CMD_T_ST_INFO:
    326 			if (sym1->st_info !=  sym2->st_info)
    327 				return (0);
    328 			break;
    329 
    330 		case SYM_CMD_T_ST_NAME:
    331 			/*
    332 			 * In simple output mode, we show the string. In
    333 			 * numeric mode, we show the string table offset.
    334 			 */
    335 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    336 				const char *n1, *n2;
    337 
    338 				symstate_add_str(argstate, symstate1);
    339 				symstate_add_str(argstate, symstate2);
    340 				n1 = elfedit_offset_to_str(symstate1->str.sec,
    341 				    sym1->st_name, ELFEDIT_MSG_DEBUG, 0);
    342 				n2 = elfedit_offset_to_str(symstate2->str.sec,
    343 				    sym2->st_name, ELFEDIT_MSG_DEBUG, 0);
    344 				if (strcmp(n1, n2) != 0)
    345 					return (0);
    346 			} else {
    347 				if (sym1->st_name !=  sym2->st_name)
    348 					return (0);
    349 			}
    350 			break;
    351 
    352 		case SYM_CMD_T_ST_OTHER:
    353 			if (sym1->st_other !=  sym2->st_other)
    354 				return (0);
    355 			break;
    356 
    357 		case SYM_CMD_T_ST_SHNDX:
    358 			{
    359 				Word	ndx1, ndx2;
    360 
    361 				ndx1 = sym1->st_shndx;
    362 				if ((ndx1 == SHN_XINDEX) &&
    363 				    (symstate1->xshndx.shndx != SHN_UNDEF)) {
    364 					symstate_add_xshndx(argstate,
    365 					    symstate1);
    366 					ndx1 = symstate1->xshndx.
    367 					    data[symstate1->ndx];
    368 				}
    369 				ndx2 = sym2->st_shndx;
    370 				if ((ndx2 == SHN_XINDEX) &&
    371 				    (symstate2->xshndx.shndx != SHN_UNDEF)) {
    372 					symstate_add_xshndx(argstate,
    373 					    symstate2);
    374 					ndx2 = symstate2->xshndx.
    375 					    data[symstate2->ndx];
    376 				}
    377 				if (ndx1 !=  ndx2)
    378 					return (0);
    379 			}
    380 			break;
    381 
    382 		case SYM_CMD_T_ST_SIZE:
    383 			if (sym1->st_size !=  sym2->st_size)
    384 				return (0);
    385 			break;
    386 
    387 		case SYM_CMD_T_ST_TYPE:
    388 			if (ELF_ST_TYPE(sym1->st_info) !=
    389 			    ELF_ST_TYPE(sym2->st_info))
    390 				return (0);
    391 			break;
    392 
    393 		case SYM_CMD_T_ST_VALUE:
    394 			if (sym1->st_value !=  sym2->st_value)
    395 				return (0);
    396 			break;
    397 
    398 		case SYM_CMD_T_ST_VISIBILITY:
    399 			if (ELF_ST_VISIBILITY(sym1->st_info) !=
    400 			    ELF_ST_VISIBILITY(sym2->st_info))
    401 				return (0);
    402 			break;
    403 		}
    404 	}
    405 
    406 	/* If we got here, there are no differences (or maybe only 1 table */
    407 	return (1);
    408 }
    409 
    410 
    411 /*
    412  * Called by print_sym() to display values for a single symbol table.
    413  *
    414  * entry:
    415  *	autoprint - If True, output is only produced if the elfedit
    416  *		autoprint flag is set. If False, output is always produced.
    417  *	cmd - SYM_CMD_T_* value giving identify of caller
    418  *	argstate - Overall state block
    419  *	symstate - State block for current symbol table.
    420  *	ndx - Index of first symbol to display
    421  *	cnt - Number of symbols to display
    422  */
    423 static void
    424 print_symstate(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate,
    425     elfedit_outstyle_t outstyle, Word ndx, Word cnt)
    426 {
    427 	Word	value;
    428 	Sym	*sym;
    429 
    430 	/*
    431 	 * If doing default output, use elfdump style where we
    432 	 * show all symbol attributes. In this case, the command
    433 	 * that called us doesn't matter
    434 	 */
    435 	if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
    436 		dump_symtab(argstate, symstate, ndx, cnt);
    437 		return;
    438 	}
    439 
    440 	sym = symstate->sym.data;
    441 
    442 	switch (cmd) {
    443 	case SYM_CMD_T_ST_BIND:
    444 		{
    445 			Conv_inv_buf_t inv_buf;
    446 
    447 			for (sym += ndx; cnt--; sym++) {
    448 				value = ELF_ST_BIND(sym->st_info);
    449 				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    450 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    451 					    conv_sym_info_bind(value,
    452 					    CONV_FMT_ALT_CF, &inv_buf));
    453 				} else {
    454 					elfedit_printf(
    455 					    MSG_ORIG(MSG_FMT_WORDVALNL),
    456 					    EC_WORD(value));
    457 				}
    458 			}
    459 		}
    460 		return;
    461 
    462 	case SYM_CMD_T_ST_INFO:
    463 		for (sym += ndx; cnt-- > 0; sym++)
    464 			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
    465 			    EC_WORD(sym->st_info));
    466 		return;
    467 
    468 	case SYM_CMD_T_ST_NAME:
    469 		/*
    470 		 * In simple output mode, we show the string. In numeric
    471 		 * mode, we show the string table offset.
    472 		 */
    473 		if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    474 			symstate_add_str(argstate, symstate);
    475 			for (sym += ndx; cnt--; sym++) {
    476 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    477 				    elfedit_offset_to_str(symstate->str.sec,
    478 				    sym->st_name, ELFEDIT_MSG_ERR, 0));
    479 			}
    480 		} else {
    481 			for (; cnt--; sym++)
    482 				elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
    483 				    EC_WORD(sym->st_name));
    484 		}
    485 		return;
    486 
    487 	case SYM_CMD_T_ST_OTHER:
    488 		for (sym += ndx; cnt-- > 0; sym++)
    489 			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
    490 			    EC_WORD(sym->st_other));
    491 		return;
    492 
    493 	case SYM_CMD_T_ST_SHNDX:
    494 		/* If there is an extended index section, fetch it */
    495 		if (symstate->xshndx.shndx != SHN_UNDEF)
    496 			symstate_add_xshndx(argstate, symstate);
    497 
    498 		for (; cnt--; ndx++) {
    499 			value = sym[ndx].st_shndx;
    500 			if ((value == SHN_XINDEX) &&
    501 			    (symstate->xshndx.sec != NULL))
    502 				value = symstate->xshndx.data[ndx];
    503 
    504 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    505 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    506 				    elfedit_shndx_to_name(argstate->obj_state,
    507 				    value));
    508 			} else {
    509 				elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
    510 				    EC_WORD(value));
    511 			}
    512 		}
    513 		return;
    514 
    515 	case SYM_CMD_T_ST_SIZE:
    516 		/*
    517 		 * machine word width integers displayed in fixed width
    518 		 * 0-filled hex format.
    519 		 */
    520 		for (sym += ndx; cnt--; sym++)
    521 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL),
    522 			    sym->st_size);
    523 		return;
    524 
    525 	case SYM_CMD_T_ST_TYPE:
    526 		{
    527 			Half mach = argstate->obj_state->os_ehdr->e_machine;
    528 			Conv_inv_buf_t inv_buf;
    529 
    530 			for (sym += ndx; cnt--; sym++) {
    531 				value = ELF_ST_TYPE(sym->st_info);
    532 				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    533 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    534 					    conv_sym_info_type(mach, value,
    535 					    CONV_FMT_ALT_CF, &inv_buf));
    536 				} else {
    537 					elfedit_printf(
    538 					    MSG_ORIG(MSG_FMT_WORDVALNL),
    539 					    EC_WORD(value));
    540 				}
    541 			}
    542 		}
    543 		return;
    544 
    545 	case SYM_CMD_T_ST_VALUE:
    546 		/*
    547 		 * machine word width integers displayed in fixed width
    548 		 * 0-filled hex format.
    549 		 */
    550 		for (sym += ndx; cnt--; sym++)
    551 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL),
    552 			    sym->st_value);
    553 		return;
    554 
    555 	case SYM_CMD_T_ST_VISIBILITY:
    556 		{
    557 			Conv_inv_buf_t inv_buf;
    558 
    559 			for (sym += ndx; cnt--; sym++) {
    560 				value = ELF_ST_VISIBILITY(sym->st_other);
    561 				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    562 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    563 					    conv_sym_other_vis(value,
    564 					    CONV_FMT_ALT_CF, &inv_buf));
    565 				} else {
    566 					elfedit_printf(
    567 					    MSG_ORIG(MSG_FMT_WORDVALNL),
    568 					    EC_WORD(value));
    569 				}
    570 			}
    571 		}
    572 		return;
    573 
    574 	}
    575 }
    576 
    577 
    578 /*
    579  * Print symbol values, taking the calling command, and output style
    580  * into account.
    581  *
    582  * entry:
    583  *	autoprint - If True, output is only produced if the elfedit
    584  *		autoprint flag is set. If False, output is always produced.
    585  *	cmd - SYM_CMD_T_* value giving identify of caller
    586  *	argstate - Overall state block
    587  *	symstate - State block for current symbol table.
    588  *	ndx - Index of first symbol to display
    589  *	cnt - Number of symbols to display
    590  */
    591 static void
    592 print_sym(SYM_CMD_T cmd, int autoprint, ARGSTATE *argstate)
    593 {
    594 	Word			ndx, tblndx;
    595 	Word			cnt;
    596 	elfedit_outstyle_t	outstyle;
    597 	SYMSTATE		*symstate;
    598 	int			only_one;
    599 
    600 	if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)))
    601 		return;
    602 
    603 	/*
    604 	 * Pick an output style. sym:dump is required to use the default
    605 	 * style. The other commands use the current output style.
    606 	 */
    607 	outstyle = (cmd == SYM_CMD_T_DUMP) ?
    608 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
    609 
    610 	/*
    611 	 * This is a nicity: Force any needed auxiliary sections to be
    612 	 * fetched here before any output is produced. This will put all
    613 	 * of the debug messages right at the top in a single cluster.
    614 	 */
    615 	symstate = argstate->symstate;
    616 	for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) {
    617 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
    618 			symstate_add_str(argstate, symstate);
    619 			if (symstate->versym.shndx != SHN_UNDEF)
    620 				symstate_add_versym(argstate, symstate);
    621 			if (symstate->xshndx.shndx != SHN_UNDEF)
    622 				symstate_add_xshndx(argstate, symstate);
    623 			continue;
    624 		}
    625 
    626 		if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    627 			switch (cmd) {
    628 			case SYM_CMD_T_ST_NAME:
    629 				symstate_add_str(argstate, symstate);
    630 				break;
    631 
    632 			case SYM_CMD_T_ST_SHNDX:
    633 				if (symstate->xshndx.shndx != SHN_UNDEF)
    634 					symstate_add_xshndx(argstate, symstate);
    635 				break;
    636 			}
    637 		}
    638 	}
    639 
    640 	/*
    641 	 * If there is more than one table, we are displaying a single
    642 	 * item, we are not using the default "elfdump" style, and all
    643 	 * the symbols have the same value for the thing we intend to
    644 	 * display, then we only want to display it once.
    645 	 */
    646 	only_one = (argstate->numsymstate > 1) && (argstate->argc > 0) &&
    647 	    (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) &&
    648 	    all_same(cmd, argstate, outstyle);
    649 
    650 	/* Run through the tables and display from each one */
    651 	symstate = argstate->symstate;
    652 	for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) {
    653 		if (argstate->argc == 0) {
    654 			ndx = 0;
    655 			cnt = symstate->sym.n;
    656 		} else {
    657 			ndx = symstate->ndx;
    658 			cnt = 1;
    659 		}
    660 
    661 		if ((tblndx > 0) && ((argstate->argc == 0) ||
    662 		    (outstyle == ELFEDIT_OUTSTYLE_DEFAULT)))
    663 			elfedit_printf(MSG_ORIG(MSG_STR_NL));
    664 
    665 		print_symstate(cmd, argstate, symstate, outstyle, ndx, cnt);
    666 		if (only_one)
    667 			break;
    668 	}
    669 }
    670 
    671 
    672 /*
    673  * The cmd_body_set_st_XXX() functions are for use by cmd_body().
    674  * They handle the case where the second plain argument is
    675  * a value to be stored in the symbol.
    676  *
    677  * entry:
    678  *	argstate - Overall state block
    679  *	symstate - State block for current symbol table.
    680  */
    681 static elfedit_cmdret_t
    682 cmd_body_set_st_bind(ARGSTATE *argstate, SYMSTATE *symstate)
    683 {
    684 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
    685 	Sym			*sym = &symstate->sym.data[symstate->ndx];
    686 	Word			gbl_ndx;
    687 	uchar_t			bind, type, old_bind;
    688 	Word			symndx;
    689 	Conv_inv_buf_t		inv_buf1, inv_buf2;
    690 
    691 	/*
    692 	 * Use the ELF_ST_BIND() macro to access the defined bits
    693 	 * of the st_info field related to symbol binding.
    694 	 * Accepts STB_ symbolic names as well as integers.
    695 	 */
    696 	bind = elfedit_atoconst_range(argstate->argv[1],
    697 	    MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STB);
    698 	old_bind = ELF_ST_BIND(sym->st_info);
    699 	type = ELF_ST_TYPE(sym->st_info);
    700 
    701 	if (old_bind == bind) {
    702 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
    703 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    704 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND),
    705 		    conv_sym_info_bind(bind, CONV_FMT_ALT_CF, &inv_buf1));
    706 	} else {
    707 		/*
    708 		 * The sh_info field of the symbol table section header
    709 		 * gives the index of the first non-local symbol in
    710 		 * the table. Issue warnings if the binding we set
    711 		 * contradicts this.
    712 		 */
    713 		gbl_ndx = symstate->sym.sec->sec_shdr->sh_info;
    714 		symndx = symstate->sym.sec->sec_shndx;
    715 		if ((bind == STB_LOCAL) && (symstate->ndx >= gbl_ndx))
    716 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    717 			    MSG_INTL(MSG_DEBUG_LBINDGSYM),
    718 			    EC_WORD(symndx), symstate->sym.sec->sec_name,
    719 			    symstate->ndx, EC_WORD(symndx), gbl_ndx);
    720 		if ((bind != STB_LOCAL) && (symstate->ndx < gbl_ndx))
    721 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    722 			    MSG_INTL(MSG_DEBUG_GBINDLSYM),
    723 			    EC_WORD(symndx), symstate->sym.sec->sec_name,
    724 			    symstate->ndx, EC_WORD(symndx), gbl_ndx);
    725 
    726 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
    727 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    728 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND),
    729 		    conv_sym_info_bind(old_bind, CONV_FMT_ALT_CF,
    730 		    &inv_buf1),
    731 		    conv_sym_info_bind(bind, CONV_FMT_ALT_CF, &inv_buf2));
    732 		ret = ELFEDIT_CMDRET_MOD;
    733 		sym->st_info = ELF_ST_INFO(bind, type);
    734 	}
    735 
    736 	return (ret);
    737 }
    738 
    739 static elfedit_cmdret_t
    740 cmd_body_set_st_name(ARGSTATE *argstate, SYMSTATE *symstate)
    741 {
    742 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
    743 	Sym			*sym = &symstate->sym.data[symstate->ndx];
    744 	Word	str_offset;
    745 
    746 	/*
    747 	 * If -n was specified, this is an offset into the string
    748 	 * table. Otherwise it is a string we need to turn into
    749 	 * an offset
    750 	 */
    751 	symstate_add_str(argstate, symstate);
    752 	if (argstate->optmask & SYM_OPT_F_NAMOFFSET) {
    753 		str_offset = elfedit_atoui(argstate->argv[1], NULL);
    754 		/* Warn if the offset is out of range */
    755 		(void) elfedit_offset_to_str(symstate->str.sec,
    756 		    str_offset, ELFEDIT_MSG_DEBUG, 1);
    757 	} else {
    758 		str_offset = elfedit_strtab_insert(argstate->obj_state,
    759 		    symstate->str.sec, NULL, argstate->argv[1]);
    760 	}
    761 
    762 	if (sym->st_name == str_offset) {
    763 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_OK),
    764 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    765 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME),
    766 		    EC_WORD(sym->st_name));
    767 	} else {
    768 		/*
    769 		 * Warn the user: Changing the name of a symbol in the dynsym
    770 		 * will break the hash table in this object.
    771 		 */
    772 		if (symstate->sym.sec->sec_shdr->sh_type == SHT_DYNSYM)
    773 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    774 			    MSG_INTL(MSG_DEBUG_DYNSYMNAMCHG),
    775 			    EC_WORD(symstate->sym.sec->sec_shndx),
    776 			    symstate->sym.sec->sec_name,
    777 			    EC_WORD(symstate->ndx));
    778 
    779 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_CHG),
    780 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    781 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME),
    782 		    EC_WORD(sym->st_name),
    783 		    EC_WORD(str_offset));
    784 		ret = ELFEDIT_CMDRET_MOD;
    785 		sym->st_name = str_offset;
    786 	}
    787 
    788 	return (ret);
    789 }
    790 
    791 static elfedit_cmdret_t
    792 cmd_body_set_st_shndx(ARGSTATE *argstate, SYMSTATE *symstate)
    793 {
    794 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
    795 	Sym			*sym = &symstate->sym.data[symstate->ndx];
    796 	Word	shndx, st_shndx, xshndx;
    797 	int	use_xshndx;
    798 	int	shndx_chg, xshndx_chg;
    799 
    800 
    801 	/*
    802 	 * By default, the sec argument is a section name. If -secshndx was
    803 	 * specified, it is a section index, and if -secshtyp is specified,
    804 	 * it is a section type.
    805 	 */
    806 	if (argstate->optmask & SYM_OPT_F_SECSHNDX)
    807 		shndx = elfedit_atoshndx(argstate->argv[1],
    808 		    argstate->obj_state->os_shnum);
    809 	else if (argstate->optmask & SYM_OPT_F_SECSHTYP)
    810 		shndx = elfedit_type_to_shndx(argstate->obj_state,
    811 		    elfedit_atoconst(argstate->argv[1], ELFEDIT_CONST_SHT));
    812 	else
    813 		shndx = elfedit_name_to_shndx(argstate->obj_state,
    814 		    argstate->argv[1]);
    815 
    816 	/*
    817 	 * We want to use an extended index section if the index is too
    818 	 * large to be represented otherwise, or if the caller specified
    819 	 * the -e option to make us do it anyway. However, we cannot
    820 	 * do this if the index is in the special reserved range between
    821 	 * SHN_LORESERVE and SHN_HIRESERVE.
    822 	 */
    823 	use_xshndx = (shndx > SHN_HIRESERVE) ||
    824 	    ((shndx < SHN_LORESERVE) &&
    825 	    (argstate->optmask & SYM_OPT_F_XSHINDEX));
    826 
    827 	/*
    828 	 * There are two cases where we have to touch the extended
    829 	 * index section:
    830 	 *
    831 	 *	1) We have determined that we need to, as determined above.
    832 	 *	2) We do not require it, but the file has an extended
    833 	 *		index section, in which case we should set the slot
    834 	 *		in that extended section to SHN_UNDEF (0).
    835 	 *
    836 	 * Fetch the extended section as required, and determine the values
    837 	 * for st_shndx and the extended section slot.
    838 	 */
    839 	if (use_xshndx) {
    840 		/* We must have an extended index section, or error out */
    841 		symstate_add_xshndx(argstate, symstate);
    842 
    843 		/* Set symbol to SHN_XINDEX, put index in the extended sec. */
    844 		st_shndx = SHN_XINDEX;
    845 		xshndx = shndx;
    846 	} else {
    847 		st_shndx = shndx;
    848 		xshndx = SHN_UNDEF;
    849 		if (symstate->xshndx.shndx != SHN_UNDEF)
    850 			use_xshndx = 1;
    851 	}
    852 	if (use_xshndx)
    853 		symstate_add_xshndx(argstate, symstate);
    854 	shndx_chg = (sym->st_shndx != st_shndx);
    855 	xshndx_chg = use_xshndx &&
    856 	    (symstate->xshndx.data[symstate->ndx] != xshndx);
    857 
    858 
    859 	/* If anything is going to change, issue appropiate warnings */
    860 	if (shndx_chg || xshndx_chg) {
    861 		/*
    862 		 * Setting the first symbol to anything other than SHN_UNDEF
    863 		 * produces a bad ELF file.
    864 		 */
    865 		if ((symstate->ndx == 0) && (shndx != SHN_UNDEF))
    866 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    867 			    MSG_INTL(MSG_DEBUG_SHNDX_UNDEF0));
    868 
    869 		/*
    870 		 * Setting SHN_XINDEX directly, instead of providing
    871 		 * an extended index and letting us decide to use
    872 		 * SHN_XINDEX to implement it, is probably a mistake.
    873 		 * Issue a warning, but go ahead and follow the directions
    874 		 * we've been given.
    875 		 */
    876 		if (shndx == SHN_XINDEX)
    877 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    878 			    MSG_INTL(MSG_DEBUG_SHNDX_XINDEX));
    879 
    880 		/*
    881 		 * If the section index can fit in the symbol, but
    882 		 * -e is being used to force it into the extended
    883 		 * index section, issue a warning.
    884 		 */
    885 		if (use_xshndx && (shndx < SHN_LORESERVE) &&
    886 		    (st_shndx == SHN_XINDEX))
    887 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    888 			    MSG_INTL(MSG_DEBUG_SHNDX_EFORCE),
    889 			    EC_WORD(symstate->sym.sec->sec_shndx),
    890 			    symstate->sym.sec->sec_name, EC_WORD(symstate->ndx),
    891 			    EC_WORD(shndx));
    892 	}
    893 
    894 	if (shndx_chg) {
    895 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
    896 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    897 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX),
    898 		    elfedit_shndx_to_name(argstate->obj_state,
    899 		    sym->st_shndx),
    900 		    elfedit_shndx_to_name(argstate->obj_state, st_shndx));
    901 		ret = ELFEDIT_CMDRET_MOD;
    902 		sym->st_shndx = st_shndx;
    903 	} else {
    904 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
    905 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    906 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX),
    907 		    elfedit_shndx_to_name(argstate->obj_state, st_shndx));
    908 	}
    909 
    910 	if (use_xshndx) {
    911 		if (xshndx_chg) {
    912 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    913 			    MSG_INTL(MSG_DEBUG_EXT_S_CHG),
    914 			    symstate->xshndx.sec->sec_shndx,
    915 			    symstate->xshndx.sec->sec_name,
    916 			    EC_WORD(symstate->ndx),
    917 			    elfedit_shndx_to_name(argstate->obj_state,
    918 			    symstate->xshndx.data[symstate->ndx]),
    919 			    elfedit_shndx_to_name(argstate->obj_state, xshndx));
    920 			ret = ELFEDIT_CMDRET_MOD;
    921 			symstate->xshndx.data[symstate->ndx] = xshndx;
    922 			elfedit_modified_data(symstate->xshndx.sec);
    923 		} else {
    924 			elfedit_msg(ELFEDIT_MSG_DEBUG,
    925 			    MSG_INTL(MSG_DEBUG_EXT_S_OK),
    926 			    symstate->xshndx.sec->sec_shndx,
    927 			    symstate->xshndx.sec->sec_name,
    928 			    EC_WORD(symstate->ndx),
    929 			    elfedit_shndx_to_name(argstate->obj_state, xshndx));
    930 		}
    931 	}
    932 
    933 	return (ret);
    934 }
    935 
    936 static elfedit_cmdret_t
    937 cmd_body_set_st_type(ARGSTATE *argstate, SYMSTATE *symstate)
    938 {
    939 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
    940 	Conv_inv_buf_t	inv_buf1, inv_buf2;
    941 	Half		mach = argstate->obj_state->os_ehdr->e_machine;
    942 	Sym		*sym = &symstate->sym.data[symstate->ndx];
    943 	uchar_t		bind, type, old_type;
    944 
    945 	/*
    946 	 * Use the ELF_ST_TYPE() macro to access the defined bits
    947 	 * of the st_info field related to symbol type.
    948 	 * Accepts STT_ symbolic names as well as integers.
    949 	 */
    950 	bind = ELF_ST_BIND(sym->st_info);
    951 	type = elfedit_atoconst_range(argstate->argv[1],
    952 	    MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STT);
    953 	old_type = ELF_ST_TYPE(sym->st_info);
    954 
    955 	if (old_type == type) {
    956 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
    957 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    958 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE),
    959 		    conv_sym_info_type(mach, type, CONV_FMT_ALT_CF,
    960 		    &inv_buf1));
    961 	} else {
    962 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
    963 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    964 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE),
    965 		    conv_sym_info_type(mach, old_type, CONV_FMT_ALT_CF,
    966 		    &inv_buf1),
    967 		    conv_sym_info_type(mach, type, CONV_FMT_ALT_CF,
    968 		    &inv_buf2));
    969 		ret = ELFEDIT_CMDRET_MOD;
    970 		sym->st_info = ELF_ST_INFO(bind, type);
    971 	}
    972 
    973 	return (ret);
    974 }
    975 
    976 static elfedit_cmdret_t
    977 cmd_body_set_st_visibility(ARGSTATE *argstate, SYMSTATE *symstate)
    978 {
    979 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
    980 	Conv_inv_buf_t	inv_buf1, inv_buf2;
    981 	Sym		*sym = &symstate->sym.data[symstate->ndx];
    982 	uchar_t		st_other = sym->st_other;
    983 	uchar_t		vis, old_vis;
    984 
    985 	/*
    986 	 * Use the ELF_ST_VISIBILITY() macro to access the
    987 	 * defined bits of the st_other field related to symbol
    988 	 * visibility. Accepts STV_ symbolic names as well as integers.
    989 	 */
    990 	vis = elfedit_atoconst_range(argstate->argv[1],
    991 	    MSG_INTL(MSG_ARG_SYMVIS), 0, STV_ELIMINATE, ELFEDIT_CONST_STV);
    992 	old_vis = st_other & MSK_SYM_VISIBILITY;
    993 
    994 	if (old_vis == vis) {
    995 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
    996 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
    997 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY),
    998 		    conv_sym_other_vis(old_vis, CONV_FMT_ALT_CF,
    999 		    &inv_buf1));
   1000 	} else {
   1001 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
   1002 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
   1003 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY),
   1004 		    conv_sym_other_vis(old_vis, CONV_FMT_ALT_CF,
   1005 		    &inv_buf1),
   1006 		    conv_sym_other_vis(vis, CONV_FMT_ALT_CF, &inv_buf2));
   1007 		ret = ELFEDIT_CMDRET_MOD;
   1008 		st_other = (st_other & ~MSK_SYM_VISIBILITY) |
   1009 		    ELF_ST_VISIBILITY(vis);
   1010 		sym->st_other = st_other;
   1011 	}
   1012 
   1013 	return (ret);
   1014 }
   1015 
   1016 
   1017 /*
   1018  * Standard argument processing for sym module
   1019  *
   1020  * entry
   1021  *	obj_state, argc, argv - Standard command arguments
   1022  *	optmask - Mask of allowed optional arguments.
   1023  *	symstate - State block for current symbol table.
   1024  *	argstate - Address of ARGSTATE block to be initialized
   1025  *
   1026  * exit:
   1027  *	On success, *argstate is initialized. On error,
   1028  *	an error is issued and this routine does not return.
   1029  *
   1030  * note:
   1031  *	Only the basic symbol table is initially referenced by
   1032  *	argstate. Use the argstate_add_XXX() routines below to
   1033  *	access any auxiliary sections needed.
   1034  */
   1035 static ARGSTATE *
   1036 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
   1037     SYM_CMD_T cmd)
   1038 {
   1039 	/*
   1040 	 * We reuse this same argstate, resizing it to the required
   1041 	 * number of symbol tables on the first call, and as necessary.
   1042 	 */
   1043 	static ARGSTATE *argstate;
   1044 	static int argstate_size = 0;
   1045 
   1046 	elfedit_getopt_state_t	getopt_state;
   1047 	elfedit_getopt_ret_t	*getopt_ret;
   1048 	elfedit_symtab_t	*symtab;
   1049 	int		explicit = 0;
   1050 	int		got_sym = 0;
   1051 	Word		index;
   1052 	Word		tblndx;
   1053 	size_t		size;
   1054 	SYMSTATE	*symstate;
   1055 
   1056 	/* If there are no symbol tables, we can't do a thing */
   1057 	if (obj_state->os_symtabnum == 0)
   1058 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB));
   1059 
   1060 	/* Calulate required size of argstate and realloc as necessary */
   1061 	size = sizeof (ARGSTATE) +
   1062 	    ((obj_state->os_symtabnum - 1) * sizeof (SYMSTATE));
   1063 	if (argstate_size != size) {
   1064 		argstate = elfedit_realloc(MSG_INTL(MSG_ALLOC_ARGSTATE),
   1065 		    argstate, size);
   1066 		argstate_size = size;
   1067 	}
   1068 	bzero(argstate, argstate_size);
   1069 	argstate->obj_state = obj_state;
   1070 
   1071 	elfedit_getopt_init(&getopt_state, &argc, &argv);
   1072 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
   1073 		argstate->optmask |= getopt_ret->gor_idmask;
   1074 		switch (getopt_ret->gor_idmask) {
   1075 		case SYM_OPT_F_SHNAME:		/* -shnam name */
   1076 			index = elfedit_name_to_shndx(obj_state,
   1077 			    getopt_ret->gor_value);
   1078 			explicit = 1;
   1079 			break;
   1080 
   1081 		case SYM_OPT_F_SHNDX:		/* -shndx index */
   1082 			index = elfedit_atoui_range(getopt_ret->gor_value,
   1083 			    MSG_INTL(MSG_ARG_SECNDX), 1,
   1084 			    obj_state->os_shnum - 1, NULL);
   1085 			explicit = 1;
   1086 			break;
   1087 
   1088 		case SYM_OPT_F_SHTYP:		/* -shtyp type */
   1089 			index = elfedit_type_to_shndx(obj_state,
   1090 			    elfedit_atoconst(getopt_ret->gor_value,
   1091 			    ELFEDIT_CONST_SHT));
   1092 			explicit = 1;
   1093 			break;
   1094 		}
   1095 	}
   1096 
   1097 	/*
   1098 	 * Usage error if there are too many plain arguments. sym:dump accepts
   1099 	 * a single argument, while the others accept 2.
   1100 	 */
   1101 	if (((cmd == SYM_CMD_T_DUMP) && (argc > 1)) || (argc > 2))
   1102 		elfedit_command_usage();
   1103 
   1104 	/*
   1105 	 * If the -symndx option was specified, the sym arg is an index
   1106 	 * into the symbol table. In this case, the symbol table must be
   1107 	 * explicitly specified (-shnam, -shndx, or -shtype).
   1108 	 */
   1109 	if ((argstate->optmask & SYM_OPT_F_SYMNDX) && !explicit)
   1110 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NEEDEXPSYMTAB));
   1111 
   1112 	/*
   1113 	 * If a section was explicitly specified, it must be a symbol table.
   1114 	 */
   1115 	if (explicit)
   1116 		(void) elfedit_sec_issymtab(obj_state,
   1117 		    &obj_state->os_secarr[index], 1, NULL);
   1118 
   1119 	/* If there may be an arbitrary amount of output, use a pager */
   1120 	if (argc == 0)
   1121 		elfedit_pager_init();
   1122 
   1123 	/* Return the updated values of argc/argv */
   1124 	argstate->argc = argc;
   1125 	argstate->argv = argv;
   1126 
   1127 	/*
   1128 	 * Decide which symbol table(s) to use. Set up the symstate
   1129 	 * array to contain them:
   1130 	 *	- If a symbol table was explicitly specified, we use
   1131 	 *		it, and only it.
   1132 	 *	- If no symbol table is explicitly specified, and the symbol
   1133 	 *		is given by name, we use all symbol tables that
   1134 	 *		contain a symbol with that name, throwing an error
   1135 	 *		if there isn't at least 1 such table.
   1136 	 *	- If no symbol table is specified, and no symbol is specified,
   1137 	 *		we use all the tables.
   1138 	 */
   1139 	symtab = obj_state->os_symtab;
   1140 	symstate = argstate->symstate;
   1141 	for (tblndx = 0; tblndx < obj_state->os_symtabnum;
   1142 	    tblndx++, symtab++) {
   1143 		/*
   1144 		 * If an explicit table is specified, only that table is
   1145 		 * considered.
   1146 		 *
   1147 		 * If no explicit table is specified, verify that table
   1148 		 * is considered to be a symbol table by the current osabi,
   1149 		 * and quietly skip it if not.
   1150 		 */
   1151 		if (explicit) {
   1152 			if (symtab->symt_shndx != index)
   1153 				continue;
   1154 		} else if (elfedit_sec_issymtab(obj_state,
   1155 		    &obj_state->os_secarr[symtab->symt_shndx], 0, NULL) == 0) {
   1156 			continue;
   1157 		}
   1158 
   1159 		symstate->sym.sec = elfedit_sec_getsymtab(obj_state, 1,
   1160 		    symtab->symt_shndx, NULL, &symstate->sym.data,
   1161 		    &symstate->sym.n, &symtab);
   1162 		symstate->versym.shndx = symtab->symt_versym;
   1163 		symstate->xshndx.shndx = symtab->symt_xshndx;
   1164 		if (argc > 0) {
   1165 			if (argstate->optmask & SYM_OPT_F_SYMNDX) {
   1166 				symstate->ndx = elfedit_atoui_range(
   1167 				    argstate->argv[0], MSG_INTL(MSG_ARG_SYM), 0,
   1168 				    symstate->sym.n - 1, NULL);
   1169 			} else {
   1170 				/*
   1171 				 * arg is a symbol name. Use the index of
   1172 				 * the first symbol that matches
   1173 				 */
   1174 
   1175 				/*
   1176 				 * We will use debug messages for failure up
   1177 				 * until we run out of symbol tables. If we
   1178 				 * don't find a table with the desired symbol
   1179 				 * before the last table, we switch to error
   1180 				 * messages. Hence, we will jump with an error
   1181 				 * if no table will work.
   1182 				 */
   1183 				int err_type = (!got_sym &&
   1184 				    ((tblndx + 1) == obj_state->os_symtabnum)) ?
   1185 				    ELFEDIT_MSG_ERR : ELFEDIT_MSG_DEBUG;
   1186 
   1187 				symstate_add_str(argstate, symstate);
   1188 
   1189 				/*
   1190 				 * If the symbol table doesn't have this
   1191 				 * symbol, then forget it.
   1192 				 */
   1193 				if (elfedit_name_to_symndx(symstate->sym.sec,
   1194 				    symstate->str.sec, argstate->argv[0],
   1195 				    err_type, &symstate->ndx) == 0) {
   1196 					bzero(symstate, sizeof (*symstate));
   1197 					continue;
   1198 				}
   1199 			}
   1200 		}
   1201 		argstate->numsymstate++;
   1202 		symstate++;
   1203 		/*
   1204 		 * If the symbol table was given explicitly, and
   1205 		 * we've just taken it, then there is no reason to
   1206 		 * continue searching.
   1207 		 */
   1208 		if (explicit)
   1209 			break;
   1210 	}
   1211 
   1212 	return (argstate);
   1213 }
   1214 
   1215 
   1216 
   1217 /*
   1218  * Called by cmd_body() to handle the value change for a single
   1219  * symbol table.
   1220  *
   1221  * entry:
   1222  *	cmd - One of the SYM_CMD_T_* constants listed above, specifying
   1223  *		which command to implement.
   1224  *	argstate - Overall state block
   1225  *	symstate - State block for current symbol table.
   1226  */
   1227 static elfedit_cmdret_t
   1228 symstate_cmd_body(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate)
   1229 {
   1230 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
   1231 	Sym			*sym = &symstate->sym.data[symstate->ndx];
   1232 
   1233 	/* You're not supposed to change the value of symbol [0] */
   1234 	if (symstate->ndx == 0)
   1235 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMELT0),
   1236 		    EC_WORD(symstate->sym.sec->sec_shndx),
   1237 		    symstate->sym.sec->sec_name, EC_WORD(symstate->ndx));
   1238 
   1239 	/* The second value is an integer giving a new value */
   1240 	switch (cmd) {
   1241 		/*
   1242 		 * SYM_CMD_T_DUMP can't get here: It never has more than
   1243 		 * one argument, and is handled above.
   1244 		 */
   1245 
   1246 	case SYM_CMD_T_ST_BIND:
   1247 		ret = cmd_body_set_st_bind(argstate, symstate);
   1248 		break;
   1249 
   1250 	case SYM_CMD_T_ST_INFO:
   1251 		{
   1252 			/* Treat st_info as a raw integer field */
   1253 			uchar_t st_info =
   1254 			    elfedit_atoui(argstate->argv[1], NULL);
   1255 
   1256 			if (sym->st_info == st_info) {
   1257 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1258 				    MSG_INTL(MSG_DEBUG_D_OK),
   1259 				    symstate->sym.sec->sec_shndx,
   1260 				    symstate->sym.sec->sec_name,
   1261 				    EC_WORD(symstate->ndx),
   1262 				    MSG_ORIG(MSG_CMD_ST_INFO),
   1263 				    EC_WORD(sym->st_info));
   1264 			} else {
   1265 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1266 				    MSG_INTL(MSG_DEBUG_D_CHG),
   1267 				    symstate->sym.sec->sec_shndx,
   1268 				    symstate->sym.sec->sec_name,
   1269 				    EC_WORD(symstate->ndx),
   1270 				    MSG_ORIG(MSG_CMD_ST_INFO),
   1271 				    EC_WORD(sym->st_info), EC_WORD(st_info));
   1272 				ret = ELFEDIT_CMDRET_MOD;
   1273 				sym->st_info = st_info;
   1274 			}
   1275 		}
   1276 	break;
   1277 
   1278 	case SYM_CMD_T_ST_NAME:
   1279 		ret = cmd_body_set_st_name(argstate, symstate);
   1280 		break;
   1281 
   1282 	case SYM_CMD_T_ST_OTHER:
   1283 		{
   1284 			/* Treat st_other as a raw integer field */
   1285 			uchar_t st_other =
   1286 			    elfedit_atoui(argstate->argv[1], NULL);
   1287 
   1288 			if (sym->st_other == st_other) {
   1289 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1290 				    MSG_INTL(MSG_DEBUG_D_OK),
   1291 				    symstate->sym.sec->sec_shndx,
   1292 				    symstate->sym.sec->sec_name,
   1293 				    EC_WORD(symstate->ndx),
   1294 				    MSG_ORIG(MSG_CMD_ST_OTHER),
   1295 				    EC_WORD(sym->st_other));
   1296 			} else {
   1297 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1298 				    MSG_INTL(MSG_DEBUG_D_CHG),
   1299 				    symstate->sym.sec->sec_shndx,
   1300 				    symstate->sym.sec->sec_name,
   1301 				    EC_WORD(symstate->ndx),
   1302 				    MSG_ORIG(MSG_CMD_ST_OTHER),
   1303 				    EC_WORD(sym->st_other), EC_WORD(st_other));
   1304 				ret = ELFEDIT_CMDRET_MOD;
   1305 				sym->st_other = st_other;
   1306 			}
   1307 		}
   1308 		break;
   1309 
   1310 	case SYM_CMD_T_ST_SHNDX:
   1311 		ret = cmd_body_set_st_shndx(argstate, symstate);
   1312 		break;
   1313 
   1314 	case SYM_CMD_T_ST_SIZE:
   1315 		{
   1316 			Xword st_size = elfedit_atoui(argstate->argv[1], NULL);
   1317 
   1318 			if (sym->st_size == st_size) {
   1319 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1320 				    MSG_INTL(MSG_DEBUG_LLX_OK),
   1321 				    symstate->sym.sec->sec_shndx,
   1322 				    symstate->sym.sec->sec_name,
   1323 				    EC_WORD(symstate->ndx),
   1324 				    MSG_ORIG(MSG_CMD_ST_SIZE),
   1325 				    EC_XWORD(sym->st_size));
   1326 			} else {
   1327 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1328 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
   1329 				    symstate->sym.sec->sec_shndx,
   1330 				    symstate->sym.sec->sec_name,
   1331 				    EC_WORD(symstate->ndx),
   1332 				    MSG_ORIG(MSG_CMD_ST_SIZE),
   1333 				    EC_XWORD(sym->st_size), EC_XWORD(st_size));
   1334 				ret = ELFEDIT_CMDRET_MOD;
   1335 				sym->st_size = st_size;
   1336 			}
   1337 		}
   1338 		break;
   1339 
   1340 	case SYM_CMD_T_ST_TYPE:
   1341 		ret = cmd_body_set_st_type(argstate, symstate);
   1342 		break;
   1343 
   1344 	case SYM_CMD_T_ST_VALUE:
   1345 		{
   1346 			Addr st_value = elfedit_atoui(argstate->argv[1], NULL);
   1347 
   1348 			if (sym->st_value == st_value) {
   1349 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1350 				    MSG_INTL(MSG_DEBUG_LLX_OK),
   1351 				    symstate->sym.sec->sec_shndx,
   1352 				    symstate->sym.sec->sec_name,
   1353 				    EC_WORD(symstate->ndx),
   1354 				    MSG_ORIG(MSG_CMD_ST_VALUE),
   1355 				    EC_ADDR(sym->st_value));
   1356 			} else {
   1357 				elfedit_msg(ELFEDIT_MSG_DEBUG,
   1358 				    MSG_INTL(MSG_DEBUG_LLX_CHG),
   1359 				    symstate->sym.sec->sec_shndx,
   1360 				    symstate->sym.sec->sec_name,
   1361 				    EC_WORD(symstate->ndx),
   1362 				    MSG_ORIG(MSG_CMD_ST_VALUE),
   1363 				    EC_ADDR(sym->st_value),
   1364 				    EC_ADDR(st_value));
   1365 				ret = ELFEDIT_CMDRET_MOD;
   1366 				ret = ELFEDIT_CMDRET_MOD;
   1367 				sym->st_value = st_value;
   1368 			}
   1369 		}
   1370 		break;
   1371 
   1372 	case SYM_CMD_T_ST_VISIBILITY:
   1373 		ret = cmd_body_set_st_visibility(argstate, symstate);
   1374 		break;
   1375 	}
   1376 
   1377 	/*
   1378 	 * If we modified the symbol table, tell libelf.
   1379 	 * Any other modified sections are the responsibility
   1380 	 * of the cmd_body_set_st_*() function that did it, but
   1381 	 * everyone modifies the table itself, so we handle that here.
   1382 	 */
   1383 	if (ret == ELFEDIT_CMDRET_MOD)
   1384 		elfedit_modified_data(symstate->sym.sec);
   1385 
   1386 	return (ret);
   1387 }
   1388 
   1389 
   1390 
   1391 
   1392 /*
   1393  * Common body for the sym: module commands. These commands
   1394  * share a large amount of common behavior, so it is convenient
   1395  * to centralize things and use the cmd argument to handle the
   1396  * small differences.
   1397  *
   1398  * entry:
   1399  *	cmd - One of the SYM_CMD_T_* constants listed above, specifying
   1400  *		which command to implement.
   1401  *	obj_state, argc, argv - Standard command arguments
   1402  */
   1403 static elfedit_cmdret_t
   1404 cmd_body(SYM_CMD_T cmd, elfedit_obj_state_t *obj_state,
   1405     int argc, const char *argv[])
   1406 {
   1407 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
   1408 	ARGSTATE		*argstate;
   1409 	SYMSTATE		*symstate;
   1410 	Word			tblndx;
   1411 
   1412 	argstate = process_args(obj_state, argc, argv, cmd);
   1413 
   1414 	/*
   1415 	 * If there are not 2 arguments, then this is a display request.
   1416 	 * If no arguments are present, the full table (or tables) is
   1417 	 * dumped. If there is one argument, then the specified item is shown.
   1418 	 */
   1419 	if (argstate->argc < 2) {
   1420 		print_sym(cmd, 0, argstate);
   1421 		return (ELFEDIT_CMDRET_NONE);
   1422 	}
   1423 
   1424 	/*
   1425 	 * When processing multiple symbol tables, it is important that
   1426 	 * any failure happen before anything is changed. Otherwise, you
   1427 	 * can end up in a situation where things are left in an inconsistent
   1428 	 * half done state. sym:st_name has that issue when the -name_offset
   1429 	 * option is used, because the string may be insertable into some
   1430 	 * (dynstr) string tables, but not all of them. So, do the tests
   1431 	 * up front, and refuse to continue if any string insertions would
   1432 	 * fail.
   1433 	 */
   1434 	if ((cmd == SYM_CMD_T_ST_NAME) && (argstate->numsymstate > 1) &&
   1435 	    ((argstate->optmask & SYM_OPT_F_NAMOFFSET) == 0)) {
   1436 		symstate = argstate->symstate;
   1437 		for (tblndx = 0; tblndx < argstate->numsymstate;
   1438 		    tblndx++, symstate++)
   1439 			elfedit_strtab_insert_test(obj_state, symstate->str.sec,
   1440 			    NULL, argstate->argv[1]);
   1441 	}
   1442 
   1443 
   1444 	/* Loop over the table(s) and make the specified value change */
   1445 	symstate = argstate->symstate;
   1446 	for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++)
   1447 		if (symstate_cmd_body(cmd, argstate, symstate) ==
   1448 		    ELFEDIT_CMDRET_MOD)
   1449 			ret = ELFEDIT_CMDRET_MOD;
   1450 
   1451 	/* Do autoprint */
   1452 	print_sym(cmd, 1, argstate);
   1453 
   1454 	return (ret);
   1455 }
   1456 
   1457 
   1458 
   1459 
   1460 /*
   1461  * Command completion functions for the various commands
   1462  */
   1463 
   1464 /*
   1465  * Handle filling in the values for -shnam, -shndx, and -shtyp options.
   1466  */
   1467 /*ARGSUSED*/
   1468 static void
   1469 cpl_sh_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
   1470     const char *argv[], int num_opt)
   1471 {
   1472 	enum { NAME, INDEX, TYPE }	op;
   1473 	elfedit_symtab_t		*symtab;
   1474 	Word 	tblndx;
   1475 
   1476 	if ((argc != num_opt) || (argc < 2))
   1477 		return;
   1478 
   1479 	if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) {
   1480 		op = NAME;
   1481 	} else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) {
   1482 		op = INDEX;
   1483 
   1484 	} else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) {
   1485 		op = TYPE;
   1486 		if (obj_state == NULL)	 /* No object available */
   1487 			elfedit_cpl_atoconst(cpldata,
   1488 			    ELFEDIT_CONST_SHT_ALLSYMTAB);
   1489 	} else {
   1490 		return;
   1491 	}
   1492 
   1493 	if (obj_state == NULL)	 /* No object available */
   1494 		return;
   1495 
   1496 	/*
   1497 	 * Loop over the symbol tables and supply command completion
   1498 	 * for the items in the file.
   1499 	 */
   1500 	symtab = obj_state->os_symtab;
   1501 	for (tblndx = 0; tblndx < obj_state->os_symtabnum;
   1502 	    tblndx++, symtab++) {
   1503 		elfedit_section_t *sec =
   1504 		    &obj_state->os_secarr[symtab->symt_shndx];
   1505 
   1506 		switch (op) {
   1507 		case NAME:
   1508 			elfedit_cpl_match(cpldata, sec->sec_name, 0);
   1509 			break;
   1510 		case INDEX:
   1511 			elfedit_cpl_ndx(cpldata, symtab->symt_shndx);
   1512 			break;
   1513 		case TYPE:
   1514 			{
   1515 				elfedit_atoui_sym_t *cpl_list;
   1516 
   1517 				(void) elfedit_sec_issymtab(obj_state,
   1518 				    sec, 1, &cpl_list);
   1519 				elfedit_cpl_atoui(cpldata, cpl_list);
   1520 			}
   1521 			break;
   1522 		}
   1523 	}
   1524 }
   1525 
   1526 /*ARGSUSED*/
   1527 static void
   1528 cpl_st_bind(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
   1529     const char *argv[], int num_opt)
   1530 {
   1531 	/* Handle -shXXX options */
   1532 	cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
   1533 
   1534 	/* The second argument can be an STB_ value */
   1535 	if (argc == (num_opt + 2))
   1536 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STB);
   1537 }
   1538 
   1539 /*ARGSUSED*/
   1540 static void
   1541 cpl_st_shndx(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
   1542     const char *argv[], int num_opt)
   1543 {
   1544 	elfedit_section_t *sec;
   1545 	enum { NAME, INDEX, TYPE } op;
   1546 	Word ndx;
   1547 
   1548 	/* Handle -shXXX options */
   1549 	cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
   1550 
   1551 	/*
   1552 	 * The second argument can be a section name, a section
   1553 	 * index (-secshndx), or a section type (-secshtyp). We
   1554 	 * can do completions for each of these.
   1555 	 */
   1556 	if (argc != (num_opt + 2))
   1557 		return;
   1558 
   1559 	op = NAME;
   1560 	for (ndx = 0; ndx < num_opt; ndx++) {
   1561 		if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SECSHNDX)) == 0)
   1562 			op = INDEX;
   1563 		else if (strcmp(argv[ndx],
   1564 		    MSG_ORIG(MSG_STR_MINUS_SECSHTYP)) == 0)
   1565 			op = TYPE;
   1566 	}
   1567 
   1568 	switch (op) {
   1569 	case NAME:
   1570 		if (obj_state == NULL)
   1571 			break;
   1572 		sec = obj_state->os_secarr;
   1573 		for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++)
   1574 			elfedit_cpl_match(cpldata, sec->sec_name, 0);
   1575 		break;
   1576 
   1577 	case INDEX:
   1578 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHN);
   1579 		break;
   1580 
   1581 	case TYPE:
   1582 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
   1583 		break;
   1584 	}
   1585 }
   1586 
   1587 /*ARGSUSED*/
   1588 static void
   1589 cpl_st_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
   1590     const char *argv[], int num_opt)
   1591 {
   1592 	/* Handle -shXXX options */
   1593 	cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
   1594 
   1595 	/* The second argument can be an STT_ value */
   1596 	if (argc == (num_opt + 2))
   1597 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STT);
   1598 }
   1599 
   1600 /*ARGSUSED*/
   1601 static void
   1602 cpl_st_visibility(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
   1603     const char *argv[], int num_opt)
   1604 {
   1605 	/* Handle -shXXX options */
   1606 	cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
   1607 
   1608 	/* The second argument can be an STV_ value */
   1609 	if (argc == (num_opt + 2))
   1610 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STV);
   1611 }
   1612 
   1613 
   1614 
   1615 /*
   1616  * Implementation functions for the commands
   1617  */
   1618 static elfedit_cmdret_t
   1619 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1620 {
   1621 	return (cmd_body(SYM_CMD_T_DUMP, obj_state, argc, argv));
   1622 }
   1623 
   1624 
   1625 static elfedit_cmdret_t
   1626 cmd_st_bind(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1627 {
   1628 	return (cmd_body(SYM_CMD_T_ST_BIND, obj_state, argc, argv));
   1629 }
   1630 
   1631 
   1632 static elfedit_cmdret_t
   1633 cmd_st_info(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1634 {
   1635 	return (cmd_body(SYM_CMD_T_ST_INFO, obj_state, argc, argv));
   1636 }
   1637 
   1638 static elfedit_cmdret_t
   1639 cmd_st_name(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1640 {
   1641 	return (cmd_body(SYM_CMD_T_ST_NAME, obj_state, argc, argv));
   1642 }
   1643 
   1644 static elfedit_cmdret_t
   1645 cmd_st_other(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1646 {
   1647 	return (cmd_body(SYM_CMD_T_ST_OTHER, obj_state, argc, argv));
   1648 }
   1649 
   1650 static elfedit_cmdret_t
   1651 cmd_st_shndx(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1652 {
   1653 	return (cmd_body(SYM_CMD_T_ST_SHNDX, obj_state, argc, argv));
   1654 }
   1655 
   1656 static elfedit_cmdret_t
   1657 cmd_st_size(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1658 {
   1659 	return (cmd_body(SYM_CMD_T_ST_SIZE, obj_state, argc, argv));
   1660 }
   1661 
   1662 static elfedit_cmdret_t
   1663 cmd_st_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1664 {
   1665 	return (cmd_body(SYM_CMD_T_ST_TYPE, obj_state, argc, argv));
   1666 }
   1667 
   1668 static elfedit_cmdret_t
   1669 cmd_st_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1670 {
   1671 	return (cmd_body(SYM_CMD_T_ST_VALUE, obj_state, argc, argv));
   1672 }
   1673 
   1674 static elfedit_cmdret_t
   1675 cmd_st_visibility(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
   1676 {
   1677 	return (cmd_body(SYM_CMD_T_ST_VISIBILITY, obj_state, argc, argv));
   1678 }
   1679 
   1680 
   1681 
   1682 /*ARGSUSED*/
   1683 elfedit_module_t *
   1684 elfedit_init(elfedit_module_version_t version)
   1685 {
   1686 	/* Multiple commands accept only the standard set of options */
   1687 	static elfedit_cmd_optarg_t opt_std[] = {
   1688 		{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
   1689 		    /* MSG_INTL(MSG_OPTDESC_SHNAM) */
   1690 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
   1691 		    SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
   1692 		{ MSG_ORIG(MSG_STR_NAME), NULL, 0 },
   1693 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
   1694 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
   1695 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
   1696 		    SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
   1697 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0 },
   1698 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
   1699 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
   1700 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
   1701 		    SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
   1702 		{ MSG_ORIG(MSG_STR_TYPE), NULL, 0 },
   1703 		{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
   1704 		    /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
   1705 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX },
   1706 		{ ELFEDIT_STDOA_OPT_O, NULL,
   1707 		    ELFEDIT_CMDOA_F_INHERIT, 0 },
   1708 		{ NULL }
   1709 	};
   1710 
   1711 	/* sym:dump */
   1712 	static const char *name_dump[] = {
   1713 	    MSG_ORIG(MSG_CMD_DUMP),
   1714 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
   1715 	    NULL
   1716 	};
   1717 	static elfedit_cmd_optarg_t opt_dump[] = {
   1718 		{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
   1719 		    /* MSG_INTL(MSG_OPTDESC_SHNAM) */
   1720 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
   1721 		    SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
   1722 		{ MSG_ORIG(MSG_STR_NAME), NULL, 0 },
   1723 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
   1724 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
   1725 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
   1726 		    SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
   1727 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0 },
   1728 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
   1729 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
   1730 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
   1731 		    SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
   1732 		{ MSG_ORIG(MSG_STR_TYPE), NULL, 0 },
   1733 		{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
   1734 		    /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
   1735 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX },
   1736 		{ NULL }
   1737 	};
   1738 	static elfedit_cmd_optarg_t arg_dump[] = {
   1739 		{ MSG_ORIG(MSG_STR_SYM),
   1740 		    /* MSG_INTL(MSG_A1_SYM) */
   1741 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1742 		    ELFEDIT_CMDOA_F_OPT },
   1743 		{ NULL }
   1744 	};
   1745 
   1746 	/* sym:st_bind */
   1747 	static const char *name_st_bind[] = {
   1748 	    MSG_ORIG(MSG_CMD_ST_BIND), NULL };
   1749 	static elfedit_cmd_optarg_t arg_st_bind[] = {
   1750 		{ MSG_ORIG(MSG_STR_SYM),
   1751 		    /* MSG_INTL(MSG_A1_SYM) */
   1752 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1753 		    ELFEDIT_CMDOA_F_OPT },
   1754 		{ MSG_ORIG(MSG_STR_VALUE),
   1755 		    /* MSG_INTL(MSG_A2_DESC_ST_BIND) */
   1756 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_BIND),
   1757 		    ELFEDIT_CMDOA_F_OPT },
   1758 		{ NULL }
   1759 	};
   1760 
   1761 	/* sym:st_info */
   1762 	static const char *name_st_info[] = {
   1763 	    MSG_ORIG(MSG_CMD_ST_INFO), NULL };
   1764 	static elfedit_cmd_optarg_t arg_st_info[] = {
   1765 		{ MSG_ORIG(MSG_STR_SYM),
   1766 		    /* MSG_INTL(MSG_A1_SYM) */
   1767 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1768 		    ELFEDIT_CMDOA_F_OPT },
   1769 		{ MSG_ORIG(MSG_STR_VALUE),
   1770 		    /* MSG_INTL(MSG_A2_DESC_ST_INFO) */
   1771 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_INFO),
   1772 		    ELFEDIT_CMDOA_F_OPT },
   1773 		{ NULL }
   1774 	};
   1775 
   1776 	/* sym:st_name */
   1777 	static const char *name_st_name[] = {
   1778 	    MSG_ORIG(MSG_CMD_ST_NAME), NULL };
   1779 	static elfedit_cmd_optarg_t opt_st_name[] = {
   1780 		{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
   1781 		    /* MSG_INTL(MSG_OPTDESC_SHNAM) */
   1782 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
   1783 		    SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
   1784 		{ MSG_ORIG(MSG_STR_NAME), NULL, 0, 0 },
   1785 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
   1786 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
   1787 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
   1788 		    SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
   1789 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0, 0 },
   1790 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
   1791 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
   1792 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
   1793 		    SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
   1794 		{ MSG_ORIG(MSG_STR_TYPE), NULL, 0, 0 },
   1795 		{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
   1796 		    /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
   1797 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
   1798 		    SYM_OPT_F_SYMNDX, 0 },
   1799 		{ MSG_ORIG(MSG_STR_MINUS_NAME_OFFSET),
   1800 		    /* MSG_INTL(MSG_OPTDESC_NAME_OFFSET) */
   1801 		    ELFEDIT_I18NHDL(MSG_OPTDESC_NAME_OFFSET), 0,
   1802 		    SYM_OPT_F_NAMOFFSET, 0 },
   1803 		{ ELFEDIT_STDOA_OPT_O, NULL,
   1804 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
   1805 		{ NULL }
   1806 	};
   1807 	static elfedit_cmd_optarg_t arg_st_name[] = {
   1808 		{ MSG_ORIG(MSG_STR_SYM),
   1809 		    /* MSG_INTL(MSG_A1_SYM) */
   1810 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1811 		    ELFEDIT_CMDOA_F_OPT },
   1812 		{ MSG_ORIG(MSG_STR_NAME),
   1813 		    /* MSG_INTL(MSG_A2_DESC_ST_NAME) */
   1814 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_NAME),
   1815 		    ELFEDIT_CMDOA_F_OPT },
   1816 		{ NULL }
   1817 	};
   1818 
   1819 	/* sym:st_other */
   1820 	static const char *name_st_other[] = {
   1821 	    MSG_ORIG(MSG_CMD_ST_OTHER), NULL };
   1822 	static elfedit_cmd_optarg_t arg_st_other[] = {
   1823 		{ MSG_ORIG(MSG_STR_SYM),
   1824 		    /* MSG_INTL(MSG_A1_SYM) */
   1825 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1826 		    ELFEDIT_CMDOA_F_OPT },
   1827 		{ MSG_ORIG(MSG_STR_VALUE),
   1828 		    /* MSG_INTL(MSG_A2_DESC_ST_OTHER) */
   1829 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_OTHER),
   1830 		    ELFEDIT_CMDOA_F_OPT },
   1831 		{ NULL }
   1832 	};
   1833 
   1834 	/* sym:st_shndx */
   1835 	static const char *name_st_shndx[] = {
   1836 	    MSG_ORIG(MSG_CMD_ST_SHNDX), NULL };
   1837 	static elfedit_cmd_optarg_t opt_st_shndx[] = {
   1838 		{ MSG_ORIG(MSG_STR_MINUS_E),
   1839 		    /* MSG_INTL(MSG_OPTDESC_E) */
   1840 		    ELFEDIT_I18NHDL(MSG_OPTDESC_E), 0, SYM_OPT_F_XSHINDEX, 0 },
   1841 		{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
   1842 		    /* MSG_INTL(MSG_OPTDESC_SHNAM) */
   1843 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
   1844 		    SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP },
   1845 		{ MSG_ORIG(MSG_STR_NAME), NULL, 0, 0 },
   1846 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
   1847 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
   1848 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
   1849 		    SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP },
   1850 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0, 0 },
   1851 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
   1852 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
   1853 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
   1854 		    SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX },
   1855 		{ MSG_ORIG(MSG_STR_TYPE), NULL, 0, 0 },
   1856 		{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
   1857 		    /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
   1858 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
   1859 		    SYM_OPT_F_SYMNDX, 0 },
   1860 		{ ELFEDIT_STDOA_OPT_O, NULL,
   1861 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
   1862 		{ MSG_ORIG(MSG_STR_MINUS_SECSHNDX),
   1863 		    /* MSG_INTL(MSG_OPTDESC_SECSHNDX) */
   1864 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHNDX),
   1865 		    0, SYM_OPT_F_SECSHNDX, SYM_OPT_F_SECSHTYP },
   1866 		{ MSG_ORIG(MSG_STR_MINUS_SECSHTYP),
   1867 		    /* MSG_INTL(MSG_OPTDESC_SECSHTYP) */
   1868 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHTYP),
   1869 		    0, SYM_OPT_F_SECSHTYP, SYM_OPT_F_SECSHNDX },
   1870 		{ NULL }
   1871 	};
   1872 	static elfedit_cmd_optarg_t arg_st_shndx[] = {
   1873 		{ MSG_ORIG(MSG_STR_SYM),
   1874 		    /* MSG_INTL(MSG_A1_SYM) */
   1875 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1876 		    ELFEDIT_CMDOA_F_OPT },
   1877 		{ MSG_ORIG(MSG_STR_SEC),
   1878 		    /* MSG_INTL(MSG_A2_DESC_ST_SEC) */
   1879 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SEC),
   1880 		    ELFEDIT_CMDOA_F_OPT },
   1881 		{ NULL }
   1882 	};
   1883 
   1884 	/* sym:st_size */
   1885 	static const char *name_st_size[] = {
   1886 	    MSG_ORIG(MSG_CMD_ST_SIZE), NULL };
   1887 	static elfedit_cmd_optarg_t arg_st_size[] = {
   1888 		{ MSG_ORIG(MSG_STR_SYM),
   1889 		    /* MSG_INTL(MSG_A1_SYM) */
   1890 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1891 		    ELFEDIT_CMDOA_F_OPT },
   1892 		{ MSG_ORIG(MSG_STR_VALUE),
   1893 		    /* MSG_INTL(MSG_A2_DESC_ST_SIZE) */
   1894 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SIZE),
   1895 		    ELFEDIT_CMDOA_F_OPT },
   1896 		{ NULL }
   1897 	};
   1898 
   1899 	/* sym:st_type */
   1900 	static const char *name_st_type[] = {
   1901 	    MSG_ORIG(MSG_CMD_ST_TYPE), NULL };
   1902 	static elfedit_cmd_optarg_t arg_st_type[] = {
   1903 		{ MSG_ORIG(MSG_STR_SYM),
   1904 		    /* MSG_INTL(MSG_A1_SYM) */
   1905 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1906 		    ELFEDIT_CMDOA_F_OPT },
   1907 		{ MSG_ORIG(MSG_STR_VALUE),
   1908 		    /* MSG_INTL(MSG_A2_DESC_ST_TYPE) */
   1909 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_TYPE),
   1910 		    ELFEDIT_CMDOA_F_OPT },
   1911 		{ NULL }
   1912 	};
   1913 
   1914 	/* sym:st_value */
   1915 	static const char *name_st_value[] = {
   1916 	    MSG_ORIG(MSG_CMD_ST_VALUE), NULL };
   1917 	static elfedit_cmd_optarg_t arg_st_value[] = {
   1918 		{ MSG_ORIG(MSG_STR_SYM),
   1919 		    /* MSG_INTL(MSG_A1_SYM) */
   1920 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1921 		    ELFEDIT_CMDOA_F_OPT },
   1922 		{ MSG_ORIG(MSG_STR_VALUE),
   1923 		    /* MSG_INTL(MSG_A2_DESC_ST_VALUE) */
   1924 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VALUE),
   1925 		    ELFEDIT_CMDOA_F_OPT },
   1926 		{ NULL }
   1927 	};
   1928 
   1929 	/* sym:st_visibility */
   1930 	static const char *name_st_visibility[] = {
   1931 	    MSG_ORIG(MSG_CMD_ST_VISIBILITY), NULL };
   1932 	static elfedit_cmd_optarg_t arg_st_visibility[] = {
   1933 		{ MSG_ORIG(MSG_STR_SYM),
   1934 		    /* MSG_INTL(MSG_A1_SYM) */
   1935 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
   1936 		    ELFEDIT_CMDOA_F_OPT },
   1937 		{ MSG_ORIG(MSG_STR_VALUE),
   1938 		    /* MSG_INTL(MSG_A2_DESC_ST_VISIBILITY) */
   1939 		    ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VISIBILITY),
   1940 		    ELFEDIT_CMDOA_F_OPT },
   1941 		{ NULL }
   1942 	};
   1943 
   1944 	static elfedit_cmd_t cmds[] = {
   1945 		/* sym:dump */
   1946 		{ cmd_dump, cpl_sh_opt, name_dump,
   1947 		    /* MSG_INTL(MSG_DESC_DUMP) */
   1948 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
   1949 		    /* MSG_INTL(MSG_HELP_DUMP) */
   1950 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
   1951 		    opt_dump, arg_dump },
   1952 
   1953 		/* sym:st_bind */
   1954 		{ cmd_st_bind, cpl_st_bind, name_st_bind,
   1955 		    /* MSG_INTL(MSG_DESC_ST_BIND) */
   1956 		    ELFEDIT_I18NHDL(MSG_DESC_ST_BIND),
   1957 		    /* MSG_INTL(MSG_HELP_ST_BIND) */
   1958 		    ELFEDIT_I18NHDL(MSG_HELP_ST_BIND),
   1959 		    opt_std, arg_st_bind },
   1960 
   1961 		/* sym:st_info */
   1962 		{ cmd_st_info, cpl_sh_opt, name_st_info,
   1963 		    /* MSG_INTL(MSG_DESC_ST_INFO) */
   1964 		    ELFEDIT_I18NHDL(MSG_DESC_ST_INFO),
   1965 		    /* MSG_INTL(MSG_HELP_ST_INFO) */
   1966 		    ELFEDIT_I18NHDL(MSG_HELP_ST_INFO),
   1967 		    opt_std, arg_st_info },
   1968 
   1969 		/* sym:st_name */
   1970 		{ cmd_st_name, cpl_sh_opt, name_st_name,
   1971 		    /* MSG_INTL(MSG_DESC_ST_NAME) */
   1972 		    ELFEDIT_I18NHDL(MSG_DESC_ST_NAME),
   1973 		    /* MSG_INTL(MSG_HELP_ST_NAME) */
   1974 		    ELFEDIT_I18NHDL(MSG_HELP_ST_NAME),
   1975 		    opt_st_name, arg_st_name },
   1976 
   1977 		/* sym:st_other */
   1978 		{ cmd_st_other, cpl_sh_opt, name_st_other,
   1979 		    /* MSG_INTL(MSG_DESC_ST_OTHER) */
   1980 		    ELFEDIT_I18NHDL(MSG_DESC_ST_OTHER),
   1981 		    /* MSG_INTL(MSG_HELP_ST_OTHER) */
   1982 		    ELFEDIT_I18NHDL(MSG_HELP_ST_OTHER),
   1983 		    opt_std, arg_st_other },
   1984 
   1985 		/* sym:st_shndx */
   1986 		{ cmd_st_shndx, cpl_st_shndx, name_st_shndx,
   1987 		    /* MSG_INTL(MSG_DESC_ST_SHNDX) */
   1988 		    ELFEDIT_I18NHDL(MSG_DESC_ST_SHNDX),
   1989 		    /* MSG_INTL(MSG_HELP_ST_SHNDX) */
   1990 		    ELFEDIT_I18NHDL(MSG_HELP_ST_SHNDX),
   1991 		    opt_st_shndx, arg_st_shndx },
   1992 
   1993 		/* sym:st_size */
   1994 		{ cmd_st_size, cpl_sh_opt, name_st_size,
   1995 		    /* MSG_INTL(MSG_DESC_ST_SIZE) */
   1996 		    ELFEDIT_I18NHDL(MSG_DESC_ST_SIZE),
   1997 		    /* MSG_INTL(MSG_HELP_ST_SIZE) */
   1998 		    ELFEDIT_I18NHDL(MSG_HELP_ST_SIZE),
   1999 		    opt_std, arg_st_size },
   2000 
   2001 		/* sym:st_type */
   2002 		{ cmd_st_type, cpl_st_type, name_st_type,
   2003 		    /* MSG_INTL(MSG_DESC_ST_TYPE) */
   2004 		    ELFEDIT_I18NHDL(MSG_DESC_ST_TYPE),
   2005 		    /* MSG_INTL(MSG_HELP_ST_TYPE) */
   2006 		    ELFEDIT_I18NHDL(MSG_HELP_ST_TYPE),
   2007 		    opt_std, arg_st_type },
   2008 
   2009 		/* sym:st_value */
   2010 		{ cmd_st_value, cpl_sh_opt, name_st_value,
   2011 		    /* MSG_INTL(MSG_DESC_ST_VALUE) */
   2012 		    ELFEDIT_I18NHDL(MSG_DESC_ST_VALUE),
   2013 		    /* MSG_INTL(MSG_HELP_ST_VALUE) */
   2014 		    ELFEDIT_I18NHDL(MSG_HELP_ST_VALUE),
   2015 		    opt_std, arg_st_value },
   2016 
   2017 		/* sym:st_visibility */
   2018 		{ cmd_st_visibility, cpl_st_visibility, name_st_visibility,
   2019 		    /* MSG_INTL(MSG_DESC_ST_VISIBILITY) */
   2020 		    ELFEDIT_I18NHDL(MSG_DESC_ST_VISIBILITY),
   2021 		    /* MSG_INTL(MSG_HELP_ST_VISIBILITY) */
   2022 		    ELFEDIT_I18NHDL(MSG_HELP_ST_VISIBILITY),
   2023 		    opt_std, arg_st_visibility },
   2024 
   2025 		{ NULL }
   2026 	};
   2027 
   2028 	static elfedit_module_t module = {
   2029 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
   2030 	    /* MSG_INTL(MSG_MOD_DESC) */
   2031 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
   2032 	    cmds, mod_i18nhdl_to_str };
   2033 
   2034 	return (&module);
   2035 }
   2036