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