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