xref: /illumos-gate/usr/src/cmd/sgs/elfedit/modules/common/sym.c (revision 069e6b7e31ba5dcbc5441b98af272714d9a5455c)
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  */
49 typedef 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  */
79 const 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  */
100 static const char *
101 mod_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  */
114 typedef 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  */
149 typedef 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;
172 typedef 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  */
203 static void
204 symstate_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 }
212 static void
213 symstate_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 }
221 static void
222 symstate_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  */
242 static void
243 dump_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  */
300 static int
301 all_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  */
423 static void
424 print_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  */
591 static void
592 print_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  */
681 static elfedit_cmdret_t
682 cmd_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 
739 static elfedit_cmdret_t
740 cmd_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 
791 static elfedit_cmdret_t
792 cmd_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 
936 static elfedit_cmdret_t
937 cmd_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 
976 static elfedit_cmdret_t
977 cmd_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  */
1035 static ARGSTATE *
1036 process_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  */
1227 static elfedit_cmdret_t
1228 symstate_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  */
1403 static elfedit_cmdret_t
1404 cmd_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*/
1468 static void
1469 cpl_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*/
1527 static void
1528 cpl_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*/
1540 static void
1541 cpl_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*/
1588 static void
1589 cpl_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*/
1601 static void
1602 cpl_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  */
1618 static elfedit_cmdret_t
1619 cmd_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 
1625 static elfedit_cmdret_t
1626 cmd_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 
1632 static elfedit_cmdret_t
1633 cmd_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 
1638 static elfedit_cmdret_t
1639 cmd_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 
1644 static elfedit_cmdret_t
1645 cmd_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 
1650 static elfedit_cmdret_t
1651 cmd_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 
1656 static elfedit_cmdret_t
1657 cmd_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 
1662 static elfedit_cmdret_t
1663 cmd_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 
1668 static elfedit_cmdret_t
1669 cmd_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 
1674 static elfedit_cmdret_t
1675 cmd_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*/
1683 elfedit_module_t *
1684 elfedit_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), 0, 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), 0, 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), 0, 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, 0,
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), 0, 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), 0, 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), 0, 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), 0, 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), 0, 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), 0, 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, 0,
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), 0, 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), 0, 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), 0, 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, 0,
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