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