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