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