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