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 *
_cap_msg(Msg mid)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 *
mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl)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
argstate_add_str(ARGSTATE * argstate,Boolean required)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
cap_group_extents(ARGSTATE * argstate,Word ndx,Word * ret_start_ndx,Word * ret_end_ndx)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 *
cap_group_id(ARGSTATE * argstate)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
argstate_cap_group(ARGSTATE * argstate,Word ndx)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
group_title(ARGSTATE * argstate,Word ndx)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
process_args(elfedit_obj_state_t * obj_state,int argc,const char * argv[],ARGSTATE * argstate)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
print_cap(CAP_CMD_T cmd,int autoprint,ARGSTATE * argstate,PRINT_CAP_T print_type,Word arg)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
arg_to_index(ARGSTATE * argstate,const char * arg,const char * argname,int print_request,PRINT_CAP_T * print_type)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
flag_bitop(ARGSTATE * argstate,Word orig,const elfedit_atoui_sym_t * const_sym)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
cap_set(ARGSTATE * argstate,Cap * cap,Word ndx,Word cap_ndx,const char * cap_name,Xword cap_tag,elfedit_const_t const_type)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
cmd_body(CAP_CMD_T cmd,elfedit_obj_state_t * obj_state,int argc,const char * argv[])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
cpl_capid_opt(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)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
cpl_eltarg(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)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
cpl_tag(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)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
cpl_hw1(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)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
cpl_sf1(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)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
cpl_hw2(elfedit_obj_state_t * obj_state,void * cpldata,int argc,const char * argv[],int num_opt)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
cmd_dump(elfedit_obj_state_t * obj_state,int argc,const char * argv[])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
cmd_tag(elfedit_obj_state_t * obj_state,int argc,const char * argv[])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
cmd_value(elfedit_obj_state_t * obj_state,int argc,const char * argv[])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
cmd_delete(elfedit_obj_state_t * obj_state,int argc,const char * argv[])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
cmd_move(elfedit_obj_state_t * obj_state,int argc,const char * argv[])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
cmd_hw1(elfedit_obj_state_t * obj_state,int argc,const char * argv[])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
cmd_sf1(elfedit_obj_state_t * obj_state,int argc,const char * argv[])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
cmd_hw2(elfedit_obj_state_t * obj_state,int argc,const char * argv[])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 *
elfedit_init(elfedit_module_version_t version)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, NULL,
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), NULL, 0 },
1247 { ELFEDIT_STDOA_OPT_CMP, NULL,
1248 ELFEDIT_CMDOA_F_INHERIT, CAP_OPT_F_CMP, 0 },
1249 { ELFEDIT_STDOA_OPT_O, NULL,
1250 ELFEDIT_CMDOA_F_INHERIT, 0, 0 },
1251 { ELFEDIT_STDOA_OPT_OR, NULL,
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), NULL, 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), NULL, 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, NULL,
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), NULL, 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, NULL,
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