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