1*ad212f6fSab /*
2*ad212f6fSab  * CDDL HEADER START
3*ad212f6fSab  *
4*ad212f6fSab  * The contents of this file are subject to the terms of the
5*ad212f6fSab  * Common Development and Distribution License (the "License").
6*ad212f6fSab  * You may not use this file except in compliance with the License.
7*ad212f6fSab  *
8*ad212f6fSab  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*ad212f6fSab  * or http://www.opensolaris.org/os/licensing.
10*ad212f6fSab  * See the License for the specific language governing permissions
11*ad212f6fSab  * and limitations under the License.
12*ad212f6fSab  *
13*ad212f6fSab  * When distributing Covered Code, include this CDDL HEADER in each
14*ad212f6fSab  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*ad212f6fSab  * If applicable, add the following below this CDDL HEADER, with the
16*ad212f6fSab  * fields enclosed by brackets "[]" replaced with your own identifying
17*ad212f6fSab  * information: Portions Copyright [yyyy] [name of copyright owner]
18*ad212f6fSab  *
19*ad212f6fSab  * CDDL HEADER END
20*ad212f6fSab  */
21*ad212f6fSab 
22*ad212f6fSab /*
23*ad212f6fSab  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24*ad212f6fSab  * Use is subject to license terms.
25*ad212f6fSab  */
26*ad212f6fSab #pragma ident	"%Z%%M%	%I%	%E% SMI"
27*ad212f6fSab 
28*ad212f6fSab #include	<stdio.h>
29*ad212f6fSab #include	<ctype.h>
30*ad212f6fSab #include	<unistd.h>
31*ad212f6fSab #include	<machdep.h>
32*ad212f6fSab #include	<elfedit.h>
33*ad212f6fSab #include	<strings.h>
34*ad212f6fSab #include	<debug.h>
35*ad212f6fSab #include	<conv.h>
36*ad212f6fSab #include	<str_msg.h>
37*ad212f6fSab 
38*ad212f6fSab 
39*ad212f6fSab 
40*ad212f6fSab 
41*ad212f6fSab #define	MAXNDXSIZE	10
42*ad212f6fSab 
43*ad212f6fSab 
44*ad212f6fSab 
45*ad212f6fSab /*
46*ad212f6fSab  * This module uses shared code for several of the commands.
47*ad212f6fSab  * It is sometimes necessary to know which specific command
48*ad212f6fSab  * is active.
49*ad212f6fSab  */
50*ad212f6fSab typedef enum {
51*ad212f6fSab 	STR_CMD_T_DUMP =	0,	/* str:dump */
52*ad212f6fSab 	STR_CMD_T_SET =		1,	/* str:set */
53*ad212f6fSab 	STR_CMD_T_ADD =		2,	/* str:add */
54*ad212f6fSab 	STR_CMD_T_ZERO =	3,	/* str:zero */
55*ad212f6fSab } STR_CMD_T;
56*ad212f6fSab 
57*ad212f6fSab 
58*ad212f6fSab 
59*ad212f6fSab #ifndef _ELF64
60*ad212f6fSab /*
61*ad212f6fSab  * We supply this function for the msg module. Only one copy is needed.
62*ad212f6fSab  */
63*ad212f6fSab const char *
64*ad212f6fSab _str_msg(Msg mid)
65*ad212f6fSab {
66*ad212f6fSab 	return (gettext(MSG_ORIG(mid)));
67*ad212f6fSab }
68*ad212f6fSab 
69*ad212f6fSab #endif
70*ad212f6fSab 
71*ad212f6fSab 
72*ad212f6fSab 
73*ad212f6fSab /*
74*ad212f6fSab  * This function is supplied to elfedit through our elfedit_module_t
75*ad212f6fSab  * definition. It translates the opaque elfedit_i18nhdl_t handles
76*ad212f6fSab  * in our module interface into the actual strings for elfedit to
77*ad212f6fSab  * use.
78*ad212f6fSab  *
79*ad212f6fSab  * note:
80*ad212f6fSab  *	This module uses Msg codes for its i18n handle type.
81*ad212f6fSab  *	So the translation is simply to use MSG_INTL() to turn
82*ad212f6fSab  *	it into a string and return it.
83*ad212f6fSab  */
84*ad212f6fSab static const char *
85*ad212f6fSab mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
86*ad212f6fSab {
87*ad212f6fSab 	Msg msg = (Msg)hdl;
88*ad212f6fSab 
89*ad212f6fSab 	return (MSG_INTL(msg));
90*ad212f6fSab }
91*ad212f6fSab 
92*ad212f6fSab 
93*ad212f6fSab 
94*ad212f6fSab /*
95*ad212f6fSab  * The sym_opt_t enum specifies a bit value for every optional
96*ad212f6fSab  * argument allowed by a command in this module.
97*ad212f6fSab  */
98*ad212f6fSab typedef enum {
99*ad212f6fSab 	STR_OPT_F_END =		1,	/* -end: zero to end of strtab */
100*ad212f6fSab 	STR_OPT_F_NOTERM =	2,	/* -noterm: str:set won't term string */
101*ad212f6fSab 	STR_OPT_F_SHNAME =	4,	/* -shnam name: section spec. by name */
102*ad212f6fSab 	STR_OPT_F_SHNDX =	8,	/* -shndx ndx: strtab spec. by index */
103*ad212f6fSab 	STR_OPT_F_SHTYP =	16,	/* -shtyp type: section spec. by type */
104*ad212f6fSab 	STR_OPT_F_STRNDX =	32,	/* -strndx: String specified by index */
105*ad212f6fSab } str_opt_t;
106*ad212f6fSab 
107*ad212f6fSab 
108*ad212f6fSab /*
109*ad212f6fSab  * A variable of type ARGSTATE is used by each command to maintain
110*ad212f6fSab  * information about the string table section being used, and for any
111*ad212f6fSab  * auxiliary sections that are related to it.
112*ad212f6fSab  */
113*ad212f6fSab typedef struct {
114*ad212f6fSab 	elfedit_obj_state_t	*obj_state;
115*ad212f6fSab 	str_opt_t		optmask;   	/* Mask of options used */
116*ad212f6fSab 	int			argc;		/* # of plain arguments */
117*ad212f6fSab 	const char		**argv;		/* Plain arguments */
118*ad212f6fSab 
119*ad212f6fSab 	struct {				/* String table */
120*ad212f6fSab 		elfedit_section_t	*sec;
121*ad212f6fSab 		Word			ndx;	/* Table offset if (argc > 0) */
122*ad212f6fSab 	} str;
123*ad212f6fSab 	struct {				/* Dynamic section */
124*ad212f6fSab 		elfedit_section_t	*sec;
125*ad212f6fSab 		Dyn			*data;
126*ad212f6fSab 		Word			n;
127*ad212f6fSab 		elfedit_dyn_elt_t	strpad;
128*ad212f6fSab 	} dyn;
129*ad212f6fSab } ARGSTATE;
130*ad212f6fSab 
131*ad212f6fSab 
132*ad212f6fSab 
133*ad212f6fSab /*
134*ad212f6fSab  * Given an ELF SHT_ section type constant, shdr_to_strtab() returns
135*ad212f6fSab  * one of the following
136*ad212f6fSab  */
137*ad212f6fSab 
138*ad212f6fSab typedef enum {
139*ad212f6fSab 	SHTOSTR_NONE = 0,		/* Type can't lead to a  string table */
140*ad212f6fSab 	SHTOSTR_STRTAB = 1,		/* type is SHT_STRTAB */
141*ad212f6fSab 	SHTOSTR_LINK_STRTAB = 2,	/* sh_link for type yields strtab */
142*ad212f6fSab 	SHTOSTR_LINK_SYMTAB = 3,	/* sh_link for type yields symtab */
143*ad212f6fSab } SHTOSTR_T;
144*ad212f6fSab 
145*ad212f6fSab static int
146*ad212f6fSab shtype_to_strtab(Word sh_type)
147*ad212f6fSab {
148*ad212f6fSab 	switch (sh_type) {
149*ad212f6fSab 	case SHT_STRTAB:
150*ad212f6fSab 		return (SHTOSTR_STRTAB);
151*ad212f6fSab 
152*ad212f6fSab 	/* These sections reference a string table via sh_link */
153*ad212f6fSab 	case SHT_DYNAMIC:
154*ad212f6fSab 	case SHT_SYMTAB:
155*ad212f6fSab 	case SHT_DYNSYM:
156*ad212f6fSab 	case SHT_SUNW_LDYNSYM:
157*ad212f6fSab 	case SHT_SUNW_verdef:
158*ad212f6fSab 	case SHT_SUNW_verneed:
159*ad212f6fSab 		return (SHTOSTR_LINK_STRTAB);
160*ad212f6fSab 
161*ad212f6fSab 	/*
162*ad212f6fSab 	 * These sections reference a symbol table via sh_link.
163*ad212f6fSab 	 * Symbol tables, in turn, reference a string table
164*ad212f6fSab 	 * via their sh_link.
165*ad212f6fSab 	 */
166*ad212f6fSab 	case SHT_HASH:
167*ad212f6fSab 	case SHT_REL:
168*ad212f6fSab 	case SHT_RELA:
169*ad212f6fSab 	case SHT_GROUP:
170*ad212f6fSab 	case SHT_SYMTAB_SHNDX:
171*ad212f6fSab 	case SHT_SUNW_move:
172*ad212f6fSab 	case SHT_SUNW_syminfo:
173*ad212f6fSab 	case SHT_SUNW_versym:
174*ad212f6fSab 	case SHT_SUNW_symsort:
175*ad212f6fSab 	case SHT_SUNW_tlssort:
176*ad212f6fSab 		return (SHTOSTR_LINK_SYMTAB);
177*ad212f6fSab 	}
178*ad212f6fSab 
179*ad212f6fSab 	/* Types that lead to string tables were caught above */
180*ad212f6fSab 	return (SHTOSTR_NONE);
181*ad212f6fSab }
182*ad212f6fSab 
183*ad212f6fSab /*
184*ad212f6fSab  * Given a section index, attempt to convert it into an index
185*ad212f6fSab  * to a string table section.
186*ad212f6fSab  */
187*ad212f6fSab static Word
188*ad212f6fSab shndx_to_strtab(elfedit_obj_state_t *obj_state, Word ndx)
189*ad212f6fSab {
190*ad212f6fSab 	/*
191*ad212f6fSab 	 * Locate and validate the string table. In the case where
192*ad212f6fSab 	 * a non-string table section is given that references a string
193*ad212f6fSab 	 * table, we will use the referenced table.
194*ad212f6fSab 	 */
195*ad212f6fSab 	if (ndx < obj_state->os_shnum) {
196*ad212f6fSab 		switch (shtype_to_strtab(
197*ad212f6fSab 		    obj_state->os_secarr[ndx].sec_shdr->sh_type)) {
198*ad212f6fSab 
199*ad212f6fSab 		/* Sections that reference a string table via sh_link */
200*ad212f6fSab 		case SHTOSTR_LINK_STRTAB:
201*ad212f6fSab 			ndx = obj_state->os_secarr[ndx].sec_shdr->sh_link;
202*ad212f6fSab 			break;
203*ad212f6fSab 
204*ad212f6fSab 		/*
205*ad212f6fSab 		 * Sections that reference a symbol tabel via sh_link,
206*ad212f6fSab 		 * which in turn reference a string table via their sh_link.
207*ad212f6fSab 		 */
208*ad212f6fSab 		case SHTOSTR_LINK_SYMTAB:
209*ad212f6fSab 			ndx = obj_state->os_secarr[ndx].sec_shdr->sh_link;
210*ad212f6fSab 			if (ndx < obj_state->os_shnum)
211*ad212f6fSab 				ndx =
212*ad212f6fSab 				    obj_state->os_secarr[ndx].sec_shdr->sh_link;
213*ad212f6fSab 			break;
214*ad212f6fSab 		}
215*ad212f6fSab 	}
216*ad212f6fSab 
217*ad212f6fSab 	return (ndx);
218*ad212f6fSab }
219*ad212f6fSab 
220*ad212f6fSab 
221*ad212f6fSab 
222*ad212f6fSab /*
223*ad212f6fSab  * Standard argument processing for string table module
224*ad212f6fSab  *
225*ad212f6fSab  * entry
226*ad212f6fSab  *	obj_state, argc, argv - Standard command arguments
227*ad212f6fSab  *	optmask - Mask of allowed optional arguments.
228*ad212f6fSab  *	argstate - Address of ARGSTATE block to be initialized
229*ad212f6fSab  *
230*ad212f6fSab  * exit:
231*ad212f6fSab  *	On success, *argstate is initialized. On error,
232*ad212f6fSab  *	an error is issued and this routine does not return.
233*ad212f6fSab  */
234*ad212f6fSab static void
235*ad212f6fSab process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
236*ad212f6fSab     STR_CMD_T cmd, ARGSTATE *argstate, int *print_only)
237*ad212f6fSab {
238*ad212f6fSab 	elfedit_getopt_state_t	getopt_state;
239*ad212f6fSab 	elfedit_getopt_ret_t	*getopt_ret;
240*ad212f6fSab 	Word			ndx;
241*ad212f6fSab 	int			argc_ok;
242*ad212f6fSab 
243*ad212f6fSab 	bzero(argstate, sizeof (*argstate));
244*ad212f6fSab 	argstate->obj_state = obj_state;
245*ad212f6fSab 
246*ad212f6fSab 	/*
247*ad212f6fSab 	 * By default, we use the section name string table pointed at
248*ad212f6fSab 	 * by the ELF header.
249*ad212f6fSab 	 */
250*ad212f6fSab 	ndx = obj_state->os_ehdr->e_shstrndx;
251*ad212f6fSab 
252*ad212f6fSab 	elfedit_getopt_init(&getopt_state, &argc, &argv);
253*ad212f6fSab 
254*ad212f6fSab 	/* Add each new option to the options mask */
255*ad212f6fSab 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
256*ad212f6fSab 		argstate->optmask |= getopt_ret->gor_idmask;
257*ad212f6fSab 
258*ad212f6fSab 		switch (getopt_ret->gor_idmask) {
259*ad212f6fSab 		case STR_OPT_F_SHNAME:		/* -shnam name */
260*ad212f6fSab 			ndx = elfedit_name_to_shndx(obj_state,
261*ad212f6fSab 			    getopt_ret->gor_value);
262*ad212f6fSab 			break;
263*ad212f6fSab 
264*ad212f6fSab 		case STR_OPT_F_SHNDX:		/* -shndx index */
265*ad212f6fSab 			ndx = elfedit_atoui(getopt_ret->gor_value, NULL);
266*ad212f6fSab 			break;
267*ad212f6fSab 
268*ad212f6fSab 		case STR_OPT_F_SHTYP:		/* -shtyp type */
269*ad212f6fSab 			ndx = elfedit_type_to_shndx(obj_state,
270*ad212f6fSab 			    elfedit_atoconst(getopt_ret->gor_value,
271*ad212f6fSab 			    ELFEDIT_CONST_SHT));
272*ad212f6fSab 			break;
273*ad212f6fSab 		}
274*ad212f6fSab 	}
275*ad212f6fSab 
276*ad212f6fSab 	/*
277*ad212f6fSab 	 * Usage error if there are the wrong number of plain arguments.
278*ad212f6fSab 	 */
279*ad212f6fSab 	switch (cmd) {
280*ad212f6fSab 	case STR_CMD_T_DUMP:
281*ad212f6fSab 		argc_ok = (argc == 0) || (argc == 1);
282*ad212f6fSab 		*print_only = 1;
283*ad212f6fSab 		break;
284*ad212f6fSab 	case STR_CMD_T_SET:
285*ad212f6fSab 		argc_ok = (argc == 1) || (argc == 2);
286*ad212f6fSab 		*print_only = (argc == 1);
287*ad212f6fSab 		break;
288*ad212f6fSab 	case STR_CMD_T_ADD:
289*ad212f6fSab 		argc_ok = (argc == 1);
290*ad212f6fSab 		*print_only = 0;
291*ad212f6fSab 		break;
292*ad212f6fSab 	case STR_CMD_T_ZERO:
293*ad212f6fSab 		/*
294*ad212f6fSab 		 * The second argument (count) and the -end option are
295*ad212f6fSab 		 * mutally exclusive.
296*ad212f6fSab 		 */
297*ad212f6fSab 		argc_ok = ((argc == 1) || (argc == 2)) &&
298*ad212f6fSab 		    !((argc == 2) && (argstate->optmask & STR_OPT_F_END));
299*ad212f6fSab 		*print_only = 0;
300*ad212f6fSab 		break;
301*ad212f6fSab 	default:
302*ad212f6fSab 		argc_ok = 0;	/* Unknown command? */
303*ad212f6fSab 		break;
304*ad212f6fSab 	}
305*ad212f6fSab 	if (!argc_ok)
306*ad212f6fSab 		elfedit_command_usage();
307*ad212f6fSab 
308*ad212f6fSab 	/* If there may be an arbitrary amount of output, use a pager */
309*ad212f6fSab 	if (argc == 0)
310*ad212f6fSab 		elfedit_pager_init();
311*ad212f6fSab 
312*ad212f6fSab 	/* Return the updated values of argc/argv */
313*ad212f6fSab 	argstate->argc = argc;
314*ad212f6fSab 	argstate->argv = argv;
315*ad212f6fSab 
316*ad212f6fSab 	/*
317*ad212f6fSab 	 * Locate and validate the string table. In the case where
318*ad212f6fSab 	 * a non-string table section is given that references a string
319*ad212f6fSab 	 * table, we will use the referenced table.
320*ad212f6fSab 	 */
321*ad212f6fSab 	ndx = shndx_to_strtab(obj_state, ndx);
322*ad212f6fSab 
323*ad212f6fSab 	/*
324*ad212f6fSab 	 * If ndx is a string table, the following will issue the
325*ad212f6fSab 	 * proper debug messages. If it is out of range, or of any
326*ad212f6fSab 	 * other type, an error is issued and it doesn't return.
327*ad212f6fSab 	 */
328*ad212f6fSab 	argstate->str.sec = elfedit_sec_getstr(obj_state, ndx);
329*ad212f6fSab 
330*ad212f6fSab 	/*
331*ad212f6fSab 	 * If there is a dynamic section, check its sh_link to the
332*ad212f6fSab 	 * string table index. If these match, then we have the
333*ad212f6fSab 	 * dynamic string table. In that case, fetch the dynamic
334*ad212f6fSab 	 * section and locate the DT_SUNW_STRPAD entry, causing
335*ad212f6fSab 	 * debug messages to be issued.
336*ad212f6fSab 	 */
337*ad212f6fSab 	argstate->dyn.sec = NULL;
338*ad212f6fSab 	elfedit_dyn_elt_init(&argstate->dyn.strpad);
339*ad212f6fSab 	if (obj_state->os_dynndx != SHN_UNDEF) {
340*ad212f6fSab 		elfedit_section_t *dynsec =
341*ad212f6fSab 		    &obj_state->os_secarr[obj_state->os_dynndx];
342*ad212f6fSab 
343*ad212f6fSab 		if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) &&
344*ad212f6fSab 		    (argstate->str.sec->sec_shndx ==
345*ad212f6fSab 		    dynsec->sec_shdr->sh_link)) {
346*ad212f6fSab 			argstate->dyn.sec = elfedit_sec_getdyn(obj_state,
347*ad212f6fSab 			    &argstate->dyn.data, &argstate->dyn.n);
348*ad212f6fSab 			(void) elfedit_dynstr_getpad(dynsec,
349*ad212f6fSab 			    &argstate->dyn.strpad);
350*ad212f6fSab 
351*ad212f6fSab 			/*
352*ad212f6fSab 			 * Does the pad value make sense?
353*ad212f6fSab 			 * Issue debug message and ignore it if not.
354*ad212f6fSab 			 */
355*ad212f6fSab 			if ((argstate->dyn.strpad.dn_seen != 0) &&
356*ad212f6fSab 			    (argstate->dyn.strpad.dn_dyn.d_un.d_val >
357*ad212f6fSab 			    argstate->str.sec->sec_data->d_size)) {
358*ad212f6fSab 				argstate->dyn.strpad.dn_seen = 0;
359*ad212f6fSab 				elfedit_msg(ELFEDIT_MSG_DEBUG,
360*ad212f6fSab 				    MSG_INTL(MSG_DEBUG_BADSTRPAD),
361*ad212f6fSab 				    EC_WORD(argstate->str.sec->sec_shndx),
362*ad212f6fSab 				    argstate->str.sec->sec_name,
363*ad212f6fSab 				    EC_XWORD(argstate->dyn.strpad.dn_dyn.
364*ad212f6fSab 				    d_un.d_val),
365*ad212f6fSab 				    EC_XWORD(argstate->str.sec->
366*ad212f6fSab 				    sec_data->d_size));
367*ad212f6fSab 
368*ad212f6fSab 			}
369*ad212f6fSab 		}
370*ad212f6fSab 	}
371*ad212f6fSab 
372*ad212f6fSab 	/* Locate the string table offset if argument is present */
373*ad212f6fSab 	if ((argc > 0) && (cmd != STR_CMD_T_ADD)) {
374*ad212f6fSab 		/*
375*ad212f6fSab 		 * If the -strndx option was specified, arg is an index
376*ad212f6fSab 		 * into the string table. Otherwise it is a string
377*ad212f6fSab 		 * to be looked up.
378*ad212f6fSab 		 */
379*ad212f6fSab 		if (argstate->optmask & STR_OPT_F_STRNDX) {
380*ad212f6fSab 			argstate->str.ndx = (elfedit_atoui_range(argv[0],
381*ad212f6fSab 			    MSG_ORIG(MSG_STR_STRING), 0,
382*ad212f6fSab 			    argstate->str.sec->sec_data->d_size - 1, NULL));
383*ad212f6fSab 		} else {
384*ad212f6fSab 			if (elfedit_sec_findstr(argstate->str.sec, 0, argv[0],
385*ad212f6fSab 			    &argstate->str.ndx) == 0)
386*ad212f6fSab 				elfedit_msg(ELFEDIT_MSG_ERR,
387*ad212f6fSab 				    MSG_INTL(MSG_ERR_STRNOTFND),
388*ad212f6fSab 				    EC_WORD(argstate->str.sec->sec_shndx),
389*ad212f6fSab 				    argstate->str.sec->sec_name, argv[0]);
390*ad212f6fSab 		}
391*ad212f6fSab 	} else {
392*ad212f6fSab 		argstate->str.ndx = 0;
393*ad212f6fSab 	}
394*ad212f6fSab }
395*ad212f6fSab 
396*ad212f6fSab 
397*ad212f6fSab 
398*ad212f6fSab /*
399*ad212f6fSab  * Print string table values, taking output style into account.
400*ad212f6fSab  *
401*ad212f6fSab  * entry:
402*ad212f6fSab  *	autoprint - If True, output is only produced if the elfedit
403*ad212f6fSab  *		autoprint flag is set. If False, output is always produced.
404*ad212f6fSab  *	argstate - State block for current symbol table.
405*ad212f6fSab  */
406*ad212f6fSab static void
407*ad212f6fSab print_strtab(int autoprint, ARGSTATE *argstate)
408*ad212f6fSab {
409*ad212f6fSab 	char			index[(MAXNDXSIZE * 2) + 4];
410*ad212f6fSab 	elfedit_outstyle_t	outstyle;
411*ad212f6fSab 	const char		*str, *limit, *tbl_limit;
412*ad212f6fSab 	Word			ndx;
413*ad212f6fSab 
414*ad212f6fSab 
415*ad212f6fSab 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
416*ad212f6fSab 		return;
417*ad212f6fSab 
418*ad212f6fSab 	outstyle = elfedit_outstyle();
419*ad212f6fSab 	if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
420*ad212f6fSab 		elfedit_printf(MSG_INTL(MSG_FMT_STRTAB),
421*ad212f6fSab 		    argstate->str.sec->sec_name);
422*ad212f6fSab 		if (argstate->dyn.strpad.dn_seen)
423*ad212f6fSab 			elfedit_printf(MSG_INTL(MSG_FMT_DYNSTRPAD),
424*ad212f6fSab 			    EC_WORD(argstate->str.sec->sec_data->d_size -
425*ad212f6fSab 			    argstate->dyn.strpad.dn_dyn.d_un.d_val),
426*ad212f6fSab 			    EC_WORD(argstate->str.sec->sec_data->d_size - 1),
427*ad212f6fSab 			    EC_WORD(argstate->dyn.strpad.dn_dyn.d_un.d_val));
428*ad212f6fSab 		elfedit_printf(MSG_INTL(MSG_FMT_DUMPTITLE));
429*ad212f6fSab 	}
430*ad212f6fSab 
431*ad212f6fSab 	str = argstate->str.sec->sec_data->d_buf;
432*ad212f6fSab 	tbl_limit = str + argstate->str.sec->sec_data->d_size;
433*ad212f6fSab 	ndx = argstate->str.ndx;
434*ad212f6fSab 	if (argstate->argc > 0) {
435*ad212f6fSab 		str += ndx;
436*ad212f6fSab 		/*
437*ad212f6fSab 		 * If first byte is NULL and this is the default output style,
438*ad212f6fSab 		 * then we want to display the range of NULL bytes, and we
439*ad212f6fSab 		 * push limit out to the last one in the sequence. Otherwise,
440*ad212f6fSab 		 * just display the string.
441*ad212f6fSab 		 */
442*ad212f6fSab 		if ((*str == '\0') && (outstyle == ELFEDIT_OUTSTYLE_DEFAULT)) {
443*ad212f6fSab 			limit = str;
444*ad212f6fSab 			while (((limit + 1) < tbl_limit) &&
445*ad212f6fSab 			    (*(limit + 1) == '\0'))
446*ad212f6fSab 				limit++;
447*ad212f6fSab 		} else {
448*ad212f6fSab 			limit = str + strlen(str) + 1;
449*ad212f6fSab 		}
450*ad212f6fSab 	} else {
451*ad212f6fSab 		/* Display the entire string table  */
452*ad212f6fSab 		limit = tbl_limit;
453*ad212f6fSab 	}
454*ad212f6fSab 
455*ad212f6fSab 
456*ad212f6fSab 	while (str < limit) {
457*ad212f6fSab 		Word	skip = strlen(str) + 1;
458*ad212f6fSab 		Word	start_ndx;
459*ad212f6fSab 
460*ad212f6fSab 		if (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) {
461*ad212f6fSab 			elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), str);
462*ad212f6fSab 			str += skip;
463*ad212f6fSab 			ndx += skip;
464*ad212f6fSab 			continue;
465*ad212f6fSab 		}
466*ad212f6fSab 
467*ad212f6fSab 		start_ndx = ndx;
468*ad212f6fSab 		if (*str == '\0')
469*ad212f6fSab 			while (((str + 1) < limit) && (*(str + 1) == '\0')) {
470*ad212f6fSab 				ndx++;
471*ad212f6fSab 				str++;
472*ad212f6fSab 			}
473*ad212f6fSab 
474*ad212f6fSab 		if (start_ndx != ndx) {
475*ad212f6fSab 			(void) snprintf(index, sizeof (index),
476*ad212f6fSab 			    MSG_ORIG(MSG_FMT_INDEXRANGE),
477*ad212f6fSab 			    EC_XWORD(start_ndx), EC_XWORD(ndx));
478*ad212f6fSab 		} else {
479*ad212f6fSab 			(void) snprintf(index, sizeof (index),
480*ad212f6fSab 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx));
481*ad212f6fSab 		}
482*ad212f6fSab 		elfedit_printf(MSG_ORIG(MSG_FMT_DUMPENTRY), index, str);
483*ad212f6fSab 		str += skip;
484*ad212f6fSab 		ndx += skip;
485*ad212f6fSab 	}
486*ad212f6fSab }
487*ad212f6fSab 
488*ad212f6fSab 
489*ad212f6fSab /*
490*ad212f6fSab  * Command body for str:set, handling the case where the 3rd
491*ad212f6fSab  * argument (new-str) is present.
492*ad212f6fSab  */
493*ad212f6fSab static elfedit_cmdret_t
494*ad212f6fSab cmd_body_set(ARGSTATE *argstate)
495*ad212f6fSab {
496*ad212f6fSab 	elfedit_section_t	*strsec = argstate->str.sec;
497*ad212f6fSab 	const char		*newstr = argstate->argv[1];
498*ad212f6fSab 	Word	ndx = argstate->str.ndx;
499*ad212f6fSab 	char	*oldstr;
500*ad212f6fSab 	int	i, len, ncp;
501*ad212f6fSab 
502*ad212f6fSab 	len = strlen(newstr);
503*ad212f6fSab 	ncp = len;
504*ad212f6fSab 	if (!(argstate->optmask & STR_OPT_F_NOTERM))
505*ad212f6fSab 		ncp++;
506*ad212f6fSab 
507*ad212f6fSab 	/* NULL string with no termination? Nothing to do */
508*ad212f6fSab 	if (ncp == 0)
509*ad212f6fSab 		return (ELFEDIT_CMDRET_NONE);
510*ad212f6fSab 
511*ad212f6fSab 	/* Does it fit? */
512*ad212f6fSab 	if ((ndx + ncp) > strsec->sec_data->d_size)
513*ad212f6fSab 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOFIT),
514*ad212f6fSab 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
515*ad212f6fSab 		    EC_WORD(ndx), newstr);
516*ad212f6fSab 
517*ad212f6fSab 	/* Does it clobber the final NULL termination? */
518*ad212f6fSab 	if (((ndx + ncp) == strsec->sec_data->d_size) &&
519*ad212f6fSab 	    (argstate->optmask & STR_OPT_F_NOTERM))
520*ad212f6fSab 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_FINALNULL),
521*ad212f6fSab 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
522*ad212f6fSab 		    EC_WORD(ndx), newstr);
523*ad212f6fSab 
524*ad212f6fSab 	/*
525*ad212f6fSab 	 * strtab[0] is always supposed to contain a NULL byte. You're not
526*ad212f6fSab 	 * supposed to mess with it. We will carry out this operation,
527*ad212f6fSab 	 * but with a debug message indicating that it is unorthodox.
528*ad212f6fSab 	 */
529*ad212f6fSab 	if ((ndx == 0) && (*newstr != '\0'))
530*ad212f6fSab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSTR0),
531*ad212f6fSab 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
532*ad212f6fSab 		    EC_WORD(ndx), newstr);
533*ad212f6fSab 
534*ad212f6fSab 	/* Does it alter the existing value? */
535*ad212f6fSab 	oldstr = ndx + (char *)strsec->sec_data->d_buf;
536*ad212f6fSab 	for (i = 0; i < ncp; i++)
537*ad212f6fSab 		if (newstr[i] != oldstr[i])
538*ad212f6fSab 			break;
539*ad212f6fSab 	if (i == ncp) {		/* No change */
540*ad212f6fSab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK),
541*ad212f6fSab 		    strsec->sec_shndx, strsec->sec_name, ndx, newstr);
542*ad212f6fSab 		return (ELFEDIT_CMDRET_NONE);
543*ad212f6fSab 	}
544*ad212f6fSab 
545*ad212f6fSab 	/*
546*ad212f6fSab 	 * If the new string is longer than the old one, then it will
547*ad212f6fSab 	 * clobber the start of the following string. The resulting
548*ad212f6fSab 	 * string table is perfectly legal, but issue a debug message
549*ad212f6fSab 	 * letting the user know.
550*ad212f6fSab 	 */
551*ad212f6fSab 	i = strlen(oldstr);
552*ad212f6fSab 	if (len > i)
553*ad212f6fSab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_LONGSTR),
554*ad212f6fSab 		    EC_WORD(strsec->sec_shndx), strsec->sec_name,
555*ad212f6fSab 		    EC_WORD(ndx), len, i);
556*ad212f6fSab 
557*ad212f6fSab 	/*
558*ad212f6fSab 	 * If we have strayed into the reserved part of the dynstr, then
559*ad212f6fSab 	 * update DT_SUNW_STRPAD.
560*ad212f6fSab 	 */
561*ad212f6fSab 	if (argstate->dyn.strpad.dn_seen) {
562*ad212f6fSab 		elfedit_dyn_elt_t	*strpad = &argstate->dyn.strpad;
563*ad212f6fSab 		Word	new_pad_ndx = ndx + len + 1;
564*ad212f6fSab 		Word	pad_ndx = argstate->str.sec->sec_data->d_size -
565*ad212f6fSab 		    strpad->dn_dyn.d_un.d_val;
566*ad212f6fSab 
567*ad212f6fSab 		if (new_pad_ndx > pad_ndx) {
568*ad212f6fSab 			elfedit_msg(ELFEDIT_MSG_DEBUG,
569*ad212f6fSab 			    MSG_INTL(MSG_DEBUG_ADDDYNSTR),
570*ad212f6fSab 			    EC_WORD(strsec->sec_shndx), strsec->sec_name,
571*ad212f6fSab 			    EC_WORD(ndx), EC_WORD(new_pad_ndx - pad_ndx),
572*ad212f6fSab 			    EC_WORD(strpad->dn_dyn.d_un.d_val),
573*ad212f6fSab 			    newstr);
574*ad212f6fSab 
575*ad212f6fSab 			strpad->dn_dyn.d_un.d_val =
576*ad212f6fSab 			    argstate->dyn.data[strpad->dn_ndx].d_un.d_val =
577*ad212f6fSab 			    (argstate->str.sec->sec_data->d_size - new_pad_ndx);
578*ad212f6fSab 			elfedit_modified_data(argstate->dyn.sec);
579*ad212f6fSab 		}
580*ad212f6fSab 	}
581*ad212f6fSab 
582*ad212f6fSab 
583*ad212f6fSab 
584*ad212f6fSab 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG),
585*ad212f6fSab 	    strsec->sec_shndx, strsec->sec_name, ndx, len, oldstr, newstr);
586*ad212f6fSab 	bcopy(newstr, oldstr, ncp);
587*ad212f6fSab 
588*ad212f6fSab 	return (ELFEDIT_CMDRET_MOD);
589*ad212f6fSab }
590*ad212f6fSab 
591*ad212f6fSab 
592*ad212f6fSab /*
593*ad212f6fSab  * Command body for str:zero
594*ad212f6fSab  */
595*ad212f6fSab static elfedit_cmdret_t
596*ad212f6fSab cmd_body_zero(ARGSTATE *argstate)
597*ad212f6fSab {
598*ad212f6fSab 	elfedit_section_t	*strsec = argstate->str.sec;
599*ad212f6fSab 	Word	count;
600*ad212f6fSab 	Word	ndx = argstate->str.ndx;
601*ad212f6fSab 	char	*oldstr = ndx + (char *)strsec->sec_data->d_buf;
602*ad212f6fSab 	Word	i;
603*ad212f6fSab 
604*ad212f6fSab 	/* How many bytes to zero? */
605*ad212f6fSab 	if (argstate->optmask & STR_OPT_F_END)
606*ad212f6fSab 		count = strsec->sec_data->d_size - argstate->str.ndx;
607*ad212f6fSab 	else if (argstate->argc == 2)
608*ad212f6fSab 		count = elfedit_atoui_range(argstate->argv[1],
609*ad212f6fSab 		    MSG_ORIG(MSG_STR_COUNT), 0,
610*ad212f6fSab 		    argstate->str.sec->sec_data->d_size - argstate->str.ndx,
611*ad212f6fSab 		    NULL);
612*ad212f6fSab 	else
613*ad212f6fSab 		count = strlen(oldstr);
614*ad212f6fSab 
615*ad212f6fSab 	/* Does it alter the existing value? */
616*ad212f6fSab 	for (i = 0; i < count; i++)
617*ad212f6fSab 		if (oldstr[i] != '\0')
618*ad212f6fSab 			break;
619*ad212f6fSab 	if (i == count) {		/* No change */
620*ad212f6fSab 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_Z_OK),
621*ad212f6fSab 		    strsec->sec_shndx, strsec->sec_name, ndx);
622*ad212f6fSab 		return (ELFEDIT_CMDRET_NONE);
623*ad212f6fSab 	}
624*ad212f6fSab 
625*ad212f6fSab 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_Z_CHG),
626*ad212f6fSab 	    strsec->sec_shndx, strsec->sec_name, ndx, count);
627*ad212f6fSab 	bzero(oldstr, count);
628*ad212f6fSab 
629*ad212f6fSab 	return (ELFEDIT_CMDRET_MOD);
630*ad212f6fSab }
631*ad212f6fSab 
632*ad212f6fSab 
633*ad212f6fSab /*
634*ad212f6fSab  * Common body for the str: module commands.
635*ad212f6fSab  *
636*ad212f6fSab  * entry:
637*ad212f6fSab  *	cmd - One of the STR_CMD_T_* constants listed above, specifying
638*ad212f6fSab  *		which command to implement.
639*ad212f6fSab  *	obj_state, argc, argv - Standard command arguments
640*ad212f6fSab  */
641*ad212f6fSab static elfedit_cmdret_t
642*ad212f6fSab cmd_body(STR_CMD_T cmd, elfedit_obj_state_t *obj_state,
643*ad212f6fSab     int argc, const char *argv[])
644*ad212f6fSab {
645*ad212f6fSab 	ARGSTATE		argstate;
646*ad212f6fSab 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
647*ad212f6fSab 	int			print_only;
648*ad212f6fSab 
649*ad212f6fSab 	process_args(obj_state, argc, argv, cmd, &argstate, &print_only);
650*ad212f6fSab 
651*ad212f6fSab 	/*
652*ad212f6fSab 	 * If this call call does not change data, display the current
653*ad212f6fSab 	 * value(s) and return.
654*ad212f6fSab 	 */
655*ad212f6fSab 	if (print_only) {
656*ad212f6fSab 		print_strtab(0, &argstate);
657*ad212f6fSab 		return (ELFEDIT_CMDRET_NONE);
658*ad212f6fSab 	}
659*ad212f6fSab 
660*ad212f6fSab 	switch (cmd) {
661*ad212f6fSab 	/* NOTE: STR_CMD_T_DUMP can't get here --- it's always print_only */
662*ad212f6fSab 
663*ad212f6fSab 	case STR_CMD_T_SET:
664*ad212f6fSab 		ret = cmd_body_set(&argstate);
665*ad212f6fSab 		break;
666*ad212f6fSab 
667*ad212f6fSab 	case STR_CMD_T_ADD:
668*ad212f6fSab 		argstate.str.ndx = elfedit_strtab_insert(obj_state,
669*ad212f6fSab 		    argstate.str.sec, argstate.dyn.sec, argstate.argv[0]);
670*ad212f6fSab 		break;
671*ad212f6fSab 
672*ad212f6fSab 	case STR_CMD_T_ZERO:
673*ad212f6fSab 		ret = cmd_body_zero(&argstate);
674*ad212f6fSab 		break;
675*ad212f6fSab 	}
676*ad212f6fSab 
677*ad212f6fSab 	/*
678*ad212f6fSab 	 * If we modified the strtab section, tell libelf.
679*ad212f6fSab 	 */
680*ad212f6fSab 	if (ret == ELFEDIT_CMDRET_MOD)
681*ad212f6fSab 		elfedit_modified_data(argstate.str.sec);
682*ad212f6fSab 
683*ad212f6fSab 	/* Do autoprint */
684*ad212f6fSab 	print_strtab(1, &argstate);
685*ad212f6fSab 
686*ad212f6fSab 	return (ret);
687*ad212f6fSab }
688*ad212f6fSab 
689*ad212f6fSab 
690*ad212f6fSab 
691*ad212f6fSab 
692*ad212f6fSab /*
693*ad212f6fSab  * Command completion functions for the various commands
694*ad212f6fSab  */
695*ad212f6fSab 
696*ad212f6fSab static void
697*ad212f6fSab add_shtyp_match(Word sh_type, void *cpldata)
698*ad212f6fSab {
699*ad212f6fSab 	char		buf[128];
700*ad212f6fSab 	const char	*s;
701*ad212f6fSab 	char		*s2;
702*ad212f6fSab 
703*ad212f6fSab 	s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_SHT, sh_type, 0);
704*ad212f6fSab 	elfedit_cpl_match(cpldata, s, 1);
705*ad212f6fSab 
706*ad212f6fSab 	/*
707*ad212f6fSab 	 * To get the informal tag names that are lowercase
708*ad212f6fSab 	 * and lack the leading SHT_, we copy the string we
709*ad212f6fSab 	 * have into a buffer and process it.
710*ad212f6fSab 	 */
711*ad212f6fSab 	if (strlen(s) < 4)
712*ad212f6fSab 		return;
713*ad212f6fSab 	(void) strlcpy(buf, s + 4, sizeof (buf));
714*ad212f6fSab 	for (s2 = buf; *s2 != '\0'; s2++)
715*ad212f6fSab 		if (isupper(*s2))
716*ad212f6fSab 			*s2 = tolower(*s2);
717*ad212f6fSab 	elfedit_cpl_match(cpldata, buf, 1);
718*ad212f6fSab }
719*ad212f6fSab 
720*ad212f6fSab /*
721*ad212f6fSab  * Handle filling in the values for -shnam, -shndx, and -shtyp options.
722*ad212f6fSab  */
723*ad212f6fSab /*ARGSUSED*/
724*ad212f6fSab static void
725*ad212f6fSab cpl_sh_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
726*ad212f6fSab     const char *argv[], int num_opt)
727*ad212f6fSab {
728*ad212f6fSab 	enum { NAME, INDEX, TYPE }	op;
729*ad212f6fSab 	elfedit_section_t		*sec;
730*ad212f6fSab 	Word 	ndx;
731*ad212f6fSab 
732*ad212f6fSab 	if ((argc != num_opt) || (argc < 2))
733*ad212f6fSab 		return;
734*ad212f6fSab 
735*ad212f6fSab 	if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) {
736*ad212f6fSab 		op = NAME;
737*ad212f6fSab 	} else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) {
738*ad212f6fSab 		op = INDEX;
739*ad212f6fSab 
740*ad212f6fSab 	} else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) {
741*ad212f6fSab 		op = TYPE;
742*ad212f6fSab 
743*ad212f6fSab 		if (obj_state == NULL) {	 /* No object available */
744*ad212f6fSab 			elfedit_atoui_sym_t *atoui_sym;
745*ad212f6fSab 
746*ad212f6fSab 			atoui_sym = elfedit_const_to_atoui(ELFEDIT_CONST_SHT);
747*ad212f6fSab 			for (; atoui_sym->sym_name != NULL; atoui_sym++)
748*ad212f6fSab 				if (shtype_to_strtab(atoui_sym->sym_value) !=
749*ad212f6fSab 				    SHTOSTR_NONE)
750*ad212f6fSab 					elfedit_cpl_match(cpldata,
751*ad212f6fSab 					    atoui_sym->sym_name, 1);
752*ad212f6fSab 		}
753*ad212f6fSab 	} else {
754*ad212f6fSab 		return;
755*ad212f6fSab 	}
756*ad212f6fSab 
757*ad212f6fSab 	if (obj_state == NULL)	 /* No object available */
758*ad212f6fSab 		return;
759*ad212f6fSab 
760*ad212f6fSab 	/*
761*ad212f6fSab 	 * Loop over the section headers and supply command completion
762*ad212f6fSab 	 * for the items in the file that can yield a string table.
763*ad212f6fSab 	 */
764*ad212f6fSab 	sec = obj_state->os_secarr;
765*ad212f6fSab 	for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++) {
766*ad212f6fSab 		Word sh_type = sec->sec_shdr->sh_type;
767*ad212f6fSab 
768*ad212f6fSab 		if (shtype_to_strtab(sh_type) == SHTOSTR_NONE)
769*ad212f6fSab 			continue;
770*ad212f6fSab 
771*ad212f6fSab 		switch (op) {
772*ad212f6fSab 		case NAME:
773*ad212f6fSab 			elfedit_cpl_match(cpldata, sec->sec_name, 0);
774*ad212f6fSab 			break;
775*ad212f6fSab 		case INDEX:
776*ad212f6fSab 			{
777*ad212f6fSab 				char index[MAXNDXSIZE];
778*ad212f6fSab 
779*ad212f6fSab 				(void) snprintf(index, sizeof (index),
780*ad212f6fSab 				    MSG_ORIG(MSG_FMT_WORDVAL),
781*ad212f6fSab 				    sec->sec_shndx);
782*ad212f6fSab 				elfedit_cpl_match(cpldata, index, 1);
783*ad212f6fSab 			}
784*ad212f6fSab 			break;
785*ad212f6fSab 		case TYPE:
786*ad212f6fSab 			add_shtyp_match(sh_type, cpldata);
787*ad212f6fSab 			break;
788*ad212f6fSab 		}
789*ad212f6fSab 	}
790*ad212f6fSab }
791*ad212f6fSab 
792*ad212f6fSab 
793*ad212f6fSab /*
794*ad212f6fSab  * Most of the commands accept an -shXXX option for the string table
795*ad212f6fSab  * and a string first argument. This routine examines which argument
796*ad212f6fSab  * is being processed, and supplies completion for these items.
797*ad212f6fSab  */
798*ad212f6fSab static void
799*ad212f6fSab cpl_sec_str(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
800*ad212f6fSab     const char *argv[], int num_opt)
801*ad212f6fSab {
802*ad212f6fSab 	const char		*str, *limit;
803*ad212f6fSab 	elfedit_section_t	*sec;
804*ad212f6fSab 	Word			strtab_ndx;
805*ad212f6fSab 	Word			ndx;
806*ad212f6fSab 
807*ad212f6fSab 	/* Handle -shXXX options */
808*ad212f6fSab 	cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt);
809*ad212f6fSab 
810*ad212f6fSab 	/* Without object state, there's no data to work from */
811*ad212f6fSab 	if (obj_state == NULL)
812*ad212f6fSab 		return;
813*ad212f6fSab 
814*ad212f6fSab 	/* If not first plain arg, return */
815*ad212f6fSab 	if (argc != (num_opt + 1))
816*ad212f6fSab 		return;
817*ad212f6fSab 
818*ad212f6fSab 	/*
819*ad212f6fSab 	 * Look at the options, looking for two things:
820*ad212f6fSab 	 *	1) A -shXXX option specifying a section. If so, turn that
821*ad212f6fSab 	 *		into a section index if possible.
822*ad212f6fSab 	 *	2) Was -strndx used? If so, we are looking at an integer
823*ad212f6fSab 	 *		value and have nothing to complete.
824*ad212f6fSab 	 */
825*ad212f6fSab 	strtab_ndx = obj_state->os_ehdr->e_shstrndx;
826*ad212f6fSab 	for (ndx = 0; ndx < num_opt; ndx++) {
827*ad212f6fSab 		if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_STRNDX)) == 0)
828*ad212f6fSab 			return;
829*ad212f6fSab 
830*ad212f6fSab 		if ((ndx+1) < num_opt) {
831*ad212f6fSab 			if (strcmp(argv[ndx],
832*ad212f6fSab 			    MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) {
833*ad212f6fSab 				Word		i;
834*ad212f6fSab 
835*ad212f6fSab 				for (i = 1; i < obj_state->os_shnum; i++)
836*ad212f6fSab 					if (strcmp(obj_state->os_secarr[i].
837*ad212f6fSab 					    sec_name, argv[ndx+1]) == 0) {
838*ad212f6fSab 						strtab_ndx = i;
839*ad212f6fSab 						break;
840*ad212f6fSab 					}
841*ad212f6fSab 			} else if (strcmp(argv[ndx],
842*ad212f6fSab 			    MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) {
843*ad212f6fSab 				elfedit_atoui_t val;
844*ad212f6fSab 
845*ad212f6fSab 				if (elfedit_atoui2(argv[ndx+1], NULL,
846*ad212f6fSab 				    &val) != 0)
847*ad212f6fSab 					strtab_ndx = val;
848*ad212f6fSab 			} else if (strcmp(argv[ndx],
849*ad212f6fSab 			    MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) {
850*ad212f6fSab 				elfedit_atoui_t	sh_type;
851*ad212f6fSab 				Word		i;
852*ad212f6fSab 
853*ad212f6fSab 				if (elfedit_atoconst2(argv[ndx+1],
854*ad212f6fSab 				    ELFEDIT_CONST_SHT, &sh_type) == 0)
855*ad212f6fSab 					continue;
856*ad212f6fSab 				for (i = 1; i < obj_state->os_shnum; i++)
857*ad212f6fSab 					if (obj_state->os_secarr[i].sec_shdr->
858*ad212f6fSab 					    sh_type == sh_type) {
859*ad212f6fSab 						strtab_ndx = i;
860*ad212f6fSab 						break;
861*ad212f6fSab 					}
862*ad212f6fSab 			}
863*ad212f6fSab 		}
864*ad212f6fSab 	}
865*ad212f6fSab 
866*ad212f6fSab 	/*
867*ad212f6fSab 	 * Locate and validate the string table. In the case where
868*ad212f6fSab 	 * a non-string table section is given that references a string
869*ad212f6fSab 	 * table, we will use the referenced table.
870*ad212f6fSab 	 */
871*ad212f6fSab 	strtab_ndx = shndx_to_strtab(obj_state, strtab_ndx);
872*ad212f6fSab 	if ((strtab_ndx >= obj_state->os_shnum) ||
873*ad212f6fSab 	    (obj_state->os_secarr[strtab_ndx].sec_shdr->sh_type != SHT_STRTAB))
874*ad212f6fSab 		return;
875*ad212f6fSab 	sec = &obj_state->os_secarr[strtab_ndx];
876*ad212f6fSab 
877*ad212f6fSab 	str = sec->sec_data->d_buf;
878*ad212f6fSab 	limit = str + sec->sec_data->d_size;
879*ad212f6fSab 	while (str < limit) {
880*ad212f6fSab 		if (*str != '\0')
881*ad212f6fSab 			elfedit_cpl_match(cpldata, str, 0);
882*ad212f6fSab 		str += strlen(str) + 1;
883*ad212f6fSab 	}
884*ad212f6fSab }
885*ad212f6fSab 
886*ad212f6fSab 
887*ad212f6fSab 
888*ad212f6fSab /*
889*ad212f6fSab  * Implementation functions for the commands
890*ad212f6fSab  */
891*ad212f6fSab static elfedit_cmdret_t
892*ad212f6fSab cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
893*ad212f6fSab {
894*ad212f6fSab 	return (cmd_body(STR_CMD_T_DUMP, obj_state, argc, argv));
895*ad212f6fSab }
896*ad212f6fSab 
897*ad212f6fSab static elfedit_cmdret_t
898*ad212f6fSab cmd_set(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
899*ad212f6fSab {
900*ad212f6fSab 	return (cmd_body(STR_CMD_T_SET, obj_state, argc, argv));
901*ad212f6fSab }
902*ad212f6fSab 
903*ad212f6fSab static elfedit_cmdret_t
904*ad212f6fSab cmd_add(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
905*ad212f6fSab {
906*ad212f6fSab 	return (cmd_body(STR_CMD_T_ADD, obj_state, argc, argv));
907*ad212f6fSab }
908*ad212f6fSab 
909*ad212f6fSab static elfedit_cmdret_t
910*ad212f6fSab cmd_zero(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
911*ad212f6fSab {
912*ad212f6fSab 	return (cmd_body(STR_CMD_T_ZERO, obj_state, argc, argv));
913*ad212f6fSab }
914*ad212f6fSab 
915*ad212f6fSab 
916*ad212f6fSab 
917*ad212f6fSab /*ARGSUSED*/
918*ad212f6fSab elfedit_module_t *
919*ad212f6fSab elfedit_init(elfedit_module_version_t version)
920*ad212f6fSab {
921*ad212f6fSab 	/* str:dump */
922*ad212f6fSab 	static const char *name_dump[] = {
923*ad212f6fSab 	    MSG_ORIG(MSG_CMD_DUMP),
924*ad212f6fSab 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
925*ad212f6fSab 	    NULL
926*ad212f6fSab 	};
927*ad212f6fSab 	static elfedit_cmd_optarg_t opt_dump[] = {
928*ad212f6fSab 		{ ELFEDIT_STDOA_OPT_O, NULL,
929*ad212f6fSab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
930*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
931*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHNAM) */
932*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
933*ad212f6fSab 		    STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP },
934*ad212f6fSab 		{ MSG_ORIG(MSG_STR_NAME), NULL, 0 },
935*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
936*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
937*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
938*ad212f6fSab 		    STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP },
939*ad212f6fSab 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0 },
940*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
941*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
942*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
943*ad212f6fSab 		    STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX },
944*ad212f6fSab 		{ MSG_ORIG(MSG_STR_TYPE), NULL, 0 },
945*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_STRNDX),
946*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_STRNDX) */
947*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0,
948*ad212f6fSab 		    STR_OPT_F_STRNDX, 0 },
949*ad212f6fSab 		{ NULL }
950*ad212f6fSab 	};
951*ad212f6fSab 	static elfedit_cmd_optarg_t arg_dump[] = {
952*ad212f6fSab 		{ MSG_ORIG(MSG_STR_STRING),
953*ad212f6fSab 		    /* MSG_INTL(MSG_A1_STRING) */
954*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_A1_STRING),
955*ad212f6fSab 		    ELFEDIT_CMDOA_F_OPT },
956*ad212f6fSab 		{ NULL }
957*ad212f6fSab 	};
958*ad212f6fSab 
959*ad212f6fSab 	/* str:set */
960*ad212f6fSab 	static const char *name_set[] = {
961*ad212f6fSab 	    MSG_ORIG(MSG_CMD_SET), NULL };
962*ad212f6fSab 	static elfedit_cmd_optarg_t opt_set[] = {
963*ad212f6fSab 		{ ELFEDIT_STDOA_OPT_O, NULL,
964*ad212f6fSab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
965*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_NOTERM),
966*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_NOTERM) */
967*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_NOTERM), 0,
968*ad212f6fSab 		    STR_OPT_F_NOTERM, 0 },
969*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
970*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHNAM) */
971*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
972*ad212f6fSab 		    STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP },
973*ad212f6fSab 		{ MSG_ORIG(MSG_STR_NAME), NULL, 0 },
974*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
975*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
976*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
977*ad212f6fSab 		    STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP },
978*ad212f6fSab 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0 },
979*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
980*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
981*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
982*ad212f6fSab 		    STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX },
983*ad212f6fSab 		{ MSG_ORIG(MSG_STR_TYPE), NULL, 0 },
984*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_STRNDX),
985*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_STRNDX) */
986*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0,
987*ad212f6fSab 		    STR_OPT_F_STRNDX, 0 },
988*ad212f6fSab 		{ NULL }
989*ad212f6fSab 	};
990*ad212f6fSab 	static elfedit_cmd_optarg_t arg_set[] = {
991*ad212f6fSab 		{ MSG_ORIG(MSG_STR_STRING),
992*ad212f6fSab 		    /* MSG_INTL(MSG_A1_STRING) */
993*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_A1_STRING),
994*ad212f6fSab 		    0 },
995*ad212f6fSab 		{ MSG_ORIG(MSG_STR_NEWSTRING),
996*ad212f6fSab 		    /* MSG_INTL(MSG_A2_NEWSTRING) */
997*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_A2_NEWSTRING),
998*ad212f6fSab 		    ELFEDIT_CMDOA_F_OPT },
999*ad212f6fSab 		{ NULL }
1000*ad212f6fSab 	};
1001*ad212f6fSab 
1002*ad212f6fSab 	/* str:add */
1003*ad212f6fSab 	static const char *name_add[] = {
1004*ad212f6fSab 	    MSG_ORIG(MSG_CMD_ADD), NULL };
1005*ad212f6fSab 	static elfedit_cmd_optarg_t opt_add[] = {
1006*ad212f6fSab 		{ ELFEDIT_STDOA_OPT_O, NULL,
1007*ad212f6fSab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1008*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
1009*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHNAM) */
1010*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
1011*ad212f6fSab 		    STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP },
1012*ad212f6fSab 		{ MSG_ORIG(MSG_STR_NAME), NULL, 0 },
1013*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
1014*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1015*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
1016*ad212f6fSab 		    STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP },
1017*ad212f6fSab 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0 },
1018*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
1019*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1020*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
1021*ad212f6fSab 		    STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX },
1022*ad212f6fSab 		{ MSG_ORIG(MSG_STR_TYPE), NULL, 0 },
1023*ad212f6fSab 		{ NULL }
1024*ad212f6fSab 	};
1025*ad212f6fSab 	static elfedit_cmd_optarg_t arg_add[] = {
1026*ad212f6fSab 		{ MSG_ORIG(MSG_STR_NEWSTRING),
1027*ad212f6fSab 		    /* MSG_INTL(MSG_A1_NEWSTRING) */
1028*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_A1_NEWSTRING),
1029*ad212f6fSab 		    0 },
1030*ad212f6fSab 		{ NULL }
1031*ad212f6fSab 	};
1032*ad212f6fSab 
1033*ad212f6fSab 	/* str:zero */
1034*ad212f6fSab 	static const char *name_zero[] = {
1035*ad212f6fSab 	    MSG_ORIG(MSG_CMD_ZERO), NULL };
1036*ad212f6fSab 	static elfedit_cmd_optarg_t opt_zero[] = {
1037*ad212f6fSab 		{ ELFEDIT_STDOA_OPT_O, NULL,
1038*ad212f6fSab 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1039*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHNAM),
1040*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHNAM) */
1041*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE,
1042*ad212f6fSab 		    STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP },
1043*ad212f6fSab 		{ MSG_ORIG(MSG_STR_NAME), NULL, 0 },
1044*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
1045*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1046*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE,
1047*ad212f6fSab 		    STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP },
1048*ad212f6fSab 		{ MSG_ORIG(MSG_STR_INDEX), NULL, 0 },
1049*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
1050*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1051*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE,
1052*ad212f6fSab 		    STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX },
1053*ad212f6fSab 		{ MSG_ORIG(MSG_STR_TYPE), NULL, 0 },
1054*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_STRNDX),
1055*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_STRNDX) */
1056*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0,
1057*ad212f6fSab 		    STR_OPT_F_STRNDX, 0 },
1058*ad212f6fSab 		{ MSG_ORIG(MSG_STR_MINUS_END),
1059*ad212f6fSab 		    /* MSG_INTL(MSG_OPTDESC_END) */
1060*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_OPTDESC_END), 0,
1061*ad212f6fSab 		    STR_OPT_F_END, 0 },
1062*ad212f6fSab 		{ NULL }
1063*ad212f6fSab 	};
1064*ad212f6fSab 	static elfedit_cmd_optarg_t arg_zero[] = {
1065*ad212f6fSab 		{ MSG_ORIG(MSG_STR_STRING),
1066*ad212f6fSab 		    /* MSG_INTL(MSG_A1_STRING) */
1067*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_A1_STRING),
1068*ad212f6fSab 		    0 },
1069*ad212f6fSab 		{ MSG_ORIG(MSG_STR_COUNT),
1070*ad212f6fSab 		    /* MSG_INTL(MSG_A2_COUNT) */
1071*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_A2_COUNT),
1072*ad212f6fSab 		    ELFEDIT_CMDOA_F_OPT },
1073*ad212f6fSab 		{ NULL }
1074*ad212f6fSab 	};
1075*ad212f6fSab 
1076*ad212f6fSab 
1077*ad212f6fSab 	static elfedit_cmd_t cmds[] = {
1078*ad212f6fSab 		/* str:dump */
1079*ad212f6fSab 		{ cmd_dump, cpl_sec_str, name_dump,
1080*ad212f6fSab 		    /* MSG_INTL(MSG_DESC_DUMP) */
1081*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
1082*ad212f6fSab 		    /* MSG_INTL(MSG_HELP_DUMP) */
1083*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
1084*ad212f6fSab 		    opt_dump, arg_dump },
1085*ad212f6fSab 
1086*ad212f6fSab 		/* str:set */
1087*ad212f6fSab 		{ cmd_set, cpl_sec_str, name_set,
1088*ad212f6fSab 		    /* MSG_INTL(MSG_DESC_SET) */
1089*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_DESC_SET),
1090*ad212f6fSab 		    /* MSG_INTL(MSG_HELP_SET) */
1091*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_HELP_SET),
1092*ad212f6fSab 		    opt_set, arg_set },
1093*ad212f6fSab 
1094*ad212f6fSab 		/* str:add */
1095*ad212f6fSab 		{ cmd_add, cpl_sh_opt, name_add,
1096*ad212f6fSab 		    /* MSG_INTL(MSG_DESC_ADD) */
1097*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_DESC_ADD),
1098*ad212f6fSab 		    /* MSG_INTL(MSG_HELP_ADD) */
1099*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_HELP_ADD),
1100*ad212f6fSab 		    opt_add, arg_add },
1101*ad212f6fSab 
1102*ad212f6fSab 		/* str:zero */
1103*ad212f6fSab 		{ cmd_zero, cpl_sec_str, name_zero,
1104*ad212f6fSab 		    /* MSG_INTL(MSG_DESC_ZERO) */
1105*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_DESC_ZERO),
1106*ad212f6fSab 		    /* MSG_INTL(MSG_HELP_ZERO) */
1107*ad212f6fSab 		    ELFEDIT_I18NHDL(MSG_HELP_ZERO),
1108*ad212f6fSab 		    opt_zero, arg_zero },
1109*ad212f6fSab 
1110*ad212f6fSab 		{ NULL }
1111*ad212f6fSab 	};
1112*ad212f6fSab 
1113*ad212f6fSab 	static elfedit_module_t module = {
1114*ad212f6fSab 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
1115*ad212f6fSab 	    /* MSG_INTL(MSG_MOD_DESC) */
1116*ad212f6fSab 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
1117*ad212f6fSab 	    cmds, mod_i18nhdl_to_str };
1118*ad212f6fSab 
1119*ad212f6fSab 	return (&module);
1120*ad212f6fSab }
1121