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