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