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