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