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