1d29b2c44Sab /*
2d29b2c44Sab  * CDDL HEADER START
3d29b2c44Sab  *
4d29b2c44Sab  * The contents of this file are subject to the terms of the
5d29b2c44Sab  * Common Development and Distribution License (the "License").
6d29b2c44Sab  * You may not use this file except in compliance with the License.
7d29b2c44Sab  *
8d29b2c44Sab  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d29b2c44Sab  * or http://www.opensolaris.org/os/licensing.
10d29b2c44Sab  * See the License for the specific language governing permissions
11d29b2c44Sab  * and limitations under the License.
12d29b2c44Sab  *
13d29b2c44Sab  * When distributing Covered Code, include this CDDL HEADER in each
14d29b2c44Sab  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d29b2c44Sab  * If applicable, add the following below this CDDL HEADER, with the
16d29b2c44Sab  * fields enclosed by brackets "[]" replaced with your own identifying
17d29b2c44Sab  * information: Portions Copyright [yyyy] [name of copyright owner]
18d29b2c44Sab  *
19d29b2c44Sab  * CDDL HEADER END
20d29b2c44Sab  */
21d29b2c44Sab 
22d29b2c44Sab /*
234f680cc6SAli Bahrami  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24d29b2c44Sab  * Use is subject to license terms.
25d29b2c44Sab  */
26d29b2c44Sab 
27d29b2c44Sab #define	ELF_TARGET_AMD64	/* SHN_AMD64_LCOMMON */
28d29b2c44Sab 
29d29b2c44Sab #include	<stdio.h>
30d29b2c44Sab #include	<unistd.h>
31d29b2c44Sab #include	<elfedit.h>
32d29b2c44Sab #include	<strings.h>
33d29b2c44Sab #include	<debug.h>
34d29b2c44Sab #include	<conv.h>
35d29b2c44Sab #include	<sym_msg.h>
36d29b2c44Sab 
37d29b2c44Sab 
38d29b2c44Sab 
39d29b2c44Sab 
40d29b2c44Sab #define	MAXNDXSIZE	10
41d29b2c44Sab 
42d29b2c44Sab 
43d29b2c44Sab 
44d29b2c44Sab /*
45d29b2c44Sab  * This module uses shared code for several of the commands.
46d29b2c44Sab  * It is sometimes necessary to know which specific command
47d29b2c44Sab  * is active.
48d29b2c44Sab  */
49d29b2c44Sab typedef enum {
50d29b2c44Sab 	SYM_CMD_T_DUMP =		0,	/* sym:dump */
51d29b2c44Sab 
52d29b2c44Sab 	SYM_CMD_T_ST_BIND =		1,	/* sym:st_bind */
53d29b2c44Sab 	SYM_CMD_T_ST_INFO =		2,	/* sym:st_info */
54d29b2c44Sab 	SYM_CMD_T_ST_NAME =		3,	/* sym:st_name */
55d29b2c44Sab 	SYM_CMD_T_ST_OTHER =		4,	/* sym:st_other */
56d29b2c44Sab 	SYM_CMD_T_ST_SHNDX =		5,	/* sym:st_shndx */
57d29b2c44Sab 	SYM_CMD_T_ST_SIZE =		6,	/* sym:st_size */
58d29b2c44Sab 	SYM_CMD_T_ST_TYPE =		7,	/* sym:st_type */
59d29b2c44Sab 	SYM_CMD_T_ST_VALUE =		8,	/* sym:st_value */
60d29b2c44Sab 	SYM_CMD_T_ST_VISIBILITY =	9	/* sym:st_visibility */
61d29b2c44Sab } SYM_CMD_T;
62d29b2c44Sab 
63d29b2c44Sab 
64d29b2c44Sab 
65d29b2c44Sab /*
66d29b2c44Sab  * ELFCLASS-specific definitions
67d29b2c44Sab  */
68d29b2c44Sab #ifdef _ELF64
69d29b2c44Sab 
70d29b2c44Sab #define	MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_64
71d29b2c44Sab 
72d29b2c44Sab #else
73d29b2c44Sab 
74d29b2c44Sab #define	MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_32
75d29b2c44Sab 
76d29b2c44Sab /*
77d29b2c44Sab  * We supply this function for the msg module. Only one copy is needed.
78d29b2c44Sab  */
79d29b2c44Sab const char *
_sym_msg(Msg mid)80d29b2c44Sab _sym_msg(Msg mid)
81d29b2c44Sab {
82d29b2c44Sab 	return (gettext(MSG_ORIG(mid)));
83d29b2c44Sab }
84d29b2c44Sab 
85d29b2c44Sab #endif
86d29b2c44Sab 
87d29b2c44Sab 
88d29b2c44Sab 
89d29b2c44Sab /*
90d29b2c44Sab  * This function is supplied to elfedit through our elfedit_module_t
91d29b2c44Sab  * definition. It translates the opaque elfedit_i18nhdl_t handles
92d29b2c44Sab  * in our module interface into the actual strings for elfedit to
93d29b2c44Sab  * use.
94d29b2c44Sab  *
95d29b2c44Sab  * note:
96d29b2c44Sab  *	This module uses Msg codes for its i18n handle type.
97d29b2c44Sab  *	So the translation is simply to use MSG_INTL() to turn
98d29b2c44Sab  *	it into a string and return it.
99d29b2c44Sab  */
100d29b2c44Sab static const char *
mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)101d29b2c44Sab mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
102d29b2c44Sab {
103d29b2c44Sab 	Msg msg = (Msg)hdl;
104d29b2c44Sab 
105d29b2c44Sab 	return (MSG_INTL(msg));
106d29b2c44Sab }
107d29b2c44Sab 
108d29b2c44Sab 
109d29b2c44Sab 
110d29b2c44Sab /*
111d29b2c44Sab  * The sym_opt_t enum specifies a bit value for every optional
112d29b2c44Sab  * argument allowed by a command in this module.
113d29b2c44Sab  */
114d29b2c44Sab typedef enum {
115d29b2c44Sab 	SYM_OPT_F_XSHINDEX =	1,	/* -e: Force shndx update to extended */
116d29b2c44Sab 					/*	 index section */
117d29b2c44Sab 	SYM_OPT_F_NAMOFFSET =	2,	/* -name_offset: sym:st_name name arg */
118d29b2c44Sab 					/*	is numeric offset */
119*9320f495SToomas Soome 					/*	rather than ASCII string */
120d29b2c44Sab 	SYM_OPT_F_SECSHNDX =	4,	/* -secshndx: Section arg is */
121d29b2c44Sab 					/*	section index, not name */
122d29b2c44Sab 	SYM_OPT_F_SECSHTYP =	8,	/* -secshtyp: Section arg is */
123d29b2c44Sab 					/*	section type, not name */
124d29b2c44Sab 	SYM_OPT_F_SHNAME =	16,	/* -shnam name: section spec. by name */
125d29b2c44Sab 	SYM_OPT_F_SHNDX =	32,	/* -shndx ndx: section spec. by index */
126d29b2c44Sab 	SYM_OPT_F_SHTYP =	64,	/* -shtyp type: section spec. by type */
127d29b2c44Sab 	SYM_OPT_F_SYMNDX =	128	/* -symndx: Sym specified by index */
128d29b2c44Sab } sym_opt_t;
129d29b2c44Sab 
130d29b2c44Sab 
131d29b2c44Sab /*
132d29b2c44Sab  * A variable of type ARGSTATE is used by each command to maintain
133d29b2c44Sab  * the overall state for a given set of arguments and the symbol tables
134d29b2c44Sab  * being managed.
135d29b2c44Sab  *
136d29b2c44Sab  * The state for each symbol table and the auxiliary sections that are
137d29b2c44Sab  * related to it are kept in a SYMSTATE sub-struct.
138d29b2c44Sab  *
139d29b2c44Sab  * One benefit of ARGSTATE is that it helps us to ensure that we only
140d29b2c44Sab  * fetch each section a single time:
141d29b2c44Sab  *	- More efficient
142d29b2c44Sab  *	- Prevents multiple ELFEDIT_MSG_DEBUG messages from
143d29b2c44Sab  *	  being produced for a given section.
144d29b2c44Sab  *
145d29b2c44Sab  * note: The symstate array in ARGSTATE is defined as having one
146d29b2c44Sab  *	element, but in reality, we allocate enough room for
147d29b2c44Sab  *	the number of elements defined in the numsymstate field.
148d29b2c44Sab  */
149d29b2c44Sab typedef struct {
150d29b2c44Sab 	Word ndx;	/* If argstate.argc > 0, this is the table index */
151d29b2c44Sab 	struct {				/* Symbol table */
152d29b2c44Sab 		elfedit_section_t	*sec;
153d29b2c44Sab 		Sym			*data;
154d29b2c44Sab 		Word			n;
155d29b2c44Sab 	} sym;
156d29b2c44Sab 	struct {				/* String table */
157d29b2c44Sab 		elfedit_section_t	*sec;
158d29b2c44Sab 	} str;
159d29b2c44Sab 	struct {				/* Versym */
160d29b2c44Sab 		Word			shndx;
161d29b2c44Sab 		elfedit_section_t	*sec;
162d29b2c44Sab 		Versym			*data;
163d29b2c44Sab 		Word			n;
164d29b2c44Sab 	} versym;
165d29b2c44Sab 	struct {				/* Extended section indices */
166d29b2c44Sab 		Word			shndx;
167d29b2c44Sab 		elfedit_section_t	*sec;
168d29b2c44Sab 		Word			*data;
169d29b2c44Sab 		Word			n;
170d29b2c44Sab 	} xshndx;
171d29b2c44Sab } SYMSTATE;
172d29b2c44Sab typedef struct {
173d29b2c44Sab 	elfedit_obj_state_t	*obj_state;
174*9320f495SToomas Soome 	sym_opt_t		optmask;	/* Mask of options used */
175d29b2c44Sab 	int			argc;		/* # of plain arguments */
176d29b2c44Sab 	const char		**argv;		/* Plain arguments */
177d29b2c44Sab 	int			numsymstate;	/* # of items in symstate[] */
178d29b2c44Sab 	SYMSTATE		symstate[1];	/* Symbol tables to process */
179d29b2c44Sab } ARGSTATE;
180d29b2c44Sab 
181d29b2c44Sab 
182d29b2c44Sab /*
183d29b2c44Sab  * We maintain the state of each symbol table and related associated
184d29b2c44Sab  * sections in a SYMSTATE structure . We don't look those auxiliary
185d29b2c44Sab  * things up unless we actually need them, both to be efficient,
186d29b2c44Sab  * and to prevent duplicate ELFEDIT_MSG_DEBUG messages from being
187d29b2c44Sab  * issued as they are located. Hence, process_args() is used to
188d29b2c44Sab  * initialize the state block with just the symbol table, and then one
189d29b2c44Sab  * of the argstate_add_XXX() functions is used as needed
190d29b2c44Sab  * to fetch the additional sections.
191d29b2c44Sab  *
192d29b2c44Sab  * entry:
193d29b2c44Sab  *	argstate - Overall state block
194d29b2c44Sab  *	symstate - State block for current symbol table.
195d29b2c44Sab  *
196d29b2c44Sab  * exit:
197d29b2c44Sab  *	If the needed auxiliary section is not found, an error is
198d29b2c44Sab  *	issued and the argstate_add_XXX() routine does not return.
199d29b2c44Sab  *	Otherwise, the fields in argstate have been filled in, ready
200d29b2c44Sab  *	for use.
201d29b2c44Sab  *
202d29b2c44Sab  */
203d29b2c44Sab static void
symstate_add_str(ARGSTATE * argstate,SYMSTATE * symstate)204d29b2c44Sab symstate_add_str(ARGSTATE *argstate, SYMSTATE *symstate)
205d29b2c44Sab {
206d29b2c44Sab 	if (symstate->str.sec != NULL)
207d29b2c44Sab 		return;
208d29b2c44Sab 
209d29b2c44Sab 	symstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
21055ef6355Sab 	    symstate->sym.sec->sec_shdr->sh_link, 0);
211d29b2c44Sab }
212d29b2c44Sab static void
symstate_add_versym(ARGSTATE * argstate,SYMSTATE * symstate)213d29b2c44Sab symstate_add_versym(ARGSTATE *argstate, SYMSTATE *symstate)
214d29b2c44Sab {
215d29b2c44Sab 	if (symstate->versym.sec != NULL)
216d29b2c44Sab 		return;
217d29b2c44Sab 
218d29b2c44Sab 	symstate->versym.sec = elfedit_sec_getversym(argstate->obj_state,
219d29b2c44Sab 	    symstate->sym.sec, &symstate->versym.data, &symstate->versym.n);
220d29b2c44Sab }
221d29b2c44Sab static void
symstate_add_xshndx(ARGSTATE * argstate,SYMSTATE * symstate)222d29b2c44Sab symstate_add_xshndx(ARGSTATE *argstate, SYMSTATE *symstate)
223d29b2c44Sab {
224d29b2c44Sab 	if (symstate->xshndx.sec != NULL)
225d29b2c44Sab 		return;
226d29b2c44Sab 
227d29b2c44Sab 	symstate->xshndx.sec = elfedit_sec_getxshndx(argstate->obj_state,
228d29b2c44Sab 	    symstate->sym.sec, &symstate->xshndx.data, &symstate->xshndx.n);
229d29b2c44Sab }
230d29b2c44Sab 
231d29b2c44Sab 
232d29b2c44Sab 
233d29b2c44Sab /*
234d29b2c44Sab  * Display symbol table entries in the style used by elfdump.
235d29b2c44Sab  *
236d29b2c44Sab  * entry:
237d29b2c44Sab  *	argstate - Overall state block
238d29b2c44Sab  *	symstate - State block for current symbol table.
239d29b2c44Sab  *	ndx - Index of first symbol to display
240d29b2c44Sab  *	cnt - Number of symbols to display
241d29b2c44Sab  */
242d29b2c44Sab static void
dump_symtab(ARGSTATE * argstate,SYMSTATE * symstate,Word ndx,Word cnt)243d29b2c44Sab dump_symtab(ARGSTATE *argstate, SYMSTATE *symstate, Word ndx, Word cnt)
244d29b2c44Sab {
245d29b2c44Sab 	char			index[MAXNDXSIZE];
246d29b2c44Sab 	Word			shndx;
247d29b2c44Sab 	const char		*shndx_name;
248d29b2c44Sab 	elfedit_section_t	*symsec;
249d29b2c44Sab 	elfedit_section_t	*strsec;
250d29b2c44Sab 	Sym			*sym;
251d29b2c44Sab 	elfedit_obj_state_t	*obj_state = argstate->obj_state;
2524f680cc6SAli Bahrami 	uchar_t			osabi = obj_state->os_ehdr->e_ident[EI_OSABI];
253d29b2c44Sab 	Half			mach = obj_state->os_ehdr->e_machine;
254d29b2c44Sab 	const char		*symname;
255d29b2c44Sab 	Versym			versym;
256d29b2c44Sab 
257d29b2c44Sab 	symsec = symstate->sym.sec;
258d29b2c44Sab 	sym = symstate->sym.data + ndx;
259d29b2c44Sab 
260d29b2c44Sab 	symstate_add_str(argstate, symstate);
261d29b2c44Sab 	strsec = symstate->str.sec;
262d29b2c44Sab 
263d29b2c44Sab 	/* If there is a versym index section, fetch it */
264d29b2c44Sab 	if (symstate->versym.shndx != SHN_UNDEF)
265d29b2c44Sab 		symstate_add_versym(argstate, symstate);
266d29b2c44Sab 
267d29b2c44Sab 	/* If there is an extended index section, fetch it */
268d29b2c44Sab 	if (symstate->xshndx.shndx != SHN_UNDEF)
269d29b2c44Sab 		symstate_add_xshndx(argstate, symstate);
270d29b2c44Sab 
271d29b2c44Sab 	elfedit_printf(MSG_INTL(MSG_FMT_SYMTAB), symsec->sec_name);
272d29b2c44Sab 	Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
273d29b2c44Sab 	for (; cnt-- > 0; ndx++, sym++) {
274d29b2c44Sab 		(void) snprintf(index, MAXNDXSIZE,
275d29b2c44Sab 		    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx));
276d29b2c44Sab 		versym = (symstate->versym.sec == NULL) ? 0 :
277d29b2c44Sab 		    symstate->versym.data[ndx];
278d29b2c44Sab 		symname = elfedit_offset_to_str(strsec, sym->st_name,
279d29b2c44Sab 		    ELFEDIT_MSG_DEBUG, 0);
280d29b2c44Sab 		shndx = sym->st_shndx;
281d29b2c44Sab 		if ((shndx == SHN_XINDEX) && (symstate->xshndx.sec != NULL))
282d29b2c44Sab 			shndx = symstate->xshndx.data[ndx];
283d29b2c44Sab 		shndx_name = elfedit_shndx_to_name(obj_state, shndx);
2844f680cc6SAli Bahrami 		Elf_syms_table_entry(NULL, ELF_DBG_ELFDUMP, index, osabi, mach,
285d29b2c44Sab 		    sym, versym, 0, shndx_name, symname);
286d29b2c44Sab 	}
287d29b2c44Sab }
288d29b2c44Sab 
289d29b2c44Sab 
290d29b2c44Sab 
291d29b2c44Sab /*
292d29b2c44Sab  * Called by print_sym() to determine if a given symbol has the same
293d29b2c44Sab  * display value for the current command in every symbol table.
294d29b2c44Sab  *
295d29b2c44Sab  * entry:
296d29b2c44Sab  *	cmd - SYM_CMD_T_* value giving identify of caller
297d29b2c44Sab  *	argstate - Overall state block
298d29b2c44Sab  *	outstyle - Output style to use
299d29b2c44Sab  */
300d29b2c44Sab static int
all_same(SYM_CMD_T cmd,ARGSTATE * argstate,elfedit_outstyle_t outstyle)301d29b2c44Sab all_same(SYM_CMD_T cmd, ARGSTATE *argstate, elfedit_outstyle_t outstyle)
302d29b2c44Sab {
303d29b2c44Sab 	Word			tblndx;
304d29b2c44Sab 	SYMSTATE		*symstate1, *symstate2;
305d29b2c44Sab 	Sym			*sym1, *sym2;
306d29b2c44Sab 
307d29b2c44Sab 	symstate1 = argstate->symstate;
308d29b2c44Sab 	for (tblndx = 0; tblndx < (argstate->numsymstate - 1);
309d29b2c44Sab 	    tblndx++, symstate1++) {
310d29b2c44Sab 		symstate2 = symstate1 + 1;
311d29b2c44Sab 		sym1 = &symstate1->sym.data[symstate1->ndx];
312d29b2c44Sab 		sym2 = &symstate2->sym.data[symstate2->ndx];
313d29b2c44Sab 
314d29b2c44Sab 		switch (cmd) {
315d29b2c44Sab 		case SYM_CMD_T_DUMP:
316d29b2c44Sab 			/* sym:dump should always show everything */
317d29b2c44Sab 			return (0);
318d29b2c44Sab 
319d29b2c44Sab 		case SYM_CMD_T_ST_BIND:
320d29b2c44Sab 			if (ELF_ST_BIND(sym1->st_info) !=
321d29b2c44Sab 			    ELF_ST_BIND(sym2->st_info))
322d29b2c44Sab 				return (0);
323d29b2c44Sab 			break;
324d29b2c44Sab 
325d29b2c44Sab 		case SYM_CMD_T_ST_INFO:
326d29b2c44Sab 			if (sym1->st_info !=  sym2->st_info)
327d29b2c44Sab 				return (0);
328d29b2c44Sab 			break;
329d29b2c44Sab 
330d29b2c44Sab 		case SYM_CMD_T_ST_NAME:
331d29b2c44Sab 			/*
332d29b2c44Sab 			 * In simple output mode, we show the string. In
333d29b2c44Sab 			 * numeric mode, we show the string table offset.
334d29b2c44Sab 			 */
335d29b2c44Sab 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
336d29b2c44Sab 				const char *n1, *n2;
337d29b2c44Sab 
338d29b2c44Sab 				symstate_add_str(argstate, symstate1);
339d29b2c44Sab 				symstate_add_str(argstate, symstate2);
340d29b2c44Sab 				n1 = elfedit_offset_to_str(symstate1->str.sec,
341d29b2c44Sab 				    sym1->st_name, ELFEDIT_MSG_DEBUG, 0);
342d29b2c44Sab 				n2 = elfedit_offset_to_str(symstate2->str.sec,
343d29b2c44Sab 				    sym2->st_name, ELFEDIT_MSG_DEBUG, 0);
344d29b2c44Sab 				if (strcmp(n1, n2) != 0)
345d29b2c44Sab 					return (0);
346d29b2c44Sab 			} else {
347d29b2c44Sab 				if (sym1->st_name !=  sym2->st_name)
348d29b2c44Sab 					return (0);
349d29b2c44Sab 			}
350d29b2c44Sab 			break;
351d29b2c44Sab 
352d29b2c44Sab 		case SYM_CMD_T_ST_OTHER:
353d29b2c44Sab 			if (sym1->st_other !=  sym2->st_other)
354d29b2c44Sab 				return (0);
355d29b2c44Sab 			break;
356d29b2c44Sab 
357d29b2c44Sab 		case SYM_CMD_T_ST_SHNDX:
358d29b2c44Sab 			{
359d29b2c44Sab 				Word	ndx1, ndx2;
360d29b2c44Sab 
361d29b2c44Sab 				ndx1 = sym1->st_shndx;
362d29b2c44Sab 				if ((ndx1 == SHN_XINDEX) &&
363d29b2c44Sab 				    (symstate1->xshndx.shndx != SHN_UNDEF)) {
364d29b2c44Sab 					symstate_add_xshndx(argstate,
365d29b2c44Sab 					    symstate1);
366d29b2c44Sab 					ndx1 = symstate1->xshndx.
367d29b2c44Sab 					    data[symstate1->ndx];
368d29b2c44Sab 				}
369d29b2c44Sab 				ndx2 = sym2->st_shndx;
370d29b2c44Sab 				if ((ndx2 == SHN_XINDEX) &&
371d29b2c44Sab 				    (symstate2->xshndx.shndx != SHN_UNDEF)) {
372d29b2c44Sab 					symstate_add_xshndx(argstate,
373d29b2c44Sab 					    symstate2);
374d29b2c44Sab 					ndx2 = symstate2->xshndx.
375d29b2c44Sab 					    data[symstate2->ndx];
376d29b2c44Sab 				}
377d29b2c44Sab 				if (ndx1 !=  ndx2)
378d29b2c44Sab 					return (0);
379d29b2c44Sab 			}
380d29b2c44Sab 			break;
381d29b2c44Sab 
382d29b2c44Sab 		case SYM_CMD_T_ST_SIZE:
383d29b2c44Sab 			if (sym1->st_size !=  sym2->st_size)
384d29b2c44Sab 				return (0);
385d29b2c44Sab 			break;
386d29b2c44Sab 
387d29b2c44Sab 		case SYM_CMD_T_ST_TYPE:
388d29b2c44Sab 			if (ELF_ST_TYPE(sym1->st_info) !=
389d29b2c44Sab 			    ELF_ST_TYPE(sym2->st_info))
390d29b2c44Sab 				return (0);
391d29b2c44Sab 			break;
392d29b2c44Sab 
393d29b2c44Sab 		case SYM_CMD_T_ST_VALUE:
394d29b2c44Sab 			if (sym1->st_value !=  sym2->st_value)
395d29b2c44Sab 				return (0);
396d29b2c44Sab 			break;
397d29b2c44Sab 
398d29b2c44Sab 		case SYM_CMD_T_ST_VISIBILITY:
399d29b2c44Sab 			if (ELF_ST_VISIBILITY(sym1->st_info) !=
400d29b2c44Sab 			    ELF_ST_VISIBILITY(sym2->st_info))
401d29b2c44Sab 				return (0);
402d29b2c44Sab 			break;
403d29b2c44Sab 		}
404d29b2c44Sab 	}
405d29b2c44Sab 
406d29b2c44Sab 	/* If we got here, there are no differences (or maybe only 1 table */
407d29b2c44Sab 	return (1);
408d29b2c44Sab }
409d29b2c44Sab 
410d29b2c44Sab 
411d29b2c44Sab /*
412d29b2c44Sab  * Called by print_sym() to display values for a single symbol table.
413d29b2c44Sab  *
414d29b2c44Sab  * entry:
415d29b2c44Sab  *	autoprint - If True, output is only produced if the elfedit
416d29b2c44Sab  *		autoprint flag is set. If False, output is always produced.
417d29b2c44Sab  *	cmd - SYM_CMD_T_* value giving identify of caller
418d29b2c44Sab  *	argstate - Overall state block
419d29b2c44Sab  *	symstate - State block for current symbol table.
420d29b2c44Sab  *	ndx - Index of first symbol to display
421d29b2c44Sab  *	cnt - Number of symbols to display
422d29b2c44Sab  */
423d29b2c44Sab static void
print_symstate(SYM_CMD_T cmd,ARGSTATE * argstate,SYMSTATE * symstate,elfedit_outstyle_t outstyle,Word ndx,Word cnt)424d29b2c44Sab print_symstate(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate,
425d29b2c44Sab     elfedit_outstyle_t outstyle, Word ndx, Word cnt)
426d29b2c44Sab {
427d29b2c44Sab 	Word	value;
428d29b2c44Sab 	Sym	*sym;
429d29b2c44Sab 
430d29b2c44Sab 	/*
431d29b2c44Sab 	 * If doing default output, use elfdump style where we
432d29b2c44Sab 	 * show all symbol attributes. In this case, the command
433d29b2c44Sab 	 * that called us doesn't matter
434d29b2c44Sab 	 */
435d29b2c44Sab 	if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
436d29b2c44Sab 		dump_symtab(argstate, symstate, ndx, cnt);
437d29b2c44Sab 		return;
438d29b2c44Sab 	}
439d29b2c44Sab 
440d29b2c44Sab 	sym = symstate->sym.data;
441d29b2c44Sab 
442d29b2c44Sab 	switch (cmd) {
443d29b2c44Sab 	case SYM_CMD_T_ST_BIND:
444d29b2c44Sab 		{
445d29b2c44Sab 			Conv_inv_buf_t inv_buf;
446d29b2c44Sab 
447d29b2c44Sab 			for (sym += ndx; cnt--; sym++) {
448d29b2c44Sab 				value = ELF_ST_BIND(sym->st_info);
449d29b2c44Sab 				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
450d29b2c44Sab 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
451d29b2c44Sab 					    conv_sym_info_bind(value,
4524f680cc6SAli Bahrami 					    CONV_FMT_ALT_CF, &inv_buf));
453d29b2c44Sab 				} else {
454d29b2c44Sab 					elfedit_printf(
455d29b2c44Sab 					    MSG_ORIG(MSG_FMT_WORDVALNL),
456d29b2c44Sab 					    EC_WORD(value));
457d29b2c44Sab 				}
458d29b2c44Sab 			}
459d29b2c44Sab 		}
460d29b2c44Sab 		return;
461d29b2c44Sab 
462d29b2c44Sab 	case SYM_CMD_T_ST_INFO:
463d29b2c44Sab 		for (sym += ndx; cnt-- > 0; sym++)
464d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
465d29b2c44Sab 			    EC_WORD(sym->st_info));
466d29b2c44Sab 		return;
467d29b2c44Sab 
468d29b2c44Sab 	case SYM_CMD_T_ST_NAME:
469d29b2c44Sab 		/*
470d29b2c44Sab 		 * In simple output mode, we show the string. In numeric
471d29b2c44Sab 		 * mode, we show the string table offset.
472d29b2c44Sab 		 */
473d29b2c44Sab 		if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
474d29b2c44Sab 			symstate_add_str(argstate, symstate);
475d29b2c44Sab 			for (sym += ndx; cnt--; sym++) {
476d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
477d29b2c44Sab 				    elfedit_offset_to_str(symstate->str.sec,
478d29b2c44Sab 				    sym->st_name, ELFEDIT_MSG_ERR, 0));
479d29b2c44Sab 			}
480d29b2c44Sab 		} else {
481d29b2c44Sab 			for (; cnt--; sym++)
482d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
483d29b2c44Sab 				    EC_WORD(sym->st_name));
484d29b2c44Sab 		}
485d29b2c44Sab 		return;
486d29b2c44Sab 
487d29b2c44Sab 	case SYM_CMD_T_ST_OTHER:
488d29b2c44Sab 		for (sym += ndx; cnt-- > 0; sym++)
489d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
490d29b2c44Sab 			    EC_WORD(sym->st_other));
491d29b2c44Sab 		return;
492d29b2c44Sab 
493d29b2c44Sab 	case SYM_CMD_T_ST_SHNDX:
494d29b2c44Sab 		/* If there is an extended index section, fetch it */
495d29b2c44Sab 		if (symstate->xshndx.shndx != SHN_UNDEF)
496d29b2c44Sab 			symstate_add_xshndx(argstate, symstate);
497d29b2c44Sab 
498d29b2c44Sab 		for (; cnt--; ndx++) {
499d29b2c44Sab 			value = sym[ndx].st_shndx;
500d29b2c44Sab 			if ((value == SHN_XINDEX) &&
501d29b2c44Sab 			    (symstate->xshndx.sec != NULL))
502d29b2c44Sab 				value = symstate->xshndx.data[ndx];
503d29b2c44Sab 
504d29b2c44Sab 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
505d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
506d29b2c44Sab 				    elfedit_shndx_to_name(argstate->obj_state,
507d29b2c44Sab 				    value));
508d29b2c44Sab 			} else {
509d29b2c44Sab 				elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
510d29b2c44Sab 				    EC_WORD(value));
511d29b2c44Sab 			}
512d29b2c44Sab 		}
513d29b2c44Sab 		return;
514d29b2c44Sab 
515d29b2c44Sab 	case SYM_CMD_T_ST_SIZE:
516d29b2c44Sab 		/*
517d29b2c44Sab 		 * machine word width integers displayed in fixed width
518d29b2c44Sab 		 * 0-filled hex format.
519d29b2c44Sab 		 */
520d29b2c44Sab 		for (sym += ndx; cnt--; sym++)
521d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL),
522d29b2c44Sab 			    sym->st_size);
523d29b2c44Sab 		return;
524d29b2c44Sab 
525d29b2c44Sab 	case SYM_CMD_T_ST_TYPE:
526d29b2c44Sab 		{
527d29b2c44Sab 			Half mach = argstate->obj_state->os_ehdr->e_machine;
528d29b2c44Sab 			Conv_inv_buf_t inv_buf;
529d29b2c44Sab 
530d29b2c44Sab 			for (sym += ndx; cnt--; sym++) {
531d29b2c44Sab 				value = ELF_ST_TYPE(sym->st_info);
532d29b2c44Sab 				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
533d29b2c44Sab 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
534d29b2c44Sab 					    conv_sym_info_type(mach, value,
5354f680cc6SAli Bahrami 					    CONV_FMT_ALT_CF, &inv_buf));
536d29b2c44Sab 				} else {
537d29b2c44Sab 					elfedit_printf(
538d29b2c44Sab 					    MSG_ORIG(MSG_FMT_WORDVALNL),
539d29b2c44Sab 					    EC_WORD(value));
540d29b2c44Sab 				}
541d29b2c44Sab 			}
542d29b2c44Sab 		}
543d29b2c44Sab 		return;
544d29b2c44Sab 
545d29b2c44Sab 	case SYM_CMD_T_ST_VALUE:
546d29b2c44Sab 		/*
547d29b2c44Sab 		 * machine word width integers displayed in fixed width
548d29b2c44Sab 		 * 0-filled hex format.
549d29b2c44Sab 		 */
550d29b2c44Sab 		for (sym += ndx; cnt--; sym++)
551d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL),
552d29b2c44Sab 			    sym->st_value);
553d29b2c44Sab 		return;
554d29b2c44Sab 
555d29b2c44Sab 	case SYM_CMD_T_ST_VISIBILITY:
556d29b2c44Sab 		{
557d29b2c44Sab 			Conv_inv_buf_t inv_buf;
558d29b2c44Sab 
559d29b2c44Sab 			for (sym += ndx; cnt--; sym++) {
560d29b2c44Sab 				value = ELF_ST_VISIBILITY(sym->st_other);
561d29b2c44Sab 				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
562d29b2c44Sab 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
563d29b2c44Sab 					    conv_sym_other_vis(value,
5644f680cc6SAli Bahrami 					    CONV_FMT_ALT_CF, &inv_buf));
565d29b2c44Sab 				} else {
566d29b2c44Sab 					elfedit_printf(
567d29b2c44Sab 					    MSG_ORIG(MSG_FMT_WORDVALNL),
568d29b2c44Sab 					    EC_WORD(value));
569d29b2c44Sab 				}
570d29b2c44Sab 			}
571d29b2c44Sab 		}
572d29b2c44Sab 		return;
573d29b2c44Sab 
574d29b2c44Sab 	}
575d29b2c44Sab }
576d29b2c44Sab 
577d29b2c44Sab 
578d29b2c44Sab /*
579d29b2c44Sab  * Print symbol values, taking the calling command, and output style
580d29b2c44Sab  * into account.
581d29b2c44Sab  *
582d29b2c44Sab  * entry:
583d29b2c44Sab  *	autoprint - If True, output is only produced if the elfedit
584d29b2c44Sab  *		autoprint flag is set. If False, output is always produced.
585d29b2c44Sab  *	cmd - SYM_CMD_T_* value giving identify of caller
586d29b2c44Sab  *	argstate - Overall state block
587d29b2c44Sab  *	symstate - State block for current symbol table.
588d29b2c44Sab  *	ndx - Index of first symbol to display
589d29b2c44Sab  *	cnt - Number of symbols to display
590d29b2c44Sab  */
591d29b2c44Sab static void
print_sym(SYM_CMD_T cmd,int autoprint,ARGSTATE * argstate)592d29b2c44Sab print_sym(SYM_CMD_T cmd, int autoprint, ARGSTATE *argstate)
593d29b2c44Sab {
594d29b2c44Sab 	Word			ndx, tblndx;
595d29b2c44Sab 	Word			cnt;
596d29b2c44Sab 	elfedit_outstyle_t	outstyle;
597d29b2c44Sab 	SYMSTATE		*symstate;
598d29b2c44Sab 	int			only_one;
599d29b2c44Sab 
600d29b2c44Sab 	if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)))
601d29b2c44Sab 		return;
602d29b2c44Sab 
603d29b2c44Sab 	/*
604d29b2c44Sab 	 * Pick an output style. sym:dump is required to use the default
605d29b2c44Sab 	 * style. The other commands use the current output style.
606d29b2c44Sab 	 */
607d29b2c44Sab 	outstyle = (cmd == SYM_CMD_T_DUMP) ?
608d29b2c44Sab 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
609d29b2c44Sab 
610d29b2c44Sab 	/*
611d29b2c44Sab 	 * This is a nicity: Force any needed auxiliary sections to be
612d29b2c44Sab 	 * fetched here before any output is produced. This will put all
613d29b2c44Sab 	 * of the debug messages right at the top in a single cluster.
614d29b2c44Sab 	 */
615d29b2c44Sab 	symstate = argstate->symstate;
616d29b2c44Sab 	for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) {
617d29b2c44Sab 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
618d29b2c44Sab 			symstate_add_str(argstate, symstate);
619d29b2c44Sab 			if (symstate->versym.shndx != SHN_UNDEF)
620d29b2c44Sab 				symstate_add_versym(argstate, symstate);
621d29b2c44Sab 			if (symstate->xshndx.shndx != SHN_UNDEF)
622d29b2c44Sab 				symstate_add_xshndx(argstate, symstate);
623d29b2c44Sab 			continue;
624d29b2c44Sab 		}
625d29b2c44Sab 
626d29b2c44Sab 		if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
627d29b2c44Sab 			switch (cmd) {
628d29b2c44Sab 			case SYM_CMD_T_ST_NAME:
629d29b2c44Sab 				symstate_add_str(argstate, symstate);
630d29b2c44Sab 				break;
631d29b2c44Sab 
632d29b2c44Sab 			case SYM_CMD_T_ST_SHNDX:
633d29b2c44Sab 				if (symstate->xshndx.shndx != SHN_UNDEF)
634d29b2c44Sab 					symstate_add_xshndx(argstate, symstate);
635d29b2c44Sab 				break;
636d29b2c44Sab 			}
637d29b2c44Sab 		}
638d29b2c44Sab 	}
639d29b2c44Sab 
640d29b2c44Sab 	/*
641d29b2c44Sab 	 * If there is more than one table, we are displaying a single
642d29b2c44Sab 	 * item, we are not using the default "elfdump" style, and all
643d29b2c44Sab 	 * the symbols have the same value for the thing we intend to
644d29b2c44Sab 	 * display, then we only want to display it once.
645d29b2c44Sab 	 */
646d29b2c44Sab 	only_one = (argstate->numsymstate > 1) && (argstate->argc > 0) &&
647d29b2c44Sab 	    (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) &&
648d29b2c44Sab 	    all_same(cmd, argstate, outstyle);
649d29b2c44Sab 
650d29b2c44Sab 	/* Run through the tables and display from each one */
651d29b2c44Sab 	symstate = argstate->symstate;
652d29b2c44Sab 	for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) {
653d29b2c44Sab 		if (argstate->argc == 0) {
654d29b2c44Sab 			ndx = 0;
655d29b2c44Sab 			cnt = symstate->sym.n;
656d29b2c44Sab 		} else {
657d29b2c44Sab 			ndx = symstate->ndx;
658d29b2c44Sab 			cnt = 1;
659d29b2c44Sab 		}
660d29b2c44Sab 
661d29b2c44Sab 		if ((tblndx > 0) && ((argstate->argc == 0) ||
662d29b2c44Sab 		    (outstyle == ELFEDIT_OUTSTYLE_DEFAULT)))
663d29b2c44Sab 			elfedit_printf(MSG_ORIG(MSG_STR_NL));
664d29b2c44Sab 
665d29b2c44Sab 		print_symstate(cmd, argstate, symstate, outstyle, ndx, cnt);
666d29b2c44Sab 		if (only_one)
667d29b2c44Sab 			break;
668d29b2c44Sab 	}
669d29b2c44Sab }
670d29b2c44Sab 
671d29b2c44Sab 
672d29b2c44Sab /*
673d29b2c44Sab  * The cmd_body_set_st_XXX() functions are for use by cmd_body().
674d29b2c44Sab  * They handle the case where the second plain argument is
675d29b2c44Sab  * a value to be stored in the symbol.
676d29b2c44Sab  *
677d29b2c44Sab  * entry:
678d29b2c44Sab  *	argstate - Overall state block
679d29b2c44Sab  *	symstate - State block for current symbol table.
680d29b2c44Sab  */
681d29b2c44Sab static elfedit_cmdret_t
cmd_body_set_st_bind(ARGSTATE * argstate,SYMSTATE * symstate)682d29b2c44Sab cmd_body_set_st_bind(ARGSTATE *argstate, SYMSTATE *symstate)
683d29b2c44Sab {
684d29b2c44Sab 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
685d29b2c44Sab 	Sym			*sym = &symstate->sym.data[symstate->ndx];
686d29b2c44Sab 	Word			gbl_ndx;
687d29b2c44Sab 	uchar_t			bind, type, old_bind;
688d29b2c44Sab 	Word			symndx;
689d29b2c44Sab 	Conv_inv_buf_t		inv_buf1, inv_buf2;
690d29b2c44Sab 
691d29b2c44Sab 	/*
692d29b2c44Sab 	 * Use the ELF_ST_BIND() macro to access the defined bits
693d29b2c44Sab 	 * of the st_info field related to symbol binding.
694d29b2c44Sab 	 * Accepts STB_ symbolic names as well as integers.
695d29b2c44Sab 	 */
696d29b2c44Sab 	bind = elfedit_atoconst_range(argstate->argv[1],
697d29b2c44Sab 	    MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STB);
698d29b2c44Sab 	old_bind = ELF_ST_BIND(sym->st_info);
699d29b2c44Sab 	type = ELF_ST_TYPE(sym->st_info);
700d29b2c44Sab 
701d29b2c44Sab 	if (old_bind == bind) {
702d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
703d29b2c44Sab 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
704d29b2c44Sab 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND),
7054f680cc6SAli Bahrami 		    conv_sym_info_bind(bind, CONV_FMT_ALT_CF, &inv_buf1));
706d29b2c44Sab 	} else {
707d29b2c44Sab 		/*
708d29b2c44Sab 		 * The sh_info field of the symbol table section header
709d29b2c44Sab 		 * gives the index of the first non-local symbol in
710d29b2c44Sab 		 * the table. Issue warnings if the binding we set
711d29b2c44Sab 		 * contradicts this.
712d29b2c44Sab 		 */
713d29b2c44Sab 		gbl_ndx = symstate->sym.sec->sec_shdr->sh_info;
714d29b2c44Sab 		symndx = symstate->sym.sec->sec_shndx;
715d29b2c44Sab 		if ((bind == STB_LOCAL) && (symstate->ndx >= gbl_ndx))
716d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
717d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_LBINDGSYM),
718d29b2c44Sab 			    EC_WORD(symndx), symstate->sym.sec->sec_name,
719d29b2c44Sab 			    symstate->ndx, EC_WORD(symndx), gbl_ndx);
720d29b2c44Sab 		if ((bind != STB_LOCAL) && (symstate->ndx < gbl_ndx))
721d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
722d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_GBINDLSYM),
723d29b2c44Sab 			    EC_WORD(symndx), symstate->sym.sec->sec_name,
724d29b2c44Sab 			    symstate->ndx, EC_WORD(symndx), gbl_ndx);
725d29b2c44Sab 
726d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
727d29b2c44Sab 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
728d29b2c44Sab 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND),
7294f680cc6SAli Bahrami 		    conv_sym_info_bind(old_bind, CONV_FMT_ALT_CF,
730d29b2c44Sab 		    &inv_buf1),
7314f680cc6SAli Bahrami 		    conv_sym_info_bind(bind, CONV_FMT_ALT_CF, &inv_buf2));
732d29b2c44Sab 		ret = ELFEDIT_CMDRET_MOD;
733d29b2c44Sab 		sym->st_info = ELF_ST_INFO(bind, type);
734d29b2c44Sab 	}
735d29b2c44Sab 
736d29b2c44Sab 	return (ret);
737d29b2c44Sab }
738d29b2c44Sab 
739d29b2c44Sab static elfedit_cmdret_t
cmd_body_set_st_name(ARGSTATE * argstate,SYMSTATE * symstate)740d29b2c44Sab cmd_body_set_st_name(ARGSTATE *argstate, SYMSTATE *symstate)
741d29b2c44Sab {
742d29b2c44Sab 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
743d29b2c44Sab 	Sym			*sym = &symstate->sym.data[symstate->ndx];
744d29b2c44Sab 	Word	str_offset;
745d29b2c44Sab 
746d29b2c44Sab 	/*
747d29b2c44Sab 	 * If -n was specified, this is an offset into the string
748d29b2c44Sab 	 * table. Otherwise it is a string we need to turn into
749d29b2c44Sab 	 * an offset
750d29b2c44Sab 	 */
751d29b2c44Sab 	symstate_add_str(argstate, symstate);
752d29b2c44Sab 	if (argstate->optmask & SYM_OPT_F_NAMOFFSET) {
753d29b2c44Sab 		str_offset = elfedit_atoui(argstate->argv[1], NULL);
754d29b2c44Sab 		/* Warn if the offset is out of range */
755d29b2c44Sab 		(void) elfedit_offset_to_str(symstate->str.sec,
756d29b2c44Sab 		    str_offset, ELFEDIT_MSG_DEBUG, 1);
757d29b2c44Sab 	} else {
758d29b2c44Sab 		str_offset = elfedit_strtab_insert(argstate->obj_state,
759d29b2c44Sab 		    symstate->str.sec, NULL, argstate->argv[1]);
760d29b2c44Sab 	}
761d29b2c44Sab 
762d29b2c44Sab 	if (sym->st_name == str_offset) {
763d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_OK),
764d29b2c44Sab 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
765d29b2c44Sab 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME),
766d29b2c44Sab 		    EC_WORD(sym->st_name));
767d29b2c44Sab 	} else {
768d29b2c44Sab 		/*
769d29b2c44Sab 		 * Warn the user: Changing the name of a symbol in the dynsym
770d29b2c44Sab 		 * will break the hash table in this object.
771d29b2c44Sab 		 */
772d29b2c44Sab 		if (symstate->sym.sec->sec_shdr->sh_type == SHT_DYNSYM)
773d29b2c44Sab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
774d29b2c44Sab 			    MSG_INTL(MSG_DEBUG_DYNSYMNAMCHG),
775d29b2c44Sab 			    EC_WORD(symstate->sym.sec->sec_shndx),
776d29b2c44Sab 			    symstate->sym.sec->sec_name,
777d29b2c44Sab 			    EC_WORD(symstate->ndx));
778d29b2c44Sab 
779d29b2c44Sab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_CHG),
780d29b2c44Sab 		    symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name,
781d29b2c44Sab 		    EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME),
782d29b2c44Sab 		    EC_WORD(sym->st_name),
783d29b2c44Sab 		    EC_WORD(str_offset));
784d29b2c44Sab 		ret = ELFEDIT_CMDRET_MOD;
785d29b2c44Sab 		sym->st_name = str_offset;
786d29b2c44Sab 	}
787d29b2c44Sab 
788d29b2c44Sab 	return (ret);
789d29b2c44Sab }
790d29b2c44Sab 
791d29b2c44Sab static elfedit_cmdret_t
cmd_body_set_st_shndx(ARGSTATE * argstate,SYMSTATE * symstate)792d29b2c44Sab cmd_body_set_st_shndx(ARGSTATE *argstate, SYMSTATE *symstate)
793d29b2c44Sab {
794d29b2c44Sab 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
795d29b2c44Sab 	Sym			*sym = &symstate->sym.data[symstate->ndx];
796d29b2c44Sab 	Word	shndx, st_shndx, xshndx;
797d29b2c44Sab 	int	use_xshndx;
798d29b2c44Sab 	int	shndx_chg, xshndx_chg;
799d29b2c44Sab 
800d29b2c44Sab 
801d29b2c44Sab 	/*
802d29b2c44Sab 	 * By default, the sec argument is a section name. If -secshndx was
803d29b2c44Sab 	 * specified, it is a section index, and if -secshtyp is specified,
804d29b2c44Sab 	 * it is a section type.
805d29b2c44Sab 	 */
806d29b2c44Sab 	if (argstate->optmask & SYM_OPT_F_SECSHNDX)
807d29b2c44Sab 		shndx = elfedit_atoshndx(argstate->argv[1],
808d29b2c44Sab 		    argstate->obj_state->os_shnum);
809d29b2c44Sab 	else if (argstate->optmask & SYM_OPT_F_SECSHTYP)
810d29b2c44Sab 		shndx = elfedit_type_to_shndx(argstate->obj_state,
811d29b2c44Sab 		    elfedit_atoconst(argstate->argv[1], ELFEDIT_CONST_SHT));
812d29b2c44Sab 	else
813d29b2c44Sab 		shndx = elfedit_name_to_shndx(argstate->obj_state,
814d29b2c44Sab 		    argstate->argv[1]);
815d29b2c44Sab 
816d29b2c44Sab 	/*
817d29b2c44Sab 	 * We want to use an extended index section if the index is too
818d29b2c44Sab 	 * large to be represented otherwise, or if the caller specified
819d29b2c44Sab 	 * the -e option to make us do it anyway. However, we cannot
820d29b2c44Sab 	 * do this if the index is in the special reserved range between
821d29b2c44Sab 	 * SHN_LORESERVE and SHN_HIRESERVE.
822d29b2c44Sab 	 */
823d29b2c44Sab 	use_xshndx = (shndx > SHN_HIRESERVE) ||
824d29b2c44Sab 	    ((shndx < SHN_LORESERVE) &&
825d29b2c44Sab 	    (argstate->optmask & SYM_OPT_F_XSHINDEX));
826d29b2c44Sab 
827d29b2c44Sab 	/*
828d29b2c44Sab 	 * There are two cases where we have to touch the extended
829d29b2c44Sab 	 * index section:
830d29b2c44Sab 	 *
831d29b2c44Sab 	 *	1) We have determined that we need to, as determined above.
832d29b2c44Sab 	 *	2) We do not require it, but the file has an extended
833d29b2c44Sab 	 *		index section, in which case we should set the slot
834d29b2c44Sab 	 *		in that extended section to SHN_UNDEF (0).
835d29b2c44Sab 	 *
836d29b2c44Sab 	 * Fetch the extended section as required, and determine the values
837d29b2c44Sab 	 * for st_shndx and the extended section slot.
838d29b2c44Sab 	 */
839d29b2c44Sab 	if (use_xshndx) {
840d29b2c44Sab 		/* We must have an extended index section, or error out */
841d29b2c44Sab 		symstate_add_xshndx(argstate, symstate);
842d29b2c44Sab 
843d29b2c44Sab 		/* Set symbol to SHN_XINDEX, put index in the extended sec. */
844d29b2c44Sab 		st_shndx = SHN_XINDEX;
845d29b2c44Sab 		xshndx = shndx;
846d29b2c44Sab 	} else {
847d29b2c44Sab 		st_shndx = shndx;
848d29b2c44Sab 		xshndx = SHN_UNDEF;
849d29b2c44Sab 		if (symstate->xshndx.shndx != SHN_UNDEF)
850d29b2c44Sab 			use_xshndx = 1;
851d29b2c44Sab 	}
852d29b2c44Sab 	if (use_xshndx)
853d29b2c44Sab 		symstate_add_xshndx(argstate, symstate);
854d29b2c44Sab 	shndx_chg = (sym->st_shndx != st_shndx);
855d29b2c44Sab 	xshndx_chg = use_xshndx &&
856d29b2c44Sab 	    (symstate->xshndx.data