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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <ctype.h> 29 #include <machdep.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 <dyn_msg.h> 36 37 38 /* 39 * Dynamic 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 DYN_CMD_T_DUMP = 0, /* dyn:dump */ 53 54 /* Commands that do not correspond directly to a specific DT tag */ 55 DYN_CMD_T_TAG = 1, /* dyn:tag */ 56 DYN_CMD_T_VALUE = 2, /* dyn:value */ 57 DYN_CMD_T_DELETE = 3, /* dyn:delete */ 58 DYN_CMD_T_MOVE = 4, /* dyn:shift */ 59 60 /* Commands that embody tag specific knowledge */ 61 DYN_CMD_T_RUNPATH = 5, /* dyn:runpath/rpath */ 62 DYN_CMD_T_POSFLAG1 = 6, /* dyn:posflag1 */ 63 DYN_CMD_T_FLAGS = 7, /* dyn:flags */ 64 DYN_CMD_T_FLAGS1 = 8, /* dyn:flags1 */ 65 DYN_CMD_T_FEATURE1 = 9, /* dyn:feature1 */ 66 DYN_CMD_T_CHECKSUM = 10 /* dyn:checksum */ 67 } DYN_CMD_T; 68 69 70 71 #ifndef _ELF64 72 /* 73 * We supply this function for the msg module 74 */ 75 const char * 76 _dyn_msg(Msg mid) 77 { 78 return (gettext(MSG_ORIG(mid))); 79 } 80 #endif 81 82 83 /* 84 * This function is supplied to elfedit through our elfedit_module_t 85 * definition. It translates the opaque elfedit_i18nhdl_t handles 86 * in our module interface into the actual strings for elfedit to 87 * use. 88 * 89 * note: 90 * This module uses Msg codes for its i18n handle type. 91 * So the translation is simply to use MSG_INTL() to turn 92 * it into a string and return it. 93 */ 94 static const char * 95 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl) 96 { 97 Msg msg = (Msg)hdl; 98 99 return (MSG_INTL(msg)); 100 } 101 102 103 104 /* 105 * The dyn_opt_t enum specifies a bit value for every optional 106 * argument allowed by a command in this module. 107 */ 108 typedef enum { 109 DYN_OPT_F_ADD = 1, /* -add: Add new elt rather than */ 110 /* modifying an existing one */ 111 DYN_OPT_F_AND = 2, /* -and: AND (&) values to dest */ 112 DYN_OPT_F_CMP = 4, /* -cmp: Complement (~) values */ 113 DYN_OPT_F_DYNNDX = 8, /* -dynndx: elt is tag index, */ 114 /* not name */ 115 DYN_OPT_F_OR = 16, /* -or: OR (|) values to dest */ 116 DYN_OPT_F_STRVAL = 32 /* -s: value is string, not integer */ 117 } dyn_opt_t; 118 119 120 /* 121 * A variable of type ARGSTATE is used by each command to maintain 122 * information about the arguments and related things. It is 123 * initialized by process_args(), and used by the other routines. 124 */ 125 typedef struct { 126 elfedit_obj_state_t *obj_state; 127 elfedit_section_t *strsec; /* Dynamic string table ref */ 128 struct { 129 elfedit_section_t *sec; /* Dynamic section reference */ 130 Dyn *data; /* Start dynamic section data */ 131 Word num; /* # dynamic elts */ 132 Word null_ndx; /* Index of first DT_NULL */ 133 Word num_null_ndx; /* # of DT_NULL elements */ 134 } dyn; 135 dyn_opt_t optmask; /* Mask of options used */ 136 int argc; /* # of plain arguments */ 137 const char **argv; /* Plain arguments */ 138 } ARGSTATE; 139 140 141 142 /* 143 * Set argstate null_ndx field for current dynamic area 144 */ 145 static void 146 set_null_ndx(ARGSTATE *argstate) 147 { 148 Word num, null_ndx; 149 150 num = argstate->dyn.num; 151 argstate->dyn.num_null_ndx = 0; 152 for (null_ndx = 0; null_ndx < num; null_ndx++) 153 if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) { 154 argstate->dyn.num_null_ndx++; 155 break; 156 } 157 argstate->dyn.null_ndx = null_ndx; 158 159 /* Count the number of remaining DT_NULL items */ 160 for (; null_ndx < num; null_ndx++) 161 if (argstate->dyn.data[null_ndx].d_tag == DT_NULL) 162 argstate->dyn.num_null_ndx++; 163 } 164 165 166 /* 167 * Convert the first available DT_NULL slot in the dynamic section 168 * into something else. 169 * 170 * entry: 171 * argstate - Argument state block 172 * d_tag, d_val - Values to be set in new element 173 * 174 * exit: 175 * If an extra DT_NULL slot is available, a debug message is 176 * issued, the slot is converted to its new use, and the argstate 177 * block state related to DT_NULL slots is updated. 178 * 179 * if no extra DT_NULL slot is present, an error is issued and 180 * this routine does not return to the caller. 181 */ 182 static Word 183 convert_dt_null(ARGSTATE *argstate, Word d_tag, Xword d_val) 184 { 185 Conv_inv_buf_t inv_buf; 186 Word ndx; 187 Dyn *dyn; 188 189 /* If we lack an extra element, we can't continue */ 190 if (argstate->dyn.num_null_ndx <= 1) 191 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL), 192 EC_WORD(argstate->dyn.sec->sec_shndx), 193 argstate->dyn.sec->sec_name); 194 195 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL), 196 EC_WORD(argstate->dyn.sec->sec_shndx), argstate->dyn.sec->sec_name, 197 EC_WORD(argstate->dyn.null_ndx), conv_dyn_tag(d_tag, 198 argstate->obj_state->os_ehdr->e_machine, 0, &inv_buf)); 199 200 ndx = argstate->dyn.null_ndx; 201 dyn = &argstate->dyn.data[ndx]; 202 dyn->d_tag = d_tag; 203 dyn->d_un.d_val = d_val; 204 205 /* Recompute the DT_NULL situation */ 206 set_null_ndx(argstate); 207 208 return (ndx); 209 } 210 211 212 /* 213 * Standard argument processing for dyn module 214 * 215 * entry 216 * obj_state, argc, argv - Standard command arguments 217 * argstate - Address of ARGSTATE block to be initialized 218 * 219 * exit: 220 * On success, *argstate is initialized. On error, 221 * an error is issued and this routine does not return. 222 */ 223 static void 224 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[], 225 ARGSTATE *argstate) 226 { 227 elfedit_getopt_state_t getopt_state; 228 elfedit_getopt_ret_t *getopt_ret; 229 230 bzero(argstate, sizeof (*argstate)); 231 argstate->obj_state = obj_state; 232 233 elfedit_getopt_init(&getopt_state, &argc, &argv); 234 235 /* Add each new option to the options mask */ 236 while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) 237 argstate->optmask |= getopt_ret->gor_idmask; 238 239 /* If there may be an arbitrary amount of output, use a pager */ 240 if (argc == 0) 241 elfedit_pager_init(); 242 243 /* Return the updated values of argc/argv */ 244 argstate->argc = argc; 245 argstate->argv = argv; 246 247 /* Locate the dynamic section, and the assocated string table */ 248 argstate->dyn.sec = elfedit_sec_getdyn(obj_state, &argstate->dyn.data, 249 &argstate->dyn.num); 250 argstate->strsec = elfedit_sec_getstr(obj_state, 251 argstate->dyn.sec->sec_shdr->sh_link); 252 253 /* Index of first DT_NULL */ 254 set_null_ndx(argstate); 255 } 256 257 258 259 /* 260 * Print ELF header values, taking the calling command, and output style 261 * into account. 262 * 263 * entry: 264 * cmd - DYN_CMD_T_* value giving identify of caller 265 * autoprint - If True, output is only produced if the elfedit 266 * autoprint flag is set. If False, output is always produced. 267 * argstate - Argument state block 268 * print_type - Specifies which dynamic elements to display. 269 * ndx = If print_type is PRINT_DYN_T_NDX, displays the index specified. 270 * Otherwise ignored. 271 */ 272 typedef enum { 273 PRINT_DYN_T_ALL = 0, /* Show all indexes */ 274 PRINT_DYN_T_NDX = 1, /* Show dynamic[arg] only */ 275 PRINT_DYN_T_TAG = 2, /* Show all elts with tag type */ 276 /* given by arg */ 277 PRINT_DYN_T_RUNPATH = 3 /* Show all runpath/rpath elts */ 278 279 } PRINT_DYN_T; 280 281 static void 282 print_dyn(DYN_CMD_T cmd, int autoprint, ARGSTATE *argstate, 283 PRINT_DYN_T print_type, Word arg) 284 { 285 elfedit_outstyle_t outstyle; 286 Conv_fmt_flags_t flags_fmt_flags; 287 Word end_ndx, cnt, ndx, printed = 0; 288 Dyn *dyn; 289 int header_done = 0; 290 Xword last_d_val; 291 292 if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) 293 return; 294 295 /* 296 * Pick an output style. dyn:dump is required to use the default 297 * style. The other commands use the current output style. 298 */ 299 outstyle = (cmd == DYN_CMD_T_DUMP) ? 300 ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); 301 302 /* 303 * When using the simple output style, omit the 304 * brackets from around the values. 305 */ 306 flags_fmt_flags = (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) ? 307 CONV_FMT_NOBKT : 0; 308 309 /* How many elements do we examine? */ 310 if (print_type == PRINT_DYN_T_NDX) { 311 if (arg >= argstate->dyn.num) 312 return; /* Out of range */ 313 ndx = arg; 314 cnt = 1; 315 } else { 316 ndx = 0; 317 cnt = argstate->dyn.num; 318 } 319 320 dyn = &argstate->dyn.data[ndx]; 321 for (; cnt--; dyn++, ndx++) { 322 union { 323 Conv_dyn_flag_buf_t flag; 324 Conv_dyn_flag1_buf_t flag1; 325 Conv_dyn_posflag1_buf_t posflag1; 326 Conv_dyn_feature1_buf_t feature1; 327 } c_buf; 328 const char *name; 329 330 /* 331 * If we are only displaying certain tag types and 332 * this isn't one of those, move on to next element. 333 */ 334 switch (print_type) { 335 case PRINT_DYN_T_TAG: 336 if (dyn->d_tag != arg) 337 continue; 338 break; 339 case PRINT_DYN_T_RUNPATH: 340 if ((dyn->d_tag != DT_RPATH) && 341 (dyn->d_tag != DT_RUNPATH)) 342 continue; 343 break; 344 } 345 346 /* 347 * Print the information numerically, and if possible 348 * as a string. 349 */ 350 name = NULL; 351 switch (dyn->d_tag) { 352 case DT_NULL: 353 if (!((outstyle == ELFEDIT_OUTSTYLE_DEFAULT) && 354 (print_type == PRINT_DYN_T_ALL) && 355 (dyn->d_un.d_val == 0))) 356 break; 357 end_ndx = ndx; 358 /* 359 * Special case: DT_NULLs can come in groups 360 * that we prefer to reduce to a single line. 361 */ 362 while ((end_ndx < (argstate->dyn.num - 1)) && 363 ((dyn + 1)->d_tag == DT_NULL) && 364 ((dyn + 1)->d_un.d_val == 0)) { 365 dyn++; 366 end_ndx++; 367 cnt--; 368 } 369 if (header_done == 0) { 370 header_done = 1; 371 Elf_dyn_title(0); 372 } 373 Elf_dyn_null_entry(0, dyn, ndx, end_ndx); 374 ndx = end_ndx; 375 printed = 1; 376 last_d_val = dyn->d_un.d_val; 377 continue; 378 379 /* 380 * Print the information numerically, and if possible 381 * as a string. 382 */ 383 case DT_NEEDED: 384 case DT_SONAME: 385 case DT_FILTER: 386 case DT_AUXILIARY: 387 case DT_CONFIG: 388 case DT_RPATH: 389 case DT_RUNPATH: 390 case DT_USED: 391 case DT_DEPAUDIT: 392 case DT_AUDIT: 393 case DT_SUNW_AUXILIARY: 394 case DT_SUNW_FILTER: 395 name = elfedit_offset_to_str(argstate->strsec, 396 dyn->d_un.d_val, ELFEDIT_MSG_DEBUG, 0); 397 break; 398 399 case DT_FLAGS: 400 name = conv_dyn_flag(dyn->d_un.d_val, 401 flags_fmt_flags, &c_buf.flag); 402 break; 403 case DT_FLAGS_1: 404 name = conv_dyn_flag1(dyn->d_un.d_val, 405 flags_fmt_flags, &c_buf.flag1); 406 break; 407 case DT_POSFLAG_1: 408 name = conv_dyn_posflag1(dyn->d_un.d_val, 409 flags_fmt_flags, &c_buf.posflag1); 410 break; 411 case DT_FEATURE_1: 412 name = conv_dyn_feature1(dyn->d_un.d_val, 413 flags_fmt_flags, &c_buf.feature1); 414 break; 415 case DT_DEPRECATED_SPARC_REGISTER: 416 name = MSG_INTL(MSG_STR_DEPRECATED); 417 break; 418 } 419 420 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { 421 if (header_done == 0) { 422 header_done = 1; 423 Elf_dyn_title(0); 424 } 425 if (name == NULL) 426 name = MSG_ORIG(MSG_STR_EMPTY); 427 Elf_dyn_entry(0, dyn, ndx, name, 428 argstate->obj_state->os_ehdr->e_machine); 429 } else { 430 /* 431 * In simple or numeric mode under a print type 432 * that is based on tag type rather than on index, 433 * quietly: If we've already printed this value, 434 * don't print it again. A common example of this 435 * is PRINT_DYN_T_RUNPATH when both DT_RPATH and 436 * DT_RUNPATH are present with the same value. 437 */ 438 switch (print_type) { 439 case PRINT_DYN_T_TAG: 440 case PRINT_DYN_T_RUNPATH: 441 if (printed && (last_d_val == dyn->d_un.d_val)) 442 continue; 443 } 444 445 if ((name != NULL) && 446 (outstyle == ELFEDIT_OUTSTYLE_SIMPLE)) { 447 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), name); 448 } else { 449 elfedit_printf(MSG_ORIG(MSG_FMT_HEXXWORDNL), 450 dyn->d_un.d_val); 451 } 452 } 453 printed = 1; 454 last_d_val = dyn->d_un.d_val; 455 } 456 457 /* 458 * If nothing was output under the print types that are 459 * based on tag type, issue an error saying it doesn't exist. 460 */ 461 if (!printed) { 462 if (print_type == PRINT_DYN_T_TAG) { 463 Conv_inv_buf_t inv_buf; 464 465 elfedit_msg(ELFEDIT_MSG_ERR, 466 MSG_INTL(MSG_ERR_NODYNELT), 467 EC_WORD(argstate->dyn.sec->sec_shndx), 468 argstate->dyn.sec->sec_name, conv_dyn_tag(arg, 469 argstate->obj_state->os_ehdr->e_machine, 470 0, &inv_buf)); 471 } 472 473 if (print_type == PRINT_DYN_T_RUNPATH) 474 elfedit_msg(ELFEDIT_MSG_ERR, 475 MSG_INTL(MSG_ERR_NORUNPATH), 476 EC_WORD(argstate->dyn.sec->sec_shndx), 477 argstate->dyn.sec->sec_name); 478 } 479 } 480 481 482 /* 483 * Process the elt argument: This will be a tag type if -dynndx is 484 * not present and this is a print request. It will be an index otherwise. 485 * 486 * entry: 487 * argstate - Argument state block 488 * arg - Argument string to be converted into an index 489 * argname - String giving the name by which the argument is 490 * referred in the online help for the command. 491 * print_request - True if the command is to print the current 492 * value(s) and return without changing anything. 493 * print_type - Address of variable containing PRINT_DYN_T_ 494 * code specifying how the elements will be displayed. 495 * 496 * exit: 497 * If print_request is False: arg is converted into an integer value. 498 * If -dynndx was used, we convert it into an integer. If it was not 499 * used, then arg is a tag name --- we find the first dynamic entry 500 * that matches. If no entry matches, and there is an extra DT_NULL, 501 * it is added. Otherwise an error is issued. *print_type is set 502 * to PRINT_DYN_T_NDX. 503 * 504 * If print_request is True: If -dynndx was used, arg is converted into 505 * an integer value, *print_type is set to PRINT_DYN_T_NDX, and 506 * the value is returned. If -dynndx was not used, *print_type is set to 507 * PRINT_DYN_T_TAG, and the tag value is returned. 508 */ 509 static Word 510 arg_to_index(ARGSTATE *argstate, const char *arg, const char *argname, 511 int print_request, PRINT_DYN_T *print_type) 512 { 513 Word ndx, dt_value; 514 515 516 /* Assume we are returning an index, alter as needed below */ 517 *print_type = PRINT_DYN_T_NDX; 518 519 /* If -dynndx was used, this is a simple numeric index */ 520 if ((argstate->optmask & DYN_OPT_F_DYNNDX) != 0) 521 return ((Word) elfedit_atoui_range(arg, argname, 0, 522 argstate->dyn.num - 1, NULL)); 523 524 /* The argument is a DT_ tag type, not a numeric index */ 525 dt_value = (Word) elfedit_atoconst(arg, ELFEDIT_CONST_DT); 526 527 /* 528 * If this is a printing request, then we let print_dyn() show 529 * all the items with this tag type. 530 */ 531 if (print_request) { 532 *print_type = PRINT_DYN_T_TAG; 533 return (dt_value); 534 } 535 536 /* Locate the first entry with the given tag type */ 537 for (ndx = 0; ndx < argstate->dyn.num; ndx++) { 538 if (argstate->dyn.data[ndx].d_tag == dt_value) { 539 elfedit_msg(ELFEDIT_MSG_DEBUG, 540 MSG_INTL(MSG_DEBUG_DT2NDX), 541 EC_WORD(argstate->dyn.sec->sec_shndx), 542 argstate->dyn.sec->sec_name, EC_WORD(ndx), arg); 543 return (ndx); 544 } 545 } 546 547 /* Not found. Can we create one? */ 548 if (argstate->dyn.num_null_ndx > 1) 549 return (convert_dt_null(argstate, dt_value, 0)); 550 551 /* No room to create one, so we're out of options and must fail */ 552 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODTELT), 553 EC_WORD(argstate->dyn.sec->sec_shndx), 554 argstate->dyn.sec->sec_name, arg); 555 556 /*NOTREACHED*/ 557 return (0); /* For lint */ 558 } 559 560 561 /* 562 * Called by cmd_body() for dyn:value. Implements the core functionality 563 * for that command. 564 * 565 * This routine expects that both the index and value arguments are 566 * present. 567 */ 568 static elfedit_cmdret_t 569 cmd_body_value(ARGSTATE *argstate, Word *ret_ndx) 570 { 571 elfedit_section_t *dynsec = argstate->dyn.sec; 572 elfedit_section_t *strsec = argstate->strsec; 573 elfedit_dyn_elt_t strpad_elt; 574 Word i; 575 Dyn *dyn = argstate->dyn.data; 576 Word numdyn = argstate->dyn.num; 577 int minus_add = ((argstate->optmask & DYN_OPT_F_ADD) != 0); 578 int minus_s = ((argstate->optmask & DYN_OPT_F_STRVAL) != 0); 579 int minus_dynndx = ((argstate->optmask & DYN_OPT_F_DYNNDX) != 0); 580 Word arg1, tmp_val; 581 Xword arg2; 582 int arg2_known = 1; 583 584 585 elfedit_dyn_elt_init(&strpad_elt); 586 587 /* 588 * The first argument is an index if -dynndx is used, and is a 589 * tag value otherwise. 590 */ 591 arg1 = minus_dynndx ? 592 elfedit_atoui_range(argstate->argv[0], MSG_ORIG(MSG_STR_ELT), 593 0, numdyn - 1, NULL) : 594 elfedit_atoconst(argstate->argv[0], ELFEDIT_CONST_DT); 595 596 if (minus_s) { 597 /* 598 * Don't allow the user to specify -s when manipulating a 599 * DT_SUNW_STRPAD element. Since DT_SUNW_STRPAD is used to 600 * manage the extra space used for strings, this would break 601 * our ability to add the string. 602 */ 603 if ((!minus_dynndx && (arg1 == DT_SUNW_STRPAD)) || 604 (minus_dynndx && (dyn[arg1].d_tag == DT_SUNW_STRPAD))) 605 elfedit_msg(ELFEDIT_MSG_ERR, 606 MSG_INTL(MSG_ERR_STRPADSTRVAL), 607 EC_WORD(dynsec->sec_shndx), dynsec->sec_name); 608 609 /* Locate DT_SUNW_STRPAD element if present */ 610 strpad_elt.dn_dyn.d_un.d_val = 0; 611 (void) elfedit_dynstr_getpad(argstate->dyn.sec, &strpad_elt); 612 613 /* 614 * Look up the string: If the user specified the -dynndx 615 * -option, then we will insert it if possible, and 616 * fail with an error if not. However, if they did not 617 * specify -dynndx, we want to look up the string if it is 618 * already there, but defer the insertion. The reason for 619 * this is that we may have to grab an unused DT_NULL element 620 * below, and if there are none available, we won't want 621 * to have modified the string table. 622 * 623 * This isn't a problem, because if the string isn't 624 * in the string table, it can't be used by a dynamic element. 625 * Hence, we don't need to insert it to know that there is 626 * no match. 627 */ 628 if (minus_dynndx == 0) { 629 if (elfedit_sec_findstr(strsec, 630 strpad_elt.dn_dyn.d_un.d_val, argstate->argv[1], 631 &tmp_val) == 0) { 632 arg2_known = 0; 633 } else { 634 arg2 = tmp_val; 635 } 636 } else { 637 arg2 = elfedit_dynstr_insert(dynsec, strsec, 638 &strpad_elt, argstate->argv[1]); 639 } 640 } else { /* Argument 2 is an integer */ 641 arg2 = elfedit_atoui(argstate->argv[1], NULL); 642 } 643 644 645 if (!minus_dynndx && !(minus_add && !arg2_known)) { 646 /* 647 * Search the dynamic section and see if an item with the 648 * specified tag value already exists. We can reduce this 649 * to a simple update of an existing value if -add is not 650 * specified or the existing d_un value matches the new one. 651 * 652 * In either of these cases, we will change arg1 to be the 653 * index, and set minus_dynndx, causing the simple update to 654 * happen immediately below. 655 */ 656 for (i = 0; i < numdyn; i++) { 657 if ((dyn[i].d_tag == arg1) && 658 (!minus_add || (dyn[i].d_un.d_val == arg2))) { 659 arg1 = i; 660 minus_dynndx = 1; 661 break; 662 } 663 } 664 } 665 666 /* 667 * If -dynndx is used, then this is a relatively simple 668 * operation, as we simply write over the specified index. 669 */ 670 if (minus_dynndx) { 671 /* 672 * If we held back from inserting a new string into 673 * the dynstr above, we insert it now, because we 674 * have a slot in the dynamic section, and we need 675 * the string offset ot finish. 676 */ 677 if (!arg2_known) 678 arg2 = elfedit_dynstr_insert(dynsec, strsec, 679 &strpad_elt, argstate->argv[1]); 680 681 *ret_ndx = arg1; 682 if (dyn[arg1].d_un.d_val == arg2) { 683 elfedit_msg(ELFEDIT_MSG_DEBUG, 684 MSG_INTL(MSG_DEBUG_X_OK), 685 dynsec->sec_shndx, dynsec->sec_name, 686 EC_WORD(arg1), EC_XWORD(arg2)); 687 return (ELFEDIT_CMDRET_NONE); 688 } else { 689 /* Warn if setting DT_NULL value to non-zero */ 690 if ((dyn[arg1].d_tag == DT_NULL) && (arg2 != 0)) 691 elfedit_msg(ELFEDIT_MSG_DEBUG, 692 MSG_INTL(MSG_DEBUG_DTNULLVALUE), 693 dynsec->sec_shndx, dynsec->sec_name, 694 EC_WORD(arg1), EC_XWORD(arg2)); 695 696 elfedit_msg(ELFEDIT_MSG_DEBUG, 697 MSG_INTL(MSG_DEBUG_X_CHG), 698 dynsec->sec_shndx, dynsec->sec_name, 699 EC_WORD(arg1), EC_XWORD(dyn[arg1].d_un.d_val), 700 EC_XWORD(arg2)); 701 dyn[arg1].d_un.d_val = arg2; 702 return (ELFEDIT_CMDRET_MOD); 703 } 704 } 705 706 /* 707 * We need a new slot in the dynamic section. If we can't have 708 * one, then we fail. 709 */ 710 if (argstate->dyn.num_null_ndx <= 1) 711 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL), 712 EC_WORD(dynsec->sec_shndx), dynsec->sec_name); 713 714 /* 715 * If we still need to insert a new string into the dynstr, 716 * then it is safe now, because if we succeed, we know that 717 * there is an available slot to receive it. If we fail, we 718 * haven't claimed the extra slot yet, and it will be unharmed. 719 */ 720 if (!arg2_known) 721 arg2 = elfedit_dynstr_insert(dynsec, strsec, 722 &strpad_elt, argstate->argv[1]); 723 724 /* Use an extra DT_NULL slot and enter the new element */ 725 *ret_ndx = convert_dt_null(argstate, arg1, arg2); 726 return (ELFEDIT_CMDRET_MOD); 727 } 728 729 730 731 /* 732 * Called by cmd_body() for dyn:runpath. Implements the core functionality 733 * for that command. 734 * 735 * History Lesson And Strategy: 736 * 737 * This routine handles both DT_RPATH and DT_RUNPATH entries, altering 738 * either or both if they are present. 739 * 740 * The original SYSV ABI only had DT_RPATH, and the runtime loader used 741 * it to search for things in the following order: 742 * 743 * DT_RPATH, LD_LIBRARY_PATH, defaults 744 * 745 * Solaris did not follow this rule, an extremely rare deviation from 746 * the ABI. Environment variables should supercede everything else, 747 * otherwise they are not very useful. This decision was made at the 748 * very beginning of the SunOS 5.x development, so we have always 749 * deviated from the ABI and and instead search in the order 750 * 751 * LD_LIBRARY_PATH, DT_RPATH, defaults 752 * 753 * Other Unix variants initially followed the ABI, but in recent years 754 * have come to agree with the early Solaris folks that it was a mistake. 755 * Hence, DT_RUNPATH was invented, with the search order: 756 * 757 * LD_LIBRARY_PATH, DT_RUNPATH, defaults 758 * 759 * So for Solaris, DT_RPATH and DT_RUNPATH mean the same thing. If both 760 * are present (which does happen), we set them both to the new 761 * value. If either one is present, we set that one. If neither is 762 * present, and we have a spare DT_NULL slot, we create a DT_RUNPATH, but 763 * not a DT_RPATH, to conserve available slots for other uses. 764 */ 765 static elfedit_cmdret_t 766 cmd_body_runpath(ARGSTATE *argstate) 767 { 768 elfedit_section_t *dynsec = argstate->dyn.sec; 769 elfedit_section_t *strsec = argstate->strsec; 770 elfedit_dyn_elt_t rpath_elt; 771 elfedit_dyn_elt_t runpath_elt; 772 elfedit_dyn_elt_t strpad_elt; 773 Word i; 774 Dyn *dyn = argstate->dyn.data; 775 Word numdyn = argstate->dyn.num; 776 777 /* Go through the tags and gather what we need */ 778 elfedit_dyn_elt_init(&rpath_elt); 779 elfedit_dyn_elt_init(&runpath_elt); 780 elfedit_dyn_elt_init(&strpad_elt); 781 for (i = 0; i < numdyn; i++) { 782 switch (dyn[i].d_tag) { 783 case DT_RPATH: 784 elfedit_dyn_elt_save(&rpath_elt, i, &dyn[i]); 785 break; 786 787 case DT_RUNPATH: 788 elfedit_dyn_elt_save(&runpath_elt, i, &dyn[i]); 789 break; 790 791 case DT_SUNW_STRPAD: 792 elfedit_dyn_elt_save(&strpad_elt, i, &dyn[i]); 793 break; 794 } 795 } 796 797 /* Do we have an available dynamic section entry to use? */ 798 if (rpath_elt.dn_seen || runpath_elt.dn_seen) { 799 /* 800 * We have seen a DT_RPATH, or a DT_RUNPATH, or both. 801 * If all of these have the same string as the desired 802 * new value, then we don't need to alter anything and can 803 * simply return. Otherwise, we'll modify them all to have 804 * the new string (below). 805 */ 806 if ((!rpath_elt.dn_seen || 807 (strcmp(elfedit_dyn_offset_to_str(strsec, &rpath_elt), 808 argstate->argv[0]) == 0)) && 809 (!runpath_elt.dn_seen || 810 (strcmp(elfedit_dyn_offset_to_str(strsec, &runpath_elt), 811 argstate->argv[0]) == 0))) { 812 if (rpath_elt.dn_seen) 813 elfedit_msg(ELFEDIT_MSG_DEBUG, 814 MSG_INTL(MSG_DEBUG_OLDRPATHOK), 815 EC_WORD(dynsec->sec_shndx), 816 dynsec->sec_name, EC_WORD(rpath_elt.dn_ndx), 817 elfedit_atoconst_value_to_str( 818 ELFEDIT_CONST_DT, DT_RPATH, 1)); 819 if (runpath_elt.dn_seen) 820 elfedit_msg(ELFEDIT_MSG_DEBUG, 821 MSG_INTL(MSG_DEBUG_OLDRPATHOK), 822 EC_WORD(dynsec->sec_shndx), 823 dynsec->sec_name, 824 EC_WORD(runpath_elt.dn_ndx), 825 elfedit_atoconst_value_to_str( 826 ELFEDIT_CONST_DT, DT_RUNPATH, 1)); 827 return (ELFEDIT_CMDRET_NONE); 828 } 829 } else if (argstate->dyn.num_null_ndx <= 1) { 830 /* 831 * There is no DT_RPATH or DT_RUNPATH in the dynamic array, 832 * and there are no extra DT_NULL entries that we can 833 * convert into one. We cannot proceed. 834 */ 835 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL), 836 EC_WORD(dynsec->sec_shndx), dynsec->sec_name); 837 } 838 839 /* Does the string exist in the table already, or can we add it? */ 840 rpath_elt.dn_dyn.d_un.d_val = runpath_elt.dn_dyn.d_un.d_val = 841 elfedit_dynstr_insert(dynsec, strsec, &strpad_elt, 842 argstate->argv[0]); 843 844 /* Update DT_RPATH entry if present */ 845 if (rpath_elt.dn_seen) { 846 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_PREVRPATH), 847 EC_WORD(dynsec->sec_shndx), dynsec->sec_name, 848 EC_WORD(rpath_elt.dn_ndx), 849 elfedit_atoconst_value_to_str( 850 ELFEDIT_CONST_DT, DT_RPATH, 1), 851 elfedit_dyn_offset_to_str(strsec, &rpath_elt)); 852 dyn[rpath_elt.dn_ndx] = rpath_elt.dn_dyn; 853 } 854 855 /* 856 * Update the DT_RUNPATH entry in the dynamic section, if present. 857 * If one is not present, and there is also no DT_RPATH, then 858 * we use a spare DT_NULL entry to create a new DT_RUNPATH. 859 */ 860 if (runpath_elt.dn_seen || !rpath_elt.dn_seen) { 861 if (runpath_elt.dn_seen) { 862 elfedit_msg(ELFEDIT_MSG_DEBUG, 863 MSG_INTL(MSG_DEBUG_PREVRPATH), 864 EC_WORD(dynsec->sec_shndx), dynsec->sec_name, 865 EC_WORD(runpath_elt.dn_ndx), 866 elfedit_atoconst_value_to_str( 867 ELFEDIT_CONST_DT, DT_RUNPATH, 1), 868 elfedit_dyn_offset_to_str(strsec, &runpath_elt)); 869 dyn[runpath_elt.dn_ndx] = runpath_elt.dn_dyn; 870 } else { /* Using a spare DT_NULL entry */ 871 (void) convert_dt_null(argstate, DT_RUNPATH, 872 runpath_elt.dn_dyn.d_un.d_val); 873 } 874 } 875 876 return (ELFEDIT_CMDRET_MOD); 877 } 878 879 880 881 /* 882 * Argument processing for the bitmask commands. Convert the arguments 883 * to integer form, apply -and/-cmp/-or, and return the resulting value. 884 * 885 * entry: 886 * argstate - Argument state block 887 * orig - Value of original bitmask 888 * const_type - ELFEDIT_CONST_* value for type of constants 889 */ 890 static Word 891 flag_bitop(ARGSTATE *argstate, Word orig, elfedit_const_t const_type) 892 { 893 Word flags = 0; 894 int i; 895 896 /* Collect the arguments */ 897 for (i = 0; i < argstate->argc; i++) 898 flags |= (Word) elfedit_atoconst(argstate->argv[i], const_type); 899 900 /* Complement the value? */ 901 if (argstate->optmask & DYN_OPT_F_CMP) 902 flags = ~flags; 903 904 /* Perform any requested bit operations */ 905 if (argstate->optmask & DYN_OPT_F_AND) 906 flags &= orig; 907 else if (argstate->optmask & DYN_OPT_F_OR) 908 flags |= orig; 909 910 return (flags); 911 } 912 913 914 915 /* 916 * Common body for the dyn: module commands. These commands 917 * share a large amount of common behavior, so it is convenient 918 * to centralize things and use the cmd argument to handle the 919 * small differences. 920 * 921 * entry: 922 * cmd - One of the DYN_CMD_T_* constants listed above, specifying 923 * which command to implement. 924 * obj_state, argc, argv - Standard command arguments 925 */ 926 static elfedit_cmdret_t 927 cmd_body(DYN_CMD_T cmd, elfedit_obj_state_t *obj_state, 928 int argc, const char *argv[]) 929 { 930 ARGSTATE argstate; 931 Dyn *dyn; 932 const char *dyn_name; 933 Word dyn_ndx, dyn_num, null_ndx; 934 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 935 PRINT_DYN_T print_type = PRINT_DYN_T_ALL; 936 Word ndx; 937 int print_only = 0; 938 int do_autoprint = 1; 939 940 /* Process the optional arguments */ 941 process_args(obj_state, argc, argv, &argstate); 942 943 dyn = argstate.dyn.data; 944 dyn_num = argstate.dyn.num; 945 dyn_name = argstate.dyn.sec->sec_name; 946 dyn_ndx = argstate.dyn.sec->sec_shndx; 947 948 /* Check number of arguments, gather information */ 949 switch (cmd) { 950 case DYN_CMD_T_DUMP: 951 /* dyn:dump can accept an optional index argument */ 952 if (argstate.argc > 1) 953 elfedit_command_usage(); 954 print_only = 1; 955 if (argstate.argc == 1) 956 ndx = arg_to_index(&argstate, argstate.argv[0], 957 MSG_ORIG(MSG_STR_ELT), print_only, &print_type); 958 break; 959 960 case DYN_CMD_T_TAG: 961 print_only = (argstate.argc != 2); 962 if (argstate.argc > 0) { 963 if (argstate.argc > 2) 964 elfedit_command_usage(); 965 ndx = arg_to_index(&argstate, argstate.argv[0], 966 MSG_ORIG(MSG_STR_ELT), print_only, &print_type); 967 } 968 break; 969 970 case DYN_CMD_T_VALUE: 971 print_only = (argstate.argc != 2); 972 if (argstate.argc > 2) 973 elfedit_command_usage(); 974 if (argstate.argc > 0) { 975 if (print_only) { 976 ndx = arg_to_index(&argstate, argstate.argv[0], 977 MSG_ORIG(MSG_STR_ELT), 978 print_only, &print_type); 979 } else { 980 print_type = PRINT_DYN_T_NDX; 981 } 982 } 983 break; 984 985 case DYN_CMD_T_DELETE: 986 if ((argstate.argc < 1) || (argstate.argc > 2)) 987 elfedit_command_usage(); 988 ndx = arg_to_index(&argstate, argstate.argv[0], 989 MSG_ORIG(MSG_STR_ELT), 990 0, &print_type); 991 do_autoprint = 0; 992 break; 993 994 case DYN_CMD_T_MOVE: 995 if ((argstate.argc < 2) || (argstate.argc > 3)) 996 elfedit_command_usage(); 997 ndx = arg_to_index(&argstate, argstate.argv[0], 998 MSG_ORIG(MSG_STR_ELT), 0, &print_type); 999 do_autoprint = 0; 1000 break; 1001 1002 case DYN_CMD_T_RUNPATH: 1003 if (argstate.argc > 1) 1004 elfedit_command_usage(); 1005 /* 1006 * dyn:runpath does not accept an explicit index 1007 * argument, so we implicitly only show the DT_RPATH and 1008 * DT_RUNPATH elements. 1009 */ 1010 print_type = PRINT_DYN_T_RUNPATH; 1011 print_only = (argstate.argc == 0); 1012 break; 1013 1014 case DYN_CMD_T_POSFLAG1: 1015 print_only = (argstate.argc == 0); 1016 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( 1017 ELFEDIT_CONST_DT, DT_POSFLAG_1, 1), 1018 MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); 1019 break; 1020 1021 case DYN_CMD_T_FLAGS: 1022 print_only = (argstate.argc == 0); 1023 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( 1024 ELFEDIT_CONST_DT, DT_FLAGS, 1), 1025 MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); 1026 break; 1027 1028 case DYN_CMD_T_FLAGS1: 1029 print_only = (argstate.argc == 0); 1030 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( 1031 ELFEDIT_CONST_DT, DT_FLAGS_1, 1), 1032 MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); 1033 break; 1034 1035 case DYN_CMD_T_FEATURE1: 1036 print_only = (argstate.argc == 0); 1037 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( 1038 ELFEDIT_CONST_DT, DT_FEATURE_1, 1), 1039 MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); 1040 break; 1041 1042 case DYN_CMD_T_CHECKSUM: 1043 ndx = arg_to_index(&argstate, elfedit_atoconst_value_to_str( 1044 ELFEDIT_CONST_DT, DT_CHECKSUM, 1), 1045 MSG_ORIG(MSG_STR_VALUE), print_only, &print_type); 1046 break; 1047 1048 default: 1049 /* Note expected: All commands should have been caught above */ 1050 elfedit_command_usage(); 1051 break; 1052 } 1053 1054 1055 /* If this is a request to print current values, do it and return */ 1056 if (print_only) { 1057 print_dyn(cmd, 0, &argstate, print_type, ndx); 1058 return (ELFEDIT_CMDRET_NONE); 1059 } 1060 1061 1062 switch (cmd) { 1063 /* 1064 * DYN_CMD_T_DUMP can't get here: It is a print-only 1065 * command. 1066 */ 1067 1068 case DYN_CMD_T_TAG: 1069 { 1070 Conv_inv_buf_t inv_buf1, inv_buf2; 1071 Half mach = argstate.obj_state->os_ehdr->e_machine; 1072 Word d_tag = (Word) elfedit_atoconst(argstate.argv[1], 1073 ELFEDIT_CONST_DT); 1074 1075 if (dyn[ndx].d_tag == d_tag) { 1076 elfedit_msg(ELFEDIT_MSG_DEBUG, 1077 MSG_INTL(MSG_DEBUG_S_OK), 1078 dyn_ndx, 1079 dyn_name, EC_WORD(ndx), 1080 conv_dyn_tag(d_tag, mach, 0, &inv_buf1)); 1081 } else { 1082 Word orig_d_tag = dyn[ndx].d_tag; 1083 1084 ret = ELFEDIT_CMDRET_MOD; 1085 dyn[ndx].d_tag = d_tag; 1086 1087 /* 1088 * Update null termination index. Warn if we 1089 * just clobbered the only DT_NULL termination 1090 * for the array. 1091 */ 1092 null_ndx = argstate.dyn.null_ndx; 1093 set_null_ndx(&argstate); 1094 if ((argstate.dyn.null_ndx >= 1095 argstate.dyn.num) && 1096 (null_ndx != argstate.dyn.null_ndx)) 1097 elfedit_msg(ELFEDIT_MSG_DEBUG, 1098 MSG_INTL(MSG_DEBUG_NULLTERM), 1099 dyn_ndx, dyn_name, 1100 EC_WORD(ndx), 1101 conv_dyn_tag(d_tag, mach, 1102 0, &inv_buf1)); 1103 1104 /* 1105 * Warning if 1106 * - Inserting a DT_NULL cuts off following 1107 * non-null elements. 1108 * - Inserting a non-DT_NULL after the 1109 * first null element, will be 1110 * ignored by rtld. 1111 */ 1112 if (d_tag == DT_NULL) { 1113 if ((ndx + 1) < null_ndx) 1114 elfedit_msg(ELFEDIT_MSG_DEBUG, 1115 MSG_INTL(MSG_DEBUG_NULCLIP), 1116 dyn_ndx, dyn_name, 1117 EC_WORD(ndx), 1118 conv_dyn_tag(d_tag, mach, 1119 0, &inv_buf1)); 1120 } else { 1121 if ((ndx + 1) > argstate.dyn.null_ndx) 1122 elfedit_msg(ELFEDIT_MSG_DEBUG, 1123 MSG_INTL(MSG_DEBUG_NULHIDE), 1124 dyn_ndx, dyn_name, 1125 EC_WORD(ndx), 1126 conv_dyn_tag(d_tag, mach, 1127 0, &inv_buf1)); 1128 } 1129 1130 /* Debug message that we changed it */ 1131 elfedit_msg(ELFEDIT_MSG_DEBUG, 1132 MSG_INTL(MSG_DEBUG_S_CHG), 1133 dyn_ndx, dyn_name, EC_WORD(ndx), 1134 conv_dyn_tag(orig_d_tag, mach, 0, 1135 &inv_buf1), 1136 conv_dyn_tag(d_tag, mach, 0, &inv_buf2)); 1137 } 1138 } 1139 break; 1140 1141 case DYN_CMD_T_VALUE: 1142 ret = cmd_body_value(&argstate, &ndx); 1143 break; 1144 1145 case DYN_CMD_T_DELETE: 1146 { 1147 Word cnt = (argstate.argc == 1) ? 1 : 1148 (Word) elfedit_atoui_range(argstate.argv[1], 1149 MSG_ORIG(MSG_STR_COUNT), 1, dyn_num - ndx, NULL); 1150 const char *msg_prefix = 1151 elfedit_sec_msgprefix(argstate.dyn.sec); 1152 1153 elfedit_array_elts_delete(msg_prefix, argstate.dyn.data, 1154 sizeof (Dyn), dyn_num, ndx, cnt); 1155 ret = ELFEDIT_CMDRET_MOD; 1156 } 1157 break; 1158 1159 case DYN_CMD_T_MOVE: 1160 { 1161 Dyn save; 1162 Word cnt; 1163 Word dstndx; 1164 const char *msg_prefix = 1165 elfedit_sec_msgprefix(argstate.dyn.sec); 1166 1167 dstndx = (Word) 1168 elfedit_atoui_range(argstate.argv[1], 1169 MSG_ORIG(MSG_STR_DST_INDEX), 0, dyn_num - 1, 1170 NULL); 1171 if (argstate.argc == 2) { 1172 cnt = 1; 1173 } else { 1174 cnt = (Word) elfedit_atoui_range( 1175 argstate.argv[2], MSG_ORIG(MSG_STR_COUNT), 1176 1, dyn_num, NULL); 1177 } 1178 elfedit_array_elts_move(msg_prefix, argstate.dyn.data, 1179 sizeof (save), dyn_num, ndx, dstndx, cnt, &save); 1180 ret = ELFEDIT_CMDRET_MOD; 1181 } 1182 break; 1183 1184 1185 case DYN_CMD_T_RUNPATH: 1186 ret = cmd_body_runpath(&argstate); 1187 break; 1188 1189 case DYN_CMD_T_POSFLAG1: 1190 { 1191 Conv_dyn_posflag1_buf_t buf1, buf2; 1192 Word flags; 1193 1194 flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val, 1195 ELFEDIT_CONST_DF_P1); 1196 1197 /* Set the value */ 1198 if (dyn[ndx].d_un.d_val == flags) { 1199 elfedit_msg(ELFEDIT_MSG_DEBUG, 1200 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, 1201 dyn_name, EC_WORD(ndx), 1202 conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0, 1203 &buf1)); 1204 } else { 1205 elfedit_msg(ELFEDIT_MSG_DEBUG, 1206 MSG_INTL(MSG_DEBUG_S_CHG), 1207 dyn_ndx, dyn_name, EC_WORD(ndx), 1208 conv_dyn_posflag1(dyn[ndx].d_un.d_val, 0, 1209 &buf1), 1210 conv_dyn_posflag1(flags, 0, &buf2)); 1211 ret = ELFEDIT_CMDRET_MOD; 1212 dyn[ndx].d_un.d_val = flags; 1213 } 1214 } 1215 break; 1216 1217 case DYN_CMD_T_FLAGS: 1218 { 1219 Conv_dyn_flag_buf_t buf1, buf2; 1220 Word flags; 1221 1222 flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val, 1223 ELFEDIT_CONST_DF); 1224 1225 /* Set the value */ 1226 if (dyn[ndx].d_un.d_val == flags) { 1227 elfedit_msg(ELFEDIT_MSG_DEBUG, 1228 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, 1229 dyn_name, EC_WORD(ndx), 1230 conv_dyn_flag(dyn[ndx].d_un.d_val, 0, 1231 &buf1)); 1232 } else { 1233 elfedit_msg(ELFEDIT_MSG_DEBUG, 1234 MSG_INTL(MSG_DEBUG_S_CHG), 1235 dyn_ndx, dyn_name, EC_WORD(ndx), 1236 conv_dyn_flag(dyn[ndx].d_un.d_val, 0, 1237 &buf1), 1238 conv_dyn_flag(flags, 0, &buf2)); 1239 ret = ELFEDIT_CMDRET_MOD; 1240 dyn[ndx].d_un.d_val = flags; 1241 } 1242 } 1243 break; 1244 1245 case DYN_CMD_T_FLAGS1: 1246 { 1247 Conv_dyn_flag1_buf_t buf1, buf2; 1248 Word flags1; 1249 1250 flags1 = flag_bitop(&argstate, dyn[ndx].d_un.d_val, 1251 ELFEDIT_CONST_DF_1); 1252 1253 /* Set the value */ 1254 if (dyn[ndx].d_un.d_val == flags1) { 1255 elfedit_msg(ELFEDIT_MSG_DEBUG, 1256 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, 1257 dyn_name, EC_WORD(ndx), 1258 conv_dyn_flag1(dyn[ndx].d_un.d_val, 1259 0, &buf1)); 1260 } else { 1261 elfedit_msg(ELFEDIT_MSG_DEBUG, 1262 MSG_INTL(MSG_DEBUG_S_CHG), 1263 dyn_ndx, dyn_name, EC_WORD(ndx), 1264 conv_dyn_flag1(dyn[ndx].d_un.d_val, 1265 0, &buf1), 1266 conv_dyn_flag1(flags1, 0, &buf2)); 1267 ret = ELFEDIT_CMDRET_MOD; 1268 dyn[ndx].d_un.d_val = flags1; 1269 } 1270 } 1271 break; 1272 1273 case DYN_CMD_T_FEATURE1: 1274 { 1275 Conv_dyn_feature1_buf_t buf1, buf2; 1276 Word flags; 1277 1278 flags = flag_bitop(&argstate, dyn[ndx].d_un.d_val, 1279 ELFEDIT_CONST_DTF_1); 1280 1281 /* Set the value */ 1282 if (dyn[ndx].d_un.d_val == flags) { 1283 elfedit_msg(ELFEDIT_MSG_DEBUG, 1284 MSG_INTL(MSG_DEBUG_S_OK), dyn_ndx, 1285 dyn_name, EC_WORD(ndx), 1286 conv_dyn_feature1(dyn[ndx].d_un.d_val, 0, 1287 &buf1)); 1288 } else { 1289 elfedit_msg(ELFEDIT_MSG_DEBUG, 1290 MSG_INTL(MSG_DEBUG_S_CHG), 1291 dyn_ndx, dyn_name, EC_WORD(ndx), 1292 conv_dyn_feature1(dyn[ndx].d_un.d_val, 0, 1293 &buf1), 1294 conv_dyn_feature1(flags, 0, &buf2)); 1295 ret = ELFEDIT_CMDRET_MOD; 1296 dyn[ndx].d_un.d_val = flags; 1297 } 1298 } 1299 break; 1300 1301 case DYN_CMD_T_CHECKSUM: 1302 { 1303 long checksum = elf_checksum(obj_state->os_elf); 1304 1305 /* Set the value */ 1306 if (dyn[ndx].d_un.d_val == checksum) { 1307 elfedit_msg(ELFEDIT_MSG_DEBUG, 1308 MSG_INTL(MSG_DEBUG_X_OK), dyn_ndx, 1309 dyn_name, EC_WORD(ndx), EC_XWORD(checksum)); 1310 } else { 1311 elfedit_msg(ELFEDIT_MSG_DEBUG, 1312 MSG_INTL(MSG_DEBUG_X_CHG), 1313 dyn_ndx, dyn_name, EC_WORD(ndx), 1314 EC_XWORD(dyn[ndx].d_un.d_val), 1315 EC_XWORD(checksum)); 1316 ret = ELFEDIT_CMDRET_MOD; 1317 dyn[ndx].d_un.d_val = checksum; 1318 } 1319 1320 } 1321 } 1322 1323 /* 1324 * If we modified the dynamic section header, tell libelf. 1325 */ 1326 if (ret == ELFEDIT_CMDRET_MOD) 1327 elfedit_modified_data(argstate.dyn.sec); 1328 1329 /* Do autoprint */ 1330 if (do_autoprint) 1331 print_dyn(cmd, 1, &argstate, print_type, ndx); 1332 1333 return (ret); 1334 } 1335 1336 1337 1338 /* 1339 * Command completion functions for the commands 1340 */ 1341 1342 /* 1343 * Command completion for the first argument, which specifies 1344 * the dynamic element to use. Examines the options to see if 1345 * -dynndx is present, and if not, supplies the completion 1346 * strings for argument 1. 1347 */ 1348 /*ARGSUSED*/ 1349 static void 1350 cpl_eltarg(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1351 const char *argv[], int num_opt) 1352 { 1353 elfedit_section_t *cache; 1354 Dyn *dyn; 1355 Word i; 1356 const char *s; 1357 char *s2; 1358 char buf[128]; 1359 1360 /* Make sure it's the first argument */ 1361 if ((argc - num_opt) != 1) 1362 return; 1363 1364 /* Is -dynndx present? If so, we don't complete tag types */ 1365 for (i = 0; i < num_opt; i++) 1366 if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_DYNNDX)) == 0) 1367 return; 1368 1369 /* 1370 * If there is no object, or if there is no dynamic section, 1371 * then supply all possible names. 1372 */ 1373 if ((obj_state == NULL) || (obj_state->os_dynndx == SHN_UNDEF)) { 1374 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT); 1375 return; 1376 } 1377 1378 /* Supply completions for the tags present in the dynamic section */ 1379 cache = &obj_state->os_secarr[obj_state->os_dynndx]; 1380 dyn = (Dyn *) cache->sec_data->d_buf; 1381 i = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize; 1382 for (; i-- > 0; dyn++) { 1383 s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_DT, 1384 dyn->d_tag, 0); 1385 if (s == NULL) 1386 continue; 1387 elfedit_cpl_match(cpldata, s, 1); 1388 1389 /* 1390 * To get the informal tag names that are lowercase 1391 * and lack the leading DT_, we copy the string we 1392 * have into a buffer and process it. 1393 */ 1394 if (strlen(s) < 3) 1395 continue; 1396 (void) strlcpy(buf, s + 3, sizeof (buf)); 1397 for (s2 = buf; *s2 != '\0'; s2++) 1398 if (isupper(*s2)) 1399 *s2 = tolower(*s2); 1400 elfedit_cpl_match(cpldata, buf, 1); 1401 } 1402 } 1403 1404 1405 /*ARGSUSED*/ 1406 static void 1407 cpl_tag(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1408 const char *argv[], int num_opt) 1409 { 1410 /* First argument */ 1411 if ((argc - num_opt) == 1) { 1412 cpl_eltarg(obj_state, cpldata, argc, argv, num_opt); 1413 return; 1414 } 1415 1416 /* The second argument is always a tag value */ 1417 if ((argc - num_opt) == 2) 1418 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DT); 1419 } 1420 1421 /*ARGSUSED*/ 1422 static void 1423 cpl_posflag1(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1424 const char *argv[], int num_opt) 1425 { 1426 /* This routine allows multiple flags to be specified */ 1427 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_P1); 1428 } 1429 1430 /*ARGSUSED*/ 1431 static void 1432 cpl_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1433 const char *argv[], int num_opt) 1434 { 1435 /* This routine allows multiple flags to be specified */ 1436 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF); 1437 } 1438 1439 /*ARGSUSED*/ 1440 static void 1441 cpl_flags1(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1442 const char *argv[], int num_opt) 1443 { 1444 /* This routine allows multiple flags to be specified */ 1445 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DF_1); 1446 } 1447 1448 /*ARGSUSED*/ 1449 static void 1450 cpl_feature1(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1451 const char *argv[], int num_opt) 1452 { 1453 /* This routine allows multiple flags to be specified */ 1454 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_DTF_1); 1455 } 1456 1457 1458 /* 1459 * Implementation functions for the commands 1460 */ 1461 static elfedit_cmdret_t 1462 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1463 { 1464 return (cmd_body(DYN_CMD_T_DUMP, obj_state, argc, argv)); 1465 } 1466 1467 static elfedit_cmdret_t 1468 cmd_tag(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1469 { 1470 return (cmd_body(DYN_CMD_T_TAG, obj_state, argc, argv)); 1471 } 1472 1473 static elfedit_cmdret_t 1474 cmd_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1475 { 1476 return (cmd_body(DYN_CMD_T_VALUE, obj_state, argc, argv)); 1477 } 1478 1479 static elfedit_cmdret_t 1480 cmd_delete(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1481 { 1482 return (cmd_body(DYN_CMD_T_DELETE, obj_state, argc, argv)); 1483 } 1484 1485 static elfedit_cmdret_t 1486 cmd_move(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1487 { 1488 return (cmd_body(DYN_CMD_T_MOVE, obj_state, argc, argv)); 1489 } 1490 1491 static elfedit_cmdret_t 1492 cmd_runpath(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1493 { 1494 return (cmd_body(DYN_CMD_T_RUNPATH, obj_state, argc, argv)); 1495 } 1496 1497 static elfedit_cmdret_t 1498 cmd_posflag1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1499 { 1500 return (cmd_body(DYN_CMD_T_POSFLAG1, obj_state, argc, argv)); 1501 } 1502 1503 static elfedit_cmdret_t 1504 cmd_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1505 { 1506 return (cmd_body(DYN_CMD_T_FLAGS, obj_state, argc, argv)); 1507 } 1508 1509 static elfedit_cmdret_t 1510 cmd_flags1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1511 { 1512 return (cmd_body(DYN_CMD_T_FLAGS1, obj_state, argc, argv)); 1513 } 1514 1515 static elfedit_cmdret_t 1516 cmd_feature1(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1517 { 1518 return (cmd_body(DYN_CMD_T_FEATURE1, obj_state, argc, argv)); 1519 } 1520 1521 static elfedit_cmdret_t 1522 cmd_checksum(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1523 { 1524 return (cmd_body(DYN_CMD_T_CHECKSUM, obj_state, argc, argv)); 1525 } 1526 1527 1528 1529 /*ARGSUSED*/ 1530 elfedit_module_t * 1531 elfedit_init(elfedit_module_version_t version) 1532 { 1533 /* For commands that only accept -o */ 1534 static elfedit_cmd_optarg_t opt_ostyle[] = { 1535 { ELFEDIT_STDOA_OPT_O, NULL, 1536 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 1537 { NULL } 1538 }; 1539 1540 /* For commands that only accept -and, -cmp, -o, -or */ 1541 static elfedit_cmd_optarg_t opt_ostyle_bitop[] = { 1542 { ELFEDIT_STDOA_OPT_AND, NULL, 1543 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_AND, DYN_OPT_F_OR }, 1544 { ELFEDIT_STDOA_OPT_CMP, NULL, 1545 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_CMP, 0 }, 1546 { ELFEDIT_STDOA_OPT_O, NULL, 1547 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 1548 { ELFEDIT_STDOA_OPT_OR, NULL, 1549 ELFEDIT_CMDOA_F_INHERIT, DYN_OPT_F_OR, DYN_OPT_F_AND }, 1550 { NULL } 1551 }; 1552 1553 /* For commands that only accept -dynndx */ 1554 static elfedit_cmd_optarg_t opt_minus_dynndx[] = { 1555 { MSG_ORIG(MSG_STR_MINUS_DYNNDX), 1556 /* MSG_INTL(MSG_OPTDESC_DYNNDX) */ 1557 ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0, 1558 DYN_OPT_F_DYNNDX, 0 }, 1559 { NULL } 1560 }; 1561 1562 /* dyn:dump */ 1563 static const char *name_dump[] = { 1564 MSG_ORIG(MSG_CMD_DUMP), 1565 MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */ 1566 NULL 1567 }; 1568 static elfedit_cmd_optarg_t arg_dump[] = { 1569 { MSG_ORIG(MSG_STR_ELT), 1570 /* MSG_INTL(MSG_ARGDESC_ELT) */ 1571 ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), 1572 ELFEDIT_CMDOA_F_OPT }, 1573 { NULL } 1574 }; 1575 1576 1577 /* dyn:tag */ 1578 static const char *name_tag[] = { MSG_ORIG(MSG_CMD_TAG), NULL }; 1579 static elfedit_cmd_optarg_t opt_tag[] = { 1580 { MSG_ORIG(MSG_STR_MINUS_DYNNDX), 1581 /* MSG_INTL(MSG_OPTDESC_DYNNDX) */ 1582 ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0, 1583 DYN_OPT_F_DYNNDX, 0 }, 1584 { ELFEDIT_STDOA_OPT_O, NULL, 1585 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 1586 { NULL } 1587 }; 1588 static elfedit_cmd_optarg_t arg_tag[] = { 1589 { MSG_ORIG(MSG_STR_ELT), 1590 /* MSG_INTL(MSG_A1_TAG_ELT) */ 1591 ELFEDIT_I18NHDL(MSG_A1_TAG_ELT), 1592 ELFEDIT_CMDOA_F_OPT }, 1593 { MSG_ORIG(MSG_STR_VALUE), 1594 /* MSG_INTL(MSG_A2_TAG_VALUE) */ 1595 ELFEDIT_I18NHDL(MSG_A2_TAG_VALUE), 1596 ELFEDIT_CMDOA_F_OPT }, 1597 { NULL } 1598 }; 1599 1600 1601 /* dyn:value */ 1602 static const char *name_value[] = { MSG_ORIG(MSG_CMD_VALUE), NULL }; 1603 static elfedit_cmd_optarg_t opt_value[] = { 1604 { MSG_ORIG(MSG_STR_MINUS_ADD), 1605 /* MSG_INTL(MSG_OPTDESC_ADD) */ 1606 ELFEDIT_I18NHDL(MSG_OPTDESC_ADD), 0, 1607 DYN_OPT_F_ADD, DYN_OPT_F_DYNNDX }, 1608 { MSG_ORIG(MSG_STR_MINUS_DYNNDX), 1609 /* MSG_INTL(MSG_OPTDESC_DYNNDX) */ 1610 ELFEDIT_I18NHDL(MSG_OPTDESC_DYNNDX), 0, 1611 DYN_OPT_F_DYNNDX, DYN_OPT_F_ADD }, 1612 { ELFEDIT_STDOA_OPT_O, NULL, 1613 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 1614 { MSG_ORIG(MSG_STR_MINUS_S), 1615 /* MSG_INTL(MSG_OPTDESC_S) */ 1616 ELFEDIT_I18NHDL(MSG_OPTDESC_S), 0, 1617 DYN_OPT_F_STRVAL, 0 }, 1618 { NULL } 1619 }; 1620 static elfedit_cmd_optarg_t arg_value[] = { 1621 { MSG_ORIG(MSG_STR_ELT), 1622 /* MSG_INTL(MSG_ARGDESC_ELT) */ 1623 ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), 1624 ELFEDIT_CMDOA_F_OPT }, 1625 { MSG_ORIG(MSG_STR_VALUE), 1626 /* MSG_INTL(MSG_A2_VALUE_VALUE) */ 1627 ELFEDIT_I18NHDL(MSG_A2_VALUE_VALUE), 1628 ELFEDIT_CMDOA_F_OPT }, 1629 { NULL } 1630 }; 1631 1632 /* dyn:delete */ 1633 static const char *name_delete[] = { MSG_ORIG(MSG_CMD_DELETE), NULL }; 1634 static elfedit_cmd_optarg_t arg_delete[] = { 1635 { MSG_ORIG(MSG_STR_ELT), 1636 /* MSG_INTL(MSG_ARGDESC_ELT) */ 1637 ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), 1638 0 }, 1639 { MSG_ORIG(MSG_STR_COUNT), 1640 /* MSG_INTL(MSG_A2_DELETE_COUNT) */ 1641 ELFEDIT_I18NHDL(MSG_A2_DELETE_COUNT), 1642 ELFEDIT_CMDOA_F_OPT }, 1643 { NULL } 1644 }; 1645 1646 /* dyn:move */ 1647 static const char *name_move[] = { MSG_ORIG(MSG_CMD_MOVE), NULL }; 1648 static elfedit_cmd_optarg_t arg_move[] = { 1649 { MSG_ORIG(MSG_STR_ELT), 1650 /* MSG_INTL(MSG_ARGDESC_ELT) */ 1651 ELFEDIT_I18NHDL(MSG_ARGDESC_ELT), 1652 0 }, 1653 { MSG_ORIG(MSG_STR_DST_INDEX), 1654 /* MSG_INTL(MSG_A2_MOVE_DST_INDEX) */ 1655 ELFEDIT_I18NHDL(MSG_A2_MOVE_DST_INDEX), 1656 0 }, 1657 { MSG_ORIG(MSG_STR_COUNT), 1658 /* MSG_INTL(MSG_A3_MOVE_COUNT) */ 1659 ELFEDIT_I18NHDL(MSG_A3_MOVE_COUNT), 1660 ELFEDIT_CMDOA_F_OPT }, 1661 { NULL } 1662 }; 1663 1664 /* dyn:runpath / dyn:rpath */ 1665 static const char *name_runpath[] = { MSG_ORIG(MSG_CMD_RUNPATH), 1666 MSG_ORIG(MSG_CMD_RUNPATH_A1), NULL }; 1667 static elfedit_cmd_optarg_t arg_runpath[] = { 1668 { MSG_ORIG(MSG_STR_NEWPATH), 1669 /* MSG_INTL(MSG_A1_RUNPATH_NEWPATH) */ 1670 ELFEDIT_I18NHDL(MSG_A1_RUNPATH_NEWPATH), 1671 ELFEDIT_CMDOA_F_OPT }, 1672 { NULL } 1673 }; 1674 1675 /* dyn:posflag1 */ 1676 static const char *name_posflag1[] = { MSG_ORIG(MSG_CMD_POSFLAG1), 1677 NULL }; 1678 static elfedit_cmd_optarg_t arg_posflag1[] = { 1679 { MSG_ORIG(MSG_STR_VALUE), 1680 /* MSG_INTL(MSG_A1_POSFLAG1_VALUE) */ 1681 ELFEDIT_I18NHDL(MSG_A1_POSFLAG1_VALUE), 1682 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, 1683 { NULL } 1684 }; 1685 1686 /* dyn:flags */ 1687 static const char *name_flags[] = { MSG_ORIG(MSG_CMD_FLAGS), NULL }; 1688 static elfedit_cmd_optarg_t arg_flags[] = { 1689 { MSG_ORIG(MSG_STR_VALUE), 1690 /* MSG_INTL(MSG_A1_FLAGS_VALUE) */ 1691 ELFEDIT_I18NHDL(MSG_A1_FLAGS_VALUE), 1692 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, 1693 { NULL } 1694 }; 1695 1696 /* dyn:flags1 */ 1697 static const char *name_flags1[] = { MSG_ORIG(MSG_CMD_FLAGS1), NULL }; 1698 static elfedit_cmd_optarg_t arg_flags1[] = { 1699 { MSG_ORIG(MSG_STR_VALUE), 1700 /* MSG_INTL(MSG_A1_FLAGS1_VALUE) */ 1701 ELFEDIT_I18NHDL(MSG_A1_FLAGS1_VALUE), 1702 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, 1703 { NULL } 1704 }; 1705 1706 /* dyn:feature1 */ 1707 static const char *name_feature1[] = { MSG_ORIG(MSG_CMD_FEATURE1), 1708 NULL }; 1709 static elfedit_cmd_optarg_t arg_feature1[] = { 1710 { MSG_ORIG(MSG_STR_VALUE), 1711 /* MSG_INTL(MSG_A1_FEATURE1_VALUE) */ 1712 ELFEDIT_I18NHDL(MSG_A1_FEATURE1_VALUE), 1713 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, 1714 { NULL } 1715 }; 1716 1717 /* dyn:checksum */ 1718 static const char *name_checksum[] = { MSG_ORIG(MSG_CMD_CHECKSUM), 1719 NULL }; 1720 1721 1722 1723 static elfedit_cmd_t cmds[] = { 1724 /* dyn:dump */ 1725 { cmd_dump, cpl_eltarg, name_dump, 1726 /* MSG_INTL(MSG_DESC_DUMP) */ 1727 ELFEDIT_I18NHDL(MSG_DESC_DUMP), 1728 /* MSG_INTL(MSG_HELP_DUMP) */ 1729 ELFEDIT_I18NHDL(MSG_HELP_DUMP), 1730 opt_minus_dynndx, arg_dump }, 1731 1732 /* dyn:tag */ 1733 { cmd_tag, cpl_tag, name_tag, 1734 /* MSG_INTL(MSG_DESC_TAG) */ 1735 ELFEDIT_I18NHDL(MSG_DESC_TAG), 1736 /* MSG_INTL(MSG_HELP_TAG) */ 1737 ELFEDIT_I18NHDL(MSG_HELP_TAG), 1738 opt_tag, arg_tag }, 1739 1740 /* dyn:value */ 1741 { cmd_value, cpl_eltarg, name_value, 1742 /* MSG_INTL(MSG_DESC_VALUE) */ 1743 ELFEDIT_I18NHDL(MSG_DESC_VALUE), 1744 /* MSG_INTL(MSG_HELP_VALUE) */ 1745 ELFEDIT_I18NHDL(MSG_HELP_VALUE), 1746 opt_value, arg_value }, 1747 1748 /* dyn:delete */ 1749 { cmd_delete, cpl_eltarg, name_delete, 1750 /* MSG_INTL(MSG_DESC_DELETE) */ 1751 ELFEDIT_I18NHDL(MSG_DESC_DELETE), 1752 /* MSG_INTL(MSG_HELP_DELETE) */ 1753 ELFEDIT_I18NHDL(MSG_HELP_DELETE), 1754 opt_minus_dynndx, arg_delete }, 1755 1756 /* dyn:move */ 1757 { cmd_move, cpl_eltarg, name_move, 1758 /* MSG_INTL(MSG_DESC_MOVE) */ 1759 ELFEDIT_I18NHDL(MSG_DESC_MOVE), 1760 /* MSG_INTL(MSG_HELP_MOVE) */ 1761 ELFEDIT_I18NHDL(MSG_HELP_MOVE), 1762 opt_minus_dynndx, arg_move }, 1763 1764 /* dyn:runpath */ 1765 { cmd_runpath, NULL, name_runpath, 1766 /* MSG_INTL(MSG_DESC_RUNPATH) */ 1767 ELFEDIT_I18NHDL(MSG_DESC_RUNPATH), 1768 /* MSG_INTL(MSG_HELP_RUNPATH) */ 1769 ELFEDIT_I18NHDL(MSG_HELP_RUNPATH), 1770 opt_ostyle, arg_runpath }, 1771 1772 /* dyn:posflag1 */ 1773 { cmd_posflag1, cpl_posflag1, name_posflag1, 1774 /* MSG_INTL(MSG_DESC_POSFLAG1) */ 1775 ELFEDIT_I18NHDL(MSG_DESC_POSFLAG1), 1776 /* MSG_INTL(MSG_HELP_POSFLAG1) */ 1777 ELFEDIT_I18NHDL(MSG_HELP_POSFLAG1), 1778 opt_ostyle_bitop, arg_posflag1 }, 1779 1780 /* dyn:flags */ 1781 { cmd_flags, cpl_flags, name_flags, 1782 /* MSG_INTL(MSG_DESC_FLAGS) */ 1783 ELFEDIT_I18NHDL(MSG_DESC_FLAGS), 1784 /* MSG_INTL(MSG_HELP_FLAGS) */ 1785 ELFEDIT_I18NHDL(MSG_HELP_FLAGS), 1786 opt_ostyle_bitop, arg_flags }, 1787 1788 /* dyn:flags1 */ 1789 { cmd_flags1, cpl_flags1, name_flags1, 1790 /* MSG_INTL(MSG_DESC_FLAGS1) */ 1791 ELFEDIT_I18NHDL(MSG_DESC_FLAGS1), 1792 /* MSG_INTL(MSG_HELP_FLAGS1) */ 1793 ELFEDIT_I18NHDL(MSG_HELP_FLAGS1), 1794 opt_ostyle_bitop, arg_flags1 }, 1795 1796 /* dyn:feature1 */ 1797 { cmd_feature1, cpl_feature1, name_feature1, 1798 /* MSG_INTL(MSG_DESC_FEATURE1) */ 1799 ELFEDIT_I18NHDL(MSG_DESC_FEATURE1), 1800 /* MSG_INTL(MSG_HELP_FEATURE1) */ 1801 ELFEDIT_I18NHDL(MSG_HELP_FEATURE1), 1802 opt_ostyle_bitop, arg_feature1 }, 1803 1804 /* dyn:checksum */ 1805 { cmd_checksum, NULL, name_checksum, 1806 /* MSG_INTL(MSG_DESC_CHECKSUM) */ 1807 ELFEDIT_I18NHDL(MSG_DESC_CHECKSUM), 1808 /* MSG_INTL(MSG_HELP_CHECKSUM) */ 1809 ELFEDIT_I18NHDL(MSG_HELP_CHECKSUM), 1810 NULL, NULL }, 1811 1812 { NULL } 1813 }; 1814 1815 static elfedit_module_t module = { 1816 ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME), 1817 /* MSG_INTL(MSG_MOD_DESC) */ 1818 ELFEDIT_I18NHDL(MSG_MOD_DESC), cmds, mod_i18nhdl_to_str }; 1819 1820 return (&module); 1821 } 1822