1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  * Copyright 2012 Milan Jurik. All rights reserved.
26  */
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_HW2 =		7,	/* cap:hw2 */
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_CAPID =	4,	/* -capid id: elt limited to given */
108 					/*	capabilities group */
109 	CAP_OPT_F_CAPNDX =	8,	/* -capndx: elt is tag index, */
110 					/*	not name */
111 	CAP_OPT_F_OR =		16,	/* -or: OR (|) values to dest */
112 	CAP_OPT_F_STRVAL =	32	/* -s: value is string, not integer */
113 } cap_opt_t;
114 
115 
116 /*
117  * A variable of type ARGSTATE is used by each command to maintain
118  * information about the arguments and related things. It is
119  * initialized by process_args(), and used by the other routines.
120  */
121 typedef struct {
122 	elfedit_obj_state_t	*obj_state;
123 	struct {
124 		elfedit_section_t *sec;	/* Capabilities section reference */
125 		Cap	*data;		/* Start of capabilities section data */
126 		Word	num;		/* # Capabilities elts */
127 		Boolean	grp_set;	/* TRUE when cap group is set */
128 		Word	grp_start_ndx;	/* capabilities group starting index */
129 		Word	grp_end_ndx;	/* capabilities group ending index */
130 	} cap;
131 	struct {			/* String table */
132 		elfedit_section_t *sec;
133 	} str;
134 	cap_opt_t	optmask;	/* Mask of options used */
135 	int		argc;		/* # of plain arguments */
136 	const char	**argv;		/* Plain arguments */
137 } ARGSTATE;
138 
139 
140 
141 /*
142  * Lookup the string table associated with the capabilities
143  * section.
144  *
145  * entry:
146  *	argstate - Argument state block
147  *	required - If TRUE, failure to obtain a string table should be
148  *		considered to be an error.
149  *
150  * exit:
151  *	If a string table is found, argstate->str is updated to reference it.
152  *	If no string table is found, and required is TRUE, an error is issued
153  *	and this routine does not return to the caller. Otherwise, this
154  *	routine returns quietly without modifying argstate->str.
155  */
156 static void
157 argstate_add_str(ARGSTATE *argstate, Boolean required)
158 {
159 	/* String table already loaded? */
160 	if (argstate->str.sec != NULL)
161 		return;
162 
163 	/*
164 	 * We can't proceed if the capabilities section does not have
165 	 * an associated string table.
166 	 */
167 	if (argstate->cap.sec->sec_shdr->sh_info == 0) {
168 		/* Error if the operation requires a string table */
169 		if (required)
170 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRTAB),
171 			    EC_WORD(argstate->cap.sec->sec_shndx),
172 			    argstate->cap.sec->sec_name);
173 		return;
174 	}
175 
176 	argstate->str.sec = elfedit_sec_getstr(argstate->obj_state,
177 	    argstate->cap.sec->sec_shdr->sh_info, 0);
178 }
179 
180 /*
181  * Given an index into the capabilities array, locate the index of the
182  * initial element in its capabilities group, and the number of elements
183  * in the group.
184  */
185 static void
186 cap_group_extents(ARGSTATE *argstate, Word ndx, Word *ret_start_ndx,
187     Word *ret_end_ndx)
188 {
189 	*ret_end_ndx = ndx;
190 
191 	/*
192 	 * The group starts with a non-NULL tag that is either the
193 	 * first tag in the array, or is preceded by a NULL tag.
194 	 */
195 	while ((ndx > 0) && (argstate->cap.data[ndx].c_tag == CA_SUNW_NULL))
196 		ndx--;
197 	while ((ndx > 0) && (argstate->cap.data[ndx - 1].c_tag != CA_SUNW_NULL))
198 		ndx--;
199 	*ret_start_ndx = ndx;
200 
201 
202 	/*
203 	 * The group is terminated by a series of 1 or more NULL tags.
204 	 */
205 	ndx = *ret_end_ndx;
206 	while (((ndx + 1) < argstate->cap.num) &&
207 	    (argstate->cap.data[ndx].c_tag != CA_SUNW_NULL))
208 		ndx++;
209 	while (((ndx + 1) < argstate->cap.num) &&
210 	    (argstate->cap.data[ndx + 1].c_tag == CA_SUNW_NULL))
211 		ndx++;
212 	*ret_end_ndx = ndx;
213 }
214 
215 /*
216  * If a CA_SUNW_ID element exists within the current capabilities group
217  * in the given argument state, return the string pointer to the name.
218  * Otherwise return a pointer to a descriptive "noname" string.
219  */
220 static const char *
221 cap_group_id(ARGSTATE *argstate)
222 {
223 	Word		ndx = argstate->cap.grp_start_ndx;
224 	Cap		*cap = argstate->cap.data + ndx;
225 
226 	for (; ndx <= argstate->cap.grp_end_ndx; ndx++, cap++) {
227 		if (cap->c_tag == CA_SUNW_ID) {
228 			argstate_add_str(argstate, TRUE);
229 			return (elfedit_offset_to_str(argstate->str.sec,
230 			    cap->c_un.c_val, ELFEDIT_MSG_ERR, 0));
231 		}
232 
233 		if (cap->c_tag == CA_SUNW_NULL)
234 			break;
235 	}
236 
237 	return ((argstate->cap.grp_start_ndx == 0) ?
238 	    MSG_INTL(MSG_STR_OBJECT) : MSG_INTL(MSG_STR_NONAME));
239 }
240 
241 
242 /*
243  * Given an index into the capabilities array, set the argstate cap.grp_*
244  * fields to reflect the capabilities group containing the index.
245  *
246  * The group concept is used to limit operations to a related group
247  * of capabilities, and prevent insert/delete/move operations from
248  * spilling across groups.
249  */
250 static void
251 argstate_cap_group(ARGSTATE *argstate, Word ndx)
252 {
253 	if (argstate->cap.grp_set == TRUE)
254 		return;
255 
256 	cap_group_extents(argstate, ndx, &argstate->cap.grp_start_ndx,
257 	    &argstate->cap.grp_end_ndx);
258 
259 	argstate->cap.grp_set = TRUE;
260 	elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CAPGRP),
261 	    EC_WORD(argstate->cap.sec->sec_shndx), argstate->cap.sec->sec_name,
262 	    EC_WORD(argstate->cap.grp_start_ndx),
263 	    EC_WORD(argstate->cap.grp_end_ndx), cap_group_id(argstate));
264 }
265 
266 /*
267  * Given an index into the capabilities array, issue a group title for
268  * the capabilities group that contains it.
269  */
270 static void
271 group_title(ARGSTATE *argstate, Word ndx)
272 {
273 	ARGSTATE	loc_argstate;
274 
275 	loc_argstate = *argstate;
276 	cap_group_extents(argstate, ndx, &loc_argstate.cap.grp_start_ndx,
277 	    &loc_argstate.cap.grp_end_ndx);
278 	elfedit_printf(MSG_INTL(MSG_FMT_CAPGRP),
279 	    EC_WORD(loc_argstate.cap.grp_start_ndx),
280 	    EC_WORD(loc_argstate.cap.grp_end_ndx), cap_group_id(&loc_argstate));
281 }
282 
283 /*
284  * Standard argument processing for cap module
285  *
286  * entry
287  *	obj_state, argc, argv - Standard command arguments
288  *	argstate - Address of ARGSTATE block to be initialized
289  *
290  * exit:
291  *	On success, *argstate is initialized. On error,
292  *	an error is issued and this routine does not return.
293  */
294 static void
295 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[],
296     ARGSTATE *argstate)
297 {
298 	elfedit_getopt_state_t	getopt_state;
299 	elfedit_getopt_ret_t	*getopt_ret;
300 	const char		*capid = NULL;
301 
302 	bzero(argstate, sizeof (*argstate));
303 	argstate->obj_state = obj_state;
304 
305 	elfedit_getopt_init(&getopt_state, &argc, &argv);
306 
307 	/* Add each new option to the options mask */
308 	while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) {
309 		argstate->optmask |= getopt_ret->gor_idmask;
310 
311 		if (getopt_ret->gor_idmask == CAP_OPT_F_CAPID)
312 			capid = getopt_ret->gor_value;
313 	}
314 
315 	/* If there may be an arbitrary amount of output, use a pager */
316 	if (argc == 0)
317 		elfedit_pager_init();
318 
319 	/* Return the updated values of argc/argv */
320 	argstate->argc = argc;
321 	argstate->argv = argv;
322 
323 	/* Locate the capabilities section */
324 	argstate->cap.sec = elfedit_sec_getcap(obj_state, &argstate->cap.data,
325 	    &argstate->cap.num);
326 
327 	/*
328 	 * If -capid was specified, locate the specified capabilities group,
329 	 * and narrow the section data to use only that group. Otherwise,
330 	 * use the whole array.
331 	 */
332 	if (capid != NULL) {
333 		Word	i;
334 		Cap	*cap = argstate->cap.data;
335 
336 		/*
337 		 * -capid requires the capability section to have an
338 		 * associated string table.
339 		 */
340 		argstate_add_str(argstate, TRUE);
341 
342 		for (i = 0; i < argstate->cap.num; i++, cap++)
343 			if ((cap->c_tag == CA_SUNW_ID) &&
344 			    (strcmp(capid, elfedit_offset_to_str(
345 			    argstate->str.sec, cap->c_un.c_val,
346 			    ELFEDIT_MSG_ERR, 0)) == 0))
347 				break;
348 
349 		if (i == argstate->cap.num)
350 			elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADCAPID),
351 			    EC_WORD(argstate->cap.sec->sec_shndx),
352 			    argstate->cap.sec->sec_name, capid);
353 		argstate_cap_group(argstate, i);
354 	} else {
355 		argstate->cap.grp_start_ndx = 0;
356 		argstate->cap.grp_end_ndx = argstate->cap.num - 1;
357 	}
358 }
359 
360 
361 
362 /*
363  * Print ELF capabilities values, taking the calling command, and output style
364  * into account.
365  *
366  * entry:
367  *	cmd - CAP_CMD_T_* value giving identify of caller
368  *	autoprint - If True, output is only produced if the elfedit
369  *		autoprint flag is set. If False, output is always produced.
370  *	argstate - Argument state block
371  *	print_type - Specifies which capabilities elements to display.
372  *	ndx = If print_type is PRINT_CAP_T_NDX, displays the index specified.
373  *		Otherwise ignored.
374  */
375 typedef enum {
376 	PRINT_CAP_T_ALL =	0,	/* Show all indexes */
377 	PRINT_CAP_T_NDX =	1,	/* Show capabilities[arg] only */
378 	PRINT_CAP_T_TAG =	2	/* Show all elts with tag type */
379 					/*	given by arg */
380 } PRINT_CAP_T;
381 
382 static void
383 print_cap(CAP_CMD_T cmd, int autoprint, ARGSTATE *argstate,
384     PRINT_CAP_T print_type, Word arg)
385 {
386 	elfedit_outstyle_t	outstyle;
387 	Word		cnt, ndx, printed = 0;
388 	Cap		*cap;
389 	Boolean		header_done = FALSE, null_seen = FALSE;
390 	const char	*str;
391 	size_t		str_size;
392 
393 	if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))
394 		return;
395 
396 	/*
397 	 * Pick an output style. cap:dump is required to use the default
398 	 * style. The other commands use the current output style.
399 	 */
400 	outstyle = (cmd == CAP_CMD_T_DUMP) ?
401 	    ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle();
402 
403 	/* How many elements do we examine? */
404 	if (print_type == PRINT_CAP_T_NDX) {
405 		if (arg >= argstate->cap.num)
406 			return;		/* Out of range */
407 		ndx = arg;
408 		cnt = 1;
409 	} else {
410 		ndx = argstate->cap.grp_start_ndx;
411 		cnt = argstate->cap.grp_end_ndx - ndx + 1;
412 	}
413 
414 	/* Load string table if there is one */
415 	argstate_add_str(argstate, FALSE);
416 	if (argstate->str.sec == NULL) {
417 		str = NULL;
418 		str_size = 0;
419 	} else {
420 		str = (const char *)argstate->str.sec->sec_data->d_buf;
421 		str_size = argstate->str.sec->sec_data->d_size;
422 	}
423 
424 	cap = &argstate->cap.data[ndx];
425 	for (; cnt--; cap++, ndx++) {
426 		/*
427 		 * If we are only displaying certain tag types and
428 		 * this isn't one of those, move on to next element.
429 		 */
430 		if ((print_type == PRINT_CAP_T_TAG) && (cap->c_tag != arg)) {
431 			if (cap->c_tag == CA_SUNW_NULL)
432 				null_seen = TRUE;
433 			continue;
434 		}
435 
436 		/*
437 		 * If capability type requires a string table, and we don't
438 		 * have one, force an error.
439 		 */
440 		switch (cap->c_tag) {
441 		case CA_SUNW_PLAT:
442 		case CA_SUNW_MACH:
443 		case CA_SUNW_ID:
444 			if (argstate->str.sec == NULL)
445 				argstate_add_str(argstate, TRUE);
446 			break;
447 		}
448 
449 		if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) {
450 			if (null_seen && (cap->c_tag != CA_SUNW_NULL)) {
451 				null_seen = FALSE;
452 				if (header_done) {
453 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
454 					    MSG_ORIG(MSG_STR_EMPTY));
455 					header_done = FALSE;
456 				}
457 			}
458 
459 			if (header_done == FALSE) {
460 				header_done = TRUE;
461 				group_title(argstate, ndx);
462 				Elf_cap_title(0);
463 			}
464 			Elf_cap_entry(NULL, cap, ndx, str, str_size,
465 			    argstate->obj_state->os_ehdr->e_machine);
466 		} else {
467 			/*
468 			 * If CAP_CMD_T_TAG, and not in default output
469 			 * style, display the tag rather than the value.
470 			 */
471 			if (cmd == CAP_CMD_T_TAG) {
472 				if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
473 					Conv_inv_buf_t	inv_buf;
474 
475 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
476 					    conv_cap_tag(cap->c_tag, 0,
477 					    &inv_buf));
478 				} else {
479 					elfedit_printf(
480 					    MSG_ORIG(MSG_FMT_WORDVALNL),
481 					    EC_WORD(cap->c_tag));
482 				}
483 				printed = 1;
484 				continue;
485 			}
486 
487 			/* Displaying the value in simple or numeric mode */
488 			if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) {
489 				Conv_cap_val_buf_t	cap_val_buf;
490 
491 				if (print_type == PRINT_CAP_T_TAG) {
492 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
493 					    conv_cap_val_hw1(cap->c_un.c_val,
494 					    argstate->obj_state->os_ehdr->
495 					    e_machine, CONV_FMT_NOBKT,
496 					    &cap_val_buf.cap_val_hw1_buf));
497 					printed = 1;
498 					continue;
499 				}
500 
501 				switch (cap->c_tag) {
502 				case CA_SUNW_HW_1:
503 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
504 					    conv_cap_val_hw1(cap->c_un.c_val,
505 					    argstate->obj_state->os_ehdr->
506 					    e_machine, CONV_FMT_NOBKT,
507 					    &cap_val_buf.cap_val_hw1_buf));
508 					printed = 1;
509 					continue;
510 				case CA_SUNW_SF_1:
511 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
512 					    conv_cap_val_sf1(cap->c_un.c_val,
513 					    argstate->obj_state->os_ehdr->
514 					    e_machine, CONV_FMT_NOBKT,
515 					    &cap_val_buf.cap_val_sf1_buf));
516 					printed = 1;
517 					continue;
518 				case CA_SUNW_HW_2:
519 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
520 					    conv_cap_val_hw2(cap->c_un.c_val,
521 					    argstate->obj_state->os_ehdr->
522 					    e_machine, CONV_FMT_NOBKT,
523 					    &cap_val_buf.cap_val_hw2_buf));
524 					printed = 1;
525 					continue;
526 				case CA_SUNW_PLAT:
527 				case CA_SUNW_MACH:
528 				case CA_SUNW_ID:
529 					elfedit_printf(MSG_ORIG(MSG_FMT_STRNL),
530 					    elfedit_offset_to_str(
531 					    argstate->str.sec, cap->c_un.c_val,
532 					    ELFEDIT_MSG_ERR, 0));
533 					printed = 1;
534 					continue;
535 				}
536 			}
537 			elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL),
538 			    EC_XWORD(cap->c_un.c_val));
539 		}
540 		printed = 1;
541 		if (cap->c_tag == CA_SUNW_NULL)
542 			null_seen = TRUE;
543 	}
544 
545 	/*
546 	 * If nothing was output under the print types that are
547 	 * based on tag type, issue an error saying it doesn't exist.
548 	 */
549 	if (!printed && (print_type == PRINT_CAP_T_TAG)) {
550 		Conv_inv_buf_t	inv_buf;
551 
552 		elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
553 		    EC_WORD(argstate->cap.sec->sec_shndx),
554 		    argstate->cap.sec->sec_name, argstate->cap.grp_start_ndx,
555 		    argstate->cap.grp_end_ndx, cap_group_id(argstate),
556 		    conv_cap_tag(arg, 0, &inv_buf));
557 	}
558 }
559 
560 
561 /*
562  * Process the elt argument: This will be a tag type if -capndx is
563  * not present and this is a print request. It will be an index otherwise.
564  *
565  * entry:
566  *	argstate - Argument state block
567  *	arg - Argument string to be converted into an index
568  *	argname - String giving the name by which the argument is
569  *		referred in the online help for the command.
570  *	print_request - True if the command is to print the current
571  *		value(s) and return without changing anything.
572  *	print_type - Address of variable containing PRINT_CAP_T_
573  *		code specifying how the elements will be displayed.
574  *
575  * exit:
576  *	If print_request is False: arg is converted into an integer value.
577  *	If -capndx was used, we convert it into an integer. If it was not
578  *	used, then arg is a tag name --- we find the first capabilities entry
579  *	that matches. If no entry matches, and there is an extra CA_NULL,
580  *	it is added. Otherwise an error is issued. *print_type is set
581  *	to PRINT_CAP_T_NDX.
582  *
583  *	If print_request is True: If -capndx was used, arg is converted into
584  *	an integer value, *print_type is set to PRINT_CAP_T_NDX, and
585  *	the value is returned. If -capndx was not used, *print_type is set to
586  *	PRINT_CAP_T_TAG, and the tag value is returned.
587  */
588 static Word
589 arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname,
590     int print_request, PRINT_CAP_T *print_type)
591 {
592 	Word		ndx, ca_value;
593 
594 
595 	/* Assume we are returning an index, alter as needed below */
596 	*print_type = PRINT_CAP_T_NDX;
597 
598 	/*
599 	 * If -capndx was used, this is a simple numeric index.
600 	 * Determine its capability group because some operations
601 	 * (move, delete) are limited to operate within it.
602 	 */
603 	if ((argstate->optmask & CAP_OPT_F_CAPNDX) != 0) {
604 		ndx = (Word) elfedit_atoui_range(arg, argname, 0,
605 		    argstate->cap.num - 1, NULL);
606 		argstate_cap_group(argstate, ndx);
607 		return (ndx);
608 	}
609 
610 	/* The argument is a CA_ tag type, not a numeric index */
611 	ca_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_CA);
612 
613 	/*
614 	 * If this is a printing request, then we let print_cap() show
615 	 * all the items with this tag type.
616 	 */
617 	if (print_request) {
618 		*print_type = PRINT_CAP_T_TAG;
619 		return (ca_value);
620 	}
621 
622 	/*
623 	 * If we haven't determined a capability group yet, either via
624 	 * -capid, or -capndx, then make it the initial group, which
625 	 * represent the object capabilities.
626 	 */
627 	if (!argstate->cap.grp_set)
628 		argstate_cap_group(argstate, 0);
629 
630 	/*
631 	 * Locate the first entry with the given tag type within the
632 	 * capabilities group.
633 	 */
634 	for (ndx = argstate->cap.grp_start_ndx;
635 	    ndx <= argstate->cap.grp_end_ndx; ndx++) {
636 		if (argstate->cap.data[ndx].c_tag == ca_value) {
637 			elfedit_msg(ELFEDIT_MSG_DEBUG,
638 			    MSG_INTL(MSG_DEBUG_CA2NDX),
639 			    EC_WORD(argstate->cap.sec->sec_shndx),
640 			    argstate->cap.sec->sec_name, EC_WORD(ndx), arg);
641 			return (ndx);
642 		}
643 
644 		/*
645 		 * If we hit a NULL, then only more NULLs can follow it and
646 		 * there's no need to look further. If there is more than
647 		 * one NULL, we can grab the first one and turn it into
648 		 * an element of the desired type.
649 		 */
650 		if (argstate->cap.data[ndx].c_tag == CA_SUNW_NULL) {
651 			if (ndx < argstate->cap.grp_end_ndx) {
652 				Conv_inv_buf_t	inv_buf;
653 
654 				elfedit_msg(ELFEDIT_MSG_DEBUG,
655 				    MSG_INTL(MSG_DEBUG_CONVNULL),
656 				    EC_WORD(argstate->cap.sec->sec_shndx),
657 				    argstate->cap.sec->sec_name, EC_WORD(ndx),
658 				    conv_cap_tag(ca_value, 0, &inv_buf));
659 				argstate->cap.data[ndx].c_tag = ca_value;
660 				bzero(&argstate->cap.data[ndx].c_un,
661 				    sizeof (argstate->cap.data[ndx].c_un));
662 				return (ndx);
663 			}
664 			break;
665 		}
666 	}
667 
668 	/* No room to create one, so we're out of options and must fail */
669 	elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAELT),
670 	    EC_WORD(argstate->cap.sec->sec_shndx),
671 	    argstate->cap.sec->sec_name, argstate->cap.grp_start_ndx,
672 	    argstate->cap.grp_end_ndx, cap_group_id(argstate), arg);
673 
674 	/*NOTREACHED*/
675 	return (0);		/* For lint */
676 }
677 
678 
679 /*
680  * Argument processing for the bitmask commands. Convert the arguments
681  * to integer form, apply -and/-cmp/-or, and return the resulting value.
682  *
683  * entry:
684  *	argstate - Argument state block
685  *	orig - Value of original bitmask
686  *	const_sym - NULL, or array of name->integer mappings for
687  *		applicable symbolic constant names.
688  */
689 static Word
690 flag_bitop(ARGSTATE *argstate, Word orig, const elfedit_atoui_sym_t *const_sym)
691 {
692 	Word flags = 0;
693 	int i;
694 
695 	/* Collect the arguments */
696 	for (i = 0; i < argstate->argc; i++)
697 		flags |= (Word) elfedit_atoui(argstate->argv[i], const_sym);
698 
699 	/* Complement the value? */
700 	if (argstate->optmask & CAP_OPT_F_CMP)
701 		flags = ~flags;
702 
703 	/* Perform any requested bit operations */
704 	if (argstate->optmask & CAP_OPT_F_AND)
705 		flags &= orig;
706 	else if (argstate->optmask & CAP_OPT_F_OR)
707 		flags |= orig;
708 
709 	return (flags);
710 }
711 
712 /*
713  * Common processing for capabilities value setting.
714  *
715  * entry:
716  *	argstate - Argument state block
717  *	cap - capabilities data pointer
718  *	ndx - capabilities data index
719  *	cap_ndx - capabilities section index
720  *	cap_name - capabilities section name
721  *	cap_tag - capabilities tag
722  *	const_type - data conversion type
723  */
724 static elfedit_cmdret_t
725 cap_set(ARGSTATE *argstate, Cap *cap, Word ndx, Word cap_ndx,
726     const char *cap_name, Xword cap_tag, elfedit_const_t const_type)
727 {
728 	Conv_cap_val_buf_t	buf1, buf2;
729 	Half			mach = argstate->obj_state->os_ehdr->e_machine;
730 	Xword			ncap, ocap;
731 
732 	ncap = flag_bitop(argstate, cap[ndx].c_un.c_val,
733 	    elfedit_const_to_atoui(const_type));
734 
735 	/* Set the value */
736 	if ((ocap = cap[ndx].c_un.c_val) == ncap) {
737 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BSB_OK),
738 		    cap_ndx, cap_name, EC_WORD(ndx),
739 		    conv_cap_val(cap_tag, ocap, mach, CONV_FMT_NOBKT, &buf1));
740 
741 		return (ELFEDIT_CMDRET_NONE);
742 	} else {
743 		elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_BSB_CHG),
744 		    cap_ndx, cap_name, EC_WORD(ndx),
745 		    conv_cap_val(cap_tag, ocap, mach, CONV_FMT_NOBKT, &buf1),
746 		    conv_cap_val(cap_tag, ncap, mach, CONV_FMT_NOBKT, &buf2));
747 
748 		cap[ndx].c_un.c_val = ncap;
749 		return (ELFEDIT_CMDRET_MOD);
750 	}
751 }
752 
753 /*
754  * Common body for the cap: module commands. These commands
755  * share a large amount of common behavior, so it is convenient
756  * to centralize things and use the cmd argument to handle the
757  * small differences.
758  *
759  * entry:
760  *	cmd - One of the CAP_CMD_T_* constants listed above, specifying
761  *		which command to implement.
762  *	obj_state, argc, argv - Standard command arguments
763  */
764 static elfedit_cmdret_t
765 cmd_body(CAP_CMD_T cmd, elfedit_obj_state_t *obj_state,
766     int argc, const char *argv[])
767 {
768 	ARGSTATE		argstate;
769 	Cap			*cap;
770 	const char		*cap_name;
771 	Word			cap_ndx;
772 	elfedit_cmdret_t	ret = ELFEDIT_CMDRET_NONE;
773 	PRINT_CAP_T		print_type = PRINT_CAP_T_ALL;
774 	Word			ndx;
775 	int			print_only = 0;
776 	int			do_autoprint = 1;
777 
778 	/* Process the optional arguments */
779 	process_args(obj_state, argc, argv, &argstate);
780 
781 	cap = argstate.cap.data;
782 	cap_name = argstate.cap.sec->sec_name;
783 	cap_ndx = argstate.cap.sec->sec_shndx;
784 
785 	/* Check number of arguments, gather information */
786 	switch (cmd) {
787 	case CAP_CMD_T_DUMP:
788 		/* cap:dump can accept an optional index argument */
789 		if (argstate.argc > 1)
790 			elfedit_command_usage();
791 		print_only = 1;
792 		if (argstate.argc == 1)
793 			ndx = arg_to_index(&argstate, argstate.argv[0],
794 			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
795 		break;
796 
797 	case CAP_CMD_T_TAG:
798 	case CAP_CMD_T_VALUE:
799 		print_only = (argstate.argc != 2);
800 		if (argstate.argc > 0) {
801 			if (argstate.argc > 2)
802 				elfedit_command_usage();
803 			ndx = arg_to_index(&argstate, argstate.argv[0],
804 			    MSG_ORIG(MSG_STR_ELT), print_only, &print_type);
805 		}
806 		break;
807 
808 	case CAP_CMD_T_DELETE:
809 		if ((argstate.argc < 1) || (argstate.argc > 2))
810 			elfedit_command_usage();
811 		ndx = arg_to_index(&argstate, argstate.argv[0],
812 		    MSG_ORIG(MSG_STR_ELT),
813 		    0, &print_type);
814 		do_autoprint = 0;
815 		break;
816 
817 	case CAP_CMD_T_MOVE:
818 		if ((argstate.argc < 2) || (argstate.argc > 3))
819 			elfedit_command_usage();
820 		ndx = arg_to_index(&argstate, argstate.argv[0],
821 		    MSG_ORIG(MSG_STR_ELT), 0, &print_type);
822 		do_autoprint = 0;
823 		break;
824 
825 	case CAP_CMD_T_HW1:
826 		print_only = (argstate.argc == 0);
827 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
828 		    ELFEDIT_CONST_CA, CA_SUNW_HW_1, 1),
829 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
830 		break;
831 
832 	case CAP_CMD_T_SF1:
833 		print_only = (argstate.argc == 0);
834 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
835 		    ELFEDIT_CONST_CA, CA_SUNW_SF_1, 1),
836 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
837 		break;
838 
839 	case CAP_CMD_T_HW2:
840 		print_only = (argstate.argc == 0);
841 		ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str(
842 		    ELFEDIT_CONST_CA, CA_SUNW_HW_2, 1),
843 		    MSG_ORIG(MSG_STR_VALUE), print_only, &print_type);
844 		break;
845 
846 	default:
847 		/* Note expected: All commands should have been caught above */
848 		elfedit_command_usage();
849 		break;
850 	}
851 
852 
853 	/* If this is a request to print current values, do it and return */
854 	if (print_only) {
855 		print_cap(cmd, 0, &argstate, print_type, ndx);
856 		return (ELFEDIT_CMDRET_NONE);
857 	}
858 
859 
860 	switch (cmd) {
861 		/*
862 		 * CAP_CMD_T_DUMP can't get here: It is a print-only
863 		 * command.
864 		 */
865 
866 	case CAP_CMD_T_TAG:
867 		{
868 			Conv_inv_buf_t	inv_buf1, inv_buf2;
869 			Word c_tag = (Word) elfedit_atoconst(argstate.argv[1],
870 			    ELFEDIT_CONST_CA);
871 
872 			if (cap[ndx].c_tag == c_tag) {
873 				elfedit_msg(ELFEDIT_MSG_DEBUG,
874 				    MSG_INTL(MSG_DEBUG_S_OK),
875 				    cap_ndx, cap_name, EC_WORD(ndx),
876 				    conv_cap_tag(c_tag, 0, &inv_buf1));
877 			} else {
878 				elfedit_msg(ELFEDIT_MSG_DEBUG,
879 				    MSG_INTL(MSG_DEBUG_S_CHG),
880 				    cap_ndx, cap_name, EC_WORD(ndx),
881 				    conv_cap_tag(cap[ndx].c_tag, 0, &inv_buf1),
882 				    conv_cap_tag(c_tag, 0, &inv_buf2));
883 				cap[ndx].c_tag = c_tag;
884 				ret = ELFEDIT_CMDRET_MOD;
885 			}
886 		}
887 		break;
888 
889 	case CAP_CMD_T_VALUE:
890 		{
891 			Xword c_val;
892 
893 			if (argstate.optmask & CAP_OPT_F_STRVAL) {
894 				argstate_add_str(&argstate, TRUE);
895 				c_val = elfedit_strtab_insert(obj_state,
896 				    argstate.str.sec, NULL, argstate.argv[1]);
897 			} else {
898 				c_val = (Xword)
899 				    elfedit_atoui(argstate.argv[1], NULL);
900 			}
901 
902 			if (cap[ndx].c_un.c_val == c_val) {
903 				elfedit_msg(ELFEDIT_MSG_DEBUG,
904 				    MSG_INTL(MSG_DEBUG_X_OK),
905 				    argstate.cap.sec->sec_shndx,
906 				    argstate.cap.sec->sec_name,
907 				    EC_WORD(ndx), EC_XWORD(c_val));
908 			} else {
909 				elfedit_msg(ELFEDIT_MSG_DEBUG,
910 				    MSG_INTL(MSG_DEBUG_X_CHG),
911 				    argstate.cap.sec->sec_shndx,
912 				    argstate.cap.sec->sec_name,
913 				    EC_WORD(ndx), EC_XWORD(cap[ndx].c_un.c_val),
914 				    EC_XWORD(c_val));
915 				cap[ndx].c_un.c_val = c_val;
916 				ret = ELFEDIT_CMDRET_MOD;
917 			}
918 		}
919 		break;
920 
921 	case CAP_CMD_T_DELETE:
922 		{
923 			Word cnt = (argstate.argc == 1) ? 1 :
924 			    (Word) elfedit_atoui_range(argstate.argv[1],
925 			    MSG_ORIG(MSG_STR_COUNT), 1,
926 			    argstate.cap.grp_end_ndx - ndx + 1, NULL);
927 			const char *msg_prefix =
928 			    elfedit_sec_msgprefix(argstate.cap.sec);
929 
930 			/*
931 			 * We want to limit the deleted elements to be
932 			 * in the range of the current capabilities group,
933 			 * and for the resulting NULL elements to be inserted
934 			 * at the end of the group, rather than at the end
935 			 * of the section. To do this, we set the array length
936 			 * in the call to the delete function so that it thinks
937 			 * the array ends with the current group.
938 			 *
939 			 * The delete function will catch attempts to delete
940 			 * past this virtual end, but the error message will
941 			 * not make sense to the user. In order to prevent that,
942 			 * we check for the condition here and provide a more
943 			 * useful error.
944 			 */
945 			if ((ndx + cnt - 1) > argstate.cap.grp_end_ndx)
946 				elfedit_msg(ELFEDIT_MSG_ERR,
947 				    MSG_INTL(MSG_ERR_GRPARRBNDS), msg_prefix,
948 				    argstate.cap.grp_start_ndx,
949 				    argstate.cap.grp_end_ndx,
950 				    cap_group_id(&argstate));
951 			elfedit_array_elts_delete(msg_prefix, cap, sizeof (Cap),
952 			    argstate.cap.grp_end_ndx + 1, ndx, cnt);
953 			ret = ELFEDIT_CMDRET_MOD;
954 		}
955 		break;
956 
957 	case CAP_CMD_T_MOVE:
958 		{
959 			Cap	save;
960 			Word	cnt;
961 			Word	dstndx;
962 			const char *msg_prefix =
963 			    elfedit_sec_msgprefix(argstate.cap.sec);
964 
965 			dstndx = (Word)
966 			    elfedit_atoui_range(argstate.argv[1],
967 			    MSG_ORIG(MSG_STR_DST_INDEX),
968 			    argstate.cap.grp_start_ndx,
969 			    argstate.cap.grp_end_ndx, NULL);
970 			if (argstate.argc == 2) {
971 				cnt = 1;
972 			} else {
973 				Word max;
974 
975 				max = argstate.cap.grp_end_ndx -
976 				    ((ndx > dstndx) ? ndx : dstndx) + 1;
977 				cnt = (Word) elfedit_atoui_range(
978 				    argstate.argv[2], MSG_ORIG(MSG_STR_COUNT),
979 				    1, max, NULL);
980 			}
981 
982 			/*
983 			 * Moves are required to be self contained within
984 			 * the bounds of the selected capability group.
985 			 * The move utility function contains bounds checking,
986 			 * but is not sub-array aware. Hence, we bounds check
987 			 * check it here, and then hand of the validated
988 			 * operation to the move utility function to execute.
989 			 */
990 			if ((ndx < argstate.cap.grp_start_ndx) ||
991 			    ((ndx + cnt) > argstate.cap.grp_end_ndx) ||
992 			    (dstndx < argstate.cap.grp_start_ndx) ||
993 			    ((dstndx + cnt) > argstate.cap.grp_end_ndx))
994 				elfedit_msg(ELFEDIT_MSG_ERR,
995 				    MSG_INTL(MSG_ERR_GRPARRBNDS), msg_prefix,
996 				    argstate.cap.grp_start_ndx,
997 				    argstate.cap.grp_end_ndx,
998 				    cap_group_id(&argstate));
999 			elfedit_array_elts_move(msg_prefix, cap, sizeof (save),
1000 			    argstate.cap.grp_end_ndx + 1, ndx, dstndx,
1001 			    cnt, &save);
1002 			ret = ELFEDIT_CMDRET_MOD;
1003 		}
1004 		break;
1005 
1006 
1007 	case CAP_CMD_T_HW1:
1008 		{
1009 			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
1010 			    CA_SUNW_HW_1, ELFEDIT_CONST_HW1_SUNW);
1011 		}
1012 		break;
1013 
1014 	case CAP_CMD_T_SF1:
1015 		{
1016 			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
1017 			    CA_SUNW_SF_1, ELFEDIT_CONST_SF1_SUNW);
1018 		}
1019 		break;
1020 
1021 	case CAP_CMD_T_HW2:
1022 		{
1023 			ret = cap_set(&argstate, cap, ndx, cap_ndx, cap_name,
1024 			    CA_SUNW_HW_2, ELFEDIT_CONST_HW2_SUNW);
1025 		}
1026 		break;
1027 	}
1028 
1029 	/*
1030 	 * If we modified the capabilities section header, tell libelf.
1031 	 */
1032 	if (ret == ELFEDIT_CMDRET_MOD)
1033 		elfedit_modified_data(argstate.cap.sec);
1034 
1035 	/* Do autoprint */
1036 	if (do_autoprint)
1037 		print_cap(cmd, 1, &argstate, print_type, ndx);
1038 
1039 	return (ret);
1040 }
1041 
1042 
1043 
1044 /*
1045  * Command completion functions for the commands
1046  */
1047 
1048 /*
1049  * -capid command completion: Supply all CA_SUNW_ID names found in the object.
1050  */
1051 static void
1052 cpl_capid_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1053     const char *argv[], int num_opt)
1054 {
1055 	elfedit_section_t	*cap_sec, *str_sec;
1056 	Cap			*cap;
1057 	Word			num;
1058 
1059 	if (obj_state == NULL)	 /* No object available */
1060 		return;
1061 
1062 	if ((argc > num_opt) || (argc < 2) ||
1063 	    (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_CAPID)) != 0))
1064 		return;
1065 
1066 	cap_sec = elfedit_sec_getcap(obj_state, &cap, &num);
1067 
1068 	/* If no associated string table, we have no strings to complete */
1069 	if (cap_sec->sec_shdr->sh_info == 0)
1070 		return;
1071 
1072 	str_sec = elfedit_sec_getstr(obj_state, cap_sec->sec_shdr->sh_info, 0);
1073 
1074 	for (; num--; cap++)
1075 		if (cap->c_tag == CA_SUNW_ID)
1076 			elfedit_cpl_match(cpldata, elfedit_offset_to_str(
1077 			    str_sec, cap->c_un.c_val, ELFEDIT_MSG_ERR, 0), 0);
1078 }
1079 
1080 /*
1081  * Command completion for the first argument, which specifies
1082  * the capabilities element to use. Examines the options to see if
1083  * -capndx is present, and if not, supplies the completion
1084  * strings for argument 1.
1085  */
1086 /*ARGSUSED*/
1087 static void
1088 cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1089     const char *argv[], int num_opt)
1090 {
1091 	Word	i;
1092 
1093 	/* -capid id_name */
1094 	if (argc <= num_opt) {
1095 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1096 		return;
1097 	}
1098 
1099 	/* Make sure it's the first argument */
1100 	if ((argc - num_opt) != 1)
1101 		return;
1102 
1103 	/* Is -capndx present? If so, we don't complete tag types */
1104 	for (i = 0; i < num_opt; i++)
1105 		if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_CAPNDX)) == 0)
1106 			return;
1107 
1108 	/*
1109 	 * Supply capability tag names. There are very few of these, so
1110 	 * rather than worry about whether a given tag exists in the
1111 	 * file or not, we simply serve up all the possibilities.
1112 	 */
1113 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
1114 }
1115 
1116 /*ARGSUSED*/
1117 static void
1118 cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1119     const char *argv[], int num_opt)
1120 {
1121 	/* -capid id_name */
1122 	if (argc <= num_opt) {
1123 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1124 		return;
1125 	}
1126 
1127 	/* First plain argument */
1128 	if ((argc - num_opt) == 1) {
1129 		cpl_eltarg(obj_state, cpldata, argc, argv, num_opt);
1130 		return;
1131 	}
1132 
1133 	/* The second argument is always a tag value */
1134 	if ((argc - num_opt) == 2)
1135 		elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_CA);
1136 }
1137 
1138 /*ARGSUSED*/
1139 static void
1140 cpl_hw1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1141     const char *argv[], int num_opt)
1142 {
1143 	/* -capid id_name */
1144 	if (argc <= num_opt) {
1145 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1146 		return;
1147 	}
1148 
1149 	/* This routine allows multiple flags to be specified */
1150 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW1_SUNW);
1151 }
1152 
1153 /*ARGSUSED*/
1154 static void
1155 cpl_sf1(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1156     const char *argv[], int num_opt)
1157 {
1158 	/* -capid id_name */
1159 	if (argc <= num_opt) {
1160 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1161 		return;
1162 	}
1163 
1164 	/* This routine allows multiple flags to be specified */
1165 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SF1_SUNW);
1166 }
1167 
1168 /*ARGSUSED*/
1169 static void
1170 cpl_hw2(elfedit_obj_state_t *obj_state, void *cpldata, int argc,
1171     const char *argv[], int num_opt)
1172 {
1173 	/* -capid id_name */
1174 	if (argc <= num_opt) {
1175 		cpl_capid_opt(obj_state, cpldata, argc, argv, num_opt);
1176 		return;
1177 	}
1178 
1179 	/* This routine allows multiple flags to be specified */
1180 	elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_HW2_SUNW);
1181 }
1182 
1183 /*
1184  * Implementation functions for the commands
1185  */
1186 static elfedit_cmdret_t
1187 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1188 {
1189 	return (cmd_body(CAP_CMD_T_DUMP, obj_state, argc, argv));
1190 }
1191 
1192 static elfedit_cmdret_t
1193 cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1194 {
1195 	return (cmd_body(CAP_CMD_T_TAG, obj_state, argc, argv));
1196 }
1197 
1198 static elfedit_cmdret_t
1199 cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1200 {
1201 	return (cmd_body(CAP_CMD_T_VALUE, obj_state, argc, argv));
1202 }
1203 
1204 static elfedit_cmdret_t
1205 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1206 {
1207 	return (cmd_body(CAP_CMD_T_DELETE, obj_state, argc, argv));
1208 }
1209 
1210 static elfedit_cmdret_t
1211 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1212 {
1213 	return (cmd_body(CAP_CMD_T_MOVE, obj_state, argc, argv));
1214 }
1215 
1216 static elfedit_cmdret_t
1217 cmd_hw1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1218 {
1219 	return (cmd_body(CAP_CMD_T_HW1, obj_state, argc, argv));
1220 }
1221 
1222 static elfedit_cmdret_t
1223 cmd_sf1(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1224 {
1225 	return (cmd_body(CAP_CMD_T_SF1, obj_state, argc, argv));
1226 }
1227 
1228 static elfedit_cmdret_t
1229 cmd_hw2(elfedit_obj_state_t *obj_state, int argc, const char *argv[])
1230 {
1231 	return (cmd_body(CAP_CMD_T_HW2, obj_state, argc, argv));
1232 }
1233 
1234 /*ARGSUSED*/
1235 elfedit_module_t *
1236 elfedit_init(elfedit_module_version_t version)
1237 {
1238 	/* For commands that only accept -capid, -and, -cmp, -o, and -or */
1239 	static elfedit_cmd_optarg_t opt_ostyle_capid_bitop[] = {
1240 		{ ELFEDIT_STDOA_OPT_AND, 0,
1241 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_AND, CAP_OPT_F_OR },
1242 		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
1243 		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
1244 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
1245 		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
1246 		{ MSG_ORIG(MSG_STR_IDNAME), 0, 0 },
1247 		{ ELFEDIT_STDOA_OPT_CMP, 0,
1248 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_CMP, 0 },
1249 		{ ELFEDIT_STDOA_OPT_O, 0,
1250 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1251 		{ ELFEDIT_STDOA_OPT_OR, 0,
1252 		    ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_OR, CAP_OPT_F_AND },
1253 		{ NULL }
1254 	};
1255 
1256 	/* For commands that only accept -capid and -capndx */
1257 	static elfedit_cmd_optarg_t opt_capid_capndx[] = {
1258 		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
1259 		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
1260 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
1261 		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
1262 		{ MSG_ORIG(MSG_STR_IDNAME), 0, 0 },
1263 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
1264 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
1265 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
1266 		    CAP_OPT_F_CAPNDX, CAP_OPT_F_CAPID },
1267 		{ NULL }
1268 	};
1269 
1270 
1271 	/* cap:dump */
1272 	static const char *name_dump[] = {
1273 	    MSG_ORIG(MSG_CMD_DUMP),
1274 	    MSG_ORIG(MSG_STR_EMPTY),	/* "" makes this the default command */
1275 	    NULL
1276 	};
1277 	static elfedit_cmd_optarg_t arg_dump[] = {
1278 		{ MSG_ORIG(MSG_STR_ELT),
1279 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1280 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1281 		    ELFEDIT_CMDOA_F_OPT },
1282 		{ NULL }
1283 	};
1284 
1285 
1286 	/* cap:tag */
1287 	static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL };
1288 	static elfedit_cmd_optarg_t opt_tag[] = {
1289 		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
1290 		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
1291 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
1292 		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
1293 		{ MSG_ORIG(MSG_STR_IDNAME), 0, 0 },
1294 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
1295 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
1296 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
1297 		    CAP_OPT_F_CAPNDX, 0 },
1298 		{ ELFEDIT_STDOA_OPT_O, 0,
1299 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1300 		{ NULL }
1301 	};
1302 	static elfedit_cmd_optarg_t arg_tag[] = {
1303 		{ MSG_ORIG(MSG_STR_ELT),
1304 		    /* MSG_INTL(MSG_A1_TAG_ELT) */
1305 		    ELFEDIT_I18NHDL(MSG_A1_TAG_ELT),
1306 		    ELFEDIT_CMDOA_F_OPT },
1307 		{ MSG_ORIG(MSG_STR_VALUE),
1308 		    /* MSG_INTL(MSG_A2_TAG_VALUE) */
1309 		    ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE),
1310 		    ELFEDIT_CMDOA_F_OPT },
1311 		{ NULL }
1312 	};
1313 
1314 
1315 	/* cap:value */
1316 	static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL };
1317 	static elfedit_cmd_optarg_t opt_value[] = {
1318 		{ MSG_ORIG(MSG_STR_MINUS_CAPID),
1319 		    /* MSG_INTL(MSG_OPTDESC_CAPID) */
1320 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPID), ELFEDIT_CMDOA_F_VALUE,
1321 		    CAP_OPT_F_CAPID, CAP_OPT_F_CAPNDX },
1322 		{ MSG_ORIG(MSG_STR_IDNAME), 0, 0 },
1323 		{ MSG_ORIG(MSG_STR_MINUS_CAPNDX),
1324 		    /* MSG_INTL(MSG_OPTDESC_CAPNDX) */
1325 		    ELFEDIT_I18NHDL(MSG_OPTDESC_CAPNDX), 0,
1326 		    CAP_OPT_F_CAPNDX, 0 },
1327 		{ ELFEDIT_STDOA_OPT_O, 0,
1328 		    ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1329 		{ MSG_ORIG(MSG_STR_MINUS_S),
1330 		    /* MSG_INTL(MSG_OPTDESC_S) */
1331 		    ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0,
1332 		    CAP_OPT_F_STRVAL, 0 },
1333 		{ NULL }
1334 	};
1335 	static elfedit_cmd_optarg_t arg_value[] = {
1336 		{ MSG_ORIG(MSG_STR_ELT),
1337 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1338 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1339 		    ELFEDIT_CMDOA_F_OPT },
1340 		{ MSG_ORIG(MSG_STR_VALUE),
1341 		    /* MSG_INTL(MSG_A2_VALUE_VALUE) */
1342 		    ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE),
1343 		    ELFEDIT_CMDOA_F_OPT },
1344 		{ NULL }
1345 	};
1346 
1347 	/* cap:delete */
1348 	static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL };
1349 	static elfedit_cmd_optarg_t arg_delete[] = {
1350 		{ MSG_ORIG(MSG_STR_ELT),
1351 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1352 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1353 		    0 },
1354 		{ MSG_ORIG(MSG_STR_COUNT),
1355 		    /* MSG_INTL(MSG_A2_DELETE_COUNT) */
1356 		    ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT),
1357 		    ELFEDIT_CMDOA_F_OPT },
1358 		{ NULL }
1359 	};
1360 
1361 	/* cap:move */
1362 	static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL };
1363 	static elfedit_cmd_optarg_t arg_move[] = {
1364 		{ MSG_ORIG(MSG_STR_ELT),
1365 		    /* MSG_INTL(MSG_ARGDESC_ELT) */
1366 		    ELFEDIT_I18NHDL(MSG_ARGDESC_ELT),
1367 		    0 },
1368 		{ MSG_ORIG(MSG_STR_DST_INDEX),
1369 		    /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */
1370 		    ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX),
1371 		    0 },
1372 		{ MSG_ORIG(MSG_STR_COUNT),
1373 		    /* MSG_INTL(MSG_A3_MOVE_COUNT) */
1374 		    ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT),
1375 		    ELFEDIT_CMDOA_F_OPT },
1376 		{ NULL }
1377 	};
1378 
1379 	/* cap:hw1 */
1380 	static const char *name_hw1[] = { MSG_ORIG(MSG_CMD_HW1), NULL };
1381 	static elfedit_cmd_optarg_t arg_hw1[] = {
1382 		{ MSG_ORIG(MSG_STR_VALUE),
1383 		    /* MSG_INTL(MSG_A1_HW1_VALUE) */
1384 		    ELFEDIT_I18NHDL(MSG_A1_HW1_VALUE),
1385 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1386 		{ NULL }
1387 	};
1388 
1389 	/* cap:sf1 */
1390 	static const char *name_sf1[] = { MSG_ORIG(MSG_CMD_SF1), NULL };
1391 	static elfedit_cmd_optarg_t arg_sf1[] = {
1392 		{ MSG_ORIG(MSG_STR_VALUE),
1393 		    /* MSG_INTL(MSG_A1_SF1_VALUE) */
1394 		    ELFEDIT_I18NHDL(MSG_A1_SF1_VALUE),
1395 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1396 		{ NULL }
1397 	};
1398 
1399 	/* cap:hw2 */
1400 	static const char *name_hw2[] = { MSG_ORIG(MSG_CMD_HW2), NULL };
1401 	static elfedit_cmd_optarg_t arg_hw2[] = {
1402 		{ MSG_ORIG(MSG_STR_VALUE),
1403 		    /* MSG_INTL(MSG_A1_HW2_VALUE) */
1404 		    ELFEDIT_I18NHDL(MSG_A1_HW2_VALUE),
1405 		    ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT },
1406 		{ NULL }
1407 	};
1408 
1409 
1410 	static elfedit_cmd_t cmds[] = {
1411 		/* cap:dump */
1412 		{ cmd_dump, cpl_eltarg, name_dump,
1413 		    /* MSG_INTL(MSG_DESC_DUMP) */
1414 		    ELFEDIT_I18NHDL(MSG_DESC_DUMP),
1415 		    /* MSG_INTL(MSG_HELP_DUMP) */
1416 		    ELFEDIT_I18NHDL(MSG_HELP_DUMP),
1417 		    opt_capid_capndx, arg_dump },
1418 
1419 		/* cap:tag */
1420 		{ cmd_tag, cpl_tag, name_tag,
1421 		    /* MSG_INTL(MSG_DESC_TAG) */
1422 		    ELFEDIT_I18NHDL(MSG_DESC_TAG),
1423 		    /* MSG_INTL(MSG_HELP_TAG) */
1424 		    ELFEDIT_I18NHDL(MSG_HELP_TAG),
1425 		    opt_tag, arg_tag },
1426 
1427 		/* cap:value */
1428 		{ cmd_value, cpl_eltarg, name_value,
1429 		    /* MSG_INTL(MSG_DESC_VALUE) */
1430 		    ELFEDIT_I18NHDL(MSG_DESC_VALUE),
1431 		    /* MSG_INTL(MSG_HELP_VALUE) */
1432 		    ELFEDIT_I18NHDL(MSG_HELP_VALUE),
1433 		    opt_value, arg_value },
1434 
1435 		/* cap:delete */
1436 		{ cmd_delete, cpl_eltarg, name_delete,
1437 		    /* MSG_INTL(MSG_DESC_DELETE) */
1438 		    ELFEDIT_I18NHDL(MSG_DESC_DELETE),
1439 		    /* MSG_INTL(MSG_HELP_DELETE) */
1440 		    ELFEDIT_I18NHDL(MSG_HELP_DELETE),
1441 		    opt_capid_capndx, arg_delete },
1442 
1443 		/* cap:move */
1444 		{ cmd_move, cpl_eltarg, name_move,
1445 		    /* MSG_INTL(MSG_DESC_MOVE) */
1446 		    ELFEDIT_I18NHDL(MSG_DESC_MOVE),
1447 		    /* MSG_INTL(MSG_HELP_MOVE) */
1448 		    ELFEDIT_I18NHDL(MSG_HELP_MOVE),
1449 		    opt_capid_capndx, arg_move },
1450 
1451 		/* cap:hw1 */
1452 		{ cmd_hw1, cpl_hw1, name_hw1,
1453 		    /* MSG_INTL(MSG_DESC_HW1) */
1454 		    ELFEDIT_I18NHDL(MSG_DESC_HW1),
1455 		    /* MSG_INTL(MSG_HELP_HW1) */
1456 		    ELFEDIT_I18NHDL(MSG_HELP_HW1),
1457 		    opt_ostyle_capid_bitop, arg_hw1 },
1458 
1459 		/* cap:sf1 */
1460 		{ cmd_sf1, cpl_sf1, name_sf1,
1461 		    /* MSG_INTL(MSG_DESC_SF1) */
1462 		    ELFEDIT_I18NHDL(MSG_DESC_SF1),
1463 		    /* MSG_INTL(MSG_HELP_SF1) */
1464 		    ELFEDIT_I18NHDL(MSG_HELP_SF1),
1465 		    opt_ostyle_capid_bitop, arg_sf1 },
1466 
1467 		/* cap:hw2 */
1468 		{ cmd_hw2, cpl_hw2, name_hw2,
1469 		    /* MSG_INTL(MSG_DESC_HW2) */
1470 		    ELFEDIT_I18NHDL(MSG_DESC_HW2),
1471 		    /* MSG_INTL(MSG_HELP_HW2) */
1472 		    ELFEDIT_I18NHDL(MSG_HELP_HW2),
1473 		    opt_ostyle_capid_bitop, arg_hw2 },
1474 
1475 		{ NULL }
1476 	};
1477 
1478 	static elfedit_module_t module = {
1479 	    ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME),
1480 	    /* MSG_INTL(MSG_MOD_DESC) */
1481 	    ELFEDIT_I18NHDL(MSG_MOD_DESC),
1482 	    cmds, mod_i18nhdl_to_str };
1483 
1484 	return (&module);
1485 }
1486