shdr.c revision 9273:9a0603d78ad3
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include	<stdio.h>
28#include	<unistd.h>
29#include	<elfedit.h>
30#include	<sys/elf_SPARC.h>
31#include	<sys/elf_amd64.h>
32#include	<strings.h>
33#include	<debug.h>
34#include	<conv.h>
35#include	<shdr_msg.h>
36
37
38
39
40/*
41 * This module uses shared code for several of the commands.
42 * It is sometimes necessary to know which specific command
43 * is active.
44 */
45typedef enum {
46	SHDR_CMD_T_DUMP =		0,	/* shdr:dump */
47
48	SHDR_CMD_T_SH_ADDR =		1,	/* shdr:sh_addr */
49	SHDR_CMD_T_SH_ADDRALIGN =	2,	/* shdr:sh_addralign */
50	SHDR_CMD_T_SH_ENTSIZE =		3,	/* shdr:sh_entsize */
51	SHDR_CMD_T_SH_FLAGS =		4,	/* shdr:sh_flags */
52	SHDR_CMD_T_SH_INFO =		5,	/* shdr:sh_info */
53	SHDR_CMD_T_SH_LINK =		6,	/* shdr:sh_link */
54	SHDR_CMD_T_SH_NAME =		7,	/* shdr:sh_name */
55	SHDR_CMD_T_SH_OFFSET =		8,	/* shdr:sh_offset */
56	SHDR_CMD_T_SH_SIZE =		9,	/* shdr:sh_size */
57	SHDR_CMD_T_SH_TYPE =		10	/* shdr:sh_type */
58} SHDR_CMD_T;
59
60
61
62#ifndef _ELF64
63/*
64 * We supply this function for the msg module. Only one copy is needed.
65 */
66const char *
67_shdr_msg(Msg mid)
68{
69	return (gettext(MSG_ORIG(mid)));
70}
71
72#endif
73
74
75
76/*
77 * This function is supplied to elfedit through our elfedit_module_t
78 * definition. It translates the opaque elfedit_i18nhdl_t handles
79 * in our module interface into the actual strings for elfedit to
80 * use.
81 *
82 * note:
83 *	This module uses Msg codes for its i18n handle type.
84 *	So the translation is simply to use MSG_INTL() to turn
85 *	it into a string and return it.
86 */
87static const char *
88mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
89{
90	Msg msg = (Msg)hdl;
91
92	return (MSG_INTL(msg));
93}
94
95
96
97/*
98 * The shdr_opt_t enum specifies a bit value for every optional
99 * argument allowed by a command in this module.
100 */
101typedef enum {
102	SHDR_OPT_F_AND =	1,	/* -and: AND (&) values to dest */
103	SHDR_OPT_F_CMP =	2,	/* -cmp: Complement (~) values */
104	SHDR_OPT_F_NAMOFFSET =	4,	/* -name_offset: Name arg is numeric */
105					/*	 ofset rather than string */
106	SHDR_OPT_F_OR =		8,	/* -or: OR (|) values to dest */
107	SHDR_OPT_F_SHNDX =	16,	/* -shndx: Section by index, not name */
108	SHDR_OPT_F_SHTYP =	32,	/* -shtyp: Section by type, not name */
109	SHDR_OPT_F_VALUE_SHNAM = 64,	/* -value_shnam: Value of sh_info or */
110					/*	sh_link given as section name */
111	SHDR_OPT_F_VALUE_SHTYP = 128	/* -value_shtyp: Value of sh_info or */
112					/*	sh_link given as section type */
113} shdr_opt_t;
114
115
116/*
117 * A variable of type ARGSTATE is used by each command to maintain
118 * information about the section headers and related things. It is
119 * initialized by process_args(), and used by the other routines.
120 */
121typedef struct {
122	elfedit_obj_state_t	*obj_state;
123	shdr_opt_t		optmask;   	/* Mask of options used */
124	int			argc;		/* # of plain arguments */
125	const char		**argv;		/* Plain arguments */
126} ARGSTATE;
127
128
129
130
131/*
132 * Standard argument processing for shdr module
133 *
134 * entry
135 *	obj_state, argc, argv - Standard command arguments
136 *	optmask - Mask of allowed optional arguments.
137 *	cmd - SHDR_CMD_T_* value giving identify of caller
138 *	argstate - Address of ARGSTATE block to be initialized
139 *
140 * exit:
141 *	On success, *argstate is initialized. On error,
142 *	an error is issued and this routine does not return.
143 */
144static void
145process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
146    SHDR_CMD_T cmd, ARGSTATE *argstate)
147{
148	elfedit_getopt_state_t	getopt_state;
149	elfedit_getopt_ret_t	*getopt_ret;
150
151	bzero(argstate, sizeof (*argstate));
152	argstate->obj_state = obj_state;
153
154	elfedit_getopt_init(&getopt_state, &argc, &argv);
155
156	/* Add each new option to the options mask */
157	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
158		argstate->optmask |= getopt_ret->gor_idmask;
159
160	/* Are the right number of plain arguments present? */
161	switch (cmd) {
162	case SHDR_CMD_T_DUMP:
163		if (argc > 1)
164			elfedit_command_usage();
165		break;
166	case SHDR_CMD_T_SH_FLAGS:
167		/* shdr:sh_flags allows an arbitrary number of arguments */
168		break;
169	default:
170		/* The remaining commands accept 2 plain arguments */
171		if (argc > 2)
172			elfedit_command_usage();
173		break;
174	}
175
176	/* If there may be an arbitrary amount of output, use a pager */
177	if (argc == 0)
178		elfedit_pager_init();
179
180	/* Return the updated values of argc/argv */
181	argstate->argc = argc;
182	argstate->argv = argv;
183}
184
185
186
187/*
188 * Options for deciding which items print_shdr() displays.
189 */
190typedef enum {
191	PRINT_SHDR_ALL,		/* Print all shdr[ndx:ndx+cnt-1] */
192	PRINT_SHDR_TYPE,	/* Print all shdr[ndx:ndx+cnt-1] with type */
193				/*	 of shdr[ndx] */
194	PRINT_SHDR_NAME,	/* Print all shdr[ndx:ndx+cnt-1] with name */
195				/*	 of shdr[ndx] */
196} PRINT_SHDR_T;
197
198/*
199 * Print section header values, taking the calling command, and output style
200 * into account.
201 *
202 * entry:
203 *	autoprint - If True, output is only produced if the elfedit
204 *		autoprint flag is set. If False, output is always produced.
205 *	cmd - SHDR_CMD_T_* value giving identify of caller
206 *	argstate - State block for section header array
207 *	ndx - Index of first section to display
208 *	cnt - Number of sections to display
209 *	print_type - Specifies which items are shown
210 */
211static void
212print_shdr(SHDR_CMD_T cmd, int autoprint, ARGSTATE *argstate,
213    Word ndx, Word cnt, PRINT_SHDR_T print_type)
214{
215	elfedit_outstyle_t	outstyle;
216	Ehdr			*ehdr = argstate->obj_state->os_ehdr;
217	uchar_t			osabi = ehdr->e_ident[EI_OSABI];
218	Half			mach = ehdr->e_machine;
219	elfedit_section_t 	*ref_sec = &argstate->obj_state->os_secarr[ndx];
220
221
222	if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) ||
223	    (cnt == 0))
224		return;
225
226	/*
227	 * Pick an output style. shdr:dump is required to use the default
228	 * style. The other commands use the current output style.
229	 */
230	outstyle = (cmd == SHDR_CMD_T_DUMP) ?
231	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
232
233	for (; cnt--; ndx++) {
234		elfedit_section_t *sec = &argstate->obj_state->os_secarr[ndx];
235		Shdr *shdr = sec->sec_shdr;
236
237		switch (print_type) {
238		case PRINT_SHDR_TYPE:
239			if (shdr->sh_type != ref_sec->sec_shdr->sh_type)
240				continue;
241			break;
242
243		case PRINT_SHDR_NAME:
244			if (strcmp(sec->sec_name, ref_sec->sec_name) != 0)
245				continue;
246			break;
247		}
248
249		/*
250		 * If doing default output, use elfdump style where we
251		 * show all section header attributes. In this case, the
252		 * command that called us doesn't matter
253		 */
254		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
255			elfedit_printf(MSG_ORIG(MSG_STR_NL));
256			elfedit_printf(MSG_INTL(MSG_ELF_SHDR), ndx,
257			    sec->sec_name);
258			Elf_shdr(NULL, osabi, mach, sec->sec_shdr);
259			continue;
260		}
261
262		/* Non-default output is handled case by case */
263		switch (cmd) {
264		case SHDR_CMD_T_SH_ADDR:
265			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
266			    EC_XWORD(shdr->sh_addr));
267			break;
268
269		case SHDR_CMD_T_SH_ADDRALIGN:
270			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
271			    EC_XWORD(shdr->sh_addralign));
272			break;
273
274		case SHDR_CMD_T_SH_ENTSIZE:
275			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
276			    EC_XWORD(shdr->sh_entsize));
277			break;
278
279		case SHDR_CMD_T_SH_FLAGS:
280			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
281				Conv_sec_flags_buf_t sec_flags_buf;
282
283				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
284				    conv_sec_flags(osabi, mach, shdr->sh_flags,
285				    CONV_FMT_NOBKT, &sec_flags_buf));
286			} else {
287				elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
288				    EC_XWORD(shdr->sh_flags));
289			}
290			break;
291
292		case SHDR_CMD_T_SH_INFO:
293			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
294			    EC_WORD(shdr->sh_info));
295			break;
296
297		case SHDR_CMD_T_SH_LINK:
298			elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
299			    EC_WORD(shdr->sh_link));
300			break;
301
302		case SHDR_CMD_T_SH_NAME:
303			/*
304			 * In simple output mode, we show the string. In
305			 * numeric mode, we show the string table offset.
306			 */
307			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
308				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
309				    sec->sec_name);
310			} else {
311				elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL),
312				    EC_WORD(shdr->sh_name));
313			}
314			break;
315
316		case SHDR_CMD_T_SH_OFFSET:
317			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
318			    EC_XWORD(shdr->sh_offset));
319			break;
320
321		case SHDR_CMD_T_SH_SIZE:
322			elfedit_printf(MSG_ORIG(MSG_FMT_XWORDHEXNL),
323			    EC_XWORD(shdr->sh_size));
324			break;
325
326		case SHDR_CMD_T_SH_TYPE:
327			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
328				Conv_inv_buf_t inv_buf;
329
330				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
331				    conv_sec_type(osabi, mach, shdr->sh_type, 0,
332				    &inv_buf));
333			} else {
334				elfedit_printf(MSG_ORIG(MSG_FMT_WORDHEXNL),
335				    EC_WORD(shdr->sh_type));
336			}
337			break;
338		}
339	}
340}
341
342
343/*
344 * Common body for the shdr: module commands. These commands
345 * share a large amount of common behavior, so it is convenient
346 * to centralize things and use the cmd argument to handle the
347 * small differences.
348 *
349 * entry:
350 *	cmd - One of the SHDR_CMD_T_* constants listed above, specifying
351 *		which command to implement.
352 *	obj_state, argc, argv - Standard command arguments
353 */
354static elfedit_cmdret_t
355cmd_body(SHDR_CMD_T cmd, elfedit_obj_state_t *obj_state,
356    int argc, const char *argv[])
357{
358	Ehdr			*ehdr = obj_state->os_ehdr;
359	uchar_t			osabi = ehdr->e_ident[EI_OSABI];
360	Half			mach = ehdr->e_machine;
361	ARGSTATE		argstate;
362	Word			ndx;
363	elfedit_section_t	*shdr_sec;
364	Shdr			*shdr;
365	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
366	PRINT_SHDR_T		print_type;
367
368	process_args(obj_state, argc, argv, cmd, &argstate);
369
370	/* If there are no arguments, dump the whole table and return */
371	if (argstate.argc == 0) {
372		print_shdr(cmd, 0, &argstate, 0, obj_state->os_shnum,
373		    PRINT_SHDR_ALL);
374		return (ELFEDIT_CMDRET_NONE);
375	}
376
377	/*
378	 * The first argument gives the section to use. This can be a
379	 * name (default), section index, or section type, depending on
380	 * the options used.
381	 */
382	if (argstate.optmask & SHDR_OPT_F_SHNDX) {
383		ndx = elfedit_atoshndx(argstate.argv[0], obj_state->os_shnum);
384		print_type = PRINT_SHDR_ALL;
385	} else if (argstate.optmask & SHDR_OPT_F_SHTYP) {
386		ndx = elfedit_type_to_shndx(obj_state,
387		    elfedit_atoconst(argstate.argv[0], ELFEDIT_CONST_SHT));
388		print_type = PRINT_SHDR_TYPE;
389	} else {
390		ndx = elfedit_name_to_shndx(obj_state, argstate.argv[0]);
391		print_type = PRINT_SHDR_NAME;
392	}
393
394	/* If there is a single argument, display that item and return */
395	if (argstate.argc == 1) {
396		Word	cnt;
397
398		cnt = (print_type == PRINT_SHDR_ALL) ?
399		    1 : obj_state->os_shnum - ndx;
400		print_shdr(cmd, 0, &argstate, ndx, cnt, print_type);
401		return (ELFEDIT_CMDRET_NONE);
402	}
403
404	/*
405	 * Section [0] is supposed to be all zero unless extended sections
406	 * are in force. Rather than setting extended values directly,
407	 * it is expected to be handled by libelf. So, a direct change here
408	 * is probably not what was intended.
409	 */
410	if (ndx == 0)
411		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSHDR0));
412
413	/* The second value is an integer giving a new value */
414	shdr_sec = &obj_state->os_secarr[ndx];
415	shdr = shdr_sec->sec_shdr;
416	switch (cmd) {
417		/*
418		 * SHDR_CMD_T_DUMP can't get here: It never has more than
419		 * one argument, and is handled above.
420		 */
421
422	case SHDR_CMD_T_SH_ADDR:
423		{
424			Addr sh_addr = elfedit_atoui(argstate.argv[1], NULL);
425
426			if (shdr->sh_addr == sh_addr) {
427				elfedit_msg(ELFEDIT_MSG_DEBUG,
428				    MSG_INTL(MSG_DEBUG_LLX_OK),
429				    ndx, shdr_sec->sec_name,
430				    MSG_ORIG(MSG_CMD_SH_ADDR),
431				    EC_ADDR(shdr->sh_addr));
432			} else {
433				elfedit_msg(ELFEDIT_MSG_DEBUG,
434				    MSG_INTL(MSG_DEBUG_LLX_CHG),
435				    ndx, shdr_sec->sec_name,
436				    MSG_ORIG(MSG_CMD_SH_ADDR),
437				    EC_ADDR(shdr->sh_addr), EC_ADDR(sh_addr));
438				ret = ELFEDIT_CMDRET_MOD;
439				shdr->sh_addr = sh_addr;
440			}
441		}
442		break;
443
444	case SHDR_CMD_T_SH_ADDRALIGN:
445		{
446			Xword	sh_addralign;
447
448			sh_addralign = elfedit_atoui(argstate.argv[1], NULL);
449			if (elfedit_bits_set(sh_addralign,
450			    sizeof (sh_addralign)) > 1)
451				elfedit_msg(ELFEDIT_MSG_DEBUG,
452				    MSG_INTL(MSG_DEBUG_ADDRALIGN),
453				    argstate.argv[1]);
454			if (shdr->sh_addralign == sh_addralign) {
455				elfedit_msg(ELFEDIT_MSG_DEBUG,
456				    MSG_INTL(MSG_DEBUG_LLX_OK),
457				    ndx, shdr_sec->sec_name,
458				    MSG_ORIG(MSG_CMD_SH_ADDRALIGN),
459				    EC_XWORD(shdr->sh_addralign));
460			} else {
461				elfedit_msg(ELFEDIT_MSG_DEBUG,
462				    MSG_INTL(MSG_DEBUG_LLX_CHG),
463				    ndx, shdr_sec->sec_name,
464				    MSG_ORIG(MSG_CMD_SH_ADDRALIGN),
465				    EC_XWORD(shdr->sh_addralign),
466				    EC_XWORD(sh_addralign));
467				ret = ELFEDIT_CMDRET_MOD;
468				shdr->sh_addralign = sh_addralign;
469			}
470		}
471		break;
472
473	case SHDR_CMD_T_SH_ENTSIZE:
474		{
475			Xword sh_entsize;
476
477			sh_entsize = elfedit_atoui(argstate.argv[1], NULL);
478			if (shdr->sh_entsize == sh_entsize) {
479				elfedit_msg(ELFEDIT_MSG_DEBUG,
480				    MSG_INTL(MSG_DEBUG_LLX_OK),
481				    ndx, shdr_sec->sec_name,
482				    MSG_ORIG(MSG_CMD_SH_ENTSIZE),
483				    EC_XWORD(shdr->sh_entsize));
484			} else {
485				elfedit_msg(ELFEDIT_MSG_DEBUG,
486				    MSG_INTL(MSG_DEBUG_LLX_CHG),
487				    ndx, shdr_sec->sec_name,
488				    MSG_ORIG(MSG_CMD_SH_ENTSIZE),
489				    EC_XWORD(shdr->sh_entsize),
490				    EC_XWORD(sh_entsize));
491				ret = ELFEDIT_CMDRET_MOD;
492				shdr->sh_entsize = sh_entsize;
493			}
494		}
495		break;
496
497	case SHDR_CMD_T_SH_FLAGS:
498		{
499			Conv_sec_flags_buf_t buf1, buf2;
500			Word	sh_flags = 0;
501			int	i;
502
503						/* Collect the flag arguments */
504			for (i = 1; i < argstate.argc; i++)
505				sh_flags |=
506				    (Word) elfedit_atoconst(argstate.argv[i],
507				    ELFEDIT_CONST_SHF);
508
509			/* Complement the value? */
510			if (argstate.optmask & SHDR_OPT_F_CMP)
511				sh_flags = ~sh_flags;
512
513			/* Perform any requested bit operations */
514			if (argstate.optmask & SHDR_OPT_F_AND)
515				sh_flags &= shdr->sh_flags;
516			else if (argstate.optmask & SHDR_OPT_F_OR)
517				sh_flags |= shdr->sh_flags;
518
519			/* Set the value */
520			if (shdr->sh_flags == sh_flags) {
521				elfedit_msg(ELFEDIT_MSG_DEBUG,
522				    MSG_INTL(MSG_DEBUG_S_OK),
523				    ndx, shdr_sec->sec_name,
524				    MSG_ORIG(MSG_CMD_SH_FLAGS),
525				    conv_sec_flags(osabi, mach,
526				    shdr->sh_flags, 0, &buf1));
527			} else {
528				elfedit_msg(ELFEDIT_MSG_DEBUG,
529				    MSG_INTL(MSG_DEBUG_S_CHG),
530				    ndx, shdr_sec->sec_name,
531				    MSG_ORIG(MSG_CMD_SH_FLAGS),
532				    conv_sec_flags(osabi, mach,
533				    shdr->sh_flags, 0, &buf1),
534				    conv_sec_flags(osabi, mach,
535				    sh_flags, 0, &buf2));
536				ret = ELFEDIT_CMDRET_MOD;
537				shdr->sh_flags = sh_flags;
538			}
539		}
540		break;
541
542	case SHDR_CMD_T_SH_INFO:
543		{
544			Word sh_info;
545
546			if (argstate.optmask & SHDR_OPT_F_VALUE_SHNAM)
547				sh_info = elfedit_name_to_shndx(obj_state,
548				    argstate.argv[1]);
549			else if (argstate.optmask & SHDR_OPT_F_VALUE_SHTYP)
550				sh_info = elfedit_type_to_shndx(obj_state,
551				    elfedit_atoconst(argstate.argv[1],
552				    ELFEDIT_CONST_SHT));
553			else
554				sh_info = elfedit_atoui(argstate.argv[1], NULL);
555
556			if (shdr->sh_info == sh_info) {
557				elfedit_msg(ELFEDIT_MSG_DEBUG,
558				    MSG_INTL(MSG_DEBUG_D_OK),
559				    ndx, shdr_sec->sec_name,
560				    MSG_ORIG(MSG_CMD_SH_INFO),
561				    EC_WORD(shdr->sh_info));
562			} else {
563				elfedit_msg(ELFEDIT_MSG_DEBUG,
564				    MSG_INTL(MSG_DEBUG_D_CHG),
565				    ndx, shdr_sec->sec_name,
566				    MSG_ORIG(MSG_CMD_SH_INFO),
567				    EC_WORD(shdr->sh_info), EC_WORD(sh_info));
568				ret = ELFEDIT_CMDRET_MOD;
569				shdr->sh_info = sh_info;
570			}
571		}
572		break;
573
574	case SHDR_CMD_T_SH_LINK:
575		{
576			Word sh_link;
577
578			if (argstate.optmask & SHDR_OPT_F_VALUE_SHNAM)
579				sh_link = elfedit_name_to_shndx(obj_state,
580				    argstate.argv[1]);
581			else if (argstate.optmask & SHDR_OPT_F_VALUE_SHTYP)
582				sh_link = elfedit_type_to_shndx(obj_state,
583				    elfedit_atoconst(argstate.argv[1],
584				    ELFEDIT_CONST_SHT));
585			else
586				sh_link = elfedit_atoui(argstate.argv[1], NULL);
587
588			if (shdr->sh_link == sh_link) {
589				elfedit_msg(ELFEDIT_MSG_DEBUG,
590				    MSG_INTL(MSG_DEBUG_D_OK),
591				    ndx, shdr_sec->sec_name,
592				    MSG_ORIG(MSG_CMD_SH_LINK),
593				    EC_WORD(shdr->sh_link));
594			} else {
595				elfedit_msg(ELFEDIT_MSG_DEBUG,
596				    MSG_INTL(MSG_DEBUG_D_CHG),
597				    ndx, shdr_sec->sec_name,
598				    MSG_ORIG(MSG_CMD_SH_LINK),
599				    EC_WORD(shdr->sh_link), EC_WORD(sh_link));
600				ret = ELFEDIT_CMDRET_MOD;
601				shdr->sh_link = sh_link;
602			}
603		}
604		break;
605
606	case SHDR_CMD_T_SH_NAME:
607		{
608			elfedit_section_t *shstr_sec =
609			    &obj_state->os_secarr[obj_state->os_shstrndx];
610			Word sh_name;
611
612			/*
613			 * If -name_offset was specified, this is an offset
614			 * into the string table. Otherwise it is a string
615			 * we need to turn into an offset.
616			 */
617			sh_name = (argstate.optmask & SHDR_OPT_F_NAMOFFSET) ?
618			    elfedit_atoui(argstate.argv[1], NULL) :
619			    elfedit_strtab_insert(obj_state,
620			    shstr_sec, NULL, argstate.argv[1]);
621			if (shdr->sh_name == sh_name) {
622				elfedit_msg(ELFEDIT_MSG_DEBUG,
623				    MSG_INTL(MSG_DEBUG_D_OK),
624				    ndx, shdr_sec->sec_name,
625				    MSG_ORIG(MSG_CMD_SH_NAME),
626				    EC_WORD(shdr->sh_name));
627			} else {
628				/*
629				 * The section name is cached, so we must
630				 * also update that value. This call will
631				 * warn if the offset is out of range, and
632				 * will supply a safe string in that case.
633				 */
634				shdr_sec->sec_name =
635				    elfedit_offset_to_str(shstr_sec,
636				    sh_name, ELFEDIT_MSG_DEBUG, 1);
637
638				elfedit_msg(ELFEDIT_MSG_DEBUG,
639				    MSG_INTL(MSG_DEBUG_D_CHG),
640				    ndx, shdr_sec->sec_name,
641				    MSG_ORIG(MSG_CMD_SH_NAME),
642				    EC_WORD(shdr->sh_name), EC_WORD(sh_name));
643				ret = ELFEDIT_CMDRET_MOD;
644				shdr->sh_name = sh_name;
645			}
646		}
647		break;
648
649	case SHDR_CMD_T_SH_OFFSET:
650		{
651			Off sh_offset;
652
653			sh_offset = elfedit_atoui(argstate.argv[1], NULL);
654			if (shdr->sh_offset == sh_offset) {
655				elfedit_msg(ELFEDIT_MSG_DEBUG,
656				    MSG_INTL(MSG_DEBUG_LLX_OK),
657				    ndx, shdr_sec->sec_name,
658				    MSG_ORIG(MSG_CMD_SH_OFFSET),
659				    EC_XWORD(shdr->sh_offset));
660			} else {
661				elfedit_msg(ELFEDIT_MSG_DEBUG,
662				    MSG_INTL(MSG_DEBUG_LLX_CHG),
663				    ndx, shdr_sec->sec_name,
664				    MSG_ORIG(MSG_CMD_SH_OFFSET),
665				    EC_XWORD(shdr->sh_offset),
666				    EC_XWORD(sh_offset));
667				ret = ELFEDIT_CMDRET_MOD;
668				shdr->sh_offset = sh_offset;
669			}
670		}
671		break;
672
673	case SHDR_CMD_T_SH_SIZE:
674		{
675			Xword sh_size;
676
677			sh_size = elfedit_atoui(argstate.argv[1], NULL);
678			if (shdr->sh_size == sh_size) {
679				elfedit_msg(ELFEDIT_MSG_DEBUG,
680				    MSG_INTL(MSG_DEBUG_LLX_OK),
681				    ndx, shdr_sec->sec_name,
682				    MSG_ORIG(MSG_CMD_SH_SIZE),
683				    EC_XWORD(shdr->sh_size));
684			} else {
685				elfedit_msg(ELFEDIT_MSG_DEBUG,
686				    MSG_INTL(MSG_DEBUG_LLX_CHG),
687				    ndx, shdr_sec->sec_name,
688				    MSG_ORIG(MSG_CMD_SH_SIZE),
689				    EC_XWORD(shdr->sh_size),
690				    EC_XWORD(sh_size));
691				ret = ELFEDIT_CMDRET_MOD;
692				shdr->sh_size = sh_size;
693			}
694		}
695		break;
696
697	case SHDR_CMD_T_SH_TYPE:
698		{
699			Word sh_type = elfedit_atoconst(argstate.argv[1],
700			    ELFEDIT_CONST_SHT);
701			Conv_inv_buf_t inv_buf1, inv_buf2;
702
703			if (shdr->sh_type == sh_type) {
704				elfedit_msg(ELFEDIT_MSG_DEBUG,
705				    MSG_INTL(MSG_DEBUG_S_OK),
706				    ndx, shdr_sec->sec_name,
707				    MSG_ORIG(MSG_CMD_SH_TYPE),
708				    conv_sec_type(osabi, mach, shdr->sh_type,
709				    0, &inv_buf1));
710			} else {
711				elfedit_msg(ELFEDIT_MSG_DEBUG,
712				    MSG_INTL(MSG_DEBUG_S_CHG),
713				    ndx, shdr_sec->sec_name,
714				    MSG_ORIG(MSG_CMD_SH_TYPE),
715				    conv_sec_type(osabi, mach, shdr->sh_type,
716				    0, &inv_buf1),
717				    conv_sec_type(osabi, mach, sh_type,
718				    0, &inv_buf2));
719				ret = ELFEDIT_CMDRET_MOD;
720				shdr->sh_type = sh_type;
721			}
722		}
723		break;
724	}
725
726	/*
727	 * If we modified the section header array, tell libelf.
728	 */
729	if (ret == ELFEDIT_CMDRET_MOD)
730		elfedit_modified_shdr(shdr_sec);
731
732	/* Do autoprint */
733	print_shdr(cmd, 1, &argstate, ndx, 1, PRINT_SHDR_ALL);
734
735	return (ret);
736}
737
738
739
740
741/*
742 * Command completion functions for the various commands
743 */
744
745/*
746 * All of the commands accept the same first argument (sec) that
747 * specifies the section. This argument can be a section name
748 * (default), section index, or section type, depending on the
749 * options used. This routine determines which case is current,
750 * and then supplies completion for the first argument.
751 */
752static void
753cpl_1starg_sec(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
754    const char *argv[], int num_opt)
755{
756	elfedit_section_t *sec;
757	enum { NAME, INDEX, TYPE } op;
758	Word ndx;
759
760	if (argc != (num_opt + 1))
761		return;
762
763	op = NAME;
764	for (ndx = 0; ndx < num_opt; ndx++) {
765		if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0)
766			op = INDEX;
767		else if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0)
768			op = TYPE;
769	}
770
771	switch (op) {
772	case NAME:
773		if (obj_state == NULL)
774			break;
775		sec = obj_state->os_secarr;
776		for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++)
777			elfedit_cpl_match(cpldata, sec->sec_name, 0);
778		break;
779
780	case INDEX:
781		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHN);
782		break;
783
784	case TYPE:
785		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
786		break;
787	}
788}
789
790
791/*ARGSUSED*/
792static void
793cpl_sh_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
794    const char *argv[], int num_opt)
795{
796	/* Handle -shXXX options */
797	cpl_1starg_sec(obj_state, cpldata, argc, argv, num_opt);
798
799	/* The second and following arguments can be an SHF_ value */
800	if (argc >= (num_opt + 2))
801		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHF);
802}
803
804/*
805 * For shdr:sh_info and shdr:sh_link: The value argument can be an
806 * integer, section name, or section type.
807 */
808/*ARGSUSED*/
809static void
810cpl_sh_infolink(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
811    const char *argv[], int num_opt)
812{
813	elfedit_section_t *sec;
814	enum { NAME, INTVAL, TYPE } op;
815	Word ndx;
816
817	/* Handle -shXXX options */
818	cpl_1starg_sec(obj_state, cpldata, argc, argv, num_opt);
819
820	if (argc != (num_opt + 2))
821		return;
822
823	op = INTVAL;
824	for (ndx = 0; ndx < num_opt; ndx++) {
825		if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_VALUE_SHNAM)) == 0)
826			op = NAME;
827		else if (strcmp(argv[ndx],
828		    MSG_ORIG(MSG_STR_MINUS_VALUE_SHTYP)) == 0)
829			op = TYPE;
830	}
831
832	switch (op) {
833	case NAME:
834		if (obj_state == NULL)
835			break;
836		sec = obj_state->os_secarr;
837		for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++)
838			elfedit_cpl_match(cpldata, sec->sec_name, 0);
839		break;
840
841	case TYPE:
842		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
843		break;
844	}
845}
846
847/*ARGSUSED*/
848static void
849cpl_sh_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
850    const char *argv[], int num_opt)
851{
852	/* Handle -shXXX options */
853	cpl_1starg_sec(obj_state, cpldata, argc, argv, num_opt);
854
855	/* The second argument can be an SHT_ value */
856	if (argc == (num_opt + 2))
857		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT);
858}
859
860
861
862/*
863 * Implementation functions for the commands
864 */
865static elfedit_cmdret_t
866cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
867{
868	return (cmd_body(SHDR_CMD_T_DUMP, obj_state, argc, argv));
869}
870
871
872static elfedit_cmdret_t
873cmd_sh_addr(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
874{
875	return (cmd_body(SHDR_CMD_T_SH_ADDR, obj_state, argc, argv));
876}
877
878
879static elfedit_cmdret_t
880cmd_sh_addralign(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
881{
882	return (cmd_body(SHDR_CMD_T_SH_ADDRALIGN, obj_state, argc, argv));
883}
884
885
886static elfedit_cmdret_t
887cmd_sh_entsize(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
888{
889	return (cmd_body(SHDR_CMD_T_SH_ENTSIZE, obj_state, argc, argv));
890}
891
892static elfedit_cmdret_t
893cmd_sh_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
894{
895	return (cmd_body(SHDR_CMD_T_SH_FLAGS, obj_state, argc, argv));
896}
897
898static elfedit_cmdret_t
899cmd_sh_info(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
900{
901	return (cmd_body(SHDR_CMD_T_SH_INFO, obj_state, argc, argv));
902}
903
904static elfedit_cmdret_t
905cmd_sh_link(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
906{
907	return (cmd_body(SHDR_CMD_T_SH_LINK, obj_state, argc, argv));
908}
909
910static elfedit_cmdret_t
911cmd_sh_name(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
912{
913	return (cmd_body(SHDR_CMD_T_SH_NAME, obj_state, argc, argv));
914}
915
916static elfedit_cmdret_t
917cmd_sh_offset(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
918{
919	return (cmd_body(SHDR_CMD_T_SH_OFFSET, obj_state, argc, argv));
920}
921
922static elfedit_cmdret_t
923cmd_sh_size(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
924{
925	return (cmd_body(SHDR_CMD_T_SH_SIZE, obj_state, argc, argv));
926}
927
928static elfedit_cmdret_t
929cmd_sh_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
930{
931	return (cmd_body(SHDR_CMD_T_SH_TYPE, obj_state, argc, argv));
932}
933
934
935
936/*ARGSUSED*/
937elfedit_module_t *
938elfedit_init(elfedit_module_version_t version)
939{
940	/* Multiple commands accept only the standard set of options */
941	static elfedit_cmd_optarg_t opt_std[] = {
942		{ ELFEDIT_STDOA_OPT_O, NULL,
943		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
944		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
945		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
946		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
947		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
948		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
949		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
950		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
951		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
952		{ NULL }
953	};
954
955	/*
956	 * sh_info and sh_link accept the standard options above,
957	 * plus -value_shnam and -value_shtyp.
958	 */
959	static elfedit_cmd_optarg_t opt_infolink[] = {
960		{ ELFEDIT_STDOA_OPT_O, NULL,
961		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
962		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
963		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
964		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
965		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
966		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
967		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
968		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
969		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
970		{ MSG_ORIG(MSG_STR_MINUS_VALUE_SHNAM),
971		    /* MSG_INTL(MSG_OPTDESC_VALUE_SHNAM) */
972		    ELFEDIT_I18NHDL(MSG_OPTDESC_VALUE_SHNAM), 0,
973		    SHDR_OPT_F_VALUE_SHNAM, SHDR_OPT_F_VALUE_SHNAM },
974		{ MSG_ORIG(MSG_STR_MINUS_VALUE_SHTYP),
975		    /* MSG_INTL(MSG_OPTDESC_VALUE_SHTYP) */
976		    ELFEDIT_I18NHDL(MSG_OPTDESC_VALUE_SHTYP), 0,
977		    SHDR_OPT_F_VALUE_SHTYP, SHDR_OPT_F_VALUE_SHTYP },
978		{ NULL }
979	};
980
981	/* shdr:sh_addr */
982	static const char *name_sh_addr[] = {
983	    MSG_ORIG(MSG_CMD_SH_ADDR), NULL };
984	static elfedit_cmd_optarg_t arg_sh_addr[] = {
985		{ MSG_ORIG(MSG_STR_SEC),
986		    /* MSG_INTL(MSG_A1_SEC) */
987		    ELFEDIT_I18NHDL(MSG_A1_SEC),
988		    ELFEDIT_CMDOA_F_OPT },
989		{ MSG_ORIG(MSG_STR_VALUE),
990		    /* MSG_INTL(MSG_A2_DESC_SH_ADDR) */
991		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ADDR),
992		    ELFEDIT_CMDOA_F_OPT },
993		{ NULL }
994	};
995
996	/* shdr:dump */
997	static const char *name_dump[] = {
998	    MSG_ORIG(MSG_CMD_DUMP),
999	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
1000	    NULL
1001	};
1002	static elfedit_cmd_optarg_t opt_dump[] = {
1003		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
1004		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1005		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
1006		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
1007		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
1008		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1009		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
1010		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
1011		{ NULL }
1012	};
1013	static elfedit_cmd_optarg_t arg_dump[] = {
1014		{ MSG_ORIG(MSG_STR_SEC),
1015		    /* MSG_INTL(MSG_A1_SEC) */
1016		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1017		    ELFEDIT_CMDOA_F_OPT },
1018		{ NULL }
1019	};
1020
1021	/* shdr:sh_addralign */
1022	static const char *name_sh_addralign[] = {
1023	    MSG_ORIG(MSG_CMD_SH_ADDRALIGN), NULL };
1024	static elfedit_cmd_optarg_t arg_sh_addralign[] = {
1025		{ MSG_ORIG(MSG_STR_SEC),
1026		    /* MSG_INTL(MSG_A1_SEC) */
1027		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1028		    ELFEDIT_CMDOA_F_OPT },
1029		{ MSG_ORIG(MSG_STR_VALUE),
1030		    /* MSG_INTL(MSG_A2_DESC_SH_ADDRALIGN) */
1031		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ADDRALIGN),
1032		    ELFEDIT_CMDOA_F_OPT },
1033		{ NULL }
1034	};
1035
1036	/* shdr:sh_entsize */
1037	static const char *name_sh_entsize[] = {
1038	    MSG_ORIG(MSG_CMD_SH_ENTSIZE), NULL };
1039	static elfedit_cmd_optarg_t arg_sh_entsize[] = {
1040		{ MSG_ORIG(MSG_STR_SEC),
1041		    /* MSG_INTL(MSG_A1_SEC) */
1042		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1043		    ELFEDIT_CMDOA_F_OPT },
1044		{ MSG_ORIG(MSG_STR_VALUE),
1045		    /* MSG_INTL(MSG_A2_DESC_SH_ENTSIZE) */
1046		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_ENTSIZE),
1047		    ELFEDIT_CMDOA_F_OPT },
1048		{ NULL }
1049	};
1050
1051	/* shdr:sh_flags */
1052	static const char *name_sh_flags[] = {
1053	    MSG_ORIG(MSG_CMD_SH_FLAGS), NULL };
1054	static elfedit_cmd_optarg_t opt_sh_flags[] = {
1055		{ ELFEDIT_STDOA_OPT_AND, NULL,
1056		    ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_AND, SHDR_OPT_F_OR },
1057		{ ELFEDIT_STDOA_OPT_CMP, NULL,
1058		    ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_CMP, 0 },
1059		{ ELFEDIT_STDOA_OPT_O, NULL,
1060		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1061		{ ELFEDIT_STDOA_OPT_OR, NULL,
1062		    ELFEDIT_CMDOA_F_INHERIT, SHDR_OPT_F_OR, SHDR_OPT_F_AND },
1063		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
1064		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1065		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
1066		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
1067		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
1068		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1069		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
1070		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
1071		{ NULL }
1072	};
1073	static elfedit_cmd_optarg_t arg_sh_flags[] = {
1074		{ MSG_ORIG(MSG_STR_SEC),
1075		    /* MSG_INTL(MSG_A1_SEC) */
1076		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1077		    ELFEDIT_CMDOA_F_OPT },
1078		{ MSG_ORIG(MSG_STR_VALUE),
1079		    /* MSG_INTL(MSG_A2_DESC_SH_FLAGS) */
1080		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_FLAGS),
1081		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1082		{ NULL }
1083	};
1084
1085	/* shdr:sh_info */
1086	static const char *name_sh_info[] = {
1087	    MSG_ORIG(MSG_CMD_SH_INFO), NULL };
1088	static elfedit_cmd_optarg_t arg_sh_info[] = {
1089		{ MSG_ORIG(MSG_STR_SEC),
1090		    /* MSG_INTL(MSG_A1_SEC) */
1091		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1092		    ELFEDIT_CMDOA_F_OPT },
1093		{ MSG_ORIG(MSG_STR_VALUE),
1094		    /* MSG_INTL(MSG_A2_DESC_SH_INFO) */
1095		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_INFO),
1096		    ELFEDIT_CMDOA_F_OPT },
1097		{ NULL }
1098	};
1099
1100	/* shdr:sh_link */
1101	static const char *name_sh_link[] = {
1102	    MSG_ORIG(MSG_CMD_SH_LINK), NULL };
1103	static elfedit_cmd_optarg_t arg_sh_link[] = {
1104		{ MSG_ORIG(MSG_STR_SEC),
1105		    /* MSG_INTL(MSG_A1_SEC) */
1106		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1107		    ELFEDIT_CMDOA_F_OPT },
1108		{ MSG_ORIG(MSG_STR_VALUE),
1109		    /* MSG_INTL(MSG_A2_DESC_SH_LINK) */
1110		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_LINK),
1111		    ELFEDIT_CMDOA_F_OPT },
1112		{ NULL }
1113	};
1114
1115	/* shdr:sh_name */
1116	static const char *name_sh_name[] = {
1117	    MSG_ORIG(MSG_CMD_SH_NAME), NULL };
1118	static elfedit_cmd_optarg_t opt_sh_name[] = {
1119		{ MSG_ORIG(MSG_STR_MINUS_NAME_OFFSET),
1120		    /* MSG_INTL(MSG_OPTDESC_NAME_OFFSET) */
1121		    ELFEDIT_I18NHDL(MSG_OPTDESC_NAME_OFFSET), 0,
1122		    SHDR_OPT_F_NAMOFFSET, 0 },
1123		{ ELFEDIT_STDOA_OPT_O, NULL,
1124		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1125		{ MSG_ORIG(MSG_STR_MINUS_SHNDX),
1126		    /* MSG_INTL(MSG_OPTDESC_SHNDX) */
1127		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), 0,
1128		    SHDR_OPT_F_SHNDX, SHDR_OPT_F_SHTYP },
1129		{ MSG_ORIG(MSG_STR_MINUS_SHTYP),
1130		    /* MSG_INTL(MSG_OPTDESC_SHTYP) */
1131		    ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), 0,
1132		    SHDR_OPT_F_SHTYP, SHDR_OPT_F_SHNDX },
1133		{ NULL }
1134	};
1135	static elfedit_cmd_optarg_t arg_sh_name[] = {
1136		{ MSG_ORIG(MSG_STR_SEC),
1137		    /* MSG_INTL(MSG_A1_SEC) */
1138		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1139		    ELFEDIT_CMDOA_F_OPT },
1140		{ MSG_ORIG(MSG_STR_NAME),
1141		    /* MSG_INTL(MSG_A2_DESC_SH_NAME) */
1142		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_NAME),
1143		    ELFEDIT_CMDOA_F_OPT },
1144		{ NULL }
1145	};
1146
1147	/* shdr:sh_offset */
1148	static const char *name_sh_offset[] = {
1149	    MSG_ORIG(MSG_CMD_SH_OFFSET), NULL };
1150	static elfedit_cmd_optarg_t arg_sh_offset[] = {
1151		{ MSG_ORIG(MSG_STR_SEC),
1152		    /* MSG_INTL(MSG_A1_SEC) */
1153		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1154		    ELFEDIT_CMDOA_F_OPT },
1155		{ MSG_ORIG(MSG_STR_VALUE),
1156		    /* MSG_INTL(MSG_A2_DESC_SH_OFFSET) */
1157		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_OFFSET),
1158		    ELFEDIT_CMDOA_F_OPT },
1159		{ NULL }
1160	};
1161
1162	/* shdr:sh_size */
1163	static const char *name_sh_size[] = {
1164	    MSG_ORIG(MSG_CMD_SH_SIZE), NULL };
1165	static elfedit_cmd_optarg_t arg_sh_size[] = {
1166		{ MSG_ORIG(MSG_STR_SEC),
1167		    /* MSG_INTL(MSG_A1_SEC) */
1168		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1169		    ELFEDIT_CMDOA_F_OPT },
1170		{ MSG_ORIG(MSG_STR_VALUE),
1171		    /* MSG_INTL(MSG_A2_DESC_SH_SIZE) */
1172		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_SIZE),
1173		    ELFEDIT_CMDOA_F_OPT },
1174		{ NULL }
1175	};
1176
1177	/* shdr:sh_type */
1178	static const char *name_sh_type[] = {
1179	    MSG_ORIG(MSG_CMD_SH_TYPE), NULL };
1180	static elfedit_cmd_optarg_t arg_sh_type[] = {
1181		{ MSG_ORIG(MSG_STR_SEC),
1182		    /* MSG_INTL(MSG_A1_SEC) */
1183		    ELFEDIT_I18NHDL(MSG_A1_SEC),
1184		    ELFEDIT_CMDOA_F_OPT },
1185		{ MSG_ORIG(MSG_STR_VALUE),
1186		    /* MSG_INTL(MSG_A2_DESC_SH_TYPE) */
1187		    ELFEDIT_I18NHDL(MSG_A2_DESC_SH_TYPE),
1188		    ELFEDIT_CMDOA_F_OPT },
1189		{ NULL }
1190	};
1191
1192	static elfedit_cmd_t cmds[] = {
1193		/* shdr:dump */
1194		{ cmd_dump, cpl_1starg_sec, name_dump,
1195		    /* MSG_INTL(MSG_DESC_DUMP) */
1196		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
1197		    /* MSG_INTL(MSG_HELP_DUMP) */
1198		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
1199		    opt_dump, arg_dump },
1200
1201		/* shdr:sh_addr */
1202		{ cmd_sh_addr, cpl_1starg_sec, name_sh_addr,
1203		    /* MSG_INTL(MSG_DESC_SH_ADDR) */
1204		    ELFEDIT_I18NHDL(MSG_DESC_SH_ADDR),
1205		    /* MSG_INTL(MSG_HELP_SH_ADDR) */
1206		    ELFEDIT_I18NHDL(MSG_HELP_SH_ADDR),
1207		    opt_std, arg_sh_addr },
1208
1209		/* shdr:sh_addralign */
1210		{ cmd_sh_addralign, cpl_1starg_sec, name_sh_addralign,
1211		    /* MSG_INTL(MSG_DESC_SH_ADDRALIGN) */
1212		    ELFEDIT_I18NHDL(MSG_DESC_SH_ADDRALIGN),
1213		    /* MSG_INTL(MSG_HELP_SH_ADDRALIGN) */
1214		    ELFEDIT_I18NHDL(MSG_HELP_SH_ADDRALIGN),
1215		    opt_std, arg_sh_addralign },
1216
1217		/* shdr:sh_entsize */
1218		{ cmd_sh_entsize, cpl_1starg_sec, name_sh_entsize,
1219		    /* MSG_INTL(MSG_DESC_SH_ENTSIZE) */
1220		    ELFEDIT_I18NHDL(MSG_DESC_SH_ENTSIZE),
1221		    /* MSG_INTL(MSG_HELP_SH_ENTSIZE) */
1222		    ELFEDIT_I18NHDL(MSG_HELP_SH_ENTSIZE),
1223		    opt_std, arg_sh_entsize },
1224
1225		/* shdr:sh_flags */
1226		{ cmd_sh_flags, cpl_sh_flags, name_sh_flags,
1227		    /* MSG_INTL(MSG_DESC_SH_FLAGS) */
1228		    ELFEDIT_I18NHDL(MSG_DESC_SH_FLAGS),
1229		    /* MSG_INTL(MSG_HELP_SH_FLAGS) */
1230		    ELFEDIT_I18NHDL(MSG_HELP_SH_FLAGS),
1231		    opt_sh_flags, arg_sh_flags },
1232
1233		/* shdr:sh_info */
1234		{ cmd_sh_info, cpl_sh_infolink, name_sh_info,
1235		    /* MSG_INTL(MSG_DESC_SH_INFO) */
1236		    ELFEDIT_I18NHDL(MSG_DESC_SH_INFO),
1237		    /* MSG_INTL(MSG_HELP_SH_INFO) */
1238		    ELFEDIT_I18NHDL(MSG_HELP_SH_INFO),
1239		    opt_infolink, arg_sh_info },
1240
1241		/* shdr:sh_link */
1242		{ cmd_sh_link, cpl_sh_infolink, name_sh_link,
1243		    /* MSG_INTL(MSG_DESC_SH_LINK) */
1244		    ELFEDIT_I18NHDL(MSG_DESC_SH_LINK),
1245		    /* MSG_INTL(MSG_HELP_SH_LINK) */
1246		    ELFEDIT_I18NHDL(MSG_HELP_SH_LINK),
1247		    opt_infolink, arg_sh_link },
1248
1249		/* shdr:sh_name */
1250		{ cmd_sh_name, cpl_1starg_sec, name_sh_name,
1251		    /* MSG_INTL(MSG_DESC_SH_NAME) */
1252		    ELFEDIT_I18NHDL(MSG_DESC_SH_NAME),
1253		    /* MSG_INTL(MSG_HELP_SH_NAME) */
1254		    ELFEDIT_I18NHDL(MSG_HELP_SH_NAME),
1255		    opt_sh_name, arg_sh_name },
1256
1257		/* shdr:sh_offset */
1258		{ cmd_sh_offset, cpl_1starg_sec, name_sh_offset,
1259		    /* MSG_INTL(MSG_DESC_SH_OFFSET) */
1260		    ELFEDIT_I18NHDL(MSG_DESC_SH_OFFSET),
1261		    /* MSG_INTL(MSG_HELP_SH_OFFSET) */
1262		    ELFEDIT_I18NHDL(MSG_HELP_SH_OFFSET),
1263		    opt_std, arg_sh_offset },
1264
1265		/* shdr:sh_size */
1266		{ cmd_sh_size, cpl_1starg_sec, name_sh_size,
1267		    /* MSG_INTL(MSG_DESC_SH_SIZE) */
1268		    ELFEDIT_I18NHDL(MSG_DESC_SH_SIZE),
1269		    /* MSG_INTL(MSG_HELP_SH_SIZE) */
1270		    ELFEDIT_I18NHDL(MSG_HELP_SH_SIZE),
1271		    opt_std, arg_sh_size },
1272
1273		/* shdr:sh_type */
1274		{ cmd_sh_type, cpl_sh_type, name_sh_type,
1275		    /* MSG_INTL(MSG_DESC_SH_TYPE) */
1276		    ELFEDIT_I18NHDL(MSG_DESC_SH_TYPE),
1277		    /* MSG_INTL(MSG_HELP_SH_TYPE) */
1278		    ELFEDIT_I18NHDL(MSG_HELP_SH_TYPE),
1279		    opt_std, arg_sh_type },
1280
1281		{ NULL }
1282	};
1283
1284	static elfedit_module_t module = {
1285	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
1286	    /* MSG_INTL(MSG_MOD_DESC) */
1287	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
1288	    cmds, mod_i18nhdl_to_str };
1289
1290	return (&module);
1291}
1292