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 #include	<stdio.h>
     28 #include	<unistd.h>
     29 #include	<elfedit.h>
     30 #include	<strings.h>
     31 #include	<debug.h>
     32 #include	<conv.h>
     33 #include	<syminfo_msg.h>
     34 
     35 
     36 
     37 /*
     38  * This module uses shared code for several of the commands.
     39  * It is sometimes necessary to know which specific command
     40  * is active.
     41  */
     42 typedef enum {
     43 	SYMINFO_CMD_T_DUMP =		0,	/* syminfo:dump */
     44 
     45 	SYMINFO_CMD_T_SI_BOUNDTO =	1,	/* syminfo:si_boundto */
     46 	SYMINFO_CMD_T_SI_FLAGS =	2	/* syminfo:si_boundto */
     47 } SYMINFO_CMD_T;
     48 
     49 
     50 
     51 #ifndef _ELF64
     52 /*
     53  * We supply this function for the msg module. Only one copy is needed.
     54  */
     55 const char *
     56 _syminfo_msg(Msg mid)
     57 {
     58 	return (gettext(MSG_ORIG(mid)));
     59 }
     60 
     61 #endif
     62 
     63 
     64 
     65 /*
     66  * This function is supplied to elfedit through our elfedit_module_t
     67  * definition. It translates the opaque elfedit_i18nhdl_t handles
     68  * in our module interface into the actual strings for elfedit to
     69  * use.
     70  *
     71  * note:
     72  *	This module uses Msg codes for its i18n handle type.
     73  *	So the translation is simply to use MSG_INTL() to turn
     74  *	it into a string and return it.
     75  */
     76 static const char *
     77 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
     78 {
     79 	Msg msg = (Msg)hdl;
     80 
     81 	return (MSG_INTL(msg));
     82 }
     83 
     84 
     85 
     86 /*
     87  * The sym_opt_t enum specifies a bit value for every optional
     88  * argument allowed by a command in this module.
     89  */
     90 typedef enum {
     91 	SYMINFO_OPT_F_AND =	1,	/* -and: AND (&) values to dest */
     92 	SYMINFO_OPT_F_CMP =	2,	/* -cmp: Complement (~) values */
     93 	SYMINFO_OPT_F_NEEDED =	4,	/* -needed: arg is name of object to */
     94 					/*	be referenced via DT_NEEDED */
     95 					/*	dynamic entry */
     96 	SYMINFO_OPT_F_OR =	8,	/* -or: OR (|) values to dest */
     97 	SYMINFO_OPT_F_SYMNDX =	16	/* -symndx: Sym specified by index */
     98 } syminfo_opt_t;
     99 
    100 
    101 /*
    102  * A variable of type ARGSTATE is used by each command to maintain
    103  * information about the syminfo section being used, as and for any
    104  * auxiliary sections that are related to it. This helps us to ensure
    105  * that we only fetch each section a single time:
    106  *	- More efficient
    107  *	- Prevents multiple ELFEDIT_MSG_DEBUG messages from
    108  *	  being produced for a given section.
    109  */
    110 typedef struct {
    111 	elfedit_obj_state_t	*obj_state;
    112 	syminfo_opt_t		optmask;   	/* Mask of options used */
    113 	int			argc;		/* # of plain arguments */
    114 	const char		**argv;		/* Plain arguments */
    115 	struct {				/* Syminfo */
    116 		elfedit_section_t	*sec;
    117 		Syminfo			*data;
    118 		Word			n;
    119 	} syminfo;
    120 	struct {				/* Symbol table */
    121 		elfedit_section_t	*sec;
    122 		Sym			*data;
    123 		Word			n;
    124 	} sym;
    125 	struct {				/* String table */
    126 		elfedit_section_t	*sec;
    127 	} str;
    128 	struct {				/* Dynamic section */
    129 		elfedit_section_t	*sec;
    130 		Dyn			*data;
    131 		Word			n;
    132 	} dynamic;
    133 } ARGSTATE;
    134 
    135 
    136 
    137 /*
    138  * Standard argument processing for syminfo module
    139  *
    140  * entry
    141  *	obj_state, argc, argv - Standard command arguments
    142  *	optmask - Mask of allowed optional arguments.
    143  *	argstate - Address of ARGSTATE block to be initialized
    144  *
    145  * exit:
    146  *	On success, *argstate is initialized. On error,
    147  *	an error is issued and this routine does not return.
    148  *
    149  * note:
    150  *	Only the syminfo section is initially referenced by
    151  *	argstate. Use the argstate_add_XXX() routines below to
    152  *	access any other sections needed.
    153  */
    154 static void
    155 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
    156     SYMINFO_CMD_T cmd, ARGSTATE *argstate)
    157 {
    158 	elfedit_getopt_state_t	getopt_state;
    159 	elfedit_getopt_ret_t	*getopt_ret;
    160 
    161 	bzero(argstate, sizeof (*argstate));
    162 	argstate->obj_state = obj_state;
    163 
    164 	elfedit_getopt_init(&getopt_state, &argc, &argv);
    165 
    166 	/* Add each new option to the options mask */
    167 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
    168 		argstate->optmask |= getopt_ret->gor_idmask;
    169 
    170 	/*
    171 	 * Usage error if there are too many plain arguments.
    172 	 *	- syminfo:dump accepts a single argument
    173 	 *	- syminfo:si_boundto accepts 2 arguments
    174 	 *	- syminfo:si_flags accepts an unbounded number
    175 	 */
    176 	if (((cmd == SYMINFO_CMD_T_DUMP) && (argc > 1)) ||
    177 	    ((cmd == SYMINFO_CMD_T_SI_BOUNDTO) && (argc > 2)))
    178 		elfedit_command_usage();
    179 
    180 	/* If there may be an arbitrary amount of output, use a pager */
    181 	if (argc == 0)
    182 		elfedit_pager_init();
    183 
    184 	/* Return the updated values of argc/argv */
    185 	argstate->argc = argc;
    186 	argstate->argv = argv;
    187 
    188 	/* Locate the syminfo section */
    189 	argstate->syminfo.sec = elfedit_sec_getsyminfo(obj_state,
    190 	    &argstate->syminfo.data, &argstate->syminfo.n);
    191 }
    192 
    193 
    194 
    195 /*
    196  * We maintain the state of the current syminfo table in a ARGSTATE
    197  * structure. A syminfo is related to the dynamic symbol table, and
    198  * can reference the dynamic section of the object. We don't look those
    199  * things up unless we actually need them, both to be efficient, and
    200  * to prevent duplicate ELFEDIT_MSG_DEBUG messages from being issued
    201  * as they are located. Hence, process_args() is used to initialze the
    202  * state block with just the syminfo section, and then one of the
    203  * argstate_add_XXX() functions is used as needed to fetch the
    204  * additional sections.
    205  *
    206  * entry:
    207  *	argstate - State block for current symbol table.
    208  *
    209  * exit:
    210  *	If the needed auxiliary section is not found, an error is
    211  *	issued and the argstate_add_XXX() routine does not return.
    212  *	Otherwise, the fields in argstate have been filled in, ready
    213  *	for use.
    214  *
    215  */
    216 static void
    217 argstate_add_sym(ARGSTATE *argstate)
    218 {
    219 	if (argstate->sym.sec != NULL)
    220 		return;
    221 
    222 	argstate->sym.sec = elfedit_sec_getsymtab(argstate->obj_state,
    223 	    1, argstate->syminfo.sec->sec_shdr->sh_link, NULL,
    224 	    &argstate->sym.data, &argstate->sym.n, NULL);
    225 }
    226 static void
    227 argstate_add_str(ARGSTATE *argstate)
    228 {
    229 	if (argstate->str.sec != NULL)
    230 		return;
    231 
    232 	argstate_add_sym(argstate);
    233 	argstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
    234 	    argstate->sym.sec->sec_shdr->sh_link, 0);
    235 }
    236 static void
    237 argstate_add_dynamic(ARGSTATE *argstate)
    238 {
    239 	if (argstate->dynamic.sec != NULL)
    240 		return;
    241 
    242 	argstate->dynamic.sec = elfedit_sec_getdyn(argstate->obj_state,
    243 	    &argstate->dynamic.data, &argstate->dynamic.n);
    244 }
    245 
    246 
    247 
    248 /*
    249  * Display syminfo section entries in the style used by elfdump.
    250  *
    251  * entry:
    252  *	argstate - State block for current symbol table.
    253  *	ndx - Index of first symbol to display
    254  *	cnt - Number of symbols to display
    255  */
    256 static void
    257 dump_syminfo(ARGSTATE *argstate, Word ndx, Word cnt)
    258 {
    259 	Syminfo			*syminfo;
    260 	Sym			*sym;
    261 	Dyn			*dyn;
    262 
    263 	syminfo = argstate->syminfo.data + ndx;
    264 
    265 	argstate_add_sym(argstate);
    266 	sym = argstate->sym.data + ndx;
    267 
    268 	argstate_add_str(argstate);
    269 
    270 	argstate_add_dynamic(argstate);
    271 	dyn = argstate->dynamic.data;
    272 
    273 	/*
    274 	 * Loop through the syminfo entries.
    275 	 */
    276 	Elf_syminfo_title(0);
    277 
    278 	for (; cnt-- > 0; ndx++, syminfo++, sym++) {
    279 		const char	*needed = NULL, *name;
    280 
    281 		name = elfedit_offset_to_str(argstate->str.sec,
    282 		    sym->st_name, ELFEDIT_MSG_ERR, 0);
    283 
    284 		if ((syminfo->si_boundto < SYMINFO_BT_LOWRESERVE) &&
    285 		    (syminfo->si_boundto < argstate->dynamic.n) &&
    286 		    ((dyn[syminfo->si_boundto].d_tag == DT_NEEDED) ||
    287 		    (dyn[syminfo->si_boundto].d_tag == DT_USED)))
    288 			needed = elfedit_offset_to_str(argstate->str.sec,
    289 			    dyn[syminfo->si_boundto].d_un.d_val,
    290 			    ELFEDIT_MSG_ERR, 0);
    291 		else
    292 			needed = MSG_ORIG(MSG_STR_EMPTY);
    293 
    294 		Elf_syminfo_entry(0, ndx, syminfo, name, needed);
    295 	}
    296 }
    297 
    298 
    299 
    300 /*
    301  * Print syminfo values, taking the calling command, and output style
    302  * into account.
    303  *
    304  * entry:
    305  *	cmd - SYMINFO_CMD_T_* value giving identify of caller
    306  *	autoprint - If True, output is only produced if the elfedit
    307  *		autoprint flag is set. If False, output is always produced.
    308  *	argstate - State block for current symbol table.
    309  *	ndx - Index of first symbol to display
    310  *	cnt - Number of symbols to display
    311  */
    312 static void
    313 print_syminfo(SYMINFO_CMD_T cmd, int autoprint, ARGSTATE *argstate,
    314     Word ndx, Word cnt)
    315 {
    316 	elfedit_outstyle_t	outstyle;
    317 	Syminfo			*syminfo;
    318 
    319 	if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) ||
    320 	    (cnt == 0))
    321 		return;
    322 
    323 	/*
    324 	 * Pick an output style. syminfo:dump is required to use the default
    325 	 * style. The other commands use the current output style.
    326 	 */
    327 	outstyle = (cmd == SYMINFO_CMD_T_DUMP) ?
    328 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
    329 
    330 	/*
    331 	 * If doing default output, use elfdump style where we
    332 	 * show all symbol attributes. In this case, the command
    333 	 * that called us doesn't matter
    334 	 */
    335 	if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
    336 		dump_syminfo(argstate, ndx, cnt);
    337 		return;
    338 	}
    339 
    340 	syminfo = argstate->syminfo.data;
    341 
    342 	switch (cmd) {
    343 	case SYMINFO_CMD_T_SI_BOUNDTO:
    344 		if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    345 			/* Find the dynamic section and string table */
    346 			argstate_add_dynamic(argstate);
    347 			argstate_add_str(argstate);
    348 		}
    349 
    350 		for (syminfo += ndx; cnt--; syminfo++) {
    351 			Half bndto = syminfo->si_boundto;
    352 
    353 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    354 				const char	*str = NULL;
    355 
    356 				switch (bndto) {
    357 				case SYMINFO_BT_SELF:
    358 					str = elfedit_atoconst_value_to_str(
    359 					    ELFEDIT_CONST_SYMINFO_BT,
    360 					    SYMINFO_BT_SELF, 1);
    361 					break;
    362 				case SYMINFO_BT_PARENT:
    363 					str = elfedit_atoconst_value_to_str(
    364 					    ELFEDIT_CONST_SYMINFO_BT,
    365 					    SYMINFO_BT_PARENT, 1);
    366 					break;
    367 				case SYMINFO_BT_NONE:
    368 					str = elfedit_atoconst_value_to_str(
    369 					    ELFEDIT_CONST_SYMINFO_BT,
    370 					    SYMINFO_BT_NONE, 1);
    371 					break;
    372 				}
    373 				if ((str == NULL) &&
    374 				    (bndto < SYMINFO_BT_LOWRESERVE) &&
    375 				    (argstate->dynamic.sec != NULL) &&
    376 				    (bndto < argstate->dynamic.n) &&
    377 				    (argstate->dynamic.data[bndto].d_tag ==
    378 				    DT_NEEDED))
    379 					str = elfedit_offset_to_str(
    380 					    argstate->str.sec,
    381 					    argstate->dynamic.data[bndto].
    382 					    d_un.d_val, ELFEDIT_MSG_ERR, 0);
    383 
    384 				if (str != NULL) {
    385 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    386 					    str);
    387 					continue;
    388 				}
    389 			}
    390 
    391 			/*
    392 			 * If we reach this point, we are either in numeric
    393 			 * mode, or we were unable to find a string above.
    394 			 * In either case, output as integer.
    395 			 */
    396 			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
    397 			    EC_WORD(bndto));
    398 		}
    399 		break;
    400 
    401 	case SYMINFO_CMD_T_SI_FLAGS:
    402 		for (syminfo += ndx; cnt--; syminfo++) {
    403 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
    404 				Conv_syminfo_flags_buf_t buf;
    405 
    406 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
    407 				    conv_syminfo_flags(syminfo->si_flags,
    408 				    CONV_FMT_NOBKT, &buf));
    409 			} else {
    410 				elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL),
    411 				    EC_WORD(syminfo->si_flags));
    412 			}
    413 		}
    414 		break;
    415 	}
    416 }
    417 
    418 
    419 /*
    420  * Convert the given argument string into a symbol table index.
    421  *
    422  * entry:
    423  *	argstate - State block for current symbol table.
    424  *	arg - String containing symbol index argument.
    425  *
    426  * exit:
    427  *	On success, returns the symbol index. On failure, an error
    428  *	is issued and this routine does not return.
    429  */
    430 static Word
    431 arg_to_symndx(ARGSTATE *argstate, const char *arg)
    432 {
    433 	Word symndx;
    434 
    435 	/*
    436 	 * If the -symndx option was specified, arg is an index
    437 	 * into the symbol table.
    438 	 */
    439 	if (argstate->optmask & SYMINFO_OPT_F_SYMNDX)
    440 		return (elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_SYM),
    441 		    0, argstate->syminfo.n - 1, NULL));
    442 
    443 	/*
    444 	 * arg is a symbol name. Return the index of the first symbol
    445 	 * that matches
    446 	 */
    447 	argstate_add_sym(argstate);
    448 	argstate_add_str(argstate);
    449 
    450 	(void) elfedit_name_to_symndx(argstate->sym.sec,
    451 	    argstate->str.sec, arg, ELFEDIT_MSG_ERR, &symndx);
    452 
    453 	return (symndx);
    454 }
    455 
    456 
    457 /*
    458  * Given a string argument representing an object, return the index of
    459  * the dynamic section that should be used for the si_boundto value.
    460  */
    461 static Half
    462 needed_to_boundto(ARGSTATE *argstate, const char *arg)
    463 {
    464 	Conv_inv_buf_t		inv_buf;
    465 	elfedit_dyn_elt_t	strpad_elt;
    466 	elfedit_dyn_elt_t	null_elt;
    467 	elfedit_section_t	*dynsec;
    468 	Word			null_cnt;
    469 	Dyn			*dyn;
    470 	Word			str_offset, ndx, numdyn;
    471 	int			have_string;
    472 
    473 	argstate_add_str(argstate);
    474 	argstate_add_dynamic(argstate);
    475 	dynsec = argstate->dynamic.sec;
    476 	numdyn = argstate->dynamic.n;
    477 
    478 	/* Locate DT_SUNW_STRPAD element if present and locate the DT_NULLs */
    479 	elfedit_dyn_elt_init(&strpad_elt);
    480 	elfedit_dyn_elt_init(&null_elt);
    481 	null_cnt = 0;
    482 	strpad_elt.dn_dyn.d_un.d_val = 0;
    483 	dyn = argstate->dynamic.data;
    484 	for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
    485 		switch (dyn->d_tag) {
    486 		case DT_NULL:
    487 			/* Count all the nulls, remember the first one */
    488 			null_cnt++;
    489 			if (!null_elt.dn_seen)
    490 				elfedit_dyn_elt_save(&null_elt, ndx, dyn);
    491 			break;
    492 
    493 		case DT_SUNW_STRPAD:
    494 			if (elfedit_test_osabi(argstate->obj_state,
    495 			    ELFOSABI_SOLARIS, 0))
    496 				elfedit_dyn_elt_save(&strpad_elt, ndx, dyn);
    497 			break;
    498 		}
    499 	}
    500 
    501 	/*
    502 	 * Look up the string in the string table and get its offset. If
    503 	 * this succeeds, then it is possible that there is a DT_NEEDED
    504 	 * dynamic entry that references it.
    505 	 */
    506 	have_string = elfedit_sec_findstr(argstate->str.sec,
    507 	    strpad_elt.dn_dyn.d_un.d_val, arg, &str_offset) != 0;
    508 	if (have_string) {
    509 		dyn = argstate->dynamic.data;
    510 		for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
    511 			if (((dyn->d_tag == DT_NEEDED) ||
    512 			    (dyn->d_tag == DT_USED)) &&
    513 			    (dyn->d_un.d_val == str_offset))
    514 				goto done;
    515 		}
    516 	}
    517 
    518 	/*
    519 	 * It doesn't already exist. We might be able to add a DT_NEEDED
    520 	 * to the dynamic section if an extra DT_NULL is available.
    521 	 * Otherwise, we have to fail here.
    522 	 */
    523 	if (null_cnt < 2)
    524 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
    525 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
    526 
    527 	/*
    528 	 * If the string is not already in the string table, try to
    529 	 * insert it. If it succeeds, we will convert the DT_NULL.
    530 	 * Otherwise, an error will be issued and control will not
    531 	 * return here.
    532 	 */
    533 	if (!have_string)
    534 		str_offset = elfedit_dynstr_insert(dynsec,
    535 		    argstate->str.sec, &strpad_elt, arg);
    536 
    537 	/* Convert the extra DT_NULL */
    538 	ndx = null_elt.dn_ndx;
    539 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
    540 	    EC_WORD(dynsec->sec_shndx), dynsec->sec_name, EC_WORD(ndx),
    541 	    conv_dyn_tag(DT_NEEDED,
    542 	    argstate->obj_state->os_ehdr->e_ident[EI_OSABI],
    543 	    argstate->obj_state->os_ehdr->e_machine,
    544 	    0, &inv_buf));
    545 	dyn = argstate->dynamic.data + ndx;
    546 	dyn->d_tag = DT_NEEDED;
    547 	dyn->d_un.d_val = str_offset;
    548 	elfedit_modified_data(dynsec);
    549 
    550 done:
    551 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDNEEDED),
    552 	    dynsec->sec_shndx, dynsec->sec_name, ndx, arg);
    553 	return (ndx);
    554 }
    555 
    556 /*
    557  * Common body for the syminfo: module commands. These commands
    558  * share a large amount of common behavior, so it is convenient
    559  * to centralize things and use the cmd argument to handle the
    560  * small differences.
    561  *
    562  * entry:
    563  *	cmd - One of the SYMINFO_CMD_T_* constants listed above, specifying
    564  *		which command to implement.
    565  *	obj_state, argc, argv - Standard command arguments
    566  */
    567 static elfedit_cmdret_t
    568 cmd_body(SYMINFO_CMD_T cmd, elfedit_obj_state_t *obj_state,
    569     int argc, const char *argv[])
    570 {
    571 	ARGSTATE		argstate;
    572 	Word			ndx;
    573 	Syminfo			*syminfo;
    574 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
    575 
    576 	process_args(obj_state, argc, argv, cmd, &argstate);
    577 
    578 	/* If there are no arguments, dump the whole table and return */
    579 	if (argstate.argc == 0) {
    580 		print_syminfo(cmd, 0, &argstate, 0, argstate.syminfo.n);
    581 		return (ELFEDIT_CMDRET_NONE);
    582 	}
    583 
    584 	/* The first argument is the symbol name/index */
    585 	ndx = arg_to_symndx(&argstate, argstate.argv[0]);
    586 
    587 	/* If there is a single argument, display that item and return */
    588 	if (argstate.argc == 1) {
    589 		print_syminfo(cmd, 0, &argstate, ndx, 1);
    590 		return (ELFEDIT_CMDRET_NONE);
    591 	}
    592 
    593 	syminfo = &argstate.syminfo.data[ndx];
    594 
    595 	/*
    596 	 * Syminfo [0] holds the value SYMINFO_CURRENT, as a versioning
    597 	 * technique. You're not supposed to mess with it.
    598 	 */
    599 	if (ndx == 0)
    600 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMINFO0),
    601 		    EC_WORD(argstate.syminfo.sec->sec_shndx),
    602 		    argstate.syminfo.sec->sec_name, EC_WORD(ndx));
    603 
    604 	/* The second value supplies a new value for the item */
    605 	switch (cmd) {
    606 		/*
    607 		 * SYMINFO_CMD_T_DUMP can't get here: It never has more than
    608 		 * one argument, and is handled above.
    609 		 */
    610 
    611 	case SYMINFO_CMD_T_SI_BOUNDTO:
    612 		{
    613 			const char *name = MSG_ORIG(MSG_CMD_SI_BOUNDTO);
    614 			Half boundto;
    615 
    616 			if (argstate.optmask & SYMINFO_OPT_F_NEEDED)
    617 				boundto = needed_to_boundto(&argstate,
    618 				    argstate.argv[1]);
    619 			else
    620 				boundto = elfedit_atoconst_range(
    621 				    argstate.argv[1], MSG_ORIG(MSG_STR_VALUE),
    622 				    0, 0xffff, ELFEDIT_CONST_SYMINFO_BT);
    623 
    624 			if (syminfo->si_boundto == boundto) {
    625 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    626 				    MSG_INTL(MSG_DEBUG_X_OK),
    627 				    argstate.syminfo.sec->sec_shndx,
    628 				    argstate.syminfo.sec->sec_name, ndx, name,
    629 				    syminfo->si_boundto);
    630 			} else {
    631 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    632 				    MSG_INTL(MSG_DEBUG_X_CHG),
    633 				    argstate.syminfo.sec->sec_shndx,
    634 				    argstate.syminfo.sec->sec_name, ndx, name,
    635 				    syminfo->si_boundto, boundto);
    636 				ret = ELFEDIT_CMDRET_MOD;
    637 				syminfo->si_boundto = boundto;
    638 			}
    639 		}
    640 		break;
    641 
    642 	case SYMINFO_CMD_T_SI_FLAGS:
    643 		{
    644 			Conv_syminfo_flags_buf_t flags_buf1, flags_buf2;
    645 			const char *name = MSG_ORIG(MSG_CMD_SI_FLAGS);
    646 			Half flags = 0;
    647 			int i;
    648 
    649 			/* Collect the arguments */
    650 			for (i = 1; i < argstate.argc; i++)
    651 				flags |= (Word)
    652 				    elfedit_atoconst(argstate.argv[i],
    653 				    ELFEDIT_CONST_SYMINFO_FLG);
    654 
    655 			/* Complement the value? */
    656 			if (argstate.optmask & SYMINFO_OPT_F_CMP)
    657 				flags = ~flags;
    658 
    659 			/* Perform any requested bit operations */
    660 			if (argstate.optmask & SYMINFO_OPT_F_AND)
    661 				flags &= syminfo->si_flags;
    662 			else if (argstate.optmask & SYMINFO_OPT_F_OR)
    663 				flags |= syminfo->si_flags;
    664 
    665 			/* Set the value */
    666 			if (syminfo->si_flags == flags) {
    667 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    668 				    MSG_INTL(MSG_DEBUG_S_OK),
    669 				    argstate.syminfo.sec->sec_shndx,
    670 				    argstate.syminfo.sec->sec_name, ndx, name,
    671 				    conv_syminfo_flags(syminfo->si_flags,
    672 				    0, &flags_buf1));
    673 			} else {
    674 				elfedit_msg(ELFEDIT_MSG_DEBUG,
    675 				    MSG_INTL(MSG_DEBUG_S_CHG),
    676 				    argstate.syminfo.sec->sec_shndx,
    677 				    argstate.syminfo.sec->sec_name, ndx, name,
    678 				    conv_syminfo_flags(syminfo->si_flags,
    679 				    0, &flags_buf1),
    680 				    conv_syminfo_flags(flags, 0, &flags_buf2));
    681 				ret = ELFEDIT_CMDRET_MOD;
    682 				syminfo->si_flags = flags;
    683 			}
    684 		}
    685 		break;
    686 	}
    687 
    688 	/*
    689 	 * If we modified the syminfo section, tell libelf.
    690 	 */
    691 	if (ret == ELFEDIT_CMDRET_MOD)
    692 		elfedit_modified_data(argstate.syminfo.sec);
    693 
    694 	/* Do autoprint */
    695 	print_syminfo(cmd, 1, &argstate, ndx, 1);
    696 
    697 	return (ret);
    698 }
    699 
    700 
    701 
    702 
    703 /*
    704  * Command completion functions for the various commands
    705  */
    706 /*ARGSUSED*/
    707 static void
    708 cpl_si_boundto(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    709     const char *argv[], int num_opt)
    710 {
    711 	int i;
    712 
    713 	/*
    714 	 * If -needed option is not present, the second argument can be
    715 	 * an SYMINFO_BT_ value.
    716 	 */
    717 	if (argc != (num_opt + 2))
    718 		return;
    719 
    720 	/* Is -needed there? If so, no completion is possible so return */
    721 	for (i = 0; i < num_opt; i++)
    722 		if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0)
    723 			return;
    724 
    725 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_BT);
    726 }
    727 
    728 /*ARGSUSED*/
    729 static void
    730 cpl_si_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
    731     const char *argv[], int num_opt)
    732 {
    733 	/* The second argument can be an SYMINFO_FLG_ value */
    734 	if (argc == (num_opt + 2))
    735 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_FLG);
    736 }
    737 
    738 
    739 
    740 /*
    741  * Implementation functions for the commands
    742  */
    743 static elfedit_cmdret_t
    744 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    745 {
    746 	return (cmd_body(SYMINFO_CMD_T_DUMP, obj_state, argc, argv));
    747 }
    748 
    749 
    750 static elfedit_cmdret_t
    751 cmd_si_boundto(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    752 {
    753 	return (cmd_body(SYMINFO_CMD_T_SI_BOUNDTO, obj_state, argc, argv));
    754 }
    755 
    756 
    757 static elfedit_cmdret_t
    758 cmd_si_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
    759 {
    760 	return (cmd_body(SYMINFO_CMD_T_SI_FLAGS, obj_state, argc, argv));
    761 }
    762 
    763 
    764 
    765 
    766 /*ARGSUSED*/
    767 elfedit_module_t *
    768 elfedit_init(elfedit_module_version_t version)
    769 {
    770 	/* sym:dump */
    771 	static const char *name_dump[] = {
    772 	    MSG_ORIG(MSG_CMD_DUMP),
    773 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
    774 	    NULL
    775 	};
    776 	static elfedit_cmd_optarg_t opt_dump[] = {
    777 		{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
    778 		    /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
    779 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
    780 		    SYMINFO_OPT_F_SYMNDX, 0 },
    781 		{ NULL }
    782 	};
    783 	static elfedit_cmd_optarg_t arg_dump[] = {
    784 		{ MSG_ORIG(MSG_STR_SYM),
    785 		    /* MSG_INTL(MSG_A1_SYM) */
    786 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
    787 		    ELFEDIT_CMDOA_F_OPT },
    788 		{ NULL }
    789 	};
    790 
    791 	/* sym:si_boundto */
    792 	static const char *name_si_boundto[] = {
    793 	    MSG_ORIG(MSG_CMD_SI_BOUNDTO), NULL };
    794 	static elfedit_cmd_optarg_t opt_si_boundto[] = {
    795 		{ MSG_ORIG(MSG_STR_MINUS_NEEDED),
    796 		    /* MSG_INTL(MSG_OPTDESC_NEEDED) */
    797 		    ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED), 0,
    798 		    SYMINFO_OPT_F_NEEDED, 0 },
    799 		{ ELFEDIT_STDOA_OPT_O, NULL,
    800 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
    801 		{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
    802 		    /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
    803 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
    804 		    SYMINFO_OPT_F_SYMNDX, 0 },
    805 		{ NULL }
    806 	};
    807 	static elfedit_cmd_optarg_t arg_si_boundto[] = {
    808 		{ MSG_ORIG(MSG_STR_SYM),
    809 		    /* MSG_INTL(MSG_A1_SYM) */
    810 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
    811 		    ELFEDIT_CMDOA_F_OPT },
    812 		{ MSG_ORIG(MSG_STR_VALUE),
    813 		    /* MSG_INTL(MSG_A2_DESC_SI_BOUNDTO) */
    814 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SI_BOUNDTO),
    815 		    ELFEDIT_CMDOA_F_OPT },
    816 		{ NULL }
    817 	};
    818 
    819 	/* sym:si_flags */
    820 	static const char *name_si_flags[] = {
    821 	    MSG_ORIG(MSG_CMD_SI_FLAGS), NULL };
    822 	static elfedit_cmd_optarg_t opt_si_flags[] = {
    823 		{ ELFEDIT_STDOA_OPT_AND, NULL, ELFEDIT_CMDOA_F_INHERIT,
    824 		    SYMINFO_OPT_F_AND, SYMINFO_OPT_F_OR },
    825 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
    826 		    ELFEDIT_CMDOA_F_INHERIT, SYMINFO_OPT_F_CMP, 0 },
    827 		{ ELFEDIT_STDOA_OPT_O, NULL,
    828 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
    829 		{ ELFEDIT_STDOA_OPT_OR, NULL, ELFEDIT_CMDOA_F_INHERIT,
    830 		    SYMINFO_OPT_F_OR, SYMINFO_OPT_F_AND },
    831 		{ MSG_ORIG(MSG_STR_MINUS_SYMNDX),
    832 		    /* MSG_INTL(MSG_OPTDESC_SYMNDX) */
    833 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0,
    834 		    SYMINFO_OPT_F_SYMNDX, 0 },
    835 		{ NULL }
    836 	};
    837 	static elfedit_cmd_optarg_t arg_si_flags[] = {
    838 		{ MSG_ORIG(MSG_STR_SYM),
    839 		    /* MSG_INTL(MSG_A1_SYM) */
    840 		    ELFEDIT_I18NHDL(MSG_A1_SYM),
    841 		    ELFEDIT_CMDOA_F_OPT },
    842 		{ MSG_ORIG(MSG_STR_VALUE),
    843 		    /* MSG_INTL(MSG_A2_DESC_SI_FLAGS) */
    844 		    ELFEDIT_I18NHDL(MSG_A2_DESC_SI_FLAGS),
    845 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
    846 		{ NULL }
    847 	};
    848 
    849 	static elfedit_cmd_t cmds[] = {
    850 		/* sym:dump */
    851 		{ cmd_dump, NULL, name_dump,
    852 		    /* MSG_INTL(MSG_DESC_DUMP) */
    853 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
    854 		    /* MSG_INTL(MSG_HELP_DUMP) */
    855 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
    856 		    opt_dump, arg_dump },
    857 
    858 		/* sym:si_boundto */
    859 		{ cmd_si_boundto, cpl_si_boundto, name_si_boundto,
    860 		    /* MSG_INTL(MSG_DESC_SI_BOUNDTO) */
    861 		    ELFEDIT_I18NHDL(MSG_DESC_SI_BOUNDTO),
    862 		    /* MSG_INTL(MSG_HELP_SI_BOUNDTO) */
    863 		    ELFEDIT_I18NHDL(MSG_HELP_SI_BOUNDTO),
    864 		    opt_si_boundto, arg_si_boundto },
    865 
    866 		/* sym:si_flags */
    867 		{ cmd_si_flags, cpl_si_flags, name_si_flags,
    868 		    /* MSG_INTL(MSG_DESC_SI_FLAGS) */
    869 		    ELFEDIT_I18NHDL(MSG_DESC_SI_FLAGS),
    870 		    /* MSG_INTL(MSG_HELP_SI_FLAGS) */
    871 		    ELFEDIT_I18NHDL(MSG_HELP_SI_FLAGS),
    872 		    opt_si_flags, arg_si_flags },
    873 
    874 		{ NULL }
    875 	};
    876 
    877 	static elfedit_module_t module = {
    878 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
    879 	    /* MSG_INTL(MSG_MOD_DESC) */
    880 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
    881 	    cmds, mod_i18nhdl_to_str };
    882 
    883 	return (&module);
    884 }
    885