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