xref: /titanic_41/usr/src/cmd/sgs/elfedit/modules/common/shdr.c (revision 1915be19b7a1f7c113b706bd54d6ca393e8d8107)
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  */
47 typedef 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  */
68 const 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  */
89 static const char *
90 mod_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  */
103 typedef 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  */
119 typedef 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  */
142 static void
143 process_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  */
197 static void
198 print_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  */
375 static elfedit_cmdret_t
376 cmd_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  */
737 static void
738 cpl_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*/
777 static void
778 cpl_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*/
790 static void
791 cpl_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  */
807 static elfedit_cmdret_t
808 cmd_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 
814 static elfedit_cmdret_t
815 cmd_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 
821 static elfedit_cmdret_t
822 cmd_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 
828 static elfedit_cmdret_t
829 cmd_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 
834 static elfedit_cmdret_t
835 cmd_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 
840 static elfedit_cmdret_t
841 cmd_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 
846 static elfedit_cmdret_t
847 cmd_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 
852 static elfedit_cmdret_t
853 cmd_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 
858 static elfedit_cmdret_t
859 cmd_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 
864 static elfedit_cmdret_t
865 cmd_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 
870 static elfedit_cmdret_t
871 cmd_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*/
879 elfedit_module_t *
880 elfedit_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