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