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