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