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