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