xref: /illumos-gate/usr/src/cmd/sgs/elfedit/modules/common/dyn.c (revision 2aeafac3612e19716bf8164f89c3c9196342979c)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include	<ctype.h>
28 #include	<elfedit.h>
29 #include	<sys/elf_SPARC.h>
30 #include	<strings.h>
31 #include	<debug.h>
32 #include	<conv.h>
33 #include	<dyn_msg.h>
34 
35 
36 /*
37  * Dynamic section
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 	/* Dump command, used as module default to display dynamic section */
47 	DYN_CMD_T_DUMP =	0,	/* dyn:dump */
48 
49 	/* Commands that do not correspond directly to a specific DT tag */
50 	DYN_CMD_T_TAG =		1,	/* dyn:tag */
51 	DYN_CMD_T_VALUE =	2,	/* dyn:value */
52 	DYN_CMD_T_DELETE =	3,	/* dyn:delete */
53 	DYN_CMD_T_MOVE =	4,	/* dyn:shift */
54 
55 	/* Commands that embody tag specific knowledge */
56 	DYN_CMD_T_RUNPATH =	5,	/* dyn:runpath/rpath */
57 	DYN_CMD_T_POSFLAG1 =	6,	/* dyn:posflag1 */
58 	DYN_CMD_T_FLAGS =	7,	/* dyn:flags */
59 	DYN_CMD_T_FLAGS1 =	8,	/* dyn:flags1 */
60 	DYN_CMD_T_FEATURE1 =	9,	/* dyn:feature1 */
61 	DYN_CMD_T_CHECKSUM =	10,	/* dyn:checksum */
62 	DYN_CMD_T_SUNW_LDMACH =	11	/* dyn:sunw_ldmach */
63 } DYN_CMD_T;
64 
65 
66 
67 #ifndef _ELF64
68 /*
69  * We supply this function for the msg module
70  */
71 const char *
72 _dyn_msg(Msg mid)
73 {
74 	return (gettext(MSG_ORIG(mid)));
75 }
76 #endif
77 
78 
79 /*
80  * This function is supplied to elfedit through our elfedit_module_t
81  * definition. It translates the opaque elfedit_i18nhdl_t handles
82  * in our module interface into the actual strings for elfedit to
83  * use.
84  *
85  * note:
86  *	This module uses Msg codes for its i18n handle type.
87  *	So the translation is simply to use MSG_INTL() to turn
88  *	it into a string and return it.
89  */
90 static const char *
91 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
92 {
93 	Msg msg = (Msg)hdl;
94 
95 	return (MSG_INTL(msg));
96 }
97 
98 
99 
100 /*
101  * The dyn_opt_t enum specifies a bit value for every optional
102  * argument allowed by a command in this module.
103  */
104 typedef enum {
105 	DYN_OPT_F_ADD =		1,	/* -add: Add new elt rather than */
106 					/*	modifying an existing one */
107 	DYN_OPT_F_AND =		2,	/* -and: AND (&) values to dest */
108 	DYN_OPT_F_CMP =		4,	/* -cmp: Complement (~) values */
109 	DYN_OPT_F_DYNNDX_ELT =	8,	/* -dynndx: 1st plain arg is tag */
110 					/*	index, not name */
111 	DYN_OPT_F_DYNNDX_VAL =	16,	/* -dynndx ndx: Index is value to */
112 					/*	option rather than 1st plain */
113 					/*	arg. Used for dyn:posflag1 */
114 	DYN_OPT_F_NEEDED =	32,	/* -needed str: Locate DT_POSFLAG_1 */
115 					/*	relative to DT_NEEDED element */
116 	DYN_OPT_F_OR =		64,	/* -or: OR (|) values to dest */
117 	DYN_OPT_F_STRVAL =	128	/* -s: value is string, not integer */
118 } dyn_opt_t;
119 
120 
121 /*
122  * A variable of type ARGSTATE is used by each command to maintain
123  * information about the arguments and related things. It is
124  * initialized by process_args(), and used by the other routines.
125  */
126 typedef struct {
127 	elfedit_obj_state_t	*obj_state;
128 	elfedit_section_t	*strsec;	/* Dynamic string table ref */
129 	struct {
130 		elfedit_section_t *sec;		/* Dynamic section reference */
131 		Dyn	*data;			/* Start dynamic section data */
132 		Word	num;			/* # dynamic elts */
133 		Word	null_ndx;		/* Index of first DT_NULL */
134 		Word	num_null_ndx;		/* # of DT_NULL elements */
135 	} dyn;
136 	dyn_opt_t		optmask;	/* Mask of options used */
137 	int			argc;		/* # of plain arguments */
138 	const char		**argv;		/* Plain arguments */
139 	const char		*dyn_elt_str;	/* Value string for */
140 						/*	DYN_OPT_F_DYNNDX_VAL */
141 						/*	or DYN_OPT_F_NEEDED */
142 } ARGSTATE;
143 
144 
145 
146 /*
147  * Set argstate null_ndx field for current dynamic area
148  */
149 static void
150 set_null_ndx(ARGSTATE *argstate)
151 {
152 	Word	num, null_ndx;
153 
154 	num = argstate->dyn.num;
155 	argstate->dyn.num_null_ndx = 0;
156 	for (null_ndx = 0; null_ndx < num; null_ndx++)
157 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) {
158 			argstate->dyn.num_null_ndx++;
159 			break;
160 		}
161 	argstate->dyn.null_ndx = null_ndx;
162 
163 	/* Count the number of remaining DT_NULL items */
164 	for (; null_ndx < num; null_ndx++)
165 		if (argstate->dyn.data[null_ndx].d_tag == DT_NULL)
166 			argstate->dyn.num_null_ndx++;
167 }
168 
169 
170 /*
171  * Convert the first available DT_NULL slot in the dynamic section
172  * into something else.
173  *
174  * entry:
175  *	argstate - Argument state block
176  *	d_tag, d_val - Values to be set in new element
177  *
178  * exit:
179  *	If an extra DT_NULL slot is available, a debug message is
180  *	issued, the slot is converted to its new use, and the argstate
181  *	block state related to DT_NULL slots is updated.
182  *
183  *	if no extra DT_NULL slot is present, an error is issued and
184  *	this routine does not return to the caller.
185  */
186 static Word
187 convert_dt_null(ARGSTATE *argstate, Xword d_tag, Xword d_val)
188 {
189 	Conv_inv_buf_t inv_buf;
190 	Word	ndx;
191 	Dyn	*dyn;
192 	Ehdr	*ehdr;
193 
194 	/* If we lack an extra element, we can't continue */
195 	if (argstate->dyn.num_null_ndx <= 1)
196 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
197 		    EC_WORD(argstate->dyn.sec->sec_shndx),
198 		    argstate->dyn.sec->sec_name);
199 
200 	ehdr = argstate->obj_state->os_ehdr;
201 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL),
202 	    EC_WORD(argstate->dyn.sec->sec_shndx), argstate->dyn.sec->sec_name,
203 	    EC_WORD(argstate->dyn.null_ndx), conv_dyn_tag(d_tag,
204 	    ehdr->e_ident[EI_OSABI], ehdr->e_machine, 0, &inv_buf));
205 
206 	ndx = argstate->dyn.null_ndx;
207 	dyn = &argstate->dyn.data[ndx];
208 	dyn->d_tag = d_tag;
209 	dyn->d_un.d_val = d_val;
210 
211 	/* Recompute the DT_NULL situation */
212 	set_null_ndx(argstate);
213 
214 	return (ndx);
215 }
216 
217 
218 /*
219  * Standard argument processing for dyn module
220  *
221  * entry
222  *	obj_state, argc, argv - Standard command arguments
223  *	argstate - Address of ARGSTATE block to be initialized
224  *
225  * exit:
226  *	On success, *argstate is initialized. On error,
227  *	an error is issued and this routine does not return.
228  */
229 static void
230 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
231     ARGSTATE *argstate)
232 {
233 	elfedit_getopt_state_t	getopt_state;
234 	elfedit_getopt_ret_t	*getopt_ret;
235 
236 	bzero(argstate, sizeof (*argstate));
237 	argstate->obj_state = obj_state;
238 
239 	elfedit_getopt_init(&getopt_state, &argc, &argv);
240 
241 	/* Add each new option to the options mask */
242 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
243 		argstate->optmask |= getopt_ret->gor_idmask;
244 		switch (getopt_ret->gor_idmask) {
245 		case DYN_OPT_F_DYNNDX_VAL:
246 		case DYN_OPT_F_NEEDED:
247 			argstate->dyn_elt_str = getopt_ret->gor_value;
248 			break;
249 		}
250 	}
251 
252 	/* If there may be an arbitrary amount of output, use a pager */
253 	if (argc == 0)
254 		elfedit_pager_init();
255 
256 	/* Return the updated values of argc/argv */
257 	argstate->argc = argc;
258 	argstate->argv = argv;
259 
260 	/* Locate the dynamic section, and the assocated string table */
261 	argstate->dyn.sec = elfedit_sec_getdyn(obj_state, &argstate->dyn.data,
262 	    &argstate->dyn.num);
263 	argstate->strsec = elfedit_sec_getstr(obj_state,
264 	    argstate->dyn.sec->sec_shdr->sh_link, 0);
265 
266 	/* Index of first DT_NULL */
267 	set_null_ndx(argstate);
268 }
269 
270 /*
271  * Print ELF header values, taking the calling command, and output style
272  * into account.
273  *
274  * entry:
275  *	cmd - DYN_CMD_T_* value giving identify of caller
276  *	autoprint - If True, output is only produced if the elfedit
277  *		autoprint flag is set. If False, output is always produced.
278  *	argstate - Argument state block
279  *	print_type - Specifies which dynamic elements to display.
280  *	arg - If print_type is PRINT_DYN_T_NDX, displays the index specified.
281  *		Otherwise ignored.
282  */
283 typedef enum {
284 	PRINT_DYN_T_ALL =	0,	/* Show all indexes */
285 	PRINT_DYN_T_NDX =	1,	/* Show dynamic[arg] only */
286 	PRINT_DYN_T_TAG =	2,	/* Show all elts with tag type */
287 					/*	given by arg */
288 	PRINT_DYN_T_RUNPATH =	3	/* Show all runpath/rpath elts */
289 
290 } PRINT_DYN_T;
291 
292 static void
293 print_dyn(DYN_CMD_T cmd, int autoprint, ARGSTATE *argstate,
294     PRINT_DYN_T print_type, Word arg)
295 {
296 	elfedit_outstyle_t	outstyle;
297 	Conv_fmt_flags_t	flags_fmt_flags;
298 	Word	end_ndx, ndx, printed = 0;
299 	Dyn	*dyn;
300 	int	header_done = 0;
301 	Xword	last_d_val;
302 	int	one_shot;
303 	int	osabi_solaris;
304 
305 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
306 		return;
307 
308 	osabi_solaris =
309 	    elfedit_test_osabi(argstate->obj_state, ELFOSABI_SOLARIS, 0);
310 
311 	/*
312 	 * Pick an output style. dyn:dump is required to use the default
313 	 * style. The other commands use the current output style.
314 	 */
315 	outstyle = (cmd == DYN_CMD_T_DUMP) ?
316 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
317 
318 	/*
319 	 * When using the simple output style, omit the
320 	 * brackets from around the values.
321 	 */
322 	flags_fmt_flags = (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) ?
323 	    CONV_FMT_NOBKT : 0;
324 
325 	/* Starting index */
326 	if (print_type == PRINT_DYN_T_NDX) {
327 		if (arg >= argstate->dyn.num)
328 			return;		/* Out of range */
329 		ndx = arg;
330 	} else {
331 		ndx = 0;
332 	}
333 
334 	/*
335 	 * one_shot is used by positional elements (e.g. DT_POSFLAG_1)
336 	 * to get the item following them to be shown even if they
337 	 * are not of the desired tag type or the count of elements
338 	 * to be displayed is only 1.
339 	 */
340 	one_shot = 0;
341 
342 	dyn = &argstate->dyn.data[ndx];
343 
344 	/*
345 	 * Loop predicate explanation:
346 	 * Normally, we want to iterate from the starting index
347 	 * to the end. However, in the case of PRINT_DYN_T_NDX, we
348 	 * only want to display one item (ndx == arg) and then quit,
349 	 * with the exception that if we've been through the loop
350 	 * and encountered a one_shot situation, we want to continue
351 	 * iterating until the one-shot situation is cleared.
352 	 */
353 	for (; (ndx < argstate->dyn.num) &&
354 	    ((print_type != PRINT_DYN_T_NDX) || ((ndx == arg) || one_shot));
355 	    dyn++, ndx++) {
356 		union {
357 			Conv_inv_buf_t		inv;
358 			Conv_dyn_flag_buf_t	flag;
359 			Conv_dyn_flag1_buf_t	flag1;
360 			Conv_dyn_posflag1_buf_t	posflag1;
361 			Conv_dyn_feature1_buf_t	feature1;
362 		} c_buf;
363 		const char	*name;
364 
365 		if (one_shot) {
366 			one_shot = 0;
367 		} else {
368 			/*
369 			 * If we are only displaying certain tag types and
370 			 * this isn't one of those, move on to next element.
371 			 */
372 			switch (print_type) {
373 			case PRINT_DYN_T_TAG:
374 				if (dyn->d_tag != arg)
375 					continue;
376 				break;
377 			case PRINT_DYN_T_RUNPATH:
378 				if ((dyn->d_tag != DT_RPATH) &&
379 				    (dyn->d_tag != DT_RUNPATH))
380 					continue;
381 				break;
382 			}
383 		}
384 
385 		/*
386 		 * Print the information numerically, and if possible
387 		 * as a string.
388 		 */
389 		name = NULL;
390 		switch (dyn->d_tag) {
391 		case DT_NULL:
392 			if (!((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) &&
393 			    (print_type == PRINT_DYN_T_ALL) &&
394 			    (dyn->d_un.d_val == 0)))
395 				break;
396 			end_ndx = ndx;
397 			/*
398 			 * Special case: DT_NULLs can come in groups
399 			 * that we prefer to reduce to a single line.
400 			 */
401 			while ((end_ndx < (argstate->dyn.num - 1)) &&
402 			    ((dyn + 1)->d_tag == DT_NULL) &&
403 			    ((dyn + 1)->d_un.d_val == 0)) {
404 				dyn++;
405 				end_ndx++;
406 			}
407 			if (header_done == 0) {
408 				header_done = 1;
409 				Elf_dyn_title(0);
410 			}
411 			Elf_dyn_null_entry(0, dyn, ndx, end_ndx);
412 			ndx = end_ndx;
413 			printed = 1;
414 			last_d_val = dyn->d_un.d_val;
415 			continue;
416 
417 		/*
418 		 * Print the information numerically, and if possible
419 		 * as a string.
420 		 */
421 		case DT_NEEDED:
422 		case DT_SONAME:
423 		case DT_FILTER:
424 		case DT_AUXILIARY:
425 		case DT_CONFIG:
426 		case DT_RPATH:
427 		case DT_RUNPATH:
428 		case DT_USED:
429 		case DT_DEPAUDIT:
430 		case DT_AUDIT:
431 			name = elfedit_offset_to_str(argstate->strsec,
432 			    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
433 			break;
434 		case DT_SUNW_AUXILIARY:
435 		case DT_SUNW_FILTER:
436 			if (osabi_solaris)
437 				name = elfedit_offset_to_str(argstate->strsec,
438 				    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
439 			break;
440 
441 		case DT_FLAGS:
442 			name = conv_dyn_flag(dyn->d_un.d_val,
443 			    flags_fmt_flags, &c_buf.flag);
444 			break;
445 		case DT_FLAGS_1:
446 			name = conv_dyn_flag1(dyn->d_un.d_val,
447 			    flags_fmt_flags, &c_buf.flag1);
448 			break;
449 		case DT_POSFLAG_1:
450 			/*
451 			 * If this is dyn:posflag1, and the print_type
452 			 * is PRINT_DYN_T_TAG, and the -needed option is
453 			 * used, then don't show any DT_POSFLAG_1 elements
454 			 * that are not followed by a DT_NEEDED element
455 			 * that matches the -needed string.
456 			 */
457 			if ((cmd == DYN_CMD_T_POSFLAG1) &&
458 			    (print_type == PRINT_DYN_T_TAG) &&
459 			    ((argstate->optmask & DYN_OPT_F_NEEDED) != 0) &&
460 			    ((ndx + 1) < argstate->dyn.num)) {
461 				Dyn *dyn1 = &argstate->dyn.data[ndx + 1];
462 
463 				if (dyn1->d_tag != DT_NEEDED)
464 					continue;
465 				name = elfedit_offset_to_str(argstate->strsec,
466 				    dyn1->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
467 				if (strncmp(name, argstate->dyn_elt_str,
468 				    strlen(argstate->dyn_elt_str)) != 0)
469 					continue;
470 			}
471 
472 			name = conv_dyn_posflag1(dyn->d_un.d_val,
473 			    flags_fmt_flags, &c_buf.posflag1);
474 			/*
475 			 * DT_POSFLAG_1 is a positional element that affects
476 			 * the following item. If using the default output
477 			 * style, then show the following item as well.
478 			 */
479 			one_shot = (outstyle == ELFEDIT_OUTSTYLE_DEFAULT);
480 			break;
481 		case DT_FEATURE_1:
482 			name = conv_dyn_feature1(dyn->d_un.d_val,
483 			    flags_fmt_flags, &c_buf.feature1);
484 			break;
485 		case DT_DEPRECATED_SPARC_REGISTER:
486 			name = MSG_INTL(MSG_STR_DEPRECATED);
487 			break;
488 		case DT_SUNW_LDMACH:
489 			if (osabi_solaris)
490 				name = conv_ehdr_mach((Half)dyn->d_un.d_val, 0,
491 				    &c_buf.inv);
492 			break;
493 		}
494 
495 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
496 			Ehdr	*ehdr;
497 
498 			if (header_done == 0) {
499 				header_done = 1;
500 				Elf_dyn_title(0);
501 			}
502 			if (name == NULL)
503 				name = MSG_ORIG(MSG_STR_EMPTY);
504 			ehdr = argstate->obj_state->os_ehdr;
505 			Elf_dyn_entry(0, dyn, ndx, name,
506 			    ehdr->e_ident[EI_OSABI], ehdr->e_machine);
507 		} else {
508 			/*
509 			 * In simple or numeric mode under a print type
510 			 * that is based on tag type rather than on index,
511 			 * if there are more than one qualifying tag, we
512 			 * want to skip printing redundant information.
513 			 */
514 			switch (print_type) {
515 			case PRINT_DYN_T_TAG:
516 				switch (dyn->d_tag) {
517 				case DT_NEEDED:
518 					/* Multiple NEEDED entries are normal */
519 					break;
520 				case DT_POSFLAG_1:
521 					/*
522 					 * Positional flags don't count,
523 					 * because each one affects a different
524 					 * item. Don't skip those even if they
525 					 * have duplicate values.
526 					 */
527 					break;
528 				default:
529 					/*
530 					 * Anything else: If we've already
531 					 * printed this value, don't print
532 					 * it again.
533 					 */
534 					if (printed &&
535 					    (last_d_val == dyn->d_un.d_val))
536 						continue;
537 				}
538 				break;
539 			case PRINT_DYN_T_RUNPATH:
540 				/*
541 				 * If we've already printed this value,
542 				 * don't print it again. This commonly
543 				 * happens when both DT_RPATH and DT_RUNPATH
544 				 * are present with the same value.
545 				 */
546 				if (printed && (last_d_val == dyn->d_un.d_val))
547 					continue;
548 				break;
549 			}
550 
551 			if ((name != NULL) &&
552 			    (outstyle == ELFEDIT_OUTSTYLE_SIMPLE)) {
553 				elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), name);
554 			} else {
555 				elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
556 				    EC_XWORD(dyn->d_un.d_val));
557 			}
558 		}
559 		printed = 1;
560 		last_d_val = dyn->d_un.d_val;
561 	}
562 
563 	/*
564 	 * If nothing was output under the print types that are
565 	 * based on tag type, issue an error saying it doesn't exist.
566 	 */
567 	if (!printed) {
568 		if (print_type == PRINT_DYN_T_TAG) {
569 			Conv_inv_buf_t	inv_buf;
570 			Ehdr		*ehdr = argstate->obj_state->os_ehdr;
571 
572 			elfedit_msg(ELFEDIT_MSG_ERR,
573 			    MSG_INTL(MSG_ERR_NODYNELT),
574 			    EC_WORD(argstate->dyn.sec->sec_shndx),
575 			    argstate->dyn.sec->sec_name, conv_dyn_tag(arg,
576 			    ehdr->e_ident[EI_OSABI], ehdr->e_machine,
577 			    0, &inv_buf));
578 		}
579 
580 		if (print_type == PRINT_DYN_T_RUNPATH)
581 			elfedit_msg(ELFEDIT_MSG_ERR,
582 			    MSG_INTL(MSG_ERR_NORUNPATH),
583 			    EC_WORD(argstate->dyn.sec->sec_shndx),
584 			    argstate->dyn.sec->sec_name);
585 	}
586 }
587 
588 
589 /*
590  * Determine the index(s) of the dynamic element(s) to be displayed and/or
591  * manipulated.
592  *
593  * entry:
594  *	argstate - Argument state block
595  *	arg - If the command being called accepts a first plain argument
596  *		named 'elt' which is used to specify the dynamic element,
597  *		arg is the value of argv[0] for that command. If the
598  *		command does not accept an 'elt' argument and instead
599  *		implicitly assumes a tag type, arg is the constant string
600  *		for that type (e.g. "DT_POSFLAG_1").
601  *	print_request - True if the command is to print the current
602  *		value(s) and return without changing anything.
603  *	print_type - Address of variable containing PRINT_DYN_T_
604  *		code specifying how the elements will be displayed.
605  *
606  * exit:
607  *	If print_request is False: This routine always returns the index
608  *	of a single dynamic element. *print_type is set to PRINT_DYN_T_NDX.
609  *	The 'elt' argument as well as any modifier options (-dynndx, -needed)
610  *	are examined to determine this index. If there are no modifier options,
611  *	the dynamic section contains no element of the desired type, and there
612  *	is an extra DT_NULL element in the section, then a new element of
613  *	the desired type is created and its index returned. Otherwise an
614  *	error is issued.
615  *
616  *	If print_request is True: If a modifier (-dynndx, -needed) was used,
617  *	*print_type is set to PRINT_DYN_T_NDX and the index of the
618  *	corresponding single dynamic element is returned. If no modifier
619  *	was used, *print_type is set to PRINT_DYN_T_TAG, and the tag
620  *	type code is returned.
621  */
622 static Word
623 arg_to_index(ARGSTATE *argstate, const char *arg,
624     int print_request, PRINT_DYN_T *print_type)
625 {
626 	Word	ndx;
627 	Xword	dt_value;
628 	Dyn	*dyn;
629 
630 
631 	/* Assume we are returning an index, alter as needed below */
632 	*print_type = PRINT_DYN_T_NDX;
633 
634 	/*
635 	 * All the commands that accept the DYN_OPT_F_DYNNDX_ELT form
636 	 * of -dynndx require a plain argument named 'elt' as their first
637 	 * argument. -dynndx is a modifier that means that 'elt' is a
638 	 * simple numeric section index. Routines that accept this form
639 	 * of -dynndx are willing to handle any tag type, so all we need
640 	 * to check is that the value is in range.
641 	 */
642 	if ((argstate->optmask & DYN_OPT_F_DYNNDX_ELT) != 0)
643 		return ((Word) elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_ELT),
644 		    0, argstate->dyn.num - 1, NULL));
645 
646 	/* arg is a DT_ tag type, not a numeric index */
647 	dt_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_DT);
648 
649 	/*
650 	 * Commands that accept the DYN_OPT_F_DYNNDX_VAL form  of
651 	 * dynndx do not accept the 'elt' argument. The index is a
652 	 * value that follows the option, and was saved in argstate by
653 	 * process_args(). Routines that accept this form of -dynndx
654 	 * require the specified element to have a specific tag type,
655 	 * so we test for this as well as for the index being in range.
656 	 */
657 	if ((argstate->optmask & DYN_OPT_F_DYNNDX_VAL) != 0) {
658 		ndx = ((Word) elfedit_atoui_range(argstate->dyn_elt_str,
659 		    MSG_ORIG(MSG_STR_INDEX), 0, argstate->dyn.num - 1, NULL));
660 		if (argstate->dyn.data[ndx].d_tag != dt_value) {
661 			Ehdr	*ehdr = argstate->obj_state->os_ehdr;
662 			uchar_t	osabi = ehdr->e_ident[EI_OSABI];
663 			Half	mach = ehdr->e_machine;
664 			Conv_inv_buf_t	is, want;
665 
666 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_WRONGTAG),
667 			    EC_WORD(argstate->dyn.sec->sec_shndx),
668 			    argstate->dyn.sec->sec_name, ndx,
669 			    conv_dyn_tag(dt_value, osabi, mach, 0, &want),
670 			    conv_dyn_tag(argstate->dyn.data[ndx].d_tag,
671 			    osabi, mach, 0, &is));
672 		}
673 		return (ndx);
674 	}
675 
676 	/*
677 	 * If this is a printing request, then we let print_dyn() show
678 	 * all the items with this tag type.
679 	 */
680 	if (print_request) {
681 		*print_type = PRINT_DYN_T_TAG;
682 		return (dt_value);
683 	}
684 
685 	/*
686 	 * Commands that accept -needed are looking for the dt_value element
687 	 * (usually DT_POSFLAG_1) that immediately preceeds the DT_NEEDED
688 	 * element with the string given by argstate->dyn_elt_str.
689 	 */
690 	if ((argstate->optmask & DYN_OPT_F_NEEDED) != 0) {
691 		Word	retndx = argstate->dyn.num;	/* Out of range value */
692 		const char	*name;
693 		size_t		len;
694 
695 		len = strlen(argstate->dyn_elt_str);
696 		for (ndx = 0, dyn = argstate->dyn.data;
697 		    ndx < argstate->dyn.num; dyn++, ndx++) {
698 			/*
699 			 * If the immediately preceeding item has the
700 			 * tag type we're looking for, and the current item
701 			 * is a DT_NEEDED with a string that matches,
702 			 * then the preceeding item is the one we want.
703 			 */
704 			if ((dyn->d_tag == DT_NEEDED) &&
705 			    (ndx > 0) && (retndx == (ndx - 1))) {
706 				name = elfedit_offset_to_str(argstate->strsec,
707 				    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0);
708 
709 				if (strncmp(name,
710 				    argstate->dyn_elt_str, len) == 0)
711 					return (retndx);
712 				continue;
713 			}
714 
715 			/*
716 			 * If the current item has the tag type we're
717 			 * looking for, make it our current candidate.
718 			 * If the next item is a DT_NEEDED with the right
719 			 * string value, we'll use it then.
720 			 */
721 			if (dyn->d_tag == dt_value)
722 				retndx = ndx;
723 		}
724 
725 		/* If we get here, no matching DT_NEEDED was found */
726 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NEEDEDNOMATCH),
727 		    EC_WORD(argstate->dyn.sec->sec_shndx),
728 		    argstate->dyn.sec->sec_name, argstate->dyn_elt_str);
729 	}
730 
731 	/* Locate the first entry with the given tag type */
732 	for (ndx = 0; ndx < argstate->dyn.num; ndx++) {
733 		if (argstate->dyn.data[ndx].d_tag == dt_value) {
734 			elfedit_msg(ELFEDIT_MSG_DEBUG,
735 			    MSG_INTL(MSG_DEBUG_DT2NDX),
736 			    EC_WORD(argstate->dyn.sec->sec_shndx),
737 			    argstate->dyn.sec->sec_name, EC_WORD(ndx), arg);
738 			return (ndx);
739 		}
740 	}
741 
742 	/* Not found. Can we create one? */
743 	if (argstate->dyn.num_null_ndx > 1)
744 		return (convert_dt_null(argstate, dt_value, 0));
745 
746 	/* No room to create one, so we're out of options and must fail */
747 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODTELT),
748 	    EC_WORD(argstate->dyn.sec->sec_shndx),
749 	    argstate->dyn.sec->sec_name, arg);
750 
751 	/*NOTREACHED*/
752 	return (0);		/* For lint */
753 }
754 
755 
756 /*
757  * Called by cmd_body() for dyn:value. Implements the core functionality
758  * for that command.
759  *
760  * This routine expects that both the index and value arguments are
761  * present.
762  */
763 static elfedit_cmdret_t
764 cmd_body_value(ARGSTATE *argstate, Word *ret_ndx)
765 {
766 	elfedit_section_t	*dynsec = argstate->dyn.sec;
767 	elfedit_section_t	*strsec = argstate->strsec;
768 	elfedit_dyn_elt_t	strpad_elt;
769 	Word	i;
770 	Dyn	*dyn = argstate->dyn.data;
771 	Word	numdyn = argstate->dyn.num;
772 	int	minus_add, minus_s, minus_dynndx;
773 	Word	tmp_val;
774 	Xword	arg1, arg2;
775 	int	arg2_known = 1;
776 
777 	minus_add = ((argstate->optmask & DYN_OPT_F_ADD) != 0);
778 	minus_s = ((argstate->optmask & DYN_OPT_F_STRVAL) != 0);
779 	minus_dynndx = ((argstate->optmask & DYN_OPT_F_DYNNDX_ELT) != 0);
780 
781 	elfedit_dyn_elt_init(&strpad_elt);
782 
783 	/*
784 	 * The first argument is an index if -dynndx is used, and is a
785 	 * tag value otherwise.
786 	 */
787 	arg1 = minus_dynndx ?
788 	    elfedit_atoui_range(argstate->argv[0], MSG_ORIG(MSG_STR_ELT),
789 	    0, numdyn - 1, NULL) :
790 	    elfedit_atoconst(argstate->argv[0], ELFEDIT_CONST_DT);
791 
792 	if (minus_s) {
793 		/*
794 		 * Don't allow the user to specify -s when manipulating a
795 		 * DT_SUNW_STRPAD element. Since DT_SUNW_STRPAD is used to
796 		 * manage the extra space used for strings, this would break
797 		 * our ability to add the string.
798 		 */
799 		if ((!minus_dynndx && (arg1 == DT_SUNW_STRPAD)) ||
800 		    (minus_dynndx && (dyn[arg1].d_tag == DT_SUNW_STRPAD)))
801 			elfedit_msg(ELFEDIT_MSG_ERR,
802 			    MSG_INTL(MSG_ERR_STRPADSTRVAL),
803 			    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
804 
805 		/* Locate DT_SUNW_STRPAD element if present */
806 		strpad_elt.dn_dyn.d_un.d_val = 0;
807 		(void) elfedit_dynstr_getpad(argstate->obj_state,
808 		    argstate->dyn.sec, &strpad_elt);
809 
810 		/*
811 		 * Look up the string: If the user specified the -dynndx
812 		 * -option, then we will insert it if possible, and
813 		 * fail with an error if not. However, if they did not
814 		 * specify -dynndx, we want to look up the string if it is
815 		 * already there, but defer the insertion. The reason for
816 		 * this is that we may have to grab an unused DT_NULL element
817 		 * below, and if there are none available, we won't want
818 		 * to have modified the string table.
819 		 *
820 		 * This isn't a problem, because if the string isn't
821 		 * in the string table, it can't be used by a dynamic element.
822 		 * Hence, we don't need to insert it to know that there is
823 		 * no match.
824 		 */
825 		if (minus_dynndx == 0) {
826 			if (elfedit_sec_findstr(strsec,
827 			    strpad_elt.dn_dyn.d_un.d_val, argstate->argv[1],
828 			    &tmp_val) == 0) {
829 				arg2_known = 0;
830 			} else {
831 				arg2 = tmp_val;
832 			}
833 		} else {
834 			arg2 = elfedit_dynstr_insert(dynsec, strsec,
835 			    &strpad_elt, argstate->argv[1]);
836 		}
837 	} else {		/* Argument 2 is an integer */
838 		arg2 = elfedit_atoui(argstate->argv[1], NULL);
839 	}
840 
841 
842 	if (!minus_dynndx && !(minus_add && !arg2_known)) {
843 		/*
844 		 * Search the dynamic section and see if an item with the
845 		 * specified tag value already exists. We can reduce this
846 		 * to a simple update of an existing value if -add is not
847 		 * specified or the existing d_un value matches the new one.
848 		 *
849 		 * In either of these cases, we will change arg1 to be the
850 		 * index, and set minus_dynndx, causing the simple update to
851 		 * happen immediately below.
852 		 */
853 		for (i = 0; i < numdyn; i++) {
854 			if ((dyn[i].d_tag == arg1) &&
855 			    (!minus_add || (dyn[i].d_un.d_val == arg2))) {
856 				arg1 = i;
857 				minus_dynndx = 1;
858 				break;
859 			}
860 		}
861 	}
862 
863 	/*
864 	 * If -dynndx is used, then this is a relatively simple
865 	 * operation, as we simply write over the specified index.
866 	 */
867 	if (minus_dynndx) {
868 		/*
869 		 * If we held back from inserting a new string into
870 		 * the dynstr above, we insert it now, because we
871 		 * have a slot in the dynamic section, and we need
872 		 * the string offset ot finish.
873 		 */
874 		if (!arg2_known)
875 			arg2 = elfedit_dynstr_insert(dynsec, strsec,
876 			    &strpad_elt, argstate->argv[1]);
877 
878 		*ret_ndx = arg1;
879 		if (dyn[arg1].d_un.d_val == arg2) {
880 			elfedit_msg(ELFEDIT_MSG_DEBUG,
881 			    MSG_INTL(MSG_DEBUG_X_OK),
882 			    dynsec->sec_shndx, dynsec->sec_name,
883 			    EC_WORD(arg1), EC_XWORD(arg2));
884 			return (ELFEDIT_CMDRET_NONE);
885 		} else {
886 			/* Warn if setting DT_NULL value to non-zero */
887 			if ((dyn[arg1].d_tag == DT_NULL) && (arg2 != 0))
888 				elfedit_msg(ELFEDIT_MSG_DEBUG,
889 				    MSG_INTL(MSG_DEBUG_DTNULLVALUE),
890 				    dynsec->sec_shndx, dynsec->sec_name,
891 				    EC_WORD(arg1), EC_XWORD(arg2));
892 
893 			elfedit_msg(ELFEDIT_MSG_DEBUG,
894 			    MSG_INTL(MSG_DEBUG_X_CHG),
895 			    dynsec->sec_shndx, dynsec->sec_name,
896 			    EC_WORD(arg1), EC_XWORD(dyn[arg1].d_un.d_val),
897 			    EC_XWORD(arg2));
898 			dyn[arg1].d_un.d_val = arg2;
899 			return (ELFEDIT_CMDRET_MOD);
900 		}
901 	}
902 
903 	/*
904 	 * We need a new slot in the dynamic section. If we can't have
905 	 * one, then we fail.
906 	 */
907 	if (argstate->dyn.num_null_ndx <= 1)
908 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
909 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
910 
911 	/*
912 	 * If we still need to insert a new string into the dynstr,
913 	 * then it is safe now, because if we succeed, we know that
914 	 * there is an available slot to receive it. If we fail, we
915 	 * haven't claimed the extra slot yet, and it will be unharmed.
916 	 */
917 	if (!arg2_known)
918 		arg2 = elfedit_dynstr_insert(dynsec, strsec,
919 		    &strpad_elt, argstate->argv[1]);
920 
921 	/* Use an extra DT_NULL slot and enter the new element */
922 	*ret_ndx = convert_dt_null(argstate, arg1, arg2);
923 	return (ELFEDIT_CMDRET_MOD);
924 }
925 
926 
927 
928 /*
929  * Called by cmd_body() for dyn:runpath. Implements the core functionality
930  * for that command.
931  *
932  * History Lesson And Strategy:
933  *
934  * This routine handles both DT_RPATH and DT_RUNPATH entries, altering
935  * either or both if they are present.
936  *
937  * The original SYSV ABI only had DT_RPATH, and the runtime loader used
938  * it to search for things in the following order:
939  *
940  *	DT_RPATH, LD_LIBRARY_PATH, defaults
941  *
942  * Solaris did not follow this rule, an extremely rare deviation from
943  * the ABI. Environment variables should supercede everything else,
944  * otherwise they are not very useful. This decision was made at the
945  * very beginning of the SunOS 5.x development, so we have always
946  * deviated from the ABI and and instead search in the order
947  *
948  *	LD_LIBRARY_PATH, DT_RPATH, defaults
949  *
950  * Other Unix variants initially followed the ABI, but in recent years
951  * have come to agree with the early Solaris folks that it was a mistake.
952  * Hence, DT_RUNPATH was invented, with the search order:
953  *
954  *	LD_LIBRARY_PATH, DT_RUNPATH, defaults
955  *
956  * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both
957  * are present (which does happen), we set them both to the new
958  * value. If either one is present, we set that one. If neither is
959  * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH, but
960  * not a DT_RPATH, to conserve available slots for other uses.
961  */
962 static elfedit_cmdret_t
963 cmd_body_runpath(ARGSTATE *argstate)
964 {
965 	elfedit_section_t	*dynsec = argstate->dyn.sec;
966 	elfedit_section_t	*strsec = argstate->strsec;
967 	elfedit_dyn_elt_t	rpath_elt;
968 	elfedit_dyn_elt_t	runpath_elt;
969 	elfedit_dyn_elt_t	strpad_elt;
970 	Word			i;
971 	Dyn			*dyn = argstate->dyn.data;
972 	Word			numdyn = argstate->dyn.num;
973 
974 	/* Go through the tags and gather what we need */
975 	elfedit_dyn_elt_init(&rpath_elt);
976 	elfedit_dyn_elt_init(&runpath_elt);
977 	elfedit_dyn_elt_init(&strpad_elt);
978 	for (i = 0; i < numdyn; i++) {
979 		switch (dyn[i].d_tag) {
980 		case DT_RPATH:
981 			elfedit_dyn_elt_save(&rpath_elt, i, &dyn[i]);
982 			break;
983 
984 		case DT_RUNPATH:
985 			elfedit_dyn_elt_save(&runpath_elt, i, &dyn[i]);
986 			break;
987 
988 		case DT_SUNW_STRPAD:
989 			if (elfedit_test_osabi(argstate->obj_state,
990 			    ELFOSABI_SOLARIS, 0))
991 				elfedit_dyn_elt_save(&strpad_elt, i, &dyn[i]);
992 			break;
993 		}
994 	}
995 
996 	/*  Do we have an available dynamic section entry to use? */
997 	if (rpath_elt.dn_seen || runpath_elt.dn_seen) {
998 		/*
999 		 * We have seen a DT_RPATH, or a DT_RUNPATH, or both.
1000 		 * If all of these have the same string as the desired
1001 		 * new value, then we don't need to alter anything and can
1002 		 * simply return. Otherwise, we'll modify them all to have
1003 		 * the new string (below).
1004 		 */
1005 		if ((!rpath_elt.dn_seen ||
1006 		    (strcmp(elfedit_dyn_offset_to_str(strsec, &rpath_elt),
1007 		    argstate->argv[0]) == 0)) &&
1008 		    (!runpath_elt.dn_seen ||
1009 		    (strcmp(elfedit_dyn_offset_to_str(strsec, &runpath_elt),
1010 		    argstate->argv[0]) == 0))) {
1011 			if (rpath_elt.dn_seen)
1012 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1013 				    MSG_INTL(MSG_DEBUG_OLDRPATHOK),
1014 				    EC_WORD(dynsec->sec_shndx),
1015 				    dynsec->sec_name, EC_WORD(rpath_elt.dn_ndx),
1016 				    elfedit_atoconst_value_to_str(
1017 				    ELFEDIT_CONST_DT, DT_RPATH, 1));
1018 			if (runpath_elt.dn_seen)
1019 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1020 				    MSG_INTL(MSG_DEBUG_OLDRPATHOK),
1021 				    EC_WORD(dynsec->sec_shndx),
1022 				    dynsec->sec_name,
1023 				    EC_WORD(runpath_elt.dn_ndx),
1024 				    elfedit_atoconst_value_to_str(
1025 				    ELFEDIT_CONST_DT, DT_RUNPATH, 1));
1026 			return (ELFEDIT_CMDRET_NONE);
1027 		}
1028 	} else if (argstate->dyn.num_null_ndx <= 1) {
1029 		/*
1030 		 * There is no DT_RPATH or DT_RUNPATH in the dynamic array,
1031 		 * and there are no extra DT_NULL entries that we can
1032 		 * convert into one. We cannot proceed.
1033 		 */
1034 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL),
1035 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name);
1036 	}
1037 
1038 	/* Does the string exist in the table already, or can we add it? */
1039 	rpath_elt.dn_dyn.d_un.d_val = runpath_elt.dn_dyn.d_un.d_val =
1040 	    elfedit_dynstr_insert(dynsec, strsec, &strpad_elt,
1041 	    argstate->argv[0]);
1042 
1043 	/* Update DT_RPATH entry if present */
1044 	if (rpath_elt.dn_seen) {
1045 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_PREVRPATH),
1046 		    EC_WORD(dynsec->sec_shndx), dynsec->sec_name,
1047 		    EC_WORD(rpath_elt.dn_ndx),
1048 		    elfedit_atoconst_value_to_str(
1049 		    ELFEDIT_CONST_DT, DT_RPATH, 1),
1050 		    elfedit_dyn_offset_to_str(strsec, &rpath_elt));
1051 		dyn[rpath_elt.dn_ndx] = rpath_elt.dn_dyn;
1052 	}
1053 
1054 	/*
1055 	 * Update the DT_RUNPATH entry in the dynamic section, if present.
1056 	 * If one is not present, and there is also no DT_RPATH, then
1057 	 * we use a spare DT_NULL entry to create a new DT_RUNPATH.
1058 	 */
1059 	if (runpath_elt.dn_seen || !rpath_elt.dn_seen) {
1060 		if (runpath_elt.dn_seen) {
1061 			elfedit_msg(ELFEDIT_MSG_DEBUG,
1062 			    MSG_INTL(MSG_DEBUG_PREVRPATH),
1063 			    EC_WORD(dynsec->sec_shndx), dynsec->sec_name,
1064 			    EC_WORD(runpath_elt.dn_ndx),
1065 			    elfedit_atoconst_value_to_str(
1066 			    ELFEDIT_CONST_DT, DT_RUNPATH, 1),
1067 			    elfedit_dyn_offset_to_str(strsec, &runpath_elt));
1068 			dyn[runpath_elt.dn_ndx] = runpath_elt.dn_dyn;
1069 		} else {	/* Using a spare DT_NULL entry */
1070 			(void) convert_dt_null(argstate, DT_RUNPATH,
1071 			    runpath_elt.dn_dyn.d_un.d_val);
1072 		}
1073 	}
1074 
1075 	return (ELFEDIT_CMDRET_MOD);
1076 }
1077 
1078 
1079 
1080 /*
1081  * Argument processing for the bitmask commands. Convert the arguments
1082  * to integer form, apply -and/-cmp/-or, and return the resulting value.
1083  *
1084  * entry:
1085  *	argstate - Argument state block
1086  *	orig - Value of original bitmask
1087  *	const_type - ELFEDIT_CONST_* value for type of constants
1088  */
1089 static Word
1090 flag_bitop(ARGSTATE *argstate, Word orig, elfedit_const_t const_type)
1091 {
1092 	Word flags = 0;
1093 	int i;
1094 
1095 	/* Collect the arguments */
1096 	for (i = 0; i < argstate->argc; i++)
1097 		flags |= (Word) elfedit_atoconst(argstate->argv[i], const_type);
1098 
1099 	/* Complement the value? */
1100 	if (argstate->optmask & DYN_OPT_F_CMP)
1101 		flags = ~flags;
1102 
1103 	/* Perform any requested bit operations */
1104 	if (argstate->optmask & DYN_OPT_F_AND)
1105 		flags &= orig;
1106 	else if (argstate->optmask & DYN_OPT_F_OR)
1107 		flags |= orig;
1108 
1109 	return (flags);
1110 }
1111 
1112 
1113 
1114 /*
1115  * Common body for the dyn: module commands. These commands
1116  * share a large amount of common behavior, so it is convenient
1117  * to centralize things and use the cmd argument to handle the
1118  * small differences.
1119  *
1120  * entry:
1121  *	cmd - One of the DYN_CMD_T_* constants listed above, specifying
1122  *		which command to implement.
1123  *	obj_state, argc, argv - Standard command arguments
1124  */
1125 static elfedit_cmdret_t
1126 cmd_body(DYN_CMD_T cmd, elfedit_obj_state_t *obj_state,
1127     int argc, const char *argv[])
1128 {
1129 	ARGSTATE		argstate;
1130 	Dyn			*dyn;
1131 	const char		*dyn_name;
1132 	Word			dyn_ndx, dyn_num, null_ndx;
1133 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
1134 	PRINT_DYN_T		print_type = PRINT_DYN_T_ALL;
1135 	Word			ndx;
1136 	int			print_only = 0;
1137 	int			do_autoprint = 1;
1138 
1139 	/* Process the optional arguments */
1140 	process_args(obj_state, argc, argv, &argstate);
1141 
1142 	dyn = argstate.dyn.data;
1143 	dyn_num = argstate.dyn.num;
1144 	dyn_name = argstate.dyn.sec->sec_name;
1145 	dyn_ndx = argstate.dyn.sec->sec_shndx;
1146 
1147 	/* Check number of arguments, gather information */
1148 	switch (cmd) {
1149 	case DYN_CMD_T_DUMP:
1150 		/* dyn:dump can accept an optional index argument */
1151 		if (argstate.argc > 1)
1152 			elfedit_command_usage();
1153 		print_only = 1;
1154 		if (argstate.argc == 1)
1155 			ndx = arg_to_index(&argstate, argstate.argv[0],
1156 			    print_only, &print_type);
1157 		break;
1158 
1159 	case DYN_CMD_T_TAG:
1160 		print_only = (argstate.argc != 2);
1161 		if (argstate.argc > 0) {
1162 			if (argstate.argc > 2)
1163 				elfedit_command_usage();
1164 			ndx = arg_to_index(&argstate, argstate.argv[0],
1165 			    print_only, &print_type);
1166 		}
1167 		break;
1168 
1169 	case DYN_CMD_T_VALUE:
1170 		print_only = (argstate.argc != 2);
1171 		if (argstate.argc > 2)
1172 			elfedit_command_usage();
1173 		if (argstate.argc > 0) {
1174 			if (print_only) {
1175 				ndx = arg_to_index(&argstate, argstate.argv[0],
1176 				    print_only, &print_type);
1177 			} else {
1178 				print_type = PRINT_DYN_T_NDX;
1179 			}
1180 		}
1181 		break;
1182 
1183 	case DYN_CMD_T_DELETE:
1184 		if ((argstate.argc < 1) || (argstate.argc > 2))
1185 			elfedit_command_usage();
1186 		ndx = arg_to_index(&argstate, argstate.argv[0],
1187 		    0, &print_type);
1188 		do_autoprint = 0;
1189 		break;
1190 
1191 	case DYN_CMD_T_MOVE:
1192 		if ((argstate.argc < 2) || (argstate.argc > 3))
1193 			elfedit_command_usage();
1194 		ndx = arg_to_index(&argstate, argstate.argv[0],
1195 		    0, &print_type);
1196 		do_autoprint = 0;
1197 		break;
1198 
1199 	case DYN_CMD_T_RUNPATH:
1200 		if (argstate.argc > 1)
1201 			elfedit_command_usage();
1202 		/*
1203 		 * dyn:runpath does not accept an explicit index
1204 		 * argument, so we implicitly only show the DT_RPATH and
1205 		 * DT_RUNPATH elements.
1206 		 */
1207 		print_type = PRINT_DYN_T_RUNPATH;
1208 		print_only = (argstate.argc == 0);
1209 		break;
1210 
1211 	case DYN_CMD_T_POSFLAG1:
1212 		print_only = (argstate.argc == 0);
1213 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1214 		    ELFEDIT_CONST_DT, DT_POSFLAG_1, 1),
1215 		    print_only, &print_type);
1216 		break;
1217 
1218 	case DYN_CMD_T_FLAGS:
1219 		print_only = (argstate.argc == 0);
1220 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1221 		    ELFEDIT_CONST_DT, DT_FLAGS, 1),
1222 		    print_only, &print_type);
1223 		break;
1224 
1225 	case DYN_CMD_T_FLAGS1:
1226 		print_only = (argstate.argc == 0);
1227 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1228 		    ELFEDIT_CONST_DT, DT_FLAGS_1, 1),
1229 		    print_only, &print_type);
1230 		break;
1231 
1232 	case DYN_CMD_T_FEATURE1:
1233 		print_only = (argstate.argc == 0);
1234 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1235 		    ELFEDIT_CONST_DT, DT_FEATURE_1, 1),
1236 		    print_only, &print_type);
1237 		break;
1238 
1239 	case DYN_CMD_T_CHECKSUM:
1240 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1241 		    ELFEDIT_CONST_DT, DT_CHECKSUM, 1),
1242 		    print_only, &print_type);
1243 		break;
1244 
1245 	case DYN_CMD_T_SUNW_LDMACH:
1246 		if (argstate.argc > 1)
1247 			elfedit_command_usage();
1248 		/* DT_SUNW_LDMACH is an ELFOSABI_SOLARIS feature */
1249 		(void) elfedit_test_osabi(argstate.obj_state,
1250 		    ELFOSABI_SOLARIS, 1);
1251 		print_only = (argstate.argc == 0);
1252 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
1253 		    ELFEDIT_CONST_DT, DT_SUNW_LDMACH, 1),
1254 		    print_only, &print_type);
1255 		break;
1256 
1257 	default:
1258 		/* Note expected: All commands should have been caught above */
1259 		elfedit_command_usage();
1260 		break;
1261 	}
1262 
1263 
1264 	/* If this is a request to print current values, do it and return */
1265 	if (print_only) {
1266 		print_dyn(cmd, 0, &argstate, print_type, ndx);
1267 		return (ELFEDIT_CMDRET_NONE);
1268 	}
1269 
1270 
1271 	switch (cmd) {
1272 		/*
1273 		 * DYN_CMD_T_DUMP can't get here: It is a print-only
1274 		 * command.
1275 		 */
1276 
1277 	case DYN_CMD_T_TAG:
1278 		{
1279 			Ehdr		*ehdr = argstate.obj_state->os_ehdr;
1280 			uchar_t		osabi = ehdr->e_ident[EI_OSABI];
1281 			Half		mach = ehdr->e_machine;
1282 			Conv_inv_buf_t	inv_buf1, inv_buf2;
1283 			Xword d_tag = (Xword) elfedit_atoconst(argstate.argv[1],
1284 			    ELFEDIT_CONST_DT);
1285 
1286 			if (dyn[ndx].d_tag == d_tag) {
1287 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1288 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, dyn_name,
1289 				    EC_WORD(ndx), conv_dyn_tag(d_tag, osabi,
1290 				    mach, 0, &inv_buf1));
1291 			} else {
1292 				Xword orig_d_tag = dyn[ndx].d_tag;
1293 
1294 				ret = ELFEDIT_CMDRET_MOD;
1295 				dyn[ndx].d_tag = d_tag;
1296 
1297 				/*
1298 				 * Update null termination index. Warn if we
1299 				 * just clobbered the only DT_NULL termination
1300 				 * for the array.
1301 				 */
1302 				null_ndx = argstate.dyn.null_ndx;
1303 				set_null_ndx(&argstate);
1304 				if ((argstate.dyn.null_ndx >=
1305 				    argstate.dyn.num) &&
1306 				    (null_ndx != argstate.dyn.null_ndx))
1307 					elfedit_msg(ELFEDIT_MSG_DEBUG,
1308 					    MSG_INTL(MSG_DEBUG_NULLTERM),
1309 					    dyn_ndx, dyn_name,
1310 					    EC_WORD(ndx), conv_dyn_tag(d_tag,
1311 					    osabi, mach, 0, &inv_buf1));
1312 
1313 				/*
1314 				 * Warning if
1315 				 *	- Inserting a DT_NULL cuts off following
1316 				 *		non-null elements.
1317 				 *	- Inserting a non-DT_NULL after the
1318 				 *		first null element, will be
1319 				 *		ignored by rtld.
1320 				 */
1321 				if (d_tag == DT_NULL) {
1322 					if ((ndx + 1) < null_ndx)
1323 						elfedit_msg(ELFEDIT_MSG_DEBUG,
1324 						    MSG_INTL(MSG_DEBUG_NULCLIP),
1325 						    dyn_ndx, dyn_name,
1326 						    EC_WORD(ndx),
1327 						    conv_dyn_tag(d_tag, osabi,
1328 						    mach, 0, &inv_buf1));
1329 				} else {
1330 					if ((ndx + 1) > argstate.dyn.null_ndx)
1331 						elfedit_msg(ELFEDIT_MSG_DEBUG,
1332 						    MSG_INTL(MSG_DEBUG_NULHIDE),
1333 						    dyn_ndx, dyn_name,
1334 						    EC_WORD(ndx),
1335 						    conv_dyn_tag(d_tag, osabi,
1336 						    mach, 0, &inv_buf1));
1337 				}
1338 
1339 				/* Debug message that we changed it */
1340 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1341 				    MSG_INTL(MSG_DEBUG_S_CHG),
1342 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1343 				    conv_dyn_tag(orig_d_tag, osabi, mach, 0,
1344 				    &inv_buf1),
1345 				    conv_dyn_tag(d_tag, osabi, mach, 0,
1346 				    &inv_buf2));
1347 			}
1348 		}
1349 		break;
1350 
1351 	case DYN_CMD_T_VALUE:
1352 		ret = cmd_body_value(&argstate, &ndx);
1353 		break;
1354 
1355 	case DYN_CMD_T_DELETE:
1356 		{
1357 			Word cnt = (argstate.argc == 1) ? 1 :
1358 			    (Word) elfedit_atoui_range(argstate.argv[1],
1359 			    MSG_ORIG(MSG_STR_COUNT), 1, dyn_num - ndx, NULL);
1360 			const char *msg_prefix =
1361 			    elfedit_sec_msgprefix(argstate.dyn.sec);
1362 
1363 			elfedit_array_elts_delete(msg_prefix, argstate.dyn.data,
1364 			    sizeof (Dyn), dyn_num, ndx, cnt);
1365 			ret = ELFEDIT_CMDRET_MOD;
1366 		}
1367 		break;
1368 
1369 	case DYN_CMD_T_MOVE:
1370 		{
1371 			Dyn	save;
1372 			Word	cnt;
1373 			Word	dstndx;
1374 			const char *msg_prefix =
1375 			    elfedit_sec_msgprefix(argstate.dyn.sec);
1376 
1377 			dstndx = (Word)
1378 			    elfedit_atoui_range(argstate.argv[1],
1379 			    MSG_ORIG(MSG_STR_DST_INDEX), 0, dyn_num - 1,
1380 			    NULL);
1381 			if (argstate.argc == 2) {
1382 				cnt = 1;
1383 			} else {
1384 				cnt = (Word) elfedit_atoui_range(
1385 				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
1386 				    1, dyn_num, NULL);
1387 			}
1388 			elfedit_array_elts_move(msg_prefix, argstate.dyn.data,
1389 			    sizeof (save), dyn_num, ndx, dstndx, cnt, &save);
1390 			ret = ELFEDIT_CMDRET_MOD;
1391 		}
1392 		break;
1393 
1394 
1395 	case DYN_CMD_T_RUNPATH:
1396 		ret = cmd_body_runpath(&argstate);
1397 		break;
1398 
1399 	case DYN_CMD_T_POSFLAG1:
1400 		{
1401 			Conv_dyn_posflag1_buf_t buf1, buf2;
1402 			Word flags;
1403 
1404 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1405 			    ELFEDIT_CONST_DF_P1);
1406 
1407 			/* Set the value */
1408 			if (dyn[ndx].d_un.d_val == flags) {
1409 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1410 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1411 				    dyn_name, EC_WORD(ndx),
1412 				    conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0,
1413 				    &buf1));
1414 			} else {
1415 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1416 				    MSG_INTL(MSG_DEBUG_S_CHG),
1417 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1418 				    conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0,
1419 				    &buf1),
1420 				    conv_dyn_posflag1(flags, 0, &buf2));
1421 				ret = ELFEDIT_CMDRET_MOD;
1422 				dyn[ndx].d_un.d_val = flags;
1423 			}
1424 		}
1425 		break;
1426 
1427 	case DYN_CMD_T_FLAGS:
1428 		{
1429 			Conv_dyn_flag_buf_t buf1, buf2;
1430 			Word flags;
1431 
1432 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1433 			    ELFEDIT_CONST_DF);
1434 
1435 			/* Set the value */
1436 			if (dyn[ndx].d_un.d_val == flags) {
1437 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1438 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1439 				    dyn_name, EC_WORD(ndx),
1440 				    conv_dyn_flag(dyn[ndx].d_un.d_val, 0,
1441 				    &buf1));
1442 			} else {
1443 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1444 				    MSG_INTL(MSG_DEBUG_S_CHG),
1445 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1446 				    conv_dyn_flag(dyn[ndx].d_un.d_val, 0,
1447 				    &buf1),
1448 				    conv_dyn_flag(flags, 0, &buf2));
1449 				ret = ELFEDIT_CMDRET_MOD;
1450 				dyn[ndx].d_un.d_val = flags;
1451 			}
1452 		}
1453 		break;
1454 
1455 	case DYN_CMD_T_FLAGS1:
1456 		{
1457 			Conv_dyn_flag1_buf_t buf1, buf2;
1458 			Word flags1;
1459 
1460 			flags1 = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1461 			    ELFEDIT_CONST_DF_1);
1462 
1463 			/* Set the value */
1464 			if (dyn[ndx].d_un.d_val == flags1) {
1465 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1466 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1467 				    dyn_name, EC_WORD(ndx),
1468 				    conv_dyn_flag1(dyn[ndx].d_un.d_val,
1469 				    0, &buf1));
1470 			} else {
1471 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1472 				    MSG_INTL(MSG_DEBUG_S_CHG),
1473 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1474 				    conv_dyn_flag1(dyn[ndx].d_un.d_val,
1475 				    0, &buf1),
1476 				    conv_dyn_flag1(flags1, 0, &buf2));
1477 				ret = ELFEDIT_CMDRET_MOD;
1478 				dyn[ndx].d_un.d_val = flags1;
1479 			}
1480 		}
1481 		break;
1482 
1483 	case DYN_CMD_T_FEATURE1:
1484 		{
1485 			Conv_dyn_feature1_buf_t buf1, buf2;
1486 			Word flags;
1487 
1488 			flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val,
1489 			    ELFEDIT_CONST_DTF_1);
1490 
1491 			/* Set the value */
1492 			if (dyn[ndx].d_un.d_val == flags) {
1493 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1494 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1495 				    dyn_name, EC_WORD(ndx),
1496 				    conv_dyn_feature1(dyn[ndx].d_un.d_val, 0,
1497 				    &buf1));
1498 			} else {
1499 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1500 				    MSG_INTL(MSG_DEBUG_S_CHG),
1501 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1502 				    conv_dyn_feature1(dyn[ndx].d_un.d_val, 0,
1503 				    &buf1),
1504 				    conv_dyn_feature1(flags, 0, &buf2));
1505 				ret = ELFEDIT_CMDRET_MOD;
1506 				dyn[ndx].d_un.d_val = flags;
1507 			}
1508 		}
1509 		break;
1510 
1511 	case DYN_CMD_T_CHECKSUM:
1512 		{
1513 			long checksum = elf_checksum(obj_state->os_elf);
1514 
1515 			/* Set the value */
1516 			if (dyn[ndx].d_un.d_val == checksum) {
1517 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1518 				    MSG_INTL(MSG_DEBUG_X_OK), dyn_ndx,
1519 				    dyn_name, EC_WORD(ndx), EC_XWORD(checksum));
1520 			} else {
1521 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1522 				    MSG_INTL(MSG_DEBUG_X_CHG),
1523 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1524 				    EC_XWORD(dyn[ndx].d_un.d_val),
1525 				    EC_XWORD(checksum));
1526 				ret = ELFEDIT_CMDRET_MOD;
1527 				dyn[ndx].d_un.d_val = checksum;
1528 			}
1529 
1530 		}
1531 		break;
1532 
1533 	case DYN_CMD_T_SUNW_LDMACH:
1534 		{
1535 			Conv_inv_buf_t buf1, buf2;
1536 			Half ldmach;
1537 
1538 			ldmach = (Half) elfedit_atoconst(argstate.argv[0],
1539 			    ELFEDIT_CONST_EM);
1540 
1541 			/* Set the value */
1542 			if (dyn[ndx].d_un.d_val == ldmach) {
1543 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1544 				    MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx,
1545 				    dyn_name, EC_WORD(ndx),
1546 				    conv_ehdr_mach(dyn[ndx].d_un.d_val, 0,
1547 				    &buf1));
1548 			} else {
1549 				elfedit_msg(ELFEDIT_MSG_DEBUG,
1550 				    MSG_INTL(MSG_DEBUG_S_CHG),
1551 				    dyn_ndx, dyn_name, EC_WORD(ndx),
1552 				    conv_ehdr_mach(dyn[ndx].d_un.d_val, 0,
1553 				    &buf1),
1554 				    conv_ehdr_mach(ldmach, 0, &buf2));
1555 				ret = ELFEDIT_CMDRET_MOD;
1556 				dyn[ndx].d_un.d_val = ldmach;
1557 			}
1558 		}
1559 		break;
1560 
1561 	}
1562 
1563 	/*
1564 	 * If we modified the dynamic section header, tell libelf.
1565 	 */
1566 	if (ret == ELFEDIT_CMDRET_MOD)
1567 		elfedit_modified_data(argstate.dyn.sec);
1568 
1569 	/* Do autoprint */
1570 	if (do_autoprint)
1571 		print_dyn(cmd, 1, &argstate, print_type, ndx);
1572 
1573 	return (ret);
1574 }
1575 
1576 
1577 
1578 /*
1579  * Command completion functions for the commands
1580  */
1581 
1582 /*
1583  * Command completion for the first argument, which specifies
1584  * the dynamic element to use. Examines the options to see if
1585  * -dynndx is present, and if not, supplies the completion
1586  * strings for argument 1.
1587  */
1588 /*ARGSUSED*/
1589 static void
1590 cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1591     const char *argv[], int num_opt)
1592 {
1593 	elfedit_section_t	*cache;
1594 	Dyn			*dyn;
1595 	Word			i;
1596 	const char		*s;
1597 	char			*s2;
1598 	char			buf[128];
1599 
1600 	/* Make sure it's the first argument */
1601 	if ((argc - num_opt) != 1)
1602 		return;
1603 
1604 	/* Is -dynndx present? If so, we don't complete tag types */
1605 	for (i = 0; i < num_opt; i++)
1606 		if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0)
1607 			return;
1608 
1609 	/*
1610 	 * If there is no object, or if there is no dynamic section,
1611 	 * then supply all possible names.
1612 	 */
1613 	if ((obj_state == NULL) || (obj_state->os_dynndx == SHN_UNDEF)) {
1614 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT);
1615 		return;
1616 	}
1617 
1618 	/* Supply completions for the tags present in the dynamic section */
1619 	cache = &obj_state->os_secarr[obj_state->os_dynndx];
1620 	dyn = (Dyn *) cache->sec_data->d_buf;
1621 	i = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize;
1622 	for (; i-- > 0; dyn++) {
1623 		s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_DT,
1624 		    dyn->d_tag, 0);
1625 		if (s == NULL)
1626 			continue;
1627 		elfedit_cpl_match(cpldata, s, 1);
1628 
1629 		/*
1630 		 * To get the informal tag names that are lowercase
1631 		 * and lack the leading DT_, we copy the string we
1632 		 * have into a buffer and process it.
1633 		 */
1634 		if (strlen(s) < 3)
1635 			continue;
1636 		(void) strlcpy(buf, s + 3, sizeof (buf));
1637 		for (s2 = buf; *s2 != '\0'; s2++)
1638 			if (isupper(*s2))
1639 				*s2 = tolower(*s2);
1640 		elfedit_cpl_match(cpldata, buf, 1);
1641 	}
1642 }
1643 
1644 
1645 /*ARGSUSED*/
1646 static void
1647 cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1648     const char *argv[], int num_opt)
1649 {
1650 	/* First argument */
1651 	if ((argc - num_opt) == 1) {
1652 		cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
1653 		return;
1654 	}
1655 
1656 	/* The second argument is always a tag value */
1657 	if ((argc - num_opt) == 2)
1658 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT);
1659 }
1660 
1661 /*ARGSUSED*/
1662 static void
1663 cpl_posflag1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1664     const char *argv[], int num_opt)
1665 {
1666 	/*
1667 	 * dyn:posflag1 accepts two mutually exclusive options that have
1668 	 * a corresponding value argument: -dynndx and -needed. If we
1669 	 * are being called to supply options for the value, handle that here.
1670 	 */
1671 	if ((num_opt > 1) && (argc == num_opt)) {
1672 		elfedit_section_t	*dynsec, *strsec;
1673 		const char		*opt = argv[num_opt - 2];
1674 		dyn_opt_t		type;
1675 		Dyn			*dyn;
1676 		Word			i, num;
1677 
1678 		/*
1679 		 * If there is no object available, or if the object has no
1680 		 * dynamic section, then there is nothing to report.
1681 		 */
1682 		if ((obj_state == NULL) || obj_state->os_dynndx == SHN_UNDEF)
1683 			return;
1684 
1685 		/*
1686 		 * Determine which option it is, bail if it isn't one of
1687 		 * the ones we are concerned with.
1688 		 */
1689 		if ((strcmp(opt, MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0))
1690 			type = DYN_OPT_F_NEEDED;
1691 		else if ((strcmp(opt, MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0))
1692 			type = DYN_OPT_F_DYNNDX_VAL;
1693 		else
1694 			return;
1695 
1696 		dynsec = elfedit_sec_getdyn(obj_state, &dyn, &num);
1697 		switch (type) {
1698 		case DYN_OPT_F_NEEDED:
1699 			strsec = elfedit_sec_getstr(obj_state,
1700 			    dynsec->sec_shdr->sh_link, 0);
1701 			for (; num-- > 0; dyn++)
1702 				if (dyn->d_tag == DT_NEEDED)
1703 					elfedit_cpl_match(cpldata,
1704 					    elfedit_offset_to_str(strsec,
1705 					    dyn->d_un.d_val, ELFEDIT_MSG_DEBUG,
1706 					    0), 0);
1707 			break;
1708 
1709 		case DYN_OPT_F_DYNNDX_VAL:
1710 			for (i = 0; i < num; i++, dyn++)
1711 				if (dyn->d_tag == DT_POSFLAG_1)
1712 					elfedit_cpl_ndx(cpldata, i);
1713 			break;
1714 		}
1715 		return;
1716 	}
1717 
1718 	/* This routine allows multiple flags to be specified */
1719 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_P1);
1720 }
1721 
1722 /*ARGSUSED*/
1723 static void
1724 cpl_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1725     const char *argv[], int num_opt)
1726 {
1727 	/* This routine allows multiple flags to be specified */
1728 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF);
1729 }
1730 
1731 /*ARGSUSED*/
1732 static void
1733 cpl_flags1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1734     const char *argv[], int num_opt)
1735 {
1736 	/* This routine allows multiple flags to be specified */
1737 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_1);
1738 }
1739 
1740 /*ARGSUSED*/
1741 static void
1742 cpl_feature1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1743     const char *argv[], int num_opt)
1744 {
1745 	/* This routine allows multiple flags to be specified */
1746 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DTF_1);
1747 }
1748 
1749 /*ARGSUSED*/
1750 static void
1751 cpl_sunw_ldmach(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1752     const char *argv[], int num_opt)
1753 {
1754 	/*
1755 	 * This command doesn't accept options, so num_opt should be
1756 	 * 0. This is a defensive measure, in case that should change.
1757 	 */
1758 	argc -= num_opt;
1759 	argv += num_opt;
1760 
1761 	if (argc == 1)
1762 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_EM);
1763 }
1764 
1765 
1766 /*
1767  * Implementation functions for the commands
1768  */
1769 static elfedit_cmdret_t
1770 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1771 {
1772 	return (cmd_body(DYN_CMD_T_DUMP, obj_state, argc, argv));
1773 }
1774 
1775 static elfedit_cmdret_t
1776 cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1777 {
1778 	return (cmd_body(DYN_CMD_T_TAG, obj_state, argc, argv));
1779 }
1780 
1781 static elfedit_cmdret_t
1782 cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1783 {
1784 	return (cmd_body(DYN_CMD_T_VALUE, obj_state, argc, argv));
1785 }
1786 
1787 static elfedit_cmdret_t
1788 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1789 {
1790 	return (cmd_body(DYN_CMD_T_DELETE, obj_state, argc, argv));
1791 }
1792 
1793 static elfedit_cmdret_t
1794 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1795 {
1796 	return (cmd_body(DYN_CMD_T_MOVE, obj_state, argc, argv));
1797 }
1798 
1799 static elfedit_cmdret_t
1800 cmd_runpath(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1801 {
1802 	return (cmd_body(DYN_CMD_T_RUNPATH, obj_state, argc, argv));
1803 }
1804 
1805 static elfedit_cmdret_t
1806 cmd_posflag1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1807 {
1808 	return (cmd_body(DYN_CMD_T_POSFLAG1, obj_state, argc, argv));
1809 }
1810 
1811 static elfedit_cmdret_t
1812 cmd_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1813 {
1814 	return (cmd_body(DYN_CMD_T_FLAGS, obj_state, argc, argv));
1815 }
1816 
1817 static elfedit_cmdret_t
1818 cmd_flags1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1819 {
1820 	return (cmd_body(DYN_CMD_T_FLAGS1, obj_state, argc, argv));
1821 }
1822 
1823 static elfedit_cmdret_t
1824 cmd_feature1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1825 {
1826 	return (cmd_body(DYN_CMD_T_FEATURE1, obj_state, argc, argv));
1827 }
1828 
1829 static elfedit_cmdret_t
1830 cmd_checksum(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1831 {
1832 	return (cmd_body(DYN_CMD_T_CHECKSUM, obj_state, argc, argv));
1833 }
1834 
1835 static elfedit_cmdret_t
1836 cmd_sunw_ldmach(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1837 {
1838 	return (cmd_body(DYN_CMD_T_SUNW_LDMACH, obj_state, argc, argv));
1839 }
1840 
1841 
1842 
1843 /*ARGSUSED*/
1844 elfedit_module_t *
1845 elfedit_init(elfedit_module_version_t version)
1846 {
1847 	/* For commands that only accept -o */
1848 	static elfedit_cmd_optarg_t opt_ostyle[] = {
1849 		{ ELFEDIT_STDOA_OPT_O, 0,
1850 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1851 		{ NULL }
1852 	};
1853 
1854 	/* For commands that only accept -and, -cmp, -o, -or */
1855 	static elfedit_cmd_optarg_t opt_ostyle_bitop[] = {
1856 		{ ELFEDIT_STDOA_OPT_AND, 0,
1857 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR },
1858 		{ ELFEDIT_STDOA_OPT_CMP, 0,
1859 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 },
1860 		{ ELFEDIT_STDOA_OPT_O, 0,
1861 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1862 		{ ELFEDIT_STDOA_OPT_OR, 0,
1863 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND },
1864 		{ NULL }
1865 	};
1866 
1867 	/* For commands that only accept -dynndx */
1868 	static elfedit_cmd_optarg_t opt_minus_dynndx[] = {
1869 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1870 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
1871 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
1872 		    DYN_OPT_F_DYNNDX_ELT, 0 },
1873 		{ NULL }
1874 	};
1875 
1876 	/* dyn:dump */
1877 	static const char *name_dump[] = {
1878 	    MSG_ORIG(MSG_CMD_DUMP),
1879 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
1880 	    NULL
1881 	};
1882 	static elfedit_cmd_optarg_t arg_dump[] = {
1883 		{ MSG_ORIG(MSG_STR_ELT),
1884 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1885 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1886 		    ELFEDIT_CMDOA_F_OPT },
1887 		{ NULL }
1888 	};
1889 
1890 
1891 	/* dyn:tag */
1892 	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
1893 	static elfedit_cmd_optarg_t opt_tag[] = {
1894 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1895 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
1896 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
1897 		    DYN_OPT_F_DYNNDX_ELT, 0 },
1898 		{ ELFEDIT_STDOA_OPT_O, 0,
1899 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1900 		{ NULL }
1901 	};
1902 	static elfedit_cmd_optarg_t arg_tag[] = {
1903 		{ MSG_ORIG(MSG_STR_ELT),
1904 		    /* MSG_INTL(MSG_A1_TAG_ELT) */
1905 		    ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
1906 		    ELFEDIT_CMDOA_F_OPT },
1907 		{ MSG_ORIG(MSG_STR_VALUE),
1908 		    /* MSG_INTL(MSG_A2_TAG_VALUE) */
1909 		    ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
1910 		    ELFEDIT_CMDOA_F_OPT },
1911 		{ NULL }
1912 	};
1913 
1914 
1915 	/* dyn:value */
1916 	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
1917 	static elfedit_cmd_optarg_t opt_value[] = {
1918 		{ MSG_ORIG(MSG_STR_MINUS_ADD),
1919 		    /* MSG_INTL(MSG_OPTDESC_ADD) */
1920 		    ELFEDIT_I18NHDL(MSG_OPTDESC_ADD), 0,
1921 		    DYN_OPT_F_ADD, DYN_OPT_F_DYNNDX_ELT },
1922 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1923 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX_ELT) */
1924 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_ELT), 0,
1925 		    DYN_OPT_F_DYNNDX_ELT, DYN_OPT_F_ADD },
1926 		{ ELFEDIT_STDOA_OPT_O, 0,
1927 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1928 		{ MSG_ORIG(MSG_STR_MINUS_S),
1929 		    /* MSG_INTL(MSG_OPTDESC_S) */
1930 		    ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0,
1931 		    DYN_OPT_F_STRVAL, 0 },
1932 		{ NULL }
1933 	};
1934 	static elfedit_cmd_optarg_t arg_value[] = {
1935 		{ MSG_ORIG(MSG_STR_ELT),
1936 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1937 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1938 		    ELFEDIT_CMDOA_F_OPT },
1939 		{ MSG_ORIG(MSG_STR_VALUE),
1940 		    /* MSG_INTL(MSG_A2_VALUE_VALUE) */
1941 		    ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
1942 		    ELFEDIT_CMDOA_F_OPT },
1943 		{ NULL }
1944 	};
1945 
1946 	/* dyn:delete */
1947 	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
1948 	static elfedit_cmd_optarg_t arg_delete[] = {
1949 		{ MSG_ORIG(MSG_STR_ELT),
1950 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1951 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1952 		    0 },
1953 		{ MSG_ORIG(MSG_STR_COUNT),
1954 		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
1955 		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
1956 		    ELFEDIT_CMDOA_F_OPT },
1957 		{ NULL }
1958 	};
1959 
1960 	/* dyn:move */
1961 	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
1962 	static elfedit_cmd_optarg_t arg_move[] = {
1963 		{ MSG_ORIG(MSG_STR_ELT),
1964 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1965 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1966 		    0 },
1967 		{ MSG_ORIG(MSG_STR_DST_INDEX),
1968 		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
1969 		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
1970 		    0 },
1971 		{ MSG_ORIG(MSG_STR_COUNT),
1972 		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
1973 		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
1974 		    ELFEDIT_CMDOA_F_OPT },
1975 		{ NULL }
1976 	};
1977 
1978 	/* dyn:runpath / dyn:rpath */
1979 	static const char *name_runpath[] = { MSG_ORIG(MSG_CMD_RUNPATH),
1980 	    MSG_ORIG(MSG_CMD_RUNPATH_A1), NULL };
1981 	static elfedit_cmd_optarg_t arg_runpath[] = {
1982 		{ MSG_ORIG(MSG_STR_NEWPATH),
1983 		    /* MSG_INTL(MSG_A1_RUNPATH_NEWPATH) */
1984 		    ELFEDIT_I18NHDL(MSG_A1_RUNPATH_NEWPATH),
1985 		    ELFEDIT_CMDOA_F_OPT },
1986 		{ NULL }
1987 	};
1988 
1989 	/* dyn:posflag1 */
1990 	static const char *name_posflag1[] = { MSG_ORIG(MSG_CMD_POSFLAG1),
1991 	    NULL };
1992 	static elfedit_cmd_optarg_t opt_posflag1[] = {
1993 		{ ELFEDIT_STDOA_OPT_AND, 0,
1994 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR },
1995 		{ ELFEDIT_STDOA_OPT_CMP, 0,
1996 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 },
1997 		{ MSG_ORIG(MSG_STR_MINUS_DYNNDX),
1998 		    /* MSG_INTL(MSG_OPTDESC_DYNNDX_VAL) */
1999 		    ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX_VAL),
2000 		    ELFEDIT_CMDOA_F_VALUE,
2001 		    DYN_OPT_F_DYNNDX_VAL, DYN_OPT_F_NEEDED },
2002 		{ MSG_ORIG(MSG_STR_INDEX), 0, 0, 0 },
2003 		{ MSG_ORIG(MSG_STR_MINUS_NEEDED),
2004 		    /* MSG_INTL(MSG_OPTDESC_NEEDED) */
2005 		    ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED),
2006 		    ELFEDIT_CMDOA_F_VALUE,
2007 		    DYN_OPT_F_NEEDED, DYN_OPT_F_DYNNDX_VAL },
2008 		{ MSG_ORIG(MSG_STR_PREFIX), 0, 0, 0 },
2009 		{ ELFEDIT_STDOA_OPT_O, 0,
2010 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
2011 		{ ELFEDIT_STDOA_OPT_OR, 0,
2012 		    ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND },
2013 		{ NULL }
2014 	};
2015 	static elfedit_cmd_optarg_t arg_posflag1[] = {
2016 		{ MSG_ORIG(MSG_STR_VALUE),
2017 		    /* MSG_INTL(MSG_A1_POSFLAG1_VALUE) */
2018 		    ELFEDIT_I18NHDL(MSG_A1_POSFLAG1_VALUE),
2019 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2020 		{ NULL }
2021 	};
2022 
2023 	/* dyn:flags */
2024 	static const char *name_flags[] = { MSG_ORIG(MSG_CMD_FLAGS), NULL };
2025 	static elfedit_cmd_optarg_t arg_flags[] = {
2026 		{ MSG_ORIG(MSG_STR_VALUE),
2027 		    /* MSG_INTL(MSG_A1_FLAGS_VALUE) */
2028 		    ELFEDIT_I18NHDL(MSG_A1_FLAGS_VALUE),
2029 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2030 		{ NULL }
2031 	};
2032 
2033 	/* dyn:flags1 */
2034 	static const char *name_flags1[] = { MSG_ORIG(MSG_CMD_FLAGS1), NULL };
2035 	static elfedit_cmd_optarg_t arg_flags1[] = {
2036 		{ MSG_ORIG(MSG_STR_VALUE),
2037 		    /* MSG_INTL(MSG_A1_FLAGS1_VALUE) */
2038 		    ELFEDIT_I18NHDL(MSG_A1_FLAGS1_VALUE),
2039 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2040 		{ NULL }
2041 	};
2042 
2043 	/* dyn:feature1 */
2044 	static const char *name_feature1[] = { MSG_ORIG(MSG_CMD_FEATURE1),
2045 	    NULL };
2046 	static elfedit_cmd_optarg_t arg_feature1[] = {
2047 		{ MSG_ORIG(MSG_STR_VALUE),
2048 		    /* MSG_INTL(MSG_A1_FEATURE1_VALUE) */
2049 		    ELFEDIT_I18NHDL(MSG_A1_FEATURE1_VALUE),
2050 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
2051 		{ NULL }
2052 	};
2053 
2054 	/* dyn:checksum */
2055 	static const char *name_checksum[] = { MSG_ORIG(MSG_CMD_CHECKSUM),
2056 	    NULL };
2057 
2058 	/* dyn:sunw_ldmach */
2059 	static const char *name_sunw_ldmach[] = { MSG_ORIG(MSG_CMD_SUNW_LDMACH),
2060 	    NULL };
2061 	static elfedit_cmd_optarg_t arg_sunw_ldmach[] = {
2062 		{ MSG_ORIG(MSG_STR_VALUE),
2063 		    /* MSG_INTL(MSG_A1_SUNW_LDMACH_VALUE) */
2064 		    ELFEDIT_I18NHDL(MSG_A1_SUNW_LDMACH_VALUE),
2065 		    ELFEDIT_CMDOA_F_OPT },
2066 		{ NULL }
2067 	};
2068 
2069 
2070 
2071 	static elfedit_cmd_t cmds[] = {
2072 		/* dyn:dump */
2073 		{ cmd_dump, cpl_eltarg, name_dump,
2074 		    /* MSG_INTL(MSG_DESC_DUMP) */
2075 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
2076 		    /* MSG_INTL(MSG_HELP_DUMP) */
2077 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
2078 		    opt_minus_dynndx, arg_dump },
2079 
2080 		/* dyn:tag */
2081 		{ cmd_tag, cpl_tag, name_tag,
2082 		    /* MSG_INTL(MSG_DESC_TAG) */
2083 		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
2084 		    /* MSG_INTL(MSG_HELP_TAG) */
2085 		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
2086 		    opt_tag, arg_tag },
2087 
2088 		/* dyn:value */
2089 		{ cmd_value, cpl_eltarg, name_value,
2090 		    /* MSG_INTL(MSG_DESC_VALUE) */
2091 		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
2092 		    /* MSG_INTL(MSG_HELP_VALUE) */
2093 		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
2094 		    opt_value, arg_value },
2095 
2096 		/* dyn:delete */
2097 		{ cmd_delete, cpl_eltarg, name_delete,
2098 		    /* MSG_INTL(MSG_DESC_DELETE) */
2099 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
2100 		    /* MSG_INTL(MSG_HELP_DELETE) */
2101 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
2102 		    opt_minus_dynndx, arg_delete },
2103 
2104 		/* dyn:move */
2105 		{ cmd_move, cpl_eltarg, name_move,
2106 		    /* MSG_INTL(MSG_DESC_MOVE) */
2107 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
2108 		    /* MSG_INTL(MSG_HELP_MOVE) */
2109 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
2110 		    opt_minus_dynndx, arg_move },
2111 
2112 		/* dyn:runpath */
2113 		{ cmd_runpath, NULL, name_runpath,
2114 		    /* MSG_INTL(MSG_DESC_RUNPATH) */
2115 		    ELFEDIT_I18NHDL(MSG_DESC_RUNPATH),
2116 		    /* MSG_INTL(MSG_HELP_RUNPATH) */
2117 		    ELFEDIT_I18NHDL(MSG_HELP_RUNPATH),
2118 		    opt_ostyle, arg_runpath },
2119 
2120 		/* dyn:posflag1 */
2121 		{ cmd_posflag1, cpl_posflag1, name_posflag1,
2122 		    /* MSG_INTL(MSG_DESC_POSFLAG1) */
2123 		    ELFEDIT_I18NHDL(MSG_DESC_POSFLAG1),
2124 		    /* MSG_INTL(MSG_HELP_POSFLAG1) */
2125 		    ELFEDIT_I18NHDL(MSG_HELP_POSFLAG1),
2126 		    opt_posflag1, arg_posflag1 },
2127 
2128 		/* dyn:flags */
2129 		{ cmd_flags, cpl_flags, name_flags,
2130 		    /* MSG_INTL(MSG_DESC_FLAGS) */
2131 		    ELFEDIT_I18NHDL(MSG_DESC_FLAGS),
2132 		    /* MSG_INTL(MSG_HELP_FLAGS) */
2133 		    ELFEDIT_I18NHDL(MSG_HELP_FLAGS),
2134 		    opt_ostyle_bitop, arg_flags },
2135 
2136 		/* dyn:flags1 */
2137 		{ cmd_flags1, cpl_flags1, name_flags1,
2138 		    /* MSG_INTL(MSG_DESC_FLAGS1) */
2139 		    ELFEDIT_I18NHDL(MSG_DESC_FLAGS1),
2140 		    /* MSG_INTL(MSG_HELP_FLAGS1) */
2141 		    ELFEDIT_I18NHDL(MSG_HELP_FLAGS1),
2142 		    opt_ostyle_bitop, arg_flags1 },
2143 
2144 		/* dyn:feature1 */
2145 		{ cmd_feature1, cpl_feature1, name_feature1,
2146 		    /* MSG_INTL(MSG_DESC_FEATURE1) */
2147 		    ELFEDIT_I18NHDL(MSG_DESC_FEATURE1),
2148 		    /* MSG_INTL(MSG_HELP_FEATURE1) */
2149 		    ELFEDIT_I18NHDL(MSG_HELP_FEATURE1),
2150 		    opt_ostyle_bitop, arg_feature1 },
2151 
2152 		/* dyn:checksum */
2153 		{ cmd_checksum, NULL, name_checksum,
2154 		    /* MSG_INTL(MSG_DESC_CHECKSUM) */
2155 		    ELFEDIT_I18NHDL(MSG_DESC_CHECKSUM),
2156 		    /* MSG_INTL(MSG_HELP_CHECKSUM) */
2157 		    ELFEDIT_I18NHDL(MSG_HELP_CHECKSUM),
2158 		    NULL, NULL },
2159 
2160 		/* dyn:sunw_ldmach */
2161 		{ cmd_sunw_ldmach, cpl_sunw_ldmach, name_sunw_ldmach,
2162 		    /* MSG_INTL(MSG_DESC_SUNW_LDMACH) */
2163 		    ELFEDIT_I18NHDL(MSG_DESC_SUNW_LDMACH),
2164 		    /* MSG_INTL(MSG_HELP_SUNW_LDMACH) */
2165 		    ELFEDIT_I18NHDL(MSG_HELP_SUNW_LDMACH),
2166 		    opt_ostyle, arg_sunw_ldmach },
2167 
2168 		{ NULL }
2169 	};
2170 
2171 	static elfedit_module_t module = {
2172 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
2173 	    /* MSG_INTL(MSG_MOD_DESC) */
2174 	    ELFEDIT_I18NHDL(MSG_MOD_DESC), cmds, mod_i18nhdl_to_str };
2175 
2176 	return (&module);
2177 }
2178