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