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