xref: /illumos-gate/usr/src/cmd/sgs/elfedit/modules/common/cap.c (revision e44e85a7f9935f0428e188393e3da61b17e83884)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include	<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	<cap_msg.h>
34 
35 
36 /*
37  * Capabilities section
38  */
39 
40 
41 
42 
43 /*
44  * This module uses shared code for several of the commands.
45  * It is sometimes necessary to know which specific command
46  * is active.
47  */
48 typedef enum {
49 	/* Dump command, used as module default to display dynamic section */
50 	CAP_CMD_T_DUMP =	0,	/* cap:dump */
51 
52 	/* Commands that do not correspond directly to a specific DT tag */
53 	CAP_CMD_T_TAG =		1,	/* cap:tag */
54 	CAP_CMD_T_VALUE =	2,	/* cap:value */
55 	CAP_CMD_T_DELETE =	3,	/* cap:delete */
56 	CAP_CMD_T_MOVE =	4,	/* cap:shift */
57 
58 	/* Commands that embody tag specific knowledge */
59 	CAP_CMD_T_HW1 =		5,	/* cap:hw1 */
60 	CAP_CMD_T_SF1 =		6,	/* cap:sf1 */
61 } CAP_CMD_T;
62 
63 
64 
65 #ifndef _ELF64
66 /*
67  * We supply this function for the msg module
68  */
69 const char *
70 _cap_msg(Msg mid)
71 {
72 	return (gettext(MSG_ORIG(mid)));
73 }
74 #endif
75 
76 
77 /*
78  * This function is supplied to elfedit through our elfedit_module_t
79  * definition. It translates the opaque elfedit_i18nhdl_t handles
80  * in our module interface into the actual strings for elfedit to
81  * use.
82  *
83  * note:
84  *	This module uses Msg codes for its i18n handle type.
85  *	So the translation is simply to use MSG_INTL() to turn
86  *	it into a string and return it.
87  */
88 static const char *
89 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)
90 {
91 	Msg msg = (Msg)hdl;
92 
93 	return (MSG_INTL(msg));
94 }
95 
96 
97 
98 /*
99  * The cap_opt_t enum specifies a bit value for every optional
100  * argument allowed by a command in this module.
101  */
102 typedef enum {
103 	CAP_OPT_F_AND =		1,	/* -and: AND (&) values to dest */
104 	CAP_OPT_F_CMP =		2,	/* -cmp: Complement (~) values */
105 	CAP_OPT_F_CAPNDX =	4,	/* -capndx: elt is tag index, */
106 					/*	not name */
107 	CAP_OPT_F_OR =		8,	/* -or: OR (|) values to dest */
108 } cap_opt_t;
109 
110 
111 /*
112  * A variable of type ARGSTATE is used by each command to maintain
113  * information about the arguments and related things. It is
114  * initialized by process_args(), and used by the other routines.
115  */
116 typedef struct {
117 	elfedit_obj_state_t	*obj_state;
118 	struct {
119 		elfedit_section_t *sec;	/* Capabilities section reference */
120 		Cap	*data;		/* Start of capabilities section data */
121 		Word	num;		/* # Capabilities elts */
122 	} cap;
123 	cap_opt_t	optmask;   	/* Mask of options used */
124 	int		argc;		/* # of plain arguments */
125 	const char	**argv;		/* Plain arguments */
126 } ARGSTATE;
127 
128 
129 
130 /*
131  * Standard argument processing for cap module
132  *
133  * entry
134  *	obj_state, argc, argv - Standard command arguments
135  *	argstate - Address of ARGSTATE block to be initialized
136  *
137  * exit:
138  *	On success, *argstate is initialized. On error,
139  *	an error is issued and this routine does not return.
140  */
141 static void
142 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
143     ARGSTATE *argstate)
144 {
145 	elfedit_getopt_state_t	getopt_state;
146 	elfedit_getopt_ret_t	*getopt_ret;
147 
148 	bzero(argstate, sizeof (*argstate));
149 	argstate->obj_state = obj_state;
150 
151 	elfedit_getopt_init(&getopt_state, &argc, &argv);
152 
153 	/* Add each new option to the options mask */
154 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL)
155 		argstate->optmask |= getopt_ret->gor_idmask;
156 
157 	/* If there may be an arbitrary amount of output, use a pager */
158 	if (argc == 0)
159 		elfedit_pager_init();
160 
161 	/* Return the updated values of argc/argv */
162 	argstate->argc = argc;
163 	argstate->argv = argv;
164 
165 	/* Locate the capabilities section */
166 	argstate->cap.sec = elfedit_sec_getcap(obj_state, &argstate->cap.data,
167 	    &argstate->cap.num);
168 }
169 
170 
171 
172 /*
173  * Print ELF capabilities values, taking the calling command, and output style
174  * into account.
175  *
176  * entry:
177  *	cmd - CAP_CMD_T_* value giving identify of caller
178  *	autoprint - If True, output is only produced if the elfedit
179  *		autoprint flag is set. If False, output is always produced.
180  *	argstate - Argument state block
181  *	print_type - Specifies which capabilities elements to display.
182  *	ndx = If print_type is PRINT_CAP_T_NDX, displays the index specified.
183  *		Otherwise ignored.
184  */
185 typedef enum {
186 	PRINT_CAP_T_ALL =	0,	/* Show all indexes */
187 	PRINT_CAP_T_NDX =	1,	/* Show capabilities[arg] only */
188 	PRINT_CAP_T_TAG =	2	/* Show all elts with tag type */
189 					/*	given by arg */
190 } PRINT_CAP_T;
191 
192 static void
193 print_cap(CAP_CMD_T cmd, int autoprint, ARGSTATE *argstate,
194     PRINT_CAP_T print_type, Word arg)
195 {
196 	elfedit_outstyle_t	outstyle;
197 	Word	cnt, ndx, printed = 0;
198 	Cap	*cap;
199 	int	header_done = 0;
200 	Xword	last_c_val = 0;
201 
202 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
203 		return;
204 
205 	/*
206 	 * Pick an output style. cap:dump is required to use the default
207 	 * style. The other commands use the current output style.
208 	 */
209 	outstyle = (cmd == CAP_CMD_T_DUMP) ?
210 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
211 
212 	/* How many elements do we examine? */
213 	if (print_type == PRINT_CAP_T_NDX) {
214 		if (arg >= argstate->cap.num)
215 			return;		/* Out of range */
216 		ndx = arg;
217 		cnt = 1;
218 	} else {
219 		ndx = 0;
220 		cnt = argstate->cap.num;
221 	}
222 
223 	cap = &argstate->cap.data[ndx];
224 	for (; cnt--; cap++, ndx++) {
225 		/*
226 		 * If we are only displaying certain tag types and
227 		 * this isn't one of those, move on to next element.
228 		 */
229 		if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg))
230 			continue;
231 
232 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
233 			if (header_done == 0) {
234 				header_done = 1;
235 				Elf_cap_title(0);
236 			}
237 			Elf_cap_entry(NULL, cap, ndx,
238 			    argstate->obj_state->os_ehdr->e_machine);
239 		} else {
240 			/*
241 			 * In simple or numeric mode under a print type
242 			 * that is based on tag type rather than on index,
243 			 * quietly: If we've already printed this value,
244 			 * don't print it again. A common example of this
245 			 * is PRINT_CAP_T_RUNPATH when both CA_RPATH and
246 			 * CA_RUNPATH are present with the same value.
247 			 */
248 			if ((print_type == PRINT_CAP_T_TAG) && printed &&
249 			    (last_c_val == cap->c_un.c_val))
250 				continue;
251 
252 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
253 				union {
254 					Conv_cap_val_hw1_buf_t	hw1;
255 					Conv_cap_val_sf1_buf_t	sf1;
256 				} c_buf;
257 
258 				switch (cap->c_tag) {
259 				case CA_SUNW_HW_1:
260 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
261 					    conv_cap_val_hw1(cap->c_un.c_val,
262 					    argstate->obj_state->os_ehdr->
263 					    e_machine,
264 					    CONV_FMT_NOBKT, &c_buf.hw1));
265 					printed = 1;
266 					continue;
267 				case CA_SUNW_SF_1:
268 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
269 					    conv_cap_val_sf1(cap->c_un.c_val,
270 					    argstate->obj_state->os_ehdr->
271 					    e_machine,
272 					    CONV_FMT_NOBKT, &c_buf.sf1));
273 					printed = 1;
274 					continue;
275 				}
276 			}
277 			elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
278 			    cap->c_un.c_val);
279 		}
280 		printed = 1;
281 		last_c_val = cap->c_un.c_val;
282 	}
283 
284 	/*
285 	 * If nothing was output under the print types that are
286 	 * based on tag type, issue an error saying it doesn't exist.
287 	 */
288 	if (!printed && (print_type == PRINT_CAP_T_TAG)) {
289 		Conv_inv_buf_t inv_buf;
290 
291 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
292 		    EC_WORD(argstate->cap.sec->sec_shndx),
293 		    argstate->cap.sec->sec_name,
294 		    conv_cap_tag(arg, 0, &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, 0, &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, 0, &inv_buf1),
532 				    conv_cap_tag(c_tag, 0, &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_const_to_atoui(ELFEDIT_CONST_AV));
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 	/* This routine allows multiple flags to be specified */
736 
737 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_AV);
738 }
739 
740 /*ARGSUSED*/
741 static void
742 cpl_sf1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
743     const char *argv[], int num_opt)
744 {
745 	/* This routine allows multiple flags to be specified */
746 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SF1_SUNW);
747 }
748 
749 
750 /*
751  * Implementation functions for the commands
752  */
753 static elfedit_cmdret_t
754 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
755 {
756 	return (cmd_body(CAP_CMD_T_DUMP, obj_state, argc, argv));
757 }
758 
759 static elfedit_cmdret_t
760 cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
761 {
762 	return (cmd_body(CAP_CMD_T_TAG, obj_state, argc, argv));
763 }
764 
765 static elfedit_cmdret_t
766 cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
767 {
768 	return (cmd_body(CAP_CMD_T_VALUE, obj_state, argc, argv));
769 }
770 
771 static elfedit_cmdret_t
772 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
773 {
774 	return (cmd_body(CAP_CMD_T_DELETE, obj_state, argc, argv));
775 }
776 
777 static elfedit_cmdret_t
778 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
779 {
780 	return (cmd_body(CAP_CMD_T_MOVE, obj_state, argc, argv));
781 }
782 
783 static elfedit_cmdret_t
784 cmd_hw1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
785 {
786 	return (cmd_body(CAP_CMD_T_HW1, obj_state, argc, argv));
787 }
788 
789 static elfedit_cmdret_t
790 cmd_sf1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
791 {
792 	return (cmd_body(CAP_CMD_T_SF1, obj_state, argc, argv));
793 }
794 
795 
796 
797 /*ARGSUSED*/
798 elfedit_module_t *
799 elfedit_init(elfedit_module_version_t version)
800 {
801 	/* For commands that only accept -and, -cmp, -o, and -or */
802 	static elfedit_cmd_optarg_t opt_ostyle_bitop[] = {
803 		{ ELFEDIT_STDOA_OPT_AND, NULL,
804 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_AND, CAP_OPT_F_OR },
805 		{ ELFEDIT_STDOA_OPT_CMP, NULL,
806 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_CMP, 0 },
807 		{ ELFEDIT_STDOA_OPT_O, NULL,
808 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
809 		{ ELFEDIT_STDOA_OPT_OR, NULL,
810 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_OR, CAP_OPT_F_AND },
811 		{ NULL }
812 	};
813 
814 	/* For commands that only accept -capndx */
815 	static elfedit_cmd_optarg_t opt_capndx[] = {
816 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
817 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
818 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
819 		    CAP_OPT_F_CAPNDX, 0 },
820 		{ NULL }
821 	};
822 
823 	/* For commands thataccept -capndx and output styles */
824 	static elfedit_cmd_optarg_t opt_ostyle_capndx[] = {
825 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
826 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
827 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
828 		    CAP_OPT_F_CAPNDX, 0 },
829 		{ ELFEDIT_STDOA_OPT_O, NULL,
830 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
831 		{ NULL }
832 	};
833 
834 
835 	/* cap:dump */
836 	static const char *name_dump[] = {
837 	    MSG_ORIG(MSG_CMD_DUMP),
838 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
839 	    NULL
840 	};
841 	static elfedit_cmd_optarg_t arg_dump[] = {
842 		{ MSG_ORIG(MSG_STR_ELT),
843 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
844 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
845 		    ELFEDIT_CMDOA_F_OPT },
846 		{ NULL }
847 	};
848 
849 
850 	/* cap:tag */
851 	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
852 	static elfedit_cmd_optarg_t arg_tag[] = {
853 		{ MSG_ORIG(MSG_STR_ELT),
854 		    /* MSG_INTL(MSG_A1_TAG_ELT) */
855 		    ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
856 		    ELFEDIT_CMDOA_F_OPT },
857 		{ MSG_ORIG(MSG_STR_VALUE),
858 		    /* MSG_INTL(MSG_A2_TAG_VALUE) */
859 		    ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
860 		    ELFEDIT_CMDOA_F_OPT },
861 		{ NULL }
862 	};
863 
864 
865 	/* cap:value */
866 	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
867 	static elfedit_cmd_optarg_t arg_value[] = {
868 		{ MSG_ORIG(MSG_STR_ELT),
869 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
870 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
871 		    ELFEDIT_CMDOA_F_OPT },
872 		{ MSG_ORIG(MSG_STR_VALUE),
873 		    /* MSG_INTL(MSG_A2_VALUE_VALUE) */
874 		    ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
875 		    ELFEDIT_CMDOA_F_OPT },
876 		{ NULL }
877 	};
878 
879 	/* cap:delete */
880 	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
881 	static elfedit_cmd_optarg_t arg_delete[] = {
882 		{ MSG_ORIG(MSG_STR_ELT),
883 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
884 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
885 		    0 },
886 		{ MSG_ORIG(MSG_STR_COUNT),
887 		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
888 		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
889 		    ELFEDIT_CMDOA_F_OPT },
890 		{ NULL }
891 	};
892 
893 	/* cap:move */
894 	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
895 	static elfedit_cmd_optarg_t arg_move[] = {
896 		{ MSG_ORIG(MSG_STR_ELT),
897 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
898 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
899 		    0 },
900 		{ MSG_ORIG(MSG_STR_DST_INDEX),
901 		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
902 		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
903 		    0 },
904 		{ MSG_ORIG(MSG_STR_COUNT),
905 		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
906 		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
907 		    ELFEDIT_CMDOA_F_OPT },
908 		{ NULL }
909 	};
910 
911 	/* cap:hw1 */
912 	static const char *name_hw1[] = { MSG_ORIG(MSG_CMD_HW1), NULL };
913 	static elfedit_cmd_optarg_t arg_hw1[] = {
914 		{ MSG_ORIG(MSG_STR_VALUE),
915 		    /* MSG_INTL(MSG_A1_HW1_VALUE) */
916 		    ELFEDIT_I18NHDL(MSG_A1_HW1_VALUE),
917 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
918 		{ NULL }
919 	};
920 
921 	/* cap:sf1 */
922 	static const char *name_sf1[] = { MSG_ORIG(MSG_CMD_SF1), NULL };
923 	static elfedit_cmd_optarg_t arg_sf1[] = {
924 		{ MSG_ORIG(MSG_STR_VALUE),
925 		    /* MSG_INTL(MSG_A1_SF1_VALUE) */
926 		    ELFEDIT_I18NHDL(MSG_A1_SF1_VALUE),
927 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
928 		{ NULL }
929 	};
930 
931 
932 
933 
934 	static elfedit_cmd_t cmds[] = {
935 		/* cap:dump */
936 		{ cmd_dump, cpl_eltarg, name_dump,
937 		    /* MSG_INTL(MSG_DESC_DUMP) */
938 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
939 		    /* MSG_INTL(MSG_HELP_DUMP) */
940 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
941 		    opt_capndx, arg_dump },
942 
943 		/* cap:tag */
944 		{ cmd_tag, cpl_tag, name_tag,
945 		    /* MSG_INTL(MSG_DESC_TAG) */
946 		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
947 		    /* MSG_INTL(MSG_HELP_TAG) */
948 		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
949 		    opt_ostyle_capndx, arg_tag },
950 
951 		/* cap:value */
952 		{ cmd_value, cpl_eltarg, name_value,
953 		    /* MSG_INTL(MSG_DESC_VALUE) */
954 		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
955 		    /* MSG_INTL(MSG_HELP_VALUE) */
956 		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
957 		    opt_ostyle_capndx, arg_value },
958 
959 		/* cap:delete */
960 		{ cmd_delete, cpl_eltarg, name_delete,
961 		    /* MSG_INTL(MSG_DESC_DELETE) */
962 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
963 		    /* MSG_INTL(MSG_HELP_DELETE) */
964 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
965 		    opt_capndx, arg_delete },
966 
967 		/* cap:move */
968 		{ cmd_move, cpl_eltarg, name_move,
969 		    /* MSG_INTL(MSG_DESC_MOVE) */
970 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
971 		    /* MSG_INTL(MSG_HELP_MOVE) */
972 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
973 		    opt_capndx, arg_move },
974 
975 		/* cap:hw1 */
976 		{ cmd_hw1, cpl_hw1, name_hw1,
977 		    /* MSG_INTL(MSG_DESC_HW1) */
978 		    ELFEDIT_I18NHDL(MSG_DESC_HW1),
979 		    /* MSG_INTL(MSG_HELP_HW1) */
980 		    ELFEDIT_I18NHDL(MSG_HELP_HW1),
981 		    opt_ostyle_bitop, arg_hw1 },
982 
983 		/* cap:sf1 */
984 		{ cmd_sf1, cpl_sf1, name_sf1,
985 		    /* MSG_INTL(MSG_DESC_SF1) */
986 		    ELFEDIT_I18NHDL(MSG_DESC_SF1),
987 		    /* MSG_INTL(MSG_HELP_SF1) */
988 		    ELFEDIT_I18NHDL(MSG_HELP_SF1),
989 		    opt_ostyle_bitop, arg_sf1 },
990 
991 		{ NULL }
992 	};
993 
994 	static elfedit_module_t module = {
995 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
996 	    /* MSG_INTL(MSG_MOD_DESC) */
997 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
998 	    cmds, mod_i18nhdl_to_str };
999 
1000 	return (&module);
1001 }
1002