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 * 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 * 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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