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