1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include	<ctype.h>
29 #include	<machdep.h>
30 #include	<elfedit.h>
31 #include	<sys/elf_SPARC.h>
32 #include	<strings.h>
33 #include	<debug.h>
34 #include	<conv.h>
35 #include	<cap_msg.h>
36 
37 
38 /*
39  * Capabilities section
40  */
41 
42 
43 
44 
45 /*
46  * This module uses shared code for several of the commands.
47  * It is sometimes necessary to know which specific command
48  * is active.
49  */
50 typedef enum {
51 	/* Dump command, used as module default to display dynamic section */
52 	CAP_CMD_T_DUMP =	0,	/* cap:dump */
53 
54 	/* Commands that do not correspond directly to a specific DT tag */
55 	CAP_CMD_T_TAG =		1,	/* cap:tag */
56 	CAP_CMD_T_VALUE =	2,	/* cap:value */
57 	CAP_CMD_T_DELETE =	3,	/* cap:delete */
58 	CAP_CMD_T_MOVE =	4,	/* cap:shift */
59 
60 	/* Commands that embody tag specific knowledge */
61 	CAP_CMD_T_HW1 =		5,	/* cap:hw1 */
62 	CAP_CMD_T_SF1 =		6,	/* cap:sf1 */
63 } CAP_CMD_T;
64 
65 
66 
67 #ifndef _ELF64
68 /*
69  * We supply this function for the msg module
70  */
71 const char *
72 _cap_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 cap_opt_t enum specifies a bit value for every optional
102  * argument allowed by a command in this module.
103  */
104 typedef enum {
105 	CAP_OPT_F_AND =		1,	/* -and: AND (&) values to dest */
106 	CAP_OPT_F_CMP =		2,	/* -cmp: Complement (~) values */
107 	CAP_OPT_F_CAPNDX =	4,	/* -capndx: elt is tag index, */
108 					/*	not name */
109 	CAP_OPT_F_OR =		8,	/* -or: OR (|) values to dest */
110 } cap_opt_t;
111 
112 
113 /*
114  * A variable of type ARGSTATE is used by each command to maintain
115  * information about the arguments and related things. It is
116  * initialized by process_args(), and used by the other routines.
117  */
118 typedef struct {
119 	elfedit_obj_state_t	*obj_state;
120 	struct {
121 		elfedit_section_t *sec;	/* Capabilities section reference */
122 		Cap	*data;		/* Start of capabilities section data */
123 		Word	num;		/* # Capabilities elts */
124 	} cap;
125 	cap_opt_t	optmask;   	/* Mask of options used */
126 	int		argc;		/* # of plain arguments */
127 	const char	**argv;		/* Plain arguments */
128 } ARGSTATE;
129 
130 
131 
132 /*
133  * Standard argument processing for cap module
134  *
135  * entry
136  *	obj_state, argc, argv - Standard command arguments
137  *	argstate - Address of ARGSTATE block to be initialized
138  *
139  * exit:
140  *	On success, *argstate is initialized. On error,
141  *	an error is issued and this routine does not return.
142  */
143 static void
144 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
145     ARGSTATE *argstate)
146 {
147 	elfedit_getopt_state_t	getopt_state;
148 	elfedit_getopt_ret_t	*getopt_ret;
149 
150 	bzero(argstate, sizeof (*argstate));
151 	argstate->obj_state = obj_state;
152 
153 	elfedit_getopt_init(&getopt_state, &argc, &argv);
154 
155 	/* Add each new option to the options mask */
156 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
157 		argstate->optmask |= getopt_ret->gor_idmask;
158 
159 	/* If there may be an arbitrary amount of output, use a pager */
160 	if (argc == 0)
161 		elfedit_pager_init();
162 
163 	/* Return the updated values of argc/argv */
164 	argstate->argc = argc;
165 	argstate->argv = argv;
166 
167 	/* Locate the capabilities section */
168 	argstate->cap.sec = elfedit_sec_getcap(obj_state, &argstate->cap.data,
169 	    &argstate->cap.num);
170 }
171 
172 
173 
174 /*
175  * Print ELF capabilities values, taking the calling command, and output style
176  * into account.
177  *
178  * entry:
179  *	cmd - CAP_CMD_T_* value giving identify of caller
180  *	autoprint - If True, output is only produced if the elfedit
181  *		autoprint flag is set. If False, output is always produced.
182  *	argstate - Argument state block
183  *	print_type - Specifies which capabilities elements to display.
184  *	ndx = If print_type is PRINT_CAP_T_NDX, displays the index specified.
185  *		Otherwise ignored.
186  */
187 typedef enum {
188 	PRINT_CAP_T_ALL =	0,	/* Show all indexes */
189 	PRINT_CAP_T_NDX =	1,	/* Show capabilities[arg] only */
190 	PRINT_CAP_T_TAG =	2	/* Show all elts with tag type */
191 					/*	given by arg */
192 } PRINT_CAP_T;
193 
194 static void
195 print_cap(CAP_CMD_T cmd, int autoprint, ARGSTATE *argstate,
196     PRINT_CAP_T print_type, Word arg)
197 {
198 	elfedit_outstyle_t	outstyle;
199 	Word	cnt, ndx, printed = 0;
200 	Cap	*cap;
201 	int	header_done = 0;
202 	Xword	last_c_val = 0;
203 
204 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
205 		return;
206 
207 	/*
208 	 * Pick an output style. cap:dump is required to use the default
209 	 * style. The other commands use the current output style.
210 	 */
211 	outstyle = (cmd == CAP_CMD_T_DUMP) ?
212 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
213 
214 	/* How many elements do we examine? */
215 	if (print_type == PRINT_CAP_T_NDX) {
216 		if (arg >= argstate->cap.num)
217 			return;		/* Out of range */
218 		ndx = arg;
219 		cnt = 1;
220 	} else {
221 		ndx = 0;
222 		cnt = argstate->cap.num;
223 	}
224 
225 	cap = &argstate->cap.data[ndx];
226 	for (; cnt--; cap++, ndx++) {
227 		/*
228 		 * If we are only displaying certain tag types and
229 		 * this isn't one of those, move on to next element.
230 		 */
231 		if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg))
232 			continue;
233 
234 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
235 			if (header_done == 0) {
236 				header_done = 1;
237 				Elf_cap_title(0);
238 			}
239 			Elf_cap_entry(NULL, cap, ndx,
240 			    argstate->obj_state->os_ehdr->e_machine);
241 		} else {
242 			/*
243 			 * In simple or numeric mode under a print type
244 			 * that is based on tag type rather than on index,
245 			 * quietly: If we've already printed this value,
246 			 * don't print it again. A common example of this
247 			 * is PRINT_CAP_T_RUNPATH when both CA_RPATH and
248 			 * CA_RUNPATH are present with the same value.
249 			 */
250 			if ((print_type == PRINT_CAP_T_TAG) && printed &&
251 			    (last_c_val == cap->c_un.c_val))
252 				continue;
253 
254 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
255 				union {
256 					Conv_cap_val_hw1_buf_t	hw1;
257 					Conv_cap_val_sf1_buf_t	sf1;
258 				} c_buf;
259 
260 				switch (cap->c_tag) {
261 				case CA_SUNW_HW_1:
262 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
263 					    conv_cap_val_hw1(cap->c_un.c_val,
264 					    argstate->obj_state->os_ehdr->
265 					    e_machine,
266 					    CONV_FMT_NOBKT, &c_buf.hw1));
267 					printed = 1;
268 					continue;
269 				case CA_SUNW_SF_1:
270 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
271 					    conv_cap_val_sf1(cap->c_un.c_val,
272 					    argstate->obj_state->os_ehdr->
273 					    e_machine,
274 					    CONV_FMT_NOBKT, &c_buf.sf1));
275 					printed = 1;
276 					continue;
277 				}
278 			}
279 			elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
280 			    cap->c_un.c_val);
281 		}
282 		printed = 1;
283 		last_c_val = cap->c_un.c_val;
284 	}
285 
286 	/*
287 	 * If nothing was output under the print types that are
288 	 * based on tag type, issue an error saying it doesn't exist.
289 	 */
290 	if (!printed && (print_type == PRINT_CAP_T_TAG)) {
291 		Conv_inv_buf_t inv_buf;
292 
293 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
294 		    EC_WORD(argstate->cap.sec->sec_shndx),
295 		    argstate->cap.sec->sec_name, conv_cap_tag(arg, &inv_buf));
296 	}
297 }
298 
299 
300 /*
301  * Process the elt argument: This will be a tag type if -capndx is
302  * not present and this is a print request. It will be an index otherwise.
303  *
304  * entry:
305  *	argstate - Argument state block
306  *	arg - Argument string to be converted into an index
307  *	argname - String giving the name by which the argument is
308  *		referred in the online help for the command.
309  *	print_request - True if the command is to print the current
310  *		value(s) and return without changing anything.
311  *	print_type - Address of variable containing PRINT_CAP_T_
312  *		code specifying how the elements will be displayed.
313  *
314  * exit:
315  *	If print_request is False: arg is converted into an integer value.
316  *	If -capndx was used, we convert it into an integer. If it was not
317  *	used, then arg is a tag name --- we find the first capabilities entry
318  *	that matches. If no entry matches, and there is an extra CA_NULL,
319  *	it is added. Otherwise an error is issued. *print_type is set
320  *	to PRINT_CAP_T_NDX.
321  *
322  *	If print_request is True: If -capndx was used, arg is converted into
323  *	an integer value, *print_type is set to PRINT_CAP_T_NDX, and
324  *	the value is returned. If -capndx was not used, *print_type is set to
325  *	PRINT_CAP_T_TAG, and the tag value is returned.
326  */
327 static Word
328 arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname,
329     int print_request, PRINT_CAP_T *print_type)
330 {
331 	Word	ndx, ca_value;
332 
333 
334 	/* Assume we are returning an index, alter as needed below */
335 	*print_type = PRINT_CAP_T_NDX;
336 
337 	/* If -capndx was used, this is a simple numeric index */
338 	if ((argstate->optmask & CAP_OPT_F_CAPNDX) != 0)
339 		return ((Word) elfedit_atoui_range(arg, argname, 0,
340 		    argstate->cap.num - 1, NULL));
341 
342 	/* The argument is a CA_ tag type, not a numeric index */
343 	ca_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_CA);
344 
345 	/*
346 	 * If this is a printing request, then we let print_cap() show
347 	 * all the items with this tag type.
348 	 */
349 	if (print_request) {
350 		*print_type = PRINT_CAP_T_TAG;
351 		return (ca_value);
352 	}
353 
354 	/* Locate the first entry with the given tag type */
355 	for (ndx = 0; ndx < argstate->cap.num; ndx++) {
356 		if (argstate->cap.data[ndx].c_tag == ca_value) {
357 			elfedit_msg(ELFEDIT_MSG_DEBUG,
358 			    MSG_INTL(MSG_DEBUG_CA2NDX),
359 			    EC_WORD(argstate->cap.sec->sec_shndx),
360 			    argstate->cap.sec->sec_name, EC_WORD(ndx), arg);
361 			return (ndx);
362 		}
363 	}
364 
365 	/* No room to create one, so we're out of options and must fail */
366 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
367 	    EC_WORD(argstate->cap.sec->sec_shndx),
368 	    argstate->cap.sec->sec_name, arg);
369 
370 	/*NOTREACHED*/
371 	return (0);		/* For lint */
372 }
373 
374 
375 /*
376  * Argument processing for the bitmask commands. Convert the arguments
377  * to integer form, apply -and/-cmp/-or, and return the resulting value.
378  *
379  * entry:
380  *	argstate - Argument state block
381  *	orig - Value of original bitmask
382  *	const_sym - NULL, or array of name->integer mappings for
383  *		applicable symbolic constant names.
384  */
385 static Word
386 flag_bitop(ARGSTATE *argstate, Word orig, const elfedit_atoui_sym_t *const_sym)
387 {
388 	Word flags = 0;
389 	int i;
390 
391 	/* Collect the arguments */
392 	for (i = 0; i < argstate->argc; i++)
393 		flags |= (Word) elfedit_atoui(argstate->argv[i], const_sym);
394 
395 	/* Complement the value? */
396 	if (argstate->optmask & CAP_OPT_F_CMP)
397 		flags = ~flags;
398 
399 	/* Perform any requested bit operations */
400 	if (argstate->optmask & CAP_OPT_F_AND)
401 		flags &= orig;
402 	else if (argstate->optmask & CAP_OPT_F_OR)
403 		flags |= orig;
404 
405 	return (flags);
406 }
407 
408 
409 
410 /*
411  * Common body for the cap: module commands. These commands
412  * share a large amount of common behavior, so it is convenient
413  * to centralize things and use the cmd argument to handle the
414  * small differences.
415  *
416  * entry:
417  *	cmd - One of the CAP_CMD_T_* constants listed above, specifying
418  *		which command to implement.
419  *	obj_state, argc, argv - Standard command arguments
420  */
421 static elfedit_cmdret_t
422 cmd_body(CAP_CMD_T cmd, elfedit_obj_state_t *obj_state,
423     int argc, const char *argv[])
424 {
425 	ARGSTATE		argstate;
426 	Cap			*cap;
427 	const char		*cap_name;
428 	Word			cap_ndx, cap_num;
429 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
430 	PRINT_CAP_T		print_type = PRINT_CAP_T_ALL;
431 	Word			ndx;
432 	int			print_only = 0;
433 	int			do_autoprint = 1;
434 
435 	/* Process the optional arguments */
436 	process_args(obj_state, argc, argv, &argstate);
437 
438 	cap = argstate.cap.data;
439 	cap_num = argstate.cap.num;
440 	cap_name = argstate.cap.sec->sec_name;
441 	cap_ndx = argstate.cap.sec->sec_shndx;
442 
443 	/* Check number of arguments, gather information */
444 	switch (cmd) {
445 	case CAP_CMD_T_DUMP:
446 		/* cap:dump can accept an optional index argument */
447 		if (argstate.argc > 1)
448 			elfedit_command_usage();
449 		print_only = 1;
450 		if (argstate.argc == 1)
451 			ndx = arg_to_index(&argstate, argstate.argv[0],
452 			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
453 		break;
454 
455 	case CAP_CMD_T_TAG:
456 	case CAP_CMD_T_VALUE:
457 		print_only = (argstate.argc != 2);
458 		if (argstate.argc > 0) {
459 			if (argstate.argc > 2)
460 				elfedit_command_usage();
461 			ndx = arg_to_index(&argstate, argstate.argv[0],
462 			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
463 		}
464 		break;
465 
466 	case CAP_CMD_T_DELETE:
467 		if ((argstate.argc < 1) || (argstate.argc > 2))
468 			elfedit_command_usage();
469 		ndx = arg_to_index(&argstate, argstate.argv[0],
470 		    MSG_ORIG(MSG_STR_ELT),
471 		    0, &print_type);
472 		do_autoprint = 0;
473 		break;
474 
475 	case CAP_CMD_T_MOVE:
476 		if ((argstate.argc < 2) || (argstate.argc > 3))
477 			elfedit_command_usage();
478 		ndx = arg_to_index(&argstate, argstate.argv[0],
479 		    MSG_ORIG(MSG_STR_ELT), 0, &print_type);
480 		do_autoprint = 0;
481 		break;
482 
483 	case CAP_CMD_T_HW1:
484 		print_only = (argstate.argc == 0);
485 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
486 		    ELFEDIT_CONST_CA, CA_SUNW_HW_1, 1),
487 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
488 		break;
489 
490 	case CAP_CMD_T_SF1:
491 		print_only = (argstate.argc == 0);
492 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
493 		    ELFEDIT_CONST_CA, CA_SUNW_SF_1, 1),
494 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
495 		break;
496 
497 	default:
498 		/* Note expected: All commands should have been caught above */
499 		elfedit_command_usage();
500 		break;
501 	}
502 
503 
504 	/* If this is a request to print current values, do it and return */
505 	if (print_only) {
506 		print_cap(cmd, 0, &argstate, print_type, ndx);
507 		return (ELFEDIT_CMDRET_NONE);
508 	}
509 
510 
511 	switch (cmd) {
512 		/*
513 		 * CAP_CMD_T_DUMP can't get here: It is a print-only
514 		 * command.
515 		 */
516 
517 	case CAP_CMD_T_TAG:
518 		{
519 			Conv_inv_buf_t	inv_buf1, inv_buf2;
520 			Word c_tag = (Word) elfedit_atoconst(argstate.argv[1],
521 			    ELFEDIT_CONST_CA);
522 
523 			if (cap[ndx].c_tag == c_tag) {
524 				elfedit_msg(ELFEDIT_MSG_DEBUG,
525 				    MSG_INTL(MSG_DEBUG_S_OK),
526 				    cap_ndx, cap_name, EC_WORD(ndx),
527 				    conv_cap_tag(c_tag, &inv_buf1));
528 			} else {
529 				elfedit_msg(ELFEDIT_MSG_DEBUG,
530 				    MSG_INTL(MSG_DEBUG_S_CHG),
531 				    cap_ndx, cap_name, EC_WORD(ndx),
532 				    conv_cap_tag(cap[ndx].c_tag, &inv_buf1),
533 				    conv_cap_tag(c_tag, &inv_buf2));
534 				cap[ndx].c_tag = c_tag;
535 				ret = ELFEDIT_CMDRET_MOD;
536 			}
537 		}
538 		break;
539 
540 	case CAP_CMD_T_VALUE:
541 		{
542 			Xword c_val = (Xword)
543 			    elfedit_atoui(argstate.argv[1], NULL);
544 
545 			if (cap[ndx].c_un.c_val == c_val) {
546 				elfedit_msg(ELFEDIT_MSG_DEBUG,
547 				    MSG_INTL(MSG_DEBUG_X_OK),
548 				    argstate.cap.sec->sec_shndx,
549 				    argstate.cap.sec->sec_name,
550 				    EC_WORD(ndx), EC_XWORD(c_val));
551 			} else {
552 				elfedit_msg(ELFEDIT_MSG_DEBUG,
553 				    MSG_INTL(MSG_DEBUG_X_CHG),
554 				    argstate.cap.sec->sec_shndx,
555 				    argstate.cap.sec->sec_name,
556 				    EC_WORD(ndx), EC_XWORD(cap[ndx].c_un.c_val),
557 				    EC_XWORD(c_val));
558 				cap[ndx].c_un.c_val = c_val;
559 				ret = ELFEDIT_CMDRET_MOD;
560 			}
561 		}
562 		break;
563 
564 	case CAP_CMD_T_DELETE:
565 		{
566 			Word cnt = (argstate.argc == 1) ? 1 :
567 			    (Word) elfedit_atoui_range(argstate.argv[1],
568 			    MSG_ORIG(MSG_STR_COUNT), 1, cap_num - ndx, NULL);
569 			const char *msg_prefix =
570 			    elfedit_sec_msgprefix(argstate.cap.sec);
571 
572 			elfedit_array_elts_delete(msg_prefix, argstate.cap.data,
573 			    sizeof (Cap), cap_num, ndx, cnt);
574 			ret = ELFEDIT_CMDRET_MOD;
575 		}
576 		break;
577 
578 	case CAP_CMD_T_MOVE:
579 		{
580 			Cap	save;
581 			Word	cnt;
582 			Word	dstndx;
583 			const char *msg_prefix =
584 			    elfedit_sec_msgprefix(argstate.cap.sec);
585 
586 			dstndx = (Word)
587 			    elfedit_atoui_range(argstate.argv[1],
588 			    MSG_ORIG(MSG_STR_DST_INDEX), 0, cap_num - 1,
589 			    NULL);
590 			if (argstate.argc == 2) {
591 				cnt = 1;
592 			} else {
593 				cnt = (Word) elfedit_atoui_range(
594 				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
595 				    1, cap_num, NULL);
596 			}
597 			elfedit_array_elts_move(msg_prefix, argstate.cap.data,
598 			    sizeof (save), cap_num, ndx, dstndx, cnt, &save);
599 			ret = ELFEDIT_CMDRET_MOD;
600 		}
601 		break;
602 
603 
604 	case CAP_CMD_T_HW1:
605 		{
606 			Conv_cap_val_hw1_buf_t buf1, buf2;
607 			Half	mach = argstate.obj_state->os_ehdr->e_machine;
608 			Xword	hw1;
609 
610 			hw1 = flag_bitop(&argstate, cap[ndx].c_un.c_val,
611 			    elfedit_mach_sunw_hw1_to_atoui(mach));
612 
613 			/* Set the value */
614 			if (cap[ndx].c_un.c_val == hw1) {
615 				elfedit_msg(ELFEDIT_MSG_DEBUG,
616 				    MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx,
617 				    cap_name, EC_WORD(ndx),
618 				    conv_cap_val_hw1(cap[ndx].c_un.c_val, mach,
619 				    CONV_FMT_NOBKT, &buf1));
620 			} else {
621 				elfedit_msg(ELFEDIT_MSG_DEBUG,
622 				    MSG_INTL(MSG_DEBUG_BSB_CHG),
623 				    cap_ndx, cap_name, EC_WORD(ndx),
624 				    conv_cap_val_hw1(cap[ndx].c_un.c_val, mach,
625 				    CONV_FMT_NOBKT, &buf1),
626 				    conv_cap_val_hw1(hw1, mach,
627 				    CONV_FMT_NOBKT, &buf2));
628 				ret = ELFEDIT_CMDRET_MOD;
629 				cap[ndx].c_un.c_val = hw1;
630 			}
631 		}
632 		break;
633 
634 	case CAP_CMD_T_SF1:
635 		{
636 			Conv_cap_val_sf1_buf_t buf1, buf2;
637 			Half	mach = argstate.obj_state->os_ehdr->e_machine;
638 			Xword	sf1;
639 
640 			sf1 = flag_bitop(&argstate, cap[ndx].c_un.c_val,
641 			    elfedit_const_to_atoui(ELFEDIT_CONST_SF1_SUNW));
642 
643 			/* Set the value */
644 			if (cap[ndx].c_un.c_val == sf1) {
645 				elfedit_msg(ELFEDIT_MSG_DEBUG,
646 				    MSG_INTL(MSG_DEBUG_BSB_OK), cap_ndx,
647 				    cap_name, EC_WORD(ndx),
648 				    conv_cap_val_sf1(cap[ndx].c_un.c_val, mach,
649 				    CONV_FMT_NOBKT, &buf1));
650 			} else {
651 				elfedit_msg(ELFEDIT_MSG_DEBUG,
652 				    MSG_INTL(MSG_DEBUG_BSB_CHG),
653 				    cap_ndx, cap_name, EC_WORD(ndx),
654 				    conv_cap_val_sf1(cap[ndx].c_un.c_val, mach,
655 				    CONV_FMT_NOBKT, &buf1),
656 				    conv_cap_val_sf1(sf1, mach,
657 				    CONV_FMT_NOBKT, &buf2));
658 				ret = ELFEDIT_CMDRET_MOD;
659 				cap[ndx].c_un.c_val = sf1;
660 			}
661 		}
662 		break;
663 	}
664 
665 	/*
666 	 * If we modified the capabilities section header, tell libelf.
667 	 */
668 	if (ret == ELFEDIT_CMDRET_MOD)
669 		elfedit_modified_data(argstate.cap.sec);
670 
671 	/* Do autoprint */
672 	if (do_autoprint)
673 		print_cap(cmd, 1, &argstate, print_type, ndx);
674 
675 	return (ret);
676 }
677 
678 
679 
680 /*
681  * Command completion functions for the commands
682  */
683 
684 /*
685  * Command completion for the first argument, which specifies
686  * the capabilities element to use. Examines the options to see if
687  * -capndx is present, and if not, supplies the completion
688  * strings for argument 1.
689  */
690 /*ARGSUSED*/
691 static void
692 cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
693     const char *argv[], int num_opt)
694 {
695 	Word			i;
696 
697 	/* Make sure it's the first argument */
698 	if ((argc - num_opt) != 1)
699 		return;
700 
701 	/* Is -capndx present? If so, we don't complete tag types */
702 	for (i = 0; i < num_opt; i++)
703 		if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_CAPNDX)) == 0)
704 			return;
705 
706 	/*
707 	 * Supply capability tag names. There are very few of these, so
708 	 * rather than worry about whether a given tag exists in the
709 	 * file or not, we simply serve up all the possibilities.
710 	 */
711 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
712 }
713 
714 
715 /*ARGSUSED*/
716 static void
717 cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
718     const char *argv[], int num_opt)
719 {
720 	/* First argument */
721 	if ((argc - num_opt) == 1) {
722 		cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
723 		return;
724 	}
725 
726 	/* The second argument is always a tag value */
727 	if ((argc - num_opt) == 2)
728 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
729 }
730 
731 /*ARGSUSED*/
732 static void
733 cpl_hw1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
734     const char *argv[], int num_opt)
735 {
736 	elfedit_atoui_sym_t *sym_const;
737 
738 	/* This routine allows multiple flags to be specified */
739 
740 	/*
741 	 * If there is no object, then supply all the hardware
742 	 * capabilities we know of.
743 	 */
744 	if (obj_state == NULL) {
745 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_AV_386);
746 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_AV_SPARC);
747 		return;
748 	}
749 
750 	/*
751 	 * Supply the hardware capabilities for the type of
752 	 * machine the object is for, if we know any.
753 	 */
754 	sym_const = elfedit_mach_sunw_hw1_to_atoui(
755 	    obj_state->os_ehdr->e_machine);
756 	if (sym_const != NULL)
757 		elfedit_cpl_atoui(cpldata, sym_const);
758 }
759 
760 /*ARGSUSED*/
761 static void
762 cpl_sf1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
763     const char *argv[], int num_opt)
764 {
765 	/* This routine allows multiple flags to be specified */
766 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SF1_SUNW);
767 }
768 
769 
770 /*
771  * Implementation functions for the commands
772  */
773 static elfedit_cmdret_t
774 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
775 {
776 	return (cmd_body(CAP_CMD_T_DUMP, obj_state, argc, argv));
777 }
778 
779 static elfedit_cmdret_t
780 cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
781 {
782 	return (cmd_body(CAP_CMD_T_TAG, obj_state, argc, argv));
783 }
784 
785 static elfedit_cmdret_t
786 cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
787 {
788 	return (cmd_body(CAP_CMD_T_VALUE, obj_state, argc, argv));
789 }
790 
791 static elfedit_cmdret_t
792 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
793 {
794 	return (cmd_body(CAP_CMD_T_DELETE, obj_state, argc, argv));
795 }
796 
797 static elfedit_cmdret_t
798 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
799 {
800 	return (cmd_body(CAP_CMD_T_MOVE, obj_state, argc, argv));
801 }
802 
803 static elfedit_cmdret_t
804 cmd_hw1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
805 {
806 	return (cmd_body(CAP_CMD_T_HW1, obj_state, argc, argv));
807 }
808 
809 static elfedit_cmdret_t
810 cmd_sf1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
811 {
812 	return (cmd_body(CAP_CMD_T_SF1, obj_state, argc, argv));
813 }
814 
815 
816 
817 /*ARGSUSED*/
818 elfedit_module_t *
819 elfedit_init(elfedit_module_version_t version)
820 {
821 	/* For commands that only accept -and, -cmp, -o, and -or */
822 	static elfedit_cmd_optarg_t opt_ostyle_bitop[] = {
823 		{ ELFEDIT_STDOA_OPT_AND, NULL,
824 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_AND, CAP_OPT_F_OR },
825 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
826 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_CMP, 0 },
827 		{ ELFEDIT_STDOA_OPT_O, NULL,
828 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
829 		{ ELFEDIT_STDOA_OPT_OR, NULL,
830 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_OR, CAP_OPT_F_AND },
831 		{ NULL }
832 	};
833 
834 	/* For commands that only accept -capndx */
835 	static elfedit_cmd_optarg_t opt_capndx[] = {
836 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
837 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
838 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
839 		    CAP_OPT_F_CAPNDX, 0 },
840 		{ NULL }
841 	};
842 
843 	/* For commands thataccept -capndx and output styles */
844 	static elfedit_cmd_optarg_t opt_ostyle_capndx[] = {
845 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
846 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
847 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
848 		    CAP_OPT_F_CAPNDX, 0 },
849 		{ ELFEDIT_STDOA_OPT_O, NULL,
850 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
851 		{ NULL }
852 	};
853 
854 
855 	/* cap:dump */
856 	static const char *name_dump[] = {
857 	    MSG_ORIG(MSG_CMD_DUMP),
858 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
859 	    NULL
860 	};
861 	static elfedit_cmd_optarg_t arg_dump[] = {
862 		{ MSG_ORIG(MSG_STR_ELT),
863 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
864 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
865 		    ELFEDIT_CMDOA_F_OPT },
866 		{ NULL }
867 	};
868 
869 
870 	/* cap:tag */
871 	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
872 	static elfedit_cmd_optarg_t arg_tag[] = {
873 		{ MSG_ORIG(MSG_STR_ELT),
874 		    /* MSG_INTL(MSG_A1_TAG_ELT) */
875 		    ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
876 		    ELFEDIT_CMDOA_F_OPT },
877 		{ MSG_ORIG(MSG_STR_VALUE),
878 		    /* MSG_INTL(MSG_A2_TAG_VALUE) */
879 		    ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
880 		    ELFEDIT_CMDOA_F_OPT },
881 		{ NULL }
882 	};
883 
884 
885 	/* cap:value */
886 	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
887 	static elfedit_cmd_optarg_t arg_value[] = {
888 		{ MSG_ORIG(MSG_STR_ELT),
889 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
890 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
891 		    ELFEDIT_CMDOA_F_OPT },
892 		{ MSG_ORIG(MSG_STR_VALUE),
893 		    /* MSG_INTL(MSG_A2_VALUE_VALUE) */
894 		    ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
895 		    ELFEDIT_CMDOA_F_OPT },
896 		{ NULL }
897 	};
898 
899 	/* cap:delete */
900 	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
901 	static elfedit_cmd_optarg_t arg_delete[] = {
902 		{ MSG_ORIG(MSG_STR_ELT),
903 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
904 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
905 		    0 },
906 		{ MSG_ORIG(MSG_STR_COUNT),
907 		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
908 		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
909 		    ELFEDIT_CMDOA_F_OPT },
910 		{ NULL }
911 	};
912 
913 	/* cap:move */
914 	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
915 	static elfedit_cmd_optarg_t arg_move[] = {
916 		{ MSG_ORIG(MSG_STR_ELT),
917 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
918 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
919 		    0 },
920 		{ MSG_ORIG(MSG_STR_DST_INDEX),
921 		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
922 		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
923 		    0 },
924 		{ MSG_ORIG(MSG_STR_COUNT),
925 		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
926 		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
927 		    ELFEDIT_CMDOA_F_OPT },
928 		{ NULL }
929 	};
930 
931 	/* cap:hw1 */
932 	static const char *name_hw1[] = { MSG_ORIG(MSG_CMD_HW1), NULL };
933 	static elfedit_cmd_optarg_t arg_hw1[] = {
934 		{ MSG_ORIG(MSG_STR_VALUE),
935 		    /* MSG_INTL(MSG_A1_HW1_VALUE) */
936 		    ELFEDIT_I18NHDL(MSG_A1_HW1_VALUE),
937 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
938 		{ NULL }
939 	};
940 
941 	/* cap:sf1 */
942 	static const char *name_sf1[] = { MSG_ORIG(MSG_CMD_SF1), NULL };
943 	static elfedit_cmd_optarg_t arg_sf1[] = {
944 		{ MSG_ORIG(MSG_STR_VALUE),
945 		    /* MSG_INTL(MSG_A1_SF1_VALUE) */
946 		    ELFEDIT_I18NHDL(MSG_A1_SF1_VALUE),
947 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
948 		{ NULL }
949 	};
950 
951 
952 
953 
954 	static elfedit_cmd_t cmds[] = {
955 		/* cap:dump */
956 		{ cmd_dump, cpl_eltarg, name_dump,
957 		    /* MSG_INTL(MSG_DESC_DUMP) */
958 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
959 		    /* MSG_INTL(MSG_HELP_DUMP) */
960 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
961 		    opt_capndx, arg_dump },
962 
963 		/* cap:tag */
964 		{ cmd_tag, cpl_tag, name_tag,
965 		    /* MSG_INTL(MSG_DESC_TAG) */
966 		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
967 		    /* MSG_INTL(MSG_HELP_TAG) */
968 		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
969 		    opt_ostyle_capndx, arg_tag },
970 
971 		/* cap:value */
972 		{ cmd_value, cpl_eltarg, name_value,
973 		    /* MSG_INTL(MSG_DESC_VALUE) */
974 		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
975 		    /* MSG_INTL(MSG_HELP_VALUE) */
976 		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
977 		    opt_ostyle_capndx, arg_value },
978 
979 		/* cap:delete */
980 		{ cmd_delete, cpl_eltarg, name_delete,
981 		    /* MSG_INTL(MSG_DESC_DELETE) */
982 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
983 		    /* MSG_INTL(MSG_HELP_DELETE) */
984 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
985 		    opt_capndx, arg_delete },
986 
987 		/* cap:move */
988 		{ cmd_move, cpl_eltarg, name_move,
989 		    /* MSG_INTL(MSG_DESC_MOVE) */
990 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
991 		    /* MSG_INTL(MSG_HELP_MOVE) */
992 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
993 		    opt_capndx, arg_move },
994 
995 		/* cap:hw1 */
996 		{ cmd_hw1, cpl_hw1, name_hw1,
997 		    /* MSG_INTL(MSG_DESC_HW1) */
998 		    ELFEDIT_I18NHDL(MSG_DESC_HW1),
999 		    /* MSG_INTL(MSG_HELP_HW1) */
1000 		    ELFEDIT_I18NHDL(MSG_HELP_HW1),
1001 		    opt_ostyle_bitop, arg_hw1 },
1002 
1003 		/* cap:sf1 */
1004 		{ cmd_sf1, cpl_sf1, name_sf1,
1005 		    /* MSG_INTL(MSG_DESC_SF1) */
1006 		    ELFEDIT_I18NHDL(MSG_DESC_SF1),
1007 		    /* MSG_INTL(MSG_HELP_SF1) */
1008 		    ELFEDIT_I18NHDL(MSG_HELP_SF1),
1009 		    opt_ostyle_bitop, arg_sf1 },
1010 
1011 		{ NULL }
1012 	};
1013 
1014 	static elfedit_module_t module = {
1015 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
1016 	    /* MSG_INTL(MSG_MOD_DESC) */
1017 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
1018 	    cmds, mod_i18nhdl_to_str };
1019 
1020 	return (&module);
1021 }
1022