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