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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #define ELF_TARGET_AMD64 /* SHN_AMD64_LCOMMON */ 29 30 #include <stdio.h> 31 #include <unistd.h> 32 #include <machdep.h> 33 #include <elfedit.h> 34 #include <strings.h> 35 #include <debug.h> 36 #include <conv.h> 37 #include <sym_msg.h> 38 39 40 41 42 #define MAXNDXSIZE 10 43 44 45 46 /* 47 * This module uses shared code for several of the commands. 48 * It is sometimes necessary to know which specific command 49 * is active. 50 */ 51 typedef enum { 52 SYM_CMD_T_DUMP = 0, /* sym:dump */ 53 54 SYM_CMD_T_ST_BIND = 1, /* sym:st_bind */ 55 SYM_CMD_T_ST_INFO = 2, /* sym:st_info */ 56 SYM_CMD_T_ST_NAME = 3, /* sym:st_name */ 57 SYM_CMD_T_ST_OTHER = 4, /* sym:st_other */ 58 SYM_CMD_T_ST_SHNDX = 5, /* sym:st_shndx */ 59 SYM_CMD_T_ST_SIZE = 6, /* sym:st_size */ 60 SYM_CMD_T_ST_TYPE = 7, /* sym:st_type */ 61 SYM_CMD_T_ST_VALUE = 8, /* sym:st_value */ 62 SYM_CMD_T_ST_VISIBILITY = 9 /* sym:st_visibility */ 63 } SYM_CMD_T; 64 65 66 67 /* 68 * ELFCLASS-specific definitions 69 */ 70 #ifdef _ELF64 71 72 #define MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_64 73 74 #else 75 76 #define MSG_FMT_XWORDVALNL MSG_FMT_XWORDVALNL_32 77 78 /* 79 * We supply this function for the msg module. Only one copy is needed. 80 */ 81 const char * 82 _sym_msg(Msg mid) 83 { 84 return (gettext(MSG_ORIG(mid))); 85 } 86 87 #endif 88 89 90 91 /* 92 * This function is supplied to elfedit through our elfedit_module_t 93 * definition. It translates the opaque elfedit_i18nhdl_t handles 94 * in our module interface into the actual strings for elfedit to 95 * use. 96 * 97 * note: 98 * This module uses Msg codes for its i18n handle type. 99 * So the translation is simply to use MSG_INTL() to turn 100 * it into a string and return it. 101 */ 102 static const char * 103 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl) 104 { 105 Msg msg = (Msg)hdl; 106 107 return (MSG_INTL(msg)); 108 } 109 110 111 112 /* 113 * The sym_opt_t enum specifies a bit value for every optional 114 * argument allowed by a command in this module. 115 */ 116 typedef enum { 117 SYM_OPT_F_XSHINDEX = 1, /* -e: Force shndx update to extended */ 118 /* index section */ 119 SYM_OPT_F_NAMOFFSET = 2, /* -name_offset: sym:st_name name arg */ 120 /* is numeric offset */ 121 /* rather than ASCII string */ 122 SYM_OPT_F_SECSHNDX = 4, /* -secshndx: Section arg is */ 123 /* section index, not name */ 124 SYM_OPT_F_SECSHTYP = 8, /* -secshtyp: Section arg is */ 125 /* section type, not name */ 126 SYM_OPT_F_SHNAME = 16, /* -shnam name: section spec. by name */ 127 SYM_OPT_F_SHNDX = 32, /* -shndx ndx: section spec. by index */ 128 SYM_OPT_F_SHTYP = 64, /* -shtyp type: section spec. by type */ 129 SYM_OPT_F_SYMNDX = 128 /* -symndx: Sym specified by index */ 130 } sym_opt_t; 131 132 133 /* 134 * A variable of type ARGSTATE is used by each command to maintain 135 * the overall state for a given set of arguments and the symbol tables 136 * being managed. 137 * 138 * The state for each symbol table and the auxiliary sections that are 139 * related to it are kept in a SYMSTATE sub-struct. 140 * 141 * One benefit of ARGSTATE is that it helps us to ensure that we only 142 * fetch each section a single time: 143 * - More efficient 144 * - Prevents multiple ELFEDIT_MSG_DEBUG messages from 145 * being produced for a given section. 146 * 147 * note: The symstate array in ARGSTATE is defined as having one 148 * element, but in reality, we allocate enough room for 149 * the number of elements defined in the numsymstate field. 150 */ 151 typedef struct { 152 Word ndx; /* If argstate.argc > 0, this is the table index */ 153 struct { /* Symbol table */ 154 elfedit_section_t *sec; 155 Sym *data; 156 Word n; 157 } sym; 158 struct { /* String table */ 159 elfedit_section_t *sec; 160 } str; 161 struct { /* Versym */ 162 Word shndx; 163 elfedit_section_t *sec; 164 Versym *data; 165 Word n; 166 } versym; 167 struct { /* Extended section indices */ 168 Word shndx; 169 elfedit_section_t *sec; 170 Word *data; 171 Word n; 172 } xshndx; 173 } SYMSTATE; 174 typedef struct { 175 elfedit_obj_state_t *obj_state; 176 sym_opt_t optmask; /* Mask of options used */ 177 int argc; /* # of plain arguments */ 178 const char **argv; /* Plain arguments */ 179 int numsymstate; /* # of items in symstate[] */ 180 SYMSTATE symstate[1]; /* Symbol tables to process */ 181 } ARGSTATE; 182 183 184 /* 185 * We maintain the state of each symbol table and related associated 186 * sections in a SYMSTATE structure . We don't look those auxiliary 187 * things up unless we actually need them, both to be efficient, 188 * and to prevent duplicate ELFEDIT_MSG_DEBUG messages from being 189 * issued as they are located. Hence, process_args() is used to 190 * initialize the state block with just the symbol table, and then one 191 * of the argstate_add_XXX() functions is used as needed 192 * to fetch the additional sections. 193 * 194 * entry: 195 * argstate - Overall state block 196 * symstate - State block for current symbol table. 197 * 198 * exit: 199 * If the needed auxiliary section is not found, an error is 200 * issued and the argstate_add_XXX() routine does not return. 201 * Otherwise, the fields in argstate have been filled in, ready 202 * for use. 203 * 204 */ 205 static void 206 symstate_add_str(ARGSTATE *argstate, SYMSTATE *symstate) 207 { 208 if (symstate->str.sec != NULL) 209 return; 210 211 symstate->str.sec = elfedit_sec_getstr(argstate->obj_state, 212 symstate->sym.sec->sec_shdr->sh_link); 213 } 214 static void 215 symstate_add_versym(ARGSTATE *argstate, SYMSTATE *symstate) 216 { 217 if (symstate->versym.sec != NULL) 218 return; 219 220 symstate->versym.sec = elfedit_sec_getversym(argstate->obj_state, 221 symstate->sym.sec, &symstate->versym.data, &symstate->versym.n); 222 } 223 static void 224 symstate_add_xshndx(ARGSTATE *argstate, SYMSTATE *symstate) 225 { 226 if (symstate->xshndx.sec != NULL) 227 return; 228 229 symstate->xshndx.sec = elfedit_sec_getxshndx(argstate->obj_state, 230 symstate->sym.sec, &symstate->xshndx.data, &symstate->xshndx.n); 231 } 232 233 234 235 /* 236 * Display symbol table entries in the style used by elfdump. 237 * 238 * entry: 239 * argstate - Overall state block 240 * symstate - State block for current symbol table. 241 * ndx - Index of first symbol to display 242 * cnt - Number of symbols to display 243 */ 244 static void 245 dump_symtab(ARGSTATE *argstate, SYMSTATE *symstate, Word ndx, Word cnt) 246 { 247 char index[MAXNDXSIZE]; 248 Word shndx; 249 const char *shndx_name; 250 elfedit_section_t *symsec; 251 elfedit_section_t *strsec; 252 Sym *sym; 253 elfedit_obj_state_t *obj_state = argstate->obj_state; 254 Half mach = obj_state->os_ehdr->e_machine; 255 const char *symname; 256 Versym versym; 257 258 symsec = symstate->sym.sec; 259 sym = symstate->sym.data + ndx; 260 261 symstate_add_str(argstate, symstate); 262 strsec = symstate->str.sec; 263 264 /* If there is a versym index section, fetch it */ 265 if (symstate->versym.shndx != SHN_UNDEF) 266 symstate_add_versym(argstate, symstate); 267 268 /* If there is an extended index section, fetch it */ 269 if (symstate->xshndx.shndx != SHN_UNDEF) 270 symstate_add_xshndx(argstate, symstate); 271 272 elfedit_printf(MSG_INTL(MSG_FMT_SYMTAB), symsec->sec_name); 273 Elf_syms_table_title(0, ELF_DBG_ELFDUMP); 274 for (; cnt-- > 0; ndx++, sym++) { 275 (void) snprintf(index, MAXNDXSIZE, 276 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx)); 277 versym = (symstate->versym.sec == NULL) ? 0 : 278 symstate->versym.data[ndx]; 279 symname = elfedit_offset_to_str(strsec, sym->st_name, 280 ELFEDIT_MSG_DEBUG, 0); 281 shndx = sym->st_shndx; 282 if ((shndx == SHN_XINDEX) && (symstate->xshndx.sec != NULL)) 283 shndx = symstate->xshndx.data[ndx]; 284 shndx_name = elfedit_shndx_to_name(obj_state, shndx); 285 Elf_syms_table_entry(NULL, ELF_DBG_ELFDUMP, index, mach, 286 sym, versym, 0, shndx_name, symname); 287 } 288 } 289 290 291 292 /* 293 * Called by print_sym() to determine if a given symbol has the same 294 * display value for the current command in every symbol table. 295 * 296 * entry: 297 * cmd - SYM_CMD_T_* value giving identify of caller 298 * argstate - Overall state block 299 * outstyle - Output style to use 300 */ 301 static int 302 all_same(SYM_CMD_T cmd, ARGSTATE *argstate, elfedit_outstyle_t outstyle) 303 { 304 Word tblndx; 305 SYMSTATE *symstate1, *symstate2; 306 Sym *sym1, *sym2; 307 308 symstate1 = argstate->symstate; 309 for (tblndx = 0; tblndx < (argstate->numsymstate - 1); 310 tblndx++, symstate1++) { 311 symstate2 = symstate1 + 1; 312 sym1 = &symstate1->sym.data[symstate1->ndx]; 313 sym2 = &symstate2->sym.data[symstate2->ndx]; 314 315 switch (cmd) { 316 case SYM_CMD_T_DUMP: 317 /* sym:dump should always show everything */ 318 return (0); 319 320 case SYM_CMD_T_ST_BIND: 321 if (ELF_ST_BIND(sym1->st_info) != 322 ELF_ST_BIND(sym2->st_info)) 323 return (0); 324 break; 325 326 case SYM_CMD_T_ST_INFO: 327 if (sym1->st_info != sym2->st_info) 328 return (0); 329 break; 330 331 case SYM_CMD_T_ST_NAME: 332 /* 333 * In simple output mode, we show the string. In 334 * numeric mode, we show the string table offset. 335 */ 336 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 337 const char *n1, *n2; 338 339 symstate_add_str(argstate, symstate1); 340 symstate_add_str(argstate, symstate2); 341 n1 = elfedit_offset_to_str(symstate1->str.sec, 342 sym1->st_name, ELFEDIT_MSG_DEBUG, 0); 343 n2 = elfedit_offset_to_str(symstate2->str.sec, 344 sym2->st_name, ELFEDIT_MSG_DEBUG, 0); 345 if (strcmp(n1, n2) != 0) 346 return (0); 347 } else { 348 if (sym1->st_name != sym2->st_name) 349 return (0); 350 } 351 break; 352 353 case SYM_CMD_T_ST_OTHER: 354 if (sym1->st_other != sym2->st_other) 355 return (0); 356 break; 357 358 case SYM_CMD_T_ST_SHNDX: 359 { 360 Word ndx1, ndx2; 361 362 ndx1 = sym1->st_shndx; 363 if ((ndx1 == SHN_XINDEX) && 364 (symstate1->xshndx.shndx != SHN_UNDEF)) { 365 symstate_add_xshndx(argstate, 366 symstate1); 367 ndx1 = symstate1->xshndx. 368 data[symstate1->ndx]; 369 } 370 ndx2 = sym2->st_shndx; 371 if ((ndx2 == SHN_XINDEX) && 372 (symstate2->xshndx.shndx != SHN_UNDEF)) { 373 symstate_add_xshndx(argstate, 374 symstate2); 375 ndx2 = symstate2->xshndx. 376 data[symstate2->ndx]; 377 } 378 if (ndx1 != ndx2) 379 return (0); 380 } 381 break; 382 383 case SYM_CMD_T_ST_SIZE: 384 if (sym1->st_size != sym2->st_size) 385 return (0); 386 break; 387 388 case SYM_CMD_T_ST_TYPE: 389 if (ELF_ST_TYPE(sym1->st_info) != 390 ELF_ST_TYPE(sym2->st_info)) 391 return (0); 392 break; 393 394 case SYM_CMD_T_ST_VALUE: 395 if (sym1->st_value != sym2->st_value) 396 return (0); 397 break; 398 399 case SYM_CMD_T_ST_VISIBILITY: 400 if (ELF_ST_VISIBILITY(sym1->st_info) != 401 ELF_ST_VISIBILITY(sym2->st_info)) 402 return (0); 403 break; 404 } 405 } 406 407 /* If we got here, there are no differences (or maybe only 1 table */ 408 return (1); 409 } 410 411 412 /* 413 * Called by print_sym() to display values for a single symbol table. 414 * 415 * entry: 416 * autoprint - If True, output is only produced if the elfedit 417 * autoprint flag is set. If False, output is always produced. 418 * cmd - SYM_CMD_T_* value giving identify of caller 419 * argstate - Overall state block 420 * symstate - State block for current symbol table. 421 * ndx - Index of first symbol to display 422 * cnt - Number of symbols to display 423 */ 424 static void 425 print_symstate(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate, 426 elfedit_outstyle_t outstyle, Word ndx, Word cnt) 427 { 428 Word value; 429 Sym *sym; 430 431 /* 432 * If doing default output, use elfdump style where we 433 * show all symbol attributes. In this case, the command 434 * that called us doesn't matter 435 */ 436 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { 437 dump_symtab(argstate, symstate, ndx, cnt); 438 return; 439 } 440 441 sym = symstate->sym.data; 442 443 switch (cmd) { 444 case SYM_CMD_T_ST_BIND: 445 { 446 Conv_inv_buf_t inv_buf; 447 448 for (sym += ndx; cnt--; sym++) { 449 value = ELF_ST_BIND(sym->st_info); 450 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 451 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), 452 conv_sym_info_bind(value, 453 CONV_FMT_ALT_FULLNAME, &inv_buf)); 454 } else { 455 elfedit_printf( 456 MSG_ORIG(MSG_FMT_WORDVALNL), 457 EC_WORD(value)); 458 } 459 } 460 } 461 return; 462 463 case SYM_CMD_T_ST_INFO: 464 for (sym += ndx; cnt-- > 0; sym++) 465 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), 466 EC_WORD(sym->st_info)); 467 return; 468 469 case SYM_CMD_T_ST_NAME: 470 /* 471 * In simple output mode, we show the string. In numeric 472 * mode, we show the string table offset. 473 */ 474 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 475 symstate_add_str(argstate, symstate); 476 for (sym += ndx; cnt--; sym++) { 477 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), 478 elfedit_offset_to_str(symstate->str.sec, 479 sym->st_name, ELFEDIT_MSG_ERR, 0)); 480 } 481 } else { 482 for (; cnt--; sym++) 483 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), 484 EC_WORD(sym->st_name)); 485 } 486 return; 487 488 case SYM_CMD_T_ST_OTHER: 489 for (sym += ndx; cnt-- > 0; sym++) 490 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), 491 EC_WORD(sym->st_other)); 492 return; 493 494 case SYM_CMD_T_ST_SHNDX: 495 /* If there is an extended index section, fetch it */ 496 if (symstate->xshndx.shndx != SHN_UNDEF) 497 symstate_add_xshndx(argstate, symstate); 498 499 for (; cnt--; ndx++) { 500 value = sym[ndx].st_shndx; 501 if ((value == SHN_XINDEX) && 502 (symstate->xshndx.sec != NULL)) 503 value = symstate->xshndx.data[ndx]; 504 505 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 506 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), 507 elfedit_shndx_to_name(argstate->obj_state, 508 value)); 509 } else { 510 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), 511 EC_WORD(value)); 512 } 513 } 514 return; 515 516 case SYM_CMD_T_ST_SIZE: 517 /* 518 * machine word width integers displayed in fixed width 519 * 0-filled hex format. 520 */ 521 for (sym += ndx; cnt--; sym++) 522 elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL), 523 sym->st_size); 524 return; 525 526 case SYM_CMD_T_ST_TYPE: 527 { 528 Half mach = argstate->obj_state->os_ehdr->e_machine; 529 Conv_inv_buf_t inv_buf; 530 531 for (sym += ndx; cnt--; sym++) { 532 value = ELF_ST_TYPE(sym->st_info); 533 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 534 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), 535 conv_sym_info_type(mach, value, 536 CONV_FMT_ALT_FULLNAME, &inv_buf)); 537 } else { 538 elfedit_printf( 539 MSG_ORIG(MSG_FMT_WORDVALNL), 540 EC_WORD(value)); 541 } 542 } 543 } 544 return; 545 546 case SYM_CMD_T_ST_VALUE: 547 /* 548 * machine word width integers displayed in fixed width 549 * 0-filled hex format. 550 */ 551 for (sym += ndx; cnt--; sym++) 552 elfedit_printf(MSG_ORIG(MSG_FMT_XWORDVALNL), 553 sym->st_value); 554 return; 555 556 case SYM_CMD_T_ST_VISIBILITY: 557 { 558 Conv_inv_buf_t inv_buf; 559 560 for (sym += ndx; cnt--; sym++) { 561 value = ELF_ST_VISIBILITY(sym->st_other); 562 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 563 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), 564 conv_sym_other_vis(value, 565 CONV_FMT_ALT_FULLNAME, &inv_buf)); 566 } else { 567 elfedit_printf( 568 MSG_ORIG(MSG_FMT_WORDVALNL), 569 EC_WORD(value)); 570 } 571 } 572 } 573 return; 574 575 } 576 } 577 578 579 /* 580 * Print symbol values, taking the calling command, and output style 581 * into account. 582 * 583 * entry: 584 * autoprint - If True, output is only produced if the elfedit 585 * autoprint flag is set. If False, output is always produced. 586 * cmd - SYM_CMD_T_* value giving identify of caller 587 * argstate - Overall state block 588 * symstate - State block for current symbol table. 589 * ndx - Index of first symbol to display 590 * cnt - Number of symbols to display 591 */ 592 static void 593 print_sym(SYM_CMD_T cmd, int autoprint, ARGSTATE *argstate) 594 { 595 Word ndx, tblndx; 596 Word cnt; 597 elfedit_outstyle_t outstyle; 598 SYMSTATE *symstate; 599 int only_one; 600 601 if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0))) 602 return; 603 604 /* 605 * Pick an output style. sym:dump is required to use the default 606 * style. The other commands use the current output style. 607 */ 608 outstyle = (cmd == SYM_CMD_T_DUMP) ? 609 ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); 610 611 /* 612 * This is a nicity: Force any needed auxiliary sections to be 613 * fetched here before any output is produced. This will put all 614 * of the debug messages right at the top in a single cluster. 615 */ 616 symstate = argstate->symstate; 617 for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) { 618 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { 619 symstate_add_str(argstate, symstate); 620 if (symstate->versym.shndx != SHN_UNDEF) 621 symstate_add_versym(argstate, symstate); 622 if (symstate->xshndx.shndx != SHN_UNDEF) 623 symstate_add_xshndx(argstate, symstate); 624 continue; 625 } 626 627 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 628 switch (cmd) { 629 case SYM_CMD_T_ST_NAME: 630 symstate_add_str(argstate, symstate); 631 break; 632 633 case SYM_CMD_T_ST_SHNDX: 634 if (symstate->xshndx.shndx != SHN_UNDEF) 635 symstate_add_xshndx(argstate, symstate); 636 break; 637 } 638 } 639 } 640 641 /* 642 * If there is more than one table, we are displaying a single 643 * item, we are not using the default "elfdump" style, and all 644 * the symbols have the same value for the thing we intend to 645 * display, then we only want to display it once. 646 */ 647 only_one = (argstate->numsymstate > 1) && (argstate->argc > 0) && 648 (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) && 649 all_same(cmd, argstate, outstyle); 650 651 /* Run through the tables and display from each one */ 652 symstate = argstate->symstate; 653 for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) { 654 if (argstate->argc == 0) { 655 ndx = 0; 656 cnt = symstate->sym.n; 657 } else { 658 ndx = symstate->ndx; 659 cnt = 1; 660 } 661 662 if ((tblndx > 0) && ((argstate->argc == 0) || 663 (outstyle == ELFEDIT_OUTSTYLE_DEFAULT))) 664 elfedit_printf(MSG_ORIG(MSG_STR_NL)); 665 666 print_symstate(cmd, argstate, symstate, outstyle, ndx, cnt); 667 if (only_one) 668 break; 669 } 670 } 671 672 673 /* 674 * The cmd_body_set_st_XXX() functions are for use by cmd_body(). 675 * They handle the case where the second plain argument is 676 * a value to be stored in the symbol. 677 * 678 * entry: 679 * argstate - Overall state block 680 * symstate - State block for current symbol table. 681 */ 682 static elfedit_cmdret_t 683 cmd_body_set_st_bind(ARGSTATE *argstate, SYMSTATE *symstate) 684 { 685 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 686 Sym *sym = &symstate->sym.data[symstate->ndx]; 687 Word gbl_ndx; 688 uchar_t bind, type, old_bind; 689 Word symndx; 690 Conv_inv_buf_t inv_buf1, inv_buf2; 691 692 /* 693 * Use the ELF_ST_BIND() macro to access the defined bits 694 * of the st_info field related to symbol binding. 695 * Accepts STB_ symbolic names as well as integers. 696 */ 697 bind = elfedit_atoconst_range(argstate->argv[1], 698 MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STB); 699 old_bind = ELF_ST_BIND(sym->st_info); 700 type = ELF_ST_TYPE(sym->st_info); 701 702 if (old_bind == bind) { 703 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), 704 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 705 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND), 706 conv_sym_info_bind(bind, CONV_FMT_ALT_FULLNAME, &inv_buf1)); 707 } else { 708 /* 709 * The sh_info field of the symbol table section header 710 * gives the index of the first non-local symbol in 711 * the table. Issue warnings if the binding we set 712 * contradicts this. 713 */ 714 gbl_ndx = symstate->sym.sec->sec_shdr->sh_info; 715 symndx = symstate->sym.sec->sec_shndx; 716 if ((bind == STB_LOCAL) && (symstate->ndx >= gbl_ndx)) 717 elfedit_msg(ELFEDIT_MSG_DEBUG, 718 MSG_INTL(MSG_DEBUG_LBINDGSYM), 719 EC_WORD(symndx), symstate->sym.sec->sec_name, 720 symstate->ndx, EC_WORD(symndx), gbl_ndx); 721 if ((bind != STB_LOCAL) && (symstate->ndx < gbl_ndx)) 722 elfedit_msg(ELFEDIT_MSG_DEBUG, 723 MSG_INTL(MSG_DEBUG_GBINDLSYM), 724 EC_WORD(symndx), symstate->sym.sec->sec_name, 725 symstate->ndx, EC_WORD(symndx), gbl_ndx); 726 727 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), 728 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 729 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_BIND), 730 conv_sym_info_bind(old_bind, CONV_FMT_ALT_FULLNAME, 731 &inv_buf1), 732 conv_sym_info_bind(bind, CONV_FMT_ALT_FULLNAME, &inv_buf2)); 733 ret = ELFEDIT_CMDRET_MOD; 734 sym->st_info = ELF_ST_INFO(bind, type); 735 } 736 737 return (ret); 738 } 739 740 static elfedit_cmdret_t 741 cmd_body_set_st_name(ARGSTATE *argstate, SYMSTATE *symstate) 742 { 743 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 744 Sym *sym = &symstate->sym.data[symstate->ndx]; 745 Word str_offset; 746 747 /* 748 * If -n was specified, this is an offset into the string 749 * table. Otherwise it is a string we need to turn into 750 * an offset 751 */ 752 symstate_add_str(argstate, symstate); 753 if (argstate->optmask & SYM_OPT_F_NAMOFFSET) { 754 str_offset = elfedit_atoui(argstate->argv[1], NULL); 755 /* Warn if the offset is out of range */ 756 (void) elfedit_offset_to_str(symstate->str.sec, 757 str_offset, ELFEDIT_MSG_DEBUG, 1); 758 } else { 759 str_offset = elfedit_strtab_insert(argstate->obj_state, 760 symstate->str.sec, NULL, argstate->argv[1]); 761 } 762 763 if (sym->st_name == str_offset) { 764 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_OK), 765 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 766 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME), 767 EC_WORD(sym->st_name)); 768 } else { 769 /* 770 * Warn the user: Changing the name of a symbol in the dynsym 771 * will break the hash table in this object. 772 */ 773 if (symstate->sym.sec->sec_shdr->sh_type == SHT_DYNSYM) 774 elfedit_msg(ELFEDIT_MSG_DEBUG, 775 MSG_INTL(MSG_DEBUG_DYNSYMNAMCHG), 776 EC_WORD(symstate->sym.sec->sec_shndx), 777 symstate->sym.sec->sec_name, 778 EC_WORD(symstate->ndx)); 779 780 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_D_CHG), 781 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 782 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_NAME), 783 EC_WORD(sym->st_name), 784 EC_WORD(str_offset)); 785 ret = ELFEDIT_CMDRET_MOD; 786 sym->st_name = str_offset; 787 } 788 789 return (ret); 790 } 791 792 static elfedit_cmdret_t 793 cmd_body_set_st_shndx(ARGSTATE *argstate, SYMSTATE *symstate) 794 { 795 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 796 Sym *sym = &symstate->sym.data[symstate->ndx]; 797 Word shndx, st_shndx, xshndx; 798 int use_xshndx; 799 int shndx_chg, xshndx_chg; 800 801 802 /* 803 * By default, the sec argument is a section name. If -secshndx was 804 * specified, it is a section index, and if -secshtyp is specified, 805 * it is a section type. 806 */ 807 if (argstate->optmask & SYM_OPT_F_SECSHNDX) 808 shndx = elfedit_atoshndx(argstate->argv[1], 809 argstate->obj_state->os_shnum); 810 else if (argstate->optmask & SYM_OPT_F_SECSHTYP) 811 shndx = elfedit_type_to_shndx(argstate->obj_state, 812 elfedit_atoconst(argstate->argv[1], ELFEDIT_CONST_SHT)); 813 else 814 shndx = elfedit_name_to_shndx(argstate->obj_state, 815 argstate->argv[1]); 816 817 /* 818 * We want to use an extended index section if the index is too 819 * large to be represented otherwise, or if the caller specified 820 * the -e option to make us do it anyway. However, we cannot 821 * do this if the index is in the special reserved range between 822 * SHN_LORESERVE and SHN_HIRESERVE. 823 */ 824 use_xshndx = (shndx > SHN_HIRESERVE) || 825 ((shndx < SHN_LORESERVE) && 826 (argstate->optmask & SYM_OPT_F_XSHINDEX)); 827 828 /* 829 * There are two cases where we have to touch the extended 830 * index section: 831 * 832 * 1) We have determined that we need to, as determined above. 833 * 2) We do not require it, but the file has an extended 834 * index section, in which case we should set the slot 835 * in that extended section to SHN_UNDEF (0). 836 * 837 * Fetch the extended section as required, and determine the values 838 * for st_shndx and the extended section slot. 839 */ 840 if (use_xshndx) { 841 /* We must have an extended index section, or error out */ 842 symstate_add_xshndx(argstate, symstate); 843 844 /* Set symbol to SHN_XINDEX, put index in the extended sec. */ 845 st_shndx = SHN_XINDEX; 846 xshndx = shndx; 847 } else { 848 st_shndx = shndx; 849 xshndx = SHN_UNDEF; 850 if (symstate->xshndx.shndx != SHN_UNDEF) 851 use_xshndx = 1; 852 } 853 if (use_xshndx) 854 symstate_add_xshndx(argstate, symstate); 855 shndx_chg = (sym->st_shndx != st_shndx); 856 xshndx_chg = use_xshndx && 857 (symstate->xshndx.data[symstate->ndx] != xshndx); 858 859 860 /* If anything is going to change, issue appropiate warnings */ 861 if (shndx_chg || xshndx_chg) { 862 /* 863 * Setting the first symbol to anything other than SHN_UNDEF 864 * produces a bad ELF file. 865 */ 866 if ((symstate->ndx == 0) && (shndx != SHN_UNDEF)) 867 elfedit_msg(ELFEDIT_MSG_DEBUG, 868 MSG_INTL(MSG_DEBUG_SHNDX_UNDEF0)); 869 870 /* 871 * Setting SHN_XINDEX directly, instead of providing 872 * an extended index and letting us decide to use 873 * SHN_XINDEX to implement it, is probably a mistake. 874 * Issue a warning, but go ahead and follow the directions 875 * we've been given. 876 */ 877 if (shndx == SHN_XINDEX) 878 elfedit_msg(ELFEDIT_MSG_DEBUG, 879 MSG_INTL(MSG_DEBUG_SHNDX_XINDEX)); 880 881 /* 882 * If the section index can fit in the symbol, but 883 * -e is being used to force it into the extended 884 * index section, issue a warning. 885 */ 886 if (use_xshndx && (shndx < SHN_LORESERVE) && 887 (st_shndx == SHN_XINDEX)) 888 elfedit_msg(ELFEDIT_MSG_DEBUG, 889 MSG_INTL(MSG_DEBUG_SHNDX_EFORCE), 890 EC_WORD(symstate->sym.sec->sec_shndx), 891 symstate->sym.sec->sec_name, EC_WORD(symstate->ndx), 892 EC_WORD(shndx)); 893 } 894 895 if (shndx_chg) { 896 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), 897 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 898 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX), 899 elfedit_shndx_to_name(argstate->obj_state, 900 sym->st_shndx), 901 elfedit_shndx_to_name(argstate->obj_state, st_shndx)); 902 ret = ELFEDIT_CMDRET_MOD; 903 sym->st_shndx = st_shndx; 904 } else { 905 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), 906 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 907 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_SHNDX), 908 elfedit_shndx_to_name(argstate->obj_state, st_shndx)); 909 } 910 911 if (use_xshndx) { 912 if (xshndx_chg) { 913 elfedit_msg(ELFEDIT_MSG_DEBUG, 914 MSG_INTL(MSG_DEBUG_EXT_S_CHG), 915 symstate->xshndx.sec->sec_shndx, 916 symstate->xshndx.sec->sec_name, 917 EC_WORD(symstate->ndx), 918 elfedit_shndx_to_name(argstate->obj_state, 919 symstate->xshndx.data[symstate->ndx]), 920 elfedit_shndx_to_name(argstate->obj_state, xshndx)); 921 ret = ELFEDIT_CMDRET_MOD; 922 symstate->xshndx.data[symstate->ndx] = xshndx; 923 elfedit_modified_data(symstate->xshndx.sec); 924 } else { 925 elfedit_msg(ELFEDIT_MSG_DEBUG, 926 MSG_INTL(MSG_DEBUG_EXT_S_OK), 927 symstate->xshndx.sec->sec_shndx, 928 symstate->xshndx.sec->sec_name, 929 EC_WORD(symstate->ndx), 930 elfedit_shndx_to_name(argstate->obj_state, xshndx)); 931 } 932 } 933 934 return (ret); 935 } 936 937 static elfedit_cmdret_t 938 cmd_body_set_st_type(ARGSTATE *argstate, SYMSTATE *symstate) 939 { 940 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 941 Conv_inv_buf_t inv_buf1, inv_buf2; 942 Half mach = argstate->obj_state->os_ehdr->e_machine; 943 Sym *sym = &symstate->sym.data[symstate->ndx]; 944 uchar_t bind, type, old_type; 945 946 /* 947 * Use the ELF_ST_TYPE() macro to access the defined bits 948 * of the st_info field related to symbol type. 949 * Accepts STT_ symbolic names as well as integers. 950 */ 951 bind = ELF_ST_BIND(sym->st_info); 952 type = elfedit_atoconst_range(argstate->argv[1], 953 MSG_INTL(MSG_ARG_SYMBIND), 0, 15, ELFEDIT_CONST_STT); 954 old_type = ELF_ST_TYPE(sym->st_info); 955 956 if (old_type == type) { 957 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), 958 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 959 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE), 960 conv_sym_info_type(mach, type, CONV_FMT_ALT_FULLNAME, 961 &inv_buf1)); 962 } else { 963 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), 964 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 965 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_TYPE), 966 conv_sym_info_type(mach, old_type, CONV_FMT_ALT_FULLNAME, 967 &inv_buf1), 968 conv_sym_info_type(mach, type, CONV_FMT_ALT_FULLNAME, 969 &inv_buf2)); 970 ret = ELFEDIT_CMDRET_MOD; 971 sym->st_info = ELF_ST_INFO(bind, type); 972 } 973 974 return (ret); 975 } 976 977 static elfedit_cmdret_t 978 cmd_body_set_st_visibility(ARGSTATE *argstate, SYMSTATE *symstate) 979 { 980 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 981 Conv_inv_buf_t inv_buf1, inv_buf2; 982 Sym *sym = &symstate->sym.data[symstate->ndx]; 983 uchar_t st_other = sym->st_other; 984 uchar_t vis, old_vis; 985 986 /* 987 * Use the ELF_ST_VISIBILITY() macro to access the 988 * defined bits of the st_other field related to symbol 989 * visibility. Accepts STV_ symbolic names as well as integers. 990 */ 991 vis = elfedit_atoconst_range(argstate->argv[1], 992 MSG_INTL(MSG_ARG_SYMVIS), 0, STV_ELIMINATE, ELFEDIT_CONST_STV); 993 old_vis = st_other & MSK_SYM_VISIBILITY; 994 995 if (old_vis == vis) { 996 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), 997 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 998 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY), 999 conv_sym_other_vis(old_vis, CONV_FMT_ALT_FULLNAME, 1000 &inv_buf1)); 1001 } else { 1002 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), 1003 symstate->sym.sec->sec_shndx, symstate->sym.sec->sec_name, 1004 EC_WORD(symstate->ndx), MSG_ORIG(MSG_CMD_ST_VISIBILITY), 1005 conv_sym_other_vis(old_vis, CONV_FMT_ALT_FULLNAME, 1006 &inv_buf1), 1007 conv_sym_other_vis(vis, CONV_FMT_ALT_FULLNAME, &inv_buf2)); 1008 ret = ELFEDIT_CMDRET_MOD; 1009 st_other = (st_other & ~MSK_SYM_VISIBILITY) | 1010 ELF_ST_VISIBILITY(vis); 1011 sym->st_other = st_other; 1012 } 1013 1014 return (ret); 1015 } 1016 1017 1018 /* 1019 * Standard argument processing for sym module 1020 * 1021 * entry 1022 * obj_state, argc, argv - Standard command arguments 1023 * optmask - Mask of allowed optional arguments. 1024 * symstate - State block for current symbol table. 1025 * argstate - Address of ARGSTATE block to be initialized 1026 * 1027 * exit: 1028 * On success, *argstate is initialized. On error, 1029 * an error is issued and this routine does not return. 1030 * 1031 * note: 1032 * Only the basic symbol table is initially referenced by 1033 * argstate. Use the argstate_add_XXX() routines below to 1034 * access any auxiliary sections needed. 1035 */ 1036 static ARGSTATE * 1037 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[], 1038 SYM_CMD_T cmd) 1039 { 1040 /* 1041 * We reuse this same argstate, resizing it to the required 1042 * number of symbol tables on the first call, and as necessary. 1043 */ 1044 static ARGSTATE *argstate; 1045 static int argstate_size = 0; 1046 1047 elfedit_getopt_state_t getopt_state; 1048 elfedit_getopt_ret_t *getopt_ret; 1049 elfedit_symtab_t *symtab; 1050 int explicit = 0; 1051 int got_sym = 0; 1052 Word index; 1053 Word tblndx; 1054 size_t size; 1055 SYMSTATE *symstate; 1056 1057 /* If there are no symbol tables, we can't do a thing */ 1058 if (obj_state->os_symtabnum == 0) 1059 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB)); 1060 1061 /* Calulate required size of argstate and realloc as necessary */ 1062 size = sizeof (ARGSTATE) + 1063 ((obj_state->os_symtabnum - 1) * sizeof (SYMSTATE)); 1064 if (argstate_size != size) { 1065 argstate = elfedit_realloc(MSG_INTL(MSG_ALLOC_ARGSTATE), 1066 argstate, size); 1067 argstate_size = size; 1068 } 1069 bzero(argstate, argstate_size); 1070 argstate->obj_state = obj_state; 1071 1072 elfedit_getopt_init(&getopt_state, &argc, &argv); 1073 while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) { 1074 argstate->optmask |= getopt_ret->gor_idmask; 1075 switch (getopt_ret->gor_idmask) { 1076 case SYM_OPT_F_SHNAME: /* -shnam name */ 1077 index = elfedit_name_to_shndx(obj_state, 1078 getopt_ret->gor_value); 1079 explicit = 1; 1080 break; 1081 1082 case SYM_OPT_F_SHNDX: /* -shndx index */ 1083 index = elfedit_atoui_range(getopt_ret->gor_value, 1084 MSG_INTL(MSG_ARG_SECNDX), 1, 1085 obj_state->os_shnum - 1, NULL); 1086 explicit = 1; 1087 break; 1088 1089 case SYM_OPT_F_SHTYP: /* -shtyp type */ 1090 index = elfedit_type_to_shndx(obj_state, 1091 elfedit_atoconst(getopt_ret->gor_value, 1092 ELFEDIT_CONST_SHT)); 1093 explicit = 1; 1094 break; 1095 } 1096 } 1097 1098 /* 1099 * Usage error if there are too many plain arguments. sym:dump accepts 1100 * a single argument, while the others accept 2. 1101 */ 1102 if (((cmd == SYM_CMD_T_DUMP) && (argc > 1)) || (argc > 2)) 1103 elfedit_command_usage(); 1104 1105 /* 1106 * If the -symndx option was specified, the sym arg is an index 1107 * into the symbol table. In this case, the symbol table must be 1108 * explicitly specified (-shnam, -shndx, or -shtype). 1109 */ 1110 if ((argstate->optmask & SYM_OPT_F_SYMNDX) && !explicit) 1111 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NEEDEXPSYMTAB)); 1112 1113 /* 1114 * If a section was explicitly specified, it needs 1115 * be a symbol table. 1116 */ 1117 if (explicit) 1118 (void) elfedit_sec_issymtab(&obj_state->os_secarr[index], 1119 1, NULL); 1120 1121 /* If there may be an arbitrary amount of output, use a pager */ 1122 if (argc == 0) 1123 elfedit_pager_init(); 1124 1125 /* Return the updated values of argc/argv */ 1126 argstate->argc = argc; 1127 argstate->argv = argv; 1128 1129 /* 1130 * Decide which symbol table(s) to use. Set up the symstate 1131 * array to contain them: 1132 * - If a symbol table was explicitly specified, we use 1133 * it, and only it. 1134 * - If no symbol table is explicitly specified, and the symbol 1135 * is given by name, we use all symbol tables that 1136 * contain a symbol with that name, throwing an error 1137 * if there isn't at least 1 such table. 1138 * - If no symbol table is specified, and no symbol is specified, 1139 * we use all the tables. 1140 */ 1141 symtab = obj_state->os_symtab; 1142 symstate = argstate->symstate; 1143 for (tblndx = 0; tblndx < obj_state->os_symtabnum; 1144 tblndx++, symtab++) { 1145 /* If explicit table specified, only that table is considered */ 1146 if (explicit && (symtab->symt_shndx != index)) 1147 continue; 1148 1149 symstate->sym.sec = elfedit_sec_getsymtab(obj_state, 1, 1150 symtab->symt_shndx, NULL, &symstate->sym.data, 1151 &symstate->sym.n, &symtab); 1152 symstate->versym.shndx = symtab->symt_versym; 1153 symstate->xshndx.shndx = symtab->symt_xshndx; 1154 if (argc > 0) { 1155 if (argstate->optmask & SYM_OPT_F_SYMNDX) { 1156 symstate->ndx = elfedit_atoui_range( 1157 argstate->argv[0], MSG_INTL(MSG_ARG_SYM), 0, 1158 symstate->sym.n - 1, NULL); 1159 } else { 1160 /* 1161 * arg is a symbol name. Use the index of 1162 * the first symbol that matches 1163 */ 1164 1165 /* 1166 * We will use debug messages for failure up 1167 * until we run out of symbol tables. If we 1168 * don't find a table with the desired symbol 1169 * before the last table, we switch to error 1170 * messages. Hence, we will jump with an error 1171 * if no table will work. 1172 */ 1173 int err_type = (!got_sym && 1174 ((tblndx + 1) == obj_state->os_symtabnum)) ? 1175 ELFEDIT_MSG_ERR : ELFEDIT_MSG_DEBUG; 1176 1177 symstate_add_str(argstate, symstate); 1178 1179 /* 1180 * If the symbol table doesn't have this 1181 * symbol, then forget it. 1182 */ 1183 if (elfedit_name_to_symndx(symstate->sym.sec, 1184 symstate->str.sec, argstate->argv[0], 1185 err_type, &symstate->ndx) == 0) { 1186 bzero(symstate, sizeof (*symstate)); 1187 continue; 1188 } 1189 } 1190 } 1191 argstate->numsymstate++; 1192 symstate++; 1193 /* 1194 * If the symbol table was given explicitly, and 1195 * we've just taken it, then there is no reason to 1196 * continue searching. 1197 */ 1198 if (explicit) 1199 break; 1200 } 1201 1202 return (argstate); 1203 } 1204 1205 1206 1207 /* 1208 * Called by cmd_body() to handle the value change for a single 1209 * symbol table. 1210 * 1211 * entry: 1212 * cmd - One of the SYM_CMD_T_* constants listed above, specifying 1213 * which command to implement. 1214 * argstate - Overall state block 1215 * symstate - State block for current symbol table. 1216 */ 1217 static elfedit_cmdret_t 1218 symstate_cmd_body(SYM_CMD_T cmd, ARGSTATE *argstate, SYMSTATE *symstate) 1219 { 1220 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 1221 Sym *sym = &symstate->sym.data[symstate->ndx]; 1222 1223 /* You're not supposed to change the value of symbol [0] */ 1224 if (symstate->ndx == 0) 1225 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMELT0), 1226 EC_WORD(symstate->sym.sec->sec_shndx), 1227 symstate->sym.sec->sec_name, EC_WORD(symstate->ndx)); 1228 1229 /* The second value is an integer giving a new value */ 1230 switch (cmd) { 1231 /* 1232 * SYM_CMD_T_DUMP can't get here: It never has more than 1233 * one argument, and is handled above. 1234 */ 1235 1236 case SYM_CMD_T_ST_BIND: 1237 ret = cmd_body_set_st_bind(argstate, symstate); 1238 break; 1239 1240 case SYM_CMD_T_ST_INFO: 1241 { 1242 /* Treat st_info as a raw integer field */ 1243 uchar_t st_info = 1244 elfedit_atoui(argstate->argv[1], NULL); 1245 1246 if (sym->st_info == st_info) { 1247 elfedit_msg(ELFEDIT_MSG_DEBUG, 1248 MSG_INTL(MSG_DEBUG_D_OK), 1249 symstate->sym.sec->sec_shndx, 1250 symstate->sym.sec->sec_name, 1251 EC_WORD(symstate->ndx), 1252 MSG_ORIG(MSG_CMD_ST_INFO), 1253 EC_WORD(sym->st_info)); 1254 } else { 1255 elfedit_msg(ELFEDIT_MSG_DEBUG, 1256 MSG_INTL(MSG_DEBUG_D_CHG), 1257 symstate->sym.sec->sec_shndx, 1258 symstate->sym.sec->sec_name, 1259 EC_WORD(symstate->ndx), 1260 MSG_ORIG(MSG_CMD_ST_INFO), 1261 EC_WORD(sym->st_info), EC_WORD(st_info)); 1262 ret = ELFEDIT_CMDRET_MOD; 1263 sym->st_info = st_info; 1264 } 1265 } 1266 break; 1267 1268 case SYM_CMD_T_ST_NAME: 1269 ret = cmd_body_set_st_name(argstate, symstate); 1270 break; 1271 1272 case SYM_CMD_T_ST_OTHER: 1273 { 1274 /* Treat st_other as a raw integer field */ 1275 uchar_t st_other = 1276 elfedit_atoui(argstate->argv[1], NULL); 1277 1278 if (sym->st_other == st_other) { 1279 elfedit_msg(ELFEDIT_MSG_DEBUG, 1280 MSG_INTL(MSG_DEBUG_D_OK), 1281 symstate->sym.sec->sec_shndx, 1282 symstate->sym.sec->sec_name, 1283 EC_WORD(symstate->ndx), 1284 MSG_ORIG(MSG_CMD_ST_OTHER), 1285 EC_WORD(sym->st_other)); 1286 } else { 1287 elfedit_msg(ELFEDIT_MSG_DEBUG, 1288 MSG_INTL(MSG_DEBUG_D_CHG), 1289 symstate->sym.sec->sec_shndx, 1290 symstate->sym.sec->sec_name, 1291 EC_WORD(symstate->ndx), 1292 MSG_ORIG(MSG_CMD_ST_OTHER), 1293 EC_WORD(sym->st_other), EC_WORD(st_other)); 1294 ret = ELFEDIT_CMDRET_MOD; 1295 sym->st_other = st_other; 1296 } 1297 } 1298 break; 1299 1300 case SYM_CMD_T_ST_SHNDX: 1301 ret = cmd_body_set_st_shndx(argstate, symstate); 1302 break; 1303 1304 case SYM_CMD_T_ST_SIZE: 1305 { 1306 Xword st_size = elfedit_atoui(argstate->argv[1], NULL); 1307 1308 if (sym->st_size == st_size) { 1309 elfedit_msg(ELFEDIT_MSG_DEBUG, 1310 MSG_INTL(MSG_DEBUG_LLX_OK), 1311 symstate->sym.sec->sec_shndx, 1312 symstate->sym.sec->sec_name, 1313 EC_WORD(symstate->ndx), 1314 MSG_ORIG(MSG_CMD_ST_SIZE), 1315 EC_XWORD(sym->st_size)); 1316 } else { 1317 elfedit_msg(ELFEDIT_MSG_DEBUG, 1318 MSG_INTL(MSG_DEBUG_LLX_CHG), 1319 symstate->sym.sec->sec_shndx, 1320 symstate->sym.sec->sec_name, 1321 EC_WORD(symstate->ndx), 1322 MSG_ORIG(MSG_CMD_ST_SIZE), 1323 EC_XWORD(sym->st_size), EC_XWORD(st_size)); 1324 ret = ELFEDIT_CMDRET_MOD; 1325 sym->st_size = st_size; 1326 } 1327 } 1328 break; 1329 1330 case SYM_CMD_T_ST_TYPE: 1331 ret = cmd_body_set_st_type(argstate, symstate); 1332 break; 1333 1334 case SYM_CMD_T_ST_VALUE: 1335 { 1336 Addr st_value = elfedit_atoui(argstate->argv[1], NULL); 1337 1338 if (sym->st_value == st_value) { 1339 elfedit_msg(ELFEDIT_MSG_DEBUG, 1340 MSG_INTL(MSG_DEBUG_LLX_OK), 1341 symstate->sym.sec->sec_shndx, 1342 symstate->sym.sec->sec_name, 1343 EC_WORD(symstate->ndx), 1344 MSG_ORIG(MSG_CMD_ST_VALUE), 1345 EC_ADDR(sym->st_value)); 1346 } else { 1347 elfedit_msg(ELFEDIT_MSG_DEBUG, 1348 MSG_INTL(MSG_DEBUG_LLX_CHG), 1349 symstate->sym.sec->sec_shndx, 1350 symstate->sym.sec->sec_name, 1351 EC_WORD(symstate->ndx), 1352 MSG_ORIG(MSG_CMD_ST_VALUE), 1353 EC_ADDR(sym->st_value), 1354 EC_ADDR(st_value)); 1355 ret = ELFEDIT_CMDRET_MOD; 1356 ret = ELFEDIT_CMDRET_MOD; 1357 sym->st_value = st_value; 1358 } 1359 } 1360 break; 1361 1362 case SYM_CMD_T_ST_VISIBILITY: 1363 ret = cmd_body_set_st_visibility(argstate, symstate); 1364 break; 1365 } 1366 1367 /* 1368 * If we modified the symbol table, tell libelf. 1369 * Any other modified sections are the responsibility 1370 * of the cmd_body_set_st_*() function that did it, but 1371 * everyone modifies the table itself, so we handle that here. 1372 */ 1373 if (ret == ELFEDIT_CMDRET_MOD) 1374 elfedit_modified_data(symstate->sym.sec); 1375 1376 return (ret); 1377 } 1378 1379 1380 1381 1382 /* 1383 * Common body for the sym: module commands. These commands 1384 * share a large amount of common behavior, so it is convenient 1385 * to centralize things and use the cmd argument to handle the 1386 * small differences. 1387 * 1388 * entry: 1389 * cmd - One of the SYM_CMD_T_* constants listed above, specifying 1390 * which command to implement. 1391 * obj_state, argc, argv - Standard command arguments 1392 */ 1393 static elfedit_cmdret_t 1394 cmd_body(SYM_CMD_T cmd, elfedit_obj_state_t *obj_state, 1395 int argc, const char *argv[]) 1396 { 1397 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 1398 ARGSTATE *argstate; 1399 SYMSTATE *symstate; 1400 Word tblndx; 1401 1402 argstate = process_args(obj_state, argc, argv, cmd); 1403 1404 /* 1405 * If there are not 2 arguments, then this is a display request. 1406 * If no arguments are present, the full table (or tables) is 1407 * dumped. If there is one argument, then the specified item is shown. 1408 */ 1409 if (argstate->argc < 2) { 1410 print_sym(cmd, 0, argstate); 1411 return (ELFEDIT_CMDRET_NONE); 1412 } 1413 1414 /* 1415 * When processing multiple symbol tables, it is important that 1416 * any failure happen before anything is changed. Otherwise, you 1417 * can end up in a situation where things are left in an inconsistent 1418 * half done state. sym:st_name has that issue when the -name_offset 1419 * option is used, because the string may be insertable into some 1420 * (dynstr) string tables, but not all of them. So, do the tests 1421 * up front, and refuse to continue if any string insertions would 1422 * fail. 1423 */ 1424 if ((cmd == SYM_CMD_T_ST_NAME) && (argstate->numsymstate > 1) && 1425 ((argstate->optmask & SYM_OPT_F_NAMOFFSET) == 0)) { 1426 symstate = argstate->symstate; 1427 for (tblndx = 0; tblndx < argstate->numsymstate; 1428 tblndx++, symstate++) 1429 elfedit_strtab_insert_test(obj_state, symstate->str.sec, 1430 NULL, argstate->argv[1]); 1431 } 1432 1433 1434 /* Loop over the table(s) and make the specified value change */ 1435 symstate = argstate->symstate; 1436 for (tblndx = 0; tblndx < argstate->numsymstate; tblndx++, symstate++) 1437 if (symstate_cmd_body(cmd, argstate, symstate) == 1438 ELFEDIT_CMDRET_MOD) 1439 ret = ELFEDIT_CMDRET_MOD; 1440 1441 /* Do autoprint */ 1442 print_sym(cmd, 1, argstate); 1443 1444 return (ret); 1445 } 1446 1447 1448 1449 1450 /* 1451 * Command completion functions for the various commands 1452 */ 1453 1454 /* 1455 * Handle filling in the values for -shnam, -shndx, and -shtyp options. 1456 */ 1457 /*ARGSUSED*/ 1458 static void 1459 cpl_sh_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1460 const char *argv[], int num_opt) 1461 { 1462 enum { NAME, INDEX, TYPE } op; 1463 elfedit_symtab_t *symtab; 1464 Word tblndx; 1465 1466 if ((argc != num_opt) || (argc < 2)) 1467 return; 1468 1469 if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) { 1470 op = NAME; 1471 } else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) { 1472 op = INDEX; 1473 1474 } else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) { 1475 op = TYPE; 1476 if (obj_state == NULL) /* No object available */ 1477 elfedit_cpl_atoconst(cpldata, 1478 ELFEDIT_CONST_SHT_ALLSYMTAB); 1479 } else { 1480 return; 1481 } 1482 1483 if (obj_state == NULL) /* No object available */ 1484 return; 1485 1486 /* 1487 * Loop over the symbol tables and supply command completion 1488 * for the items in the file. 1489 */ 1490 symtab = obj_state->os_symtab; 1491 for (tblndx = 0; tblndx < obj_state->os_symtabnum; 1492 tblndx++, symtab++) { 1493 elfedit_section_t *sec = 1494 &obj_state->os_secarr[symtab->symt_shndx]; 1495 1496 switch (op) { 1497 case NAME: 1498 elfedit_cpl_match(cpldata, sec->sec_name, 0); 1499 break; 1500 case INDEX: 1501 { 1502 char index[MAXNDXSIZE]; 1503 1504 (void) snprintf(index, sizeof (index), 1505 MSG_ORIG(MSG_FMT_WORDVAL), 1506 symtab->symt_shndx); 1507 elfedit_cpl_match(cpldata, index, 1); 1508 } 1509 break; 1510 case TYPE: 1511 { 1512 elfedit_atoui_sym_t *cpl_list; 1513 1514 (void) elfedit_sec_issymtab(sec, 1, &cpl_list); 1515 elfedit_cpl_atoui(cpldata, cpl_list); 1516 } 1517 break; 1518 } 1519 } 1520 } 1521 1522 /*ARGSUSED*/ 1523 static void 1524 cpl_st_bind(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1525 const char *argv[], int num_opt) 1526 { 1527 /* Handle -shXXX options */ 1528 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); 1529 1530 /* The second argument can be an STB_ value */ 1531 if (argc == (num_opt + 2)) 1532 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STB); 1533 } 1534 1535 /*ARGSUSED*/ 1536 static void 1537 cpl_st_shndx(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1538 const char *argv[], int num_opt) 1539 { 1540 elfedit_section_t *sec; 1541 enum { NAME, INDEX, TYPE } op; 1542 Word ndx; 1543 1544 /* Handle -shXXX options */ 1545 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); 1546 1547 /* 1548 * The second argument can be a section name, a section 1549 * index (-secshndx), or a section type (-secshtyp). We 1550 * can do completions for each of these. 1551 */ 1552 if (argc != (num_opt + 2)) 1553 return; 1554 1555 op = NAME; 1556 for (ndx = 0; ndx < num_opt; ndx++) { 1557 if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_SECSHNDX)) == 0) 1558 op = INDEX; 1559 else if (strcmp(argv[ndx], 1560 MSG_ORIG(MSG_STR_MINUS_SECSHTYP)) == 0) 1561 op = TYPE; 1562 } 1563 1564 switch (op) { 1565 case NAME: 1566 if (obj_state == NULL) 1567 break; 1568 sec = obj_state->os_secarr; 1569 for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++) 1570 elfedit_cpl_match(cpldata, sec->sec_name, 0); 1571 break; 1572 1573 case INDEX: 1574 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHN); 1575 break; 1576 1577 case TYPE: 1578 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SHT); 1579 break; 1580 } 1581 } 1582 1583 /*ARGSUSED*/ 1584 static void 1585 cpl_st_type(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1586 const char *argv[], int num_opt) 1587 { 1588 /* Handle -shXXX options */ 1589 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); 1590 1591 /* The second argument can be an STT_ value */ 1592 if (argc == (num_opt + 2)) 1593 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STT); 1594 } 1595 1596 /*ARGSUSED*/ 1597 static void 1598 cpl_st_visibility(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 1599 const char *argv[], int num_opt) 1600 { 1601 /* Handle -shXXX options */ 1602 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); 1603 1604 /* The second argument can be an STV_ value */ 1605 if (argc == (num_opt + 2)) 1606 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_STV); 1607 } 1608 1609 1610 1611 /* 1612 * Implementation functions for the commands 1613 */ 1614 static elfedit_cmdret_t 1615 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1616 { 1617 return (cmd_body(SYM_CMD_T_DUMP, obj_state, argc, argv)); 1618 } 1619 1620 1621 static elfedit_cmdret_t 1622 cmd_st_bind(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1623 { 1624 return (cmd_body(SYM_CMD_T_ST_BIND, obj_state, argc, argv)); 1625 } 1626 1627 1628 static elfedit_cmdret_t 1629 cmd_st_info(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1630 { 1631 return (cmd_body(SYM_CMD_T_ST_INFO, obj_state, argc, argv)); 1632 } 1633 1634 static elfedit_cmdret_t 1635 cmd_st_name(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1636 { 1637 return (cmd_body(SYM_CMD_T_ST_NAME, obj_state, argc, argv)); 1638 } 1639 1640 static elfedit_cmdret_t 1641 cmd_st_other(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1642 { 1643 return (cmd_body(SYM_CMD_T_ST_OTHER, obj_state, argc, argv)); 1644 } 1645 1646 static elfedit_cmdret_t 1647 cmd_st_shndx(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1648 { 1649 return (cmd_body(SYM_CMD_T_ST_SHNDX, obj_state, argc, argv)); 1650 } 1651 1652 static elfedit_cmdret_t 1653 cmd_st_size(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1654 { 1655 return (cmd_body(SYM_CMD_T_ST_SIZE, obj_state, argc, argv)); 1656 } 1657 1658 static elfedit_cmdret_t 1659 cmd_st_type(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1660 { 1661 return (cmd_body(SYM_CMD_T_ST_TYPE, obj_state, argc, argv)); 1662 } 1663 1664 static elfedit_cmdret_t 1665 cmd_st_value(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1666 { 1667 return (cmd_body(SYM_CMD_T_ST_VALUE, obj_state, argc, argv)); 1668 } 1669 1670 static elfedit_cmdret_t 1671 cmd_st_visibility(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 1672 { 1673 return (cmd_body(SYM_CMD_T_ST_VISIBILITY, obj_state, argc, argv)); 1674 } 1675 1676 1677 1678 /*ARGSUSED*/ 1679 elfedit_module_t * 1680 elfedit_init(elfedit_module_version_t version) 1681 { 1682 /* Multiple commands accept only the standard set of options */ 1683 static elfedit_cmd_optarg_t opt_std[] = { 1684 { MSG_ORIG(MSG_STR_MINUS_SHNAM), 1685 /* MSG_INTL(MSG_OPTDESC_SHNAM) */ 1686 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, 1687 SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP }, 1688 { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, 1689 { MSG_ORIG(MSG_STR_MINUS_SHNDX), 1690 /* MSG_INTL(MSG_OPTDESC_SHNDX) */ 1691 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, 1692 SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP }, 1693 { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, 1694 { MSG_ORIG(MSG_STR_MINUS_SHTYP), 1695 /* MSG_INTL(MSG_OPTDESC_SHTYP) */ 1696 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, 1697 SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX }, 1698 { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, 1699 { MSG_ORIG(MSG_STR_MINUS_SYMNDX), 1700 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ 1701 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX }, 1702 { ELFEDIT_STDOA_OPT_O, NULL, 1703 ELFEDIT_CMDOA_F_INHERIT, 0 }, 1704 { NULL } 1705 }; 1706 1707 /* sym:dump */ 1708 static const char *name_dump[] = { 1709 MSG_ORIG(MSG_CMD_DUMP), 1710 MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */ 1711 NULL 1712 }; 1713 static elfedit_cmd_optarg_t opt_dump[] = { 1714 { MSG_ORIG(MSG_STR_MINUS_SHNAM), 1715 /* MSG_INTL(MSG_OPTDESC_SHNAM) */ 1716 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, 1717 SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP }, 1718 { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, 1719 { MSG_ORIG(MSG_STR_MINUS_SHNDX), 1720 /* MSG_INTL(MSG_OPTDESC_SHNDX) */ 1721 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, 1722 SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP }, 1723 { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, 1724 { MSG_ORIG(MSG_STR_MINUS_SHTYP), 1725 /* MSG_INTL(MSG_OPTDESC_SHTYP) */ 1726 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, 1727 SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX }, 1728 { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, 1729 { MSG_ORIG(MSG_STR_MINUS_SYMNDX), 1730 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ 1731 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, SYM_OPT_F_SYMNDX }, 1732 { NULL } 1733 }; 1734 static elfedit_cmd_optarg_t arg_dump[] = { 1735 { MSG_ORIG(MSG_STR_SYM), 1736 /* MSG_INTL(MSG_A1_SYM) */ 1737 ELFEDIT_I18NHDL(MSG_A1_SYM), 1738 ELFEDIT_CMDOA_F_OPT }, 1739 { NULL } 1740 }; 1741 1742 /* sym:st_bind */ 1743 static const char *name_st_bind[] = { 1744 MSG_ORIG(MSG_CMD_ST_BIND), NULL }; 1745 static elfedit_cmd_optarg_t arg_st_bind[] = { 1746 { MSG_ORIG(MSG_STR_SYM), 1747 /* MSG_INTL(MSG_A1_SYM) */ 1748 ELFEDIT_I18NHDL(MSG_A1_SYM), 1749 ELFEDIT_CMDOA_F_OPT }, 1750 { MSG_ORIG(MSG_STR_VALUE), 1751 /* MSG_INTL(MSG_A2_DESC_ST_BIND) */ 1752 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_BIND), 1753 ELFEDIT_CMDOA_F_OPT }, 1754 { NULL } 1755 }; 1756 1757 /* sym:st_info */ 1758 static const char *name_st_info[] = { 1759 MSG_ORIG(MSG_CMD_ST_INFO), NULL }; 1760 static elfedit_cmd_optarg_t arg_st_info[] = { 1761 { MSG_ORIG(MSG_STR_SYM), 1762 /* MSG_INTL(MSG_A1_SYM) */ 1763 ELFEDIT_I18NHDL(MSG_A1_SYM), 1764 ELFEDIT_CMDOA_F_OPT }, 1765 { MSG_ORIG(MSG_STR_VALUE), 1766 /* MSG_INTL(MSG_A2_DESC_ST_INFO) */ 1767 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_INFO), 1768 ELFEDIT_CMDOA_F_OPT }, 1769 { NULL } 1770 }; 1771 1772 /* sym:st_name */ 1773 static const char *name_st_name[] = { 1774 MSG_ORIG(MSG_CMD_ST_NAME), NULL }; 1775 static elfedit_cmd_optarg_t opt_st_name[] = { 1776 { MSG_ORIG(MSG_STR_MINUS_SHNAM), 1777 /* MSG_INTL(MSG_OPTDESC_SHNAM) */ 1778 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, 1779 SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP }, 1780 { MSG_ORIG(MSG_STR_NAME), NULL, 0, 0 }, 1781 { MSG_ORIG(MSG_STR_MINUS_SHNDX), 1782 /* MSG_INTL(MSG_OPTDESC_SHNDX) */ 1783 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, 1784 SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP }, 1785 { MSG_ORIG(MSG_STR_INDEX), NULL, 0, 0 }, 1786 { MSG_ORIG(MSG_STR_MINUS_SHTYP), 1787 /* MSG_INTL(MSG_OPTDESC_SHTYP) */ 1788 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, 1789 SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX }, 1790 { MSG_ORIG(MSG_STR_TYPE), NULL, 0, 0 }, 1791 { MSG_ORIG(MSG_STR_MINUS_SYMNDX), 1792 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ 1793 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, 1794 SYM_OPT_F_SYMNDX, 0 }, 1795 { MSG_ORIG(MSG_STR_MINUS_NAME_OFFSET), 1796 /* MSG_INTL(MSG_OPTDESC_NAME_OFFSET) */ 1797 ELFEDIT_I18NHDL(MSG_OPTDESC_NAME_OFFSET), 0, 1798 SYM_OPT_F_NAMOFFSET, 0 }, 1799 { ELFEDIT_STDOA_OPT_O, NULL, 1800 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 1801 { NULL } 1802 }; 1803 static elfedit_cmd_optarg_t arg_st_name[] = { 1804 { MSG_ORIG(MSG_STR_SYM), 1805 /* MSG_INTL(MSG_A1_SYM) */ 1806 ELFEDIT_I18NHDL(MSG_A1_SYM), 1807 ELFEDIT_CMDOA_F_OPT }, 1808 { MSG_ORIG(MSG_STR_NAME), 1809 /* MSG_INTL(MSG_A2_DESC_ST_NAME) */ 1810 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_NAME), 1811 ELFEDIT_CMDOA_F_OPT }, 1812 { NULL } 1813 }; 1814 1815 /* sym:st_other */ 1816 static const char *name_st_other[] = { 1817 MSG_ORIG(MSG_CMD_ST_OTHER), NULL }; 1818 static elfedit_cmd_optarg_t arg_st_other[] = { 1819 { MSG_ORIG(MSG_STR_SYM), 1820 /* MSG_INTL(MSG_A1_SYM) */ 1821 ELFEDIT_I18NHDL(MSG_A1_SYM), 1822 ELFEDIT_CMDOA_F_OPT }, 1823 { MSG_ORIG(MSG_STR_VALUE), 1824 /* MSG_INTL(MSG_A2_DESC_ST_OTHER) */ 1825 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_OTHER), 1826 ELFEDIT_CMDOA_F_OPT }, 1827 { NULL } 1828 }; 1829 1830 /* sym:st_shndx */ 1831 static const char *name_st_shndx[] = { 1832 MSG_ORIG(MSG_CMD_ST_SHNDX), NULL }; 1833 static elfedit_cmd_optarg_t opt_st_shndx[] = { 1834 { MSG_ORIG(MSG_STR_MINUS_E), 1835 /* MSG_INTL(MSG_OPTDESC_E) */ 1836 ELFEDIT_I18NHDL(MSG_OPTDESC_E), 0, SYM_OPT_F_XSHINDEX, 0 }, 1837 { MSG_ORIG(MSG_STR_MINUS_SHNAM), 1838 /* MSG_INTL(MSG_OPTDESC_SHNAM) */ 1839 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, 1840 SYM_OPT_F_SHNAME, SYM_OPT_F_SHNDX | SYM_OPT_F_SHTYP }, 1841 { MSG_ORIG(MSG_STR_NAME), NULL, 0, 0 }, 1842 { MSG_ORIG(MSG_STR_MINUS_SHNDX), 1843 /* MSG_INTL(MSG_OPTDESC_SHNDX) */ 1844 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, 1845 SYM_OPT_F_SHNDX, SYM_OPT_F_SHNAME | SYM_OPT_F_SHTYP }, 1846 { MSG_ORIG(MSG_STR_INDEX), NULL, 0, 0 }, 1847 { MSG_ORIG(MSG_STR_MINUS_SHTYP), 1848 /* MSG_INTL(MSG_OPTDESC_SHTYP) */ 1849 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, 1850 SYM_OPT_F_SHTYP, SYM_OPT_F_SHNAME | SYM_OPT_F_SHNDX }, 1851 { MSG_ORIG(MSG_STR_TYPE), NULL, 0, 0 }, 1852 { MSG_ORIG(MSG_STR_MINUS_SYMNDX), 1853 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ 1854 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, 1855 SYM_OPT_F_SYMNDX, 0 }, 1856 { ELFEDIT_STDOA_OPT_O, NULL, 1857 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 1858 { MSG_ORIG(MSG_STR_MINUS_SECSHNDX), 1859 /* MSG_INTL(MSG_OPTDESC_SECSHNDX) */ 1860 ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHNDX), 1861 0, SYM_OPT_F_SECSHNDX, SYM_OPT_F_SECSHTYP }, 1862 { MSG_ORIG(MSG_STR_MINUS_SECSHTYP), 1863 /* MSG_INTL(MSG_OPTDESC_SECSHTYP) */ 1864 ELFEDIT_I18NHDL(MSG_OPTDESC_SECSHTYP), 1865 0, SYM_OPT_F_SECSHTYP, SYM_OPT_F_SECSHNDX }, 1866 { NULL } 1867 }; 1868 static elfedit_cmd_optarg_t arg_st_shndx[] = { 1869 { MSG_ORIG(MSG_STR_SYM), 1870 /* MSG_INTL(MSG_A1_SYM) */ 1871 ELFEDIT_I18NHDL(MSG_A1_SYM), 1872 ELFEDIT_CMDOA_F_OPT }, 1873 { MSG_ORIG(MSG_STR_SEC), 1874 /* MSG_INTL(MSG_A2_DESC_ST_SEC) */ 1875 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SEC), 1876 ELFEDIT_CMDOA_F_OPT }, 1877 { NULL } 1878 }; 1879 1880 /* sym:st_size */ 1881 static const char *name_st_size[] = { 1882 MSG_ORIG(MSG_CMD_ST_SIZE), NULL }; 1883 static elfedit_cmd_optarg_t arg_st_size[] = { 1884 { MSG_ORIG(MSG_STR_SYM), 1885 /* MSG_INTL(MSG_A1_SYM) */ 1886 ELFEDIT_I18NHDL(MSG_A1_SYM), 1887 ELFEDIT_CMDOA_F_OPT }, 1888 { MSG_ORIG(MSG_STR_VALUE), 1889 /* MSG_INTL(MSG_A2_DESC_ST_SIZE) */ 1890 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_SIZE), 1891 ELFEDIT_CMDOA_F_OPT }, 1892 { NULL } 1893 }; 1894 1895 /* sym:st_type */ 1896 static const char *name_st_type[] = { 1897 MSG_ORIG(MSG_CMD_ST_TYPE), NULL }; 1898 static elfedit_cmd_optarg_t arg_st_type[] = { 1899 { MSG_ORIG(MSG_STR_SYM), 1900 /* MSG_INTL(MSG_A1_SYM) */ 1901 ELFEDIT_I18NHDL(MSG_A1_SYM), 1902 ELFEDIT_CMDOA_F_OPT }, 1903 { MSG_ORIG(MSG_STR_VALUE), 1904 /* MSG_INTL(MSG_A2_DESC_ST_TYPE) */ 1905 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_TYPE), 1906 ELFEDIT_CMDOA_F_OPT }, 1907 { NULL } 1908 }; 1909 1910 /* sym:st_value */ 1911 static const char *name_st_value[] = { 1912 MSG_ORIG(MSG_CMD_ST_VALUE), NULL }; 1913 static elfedit_cmd_optarg_t arg_st_value[] = { 1914 { MSG_ORIG(MSG_STR_SYM), 1915 /* MSG_INTL(MSG_A1_SYM) */ 1916 ELFEDIT_I18NHDL(MSG_A1_SYM), 1917 ELFEDIT_CMDOA_F_OPT }, 1918 { MSG_ORIG(MSG_STR_VALUE), 1919 /* MSG_INTL(MSG_A2_DESC_ST_VALUE) */ 1920 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VALUE), 1921 ELFEDIT_CMDOA_F_OPT }, 1922 { NULL } 1923 }; 1924 1925 /* sym:st_visibility */ 1926 static const char *name_st_visibility[] = { 1927 MSG_ORIG(MSG_CMD_ST_VISIBILITY), NULL }; 1928 static elfedit_cmd_optarg_t arg_st_visibility[] = { 1929 { MSG_ORIG(MSG_STR_SYM), 1930 /* MSG_INTL(MSG_A1_SYM) */ 1931 ELFEDIT_I18NHDL(MSG_A1_SYM), 1932 ELFEDIT_CMDOA_F_OPT }, 1933 { MSG_ORIG(MSG_STR_VALUE), 1934 /* MSG_INTL(MSG_A2_DESC_ST_VISIBILITY) */ 1935 ELFEDIT_I18NHDL(MSG_A2_DESC_ST_VISIBILITY), 1936 ELFEDIT_CMDOA_F_OPT }, 1937 { NULL } 1938 }; 1939 1940 static elfedit_cmd_t cmds[] = { 1941 /* sym:dump */ 1942 { cmd_dump, cpl_sh_opt, name_dump, 1943 /* MSG_INTL(MSG_DESC_DUMP) */ 1944 ELFEDIT_I18NHDL(MSG_DESC_DUMP), 1945 /* MSG_INTL(MSG_HELP_DUMP) */ 1946 ELFEDIT_I18NHDL(MSG_HELP_DUMP), 1947 opt_dump, arg_dump }, 1948 1949 /* sym:st_bind */ 1950 { cmd_st_bind, cpl_st_bind, name_st_bind, 1951 /* MSG_INTL(MSG_DESC_ST_BIND) */ 1952 ELFEDIT_I18NHDL(MSG_DESC_ST_BIND), 1953 /* MSG_INTL(MSG_HELP_ST_BIND) */ 1954 ELFEDIT_I18NHDL(MSG_HELP_ST_BIND), 1955 opt_std, arg_st_bind }, 1956 1957 /* sym:st_info */ 1958 { cmd_st_info, cpl_sh_opt, name_st_info, 1959 /* MSG_INTL(MSG_DESC_ST_INFO) */ 1960 ELFEDIT_I18NHDL(MSG_DESC_ST_INFO), 1961 /* MSG_INTL(MSG_HELP_ST_INFO) */ 1962 ELFEDIT_I18NHDL(MSG_HELP_ST_INFO), 1963 opt_std, arg_st_info }, 1964 1965 /* sym:st_name */ 1966 { cmd_st_name, cpl_sh_opt, name_st_name, 1967 /* MSG_INTL(MSG_DESC_ST_NAME) */ 1968 ELFEDIT_I18NHDL(MSG_DESC_ST_NAME), 1969 /* MSG_INTL(MSG_HELP_ST_NAME) */ 1970 ELFEDIT_I18NHDL(MSG_HELP_ST_NAME), 1971 opt_st_name, arg_st_name }, 1972 1973 /* sym:st_other */ 1974 { cmd_st_other, cpl_sh_opt, name_st_other, 1975 /* MSG_INTL(MSG_DESC_ST_OTHER) */ 1976 ELFEDIT_I18NHDL(MSG_DESC_ST_OTHER), 1977 /* MSG_INTL(MSG_HELP_ST_OTHER) */ 1978 ELFEDIT_I18NHDL(MSG_HELP_ST_OTHER), 1979 opt_std, arg_st_other }, 1980 1981 /* sym:st_shndx */ 1982 { cmd_st_shndx, cpl_st_shndx, name_st_shndx, 1983 /* MSG_INTL(MSG_DESC_ST_SHNDX) */ 1984 ELFEDIT_I18NHDL(MSG_DESC_ST_SHNDX), 1985 /* MSG_INTL(MSG_HELP_ST_SHNDX) */ 1986 ELFEDIT_I18NHDL(MSG_HELP_ST_SHNDX), 1987 opt_st_shndx, arg_st_shndx }, 1988 1989 /* sym:st_size */ 1990 { cmd_st_size, cpl_sh_opt, name_st_size, 1991 /* MSG_INTL(MSG_DESC_ST_SIZE) */ 1992 ELFEDIT_I18NHDL(MSG_DESC_ST_SIZE), 1993 /* MSG_INTL(MSG_HELP_ST_SIZE) */ 1994 ELFEDIT_I18NHDL(MSG_HELP_ST_SIZE), 1995 opt_std, arg_st_size }, 1996 1997 /* sym:st_type */ 1998 { cmd_st_type, cpl_st_type, name_st_type, 1999 /* MSG_INTL(MSG_DESC_ST_TYPE) */ 2000 ELFEDIT_I18NHDL(MSG_DESC_ST_TYPE), 2001 /* MSG_INTL(MSG_HELP_ST_TYPE) */ 2002 ELFEDIT_I18NHDL(MSG_HELP_ST_TYPE), 2003 opt_std, arg_st_type }, 2004 2005 /* sym:st_value */ 2006 { cmd_st_value, cpl_sh_opt, name_st_value, 2007 /* MSG_INTL(MSG_DESC_ST_VALUE) */ 2008 ELFEDIT_I18NHDL(MSG_DESC_ST_VALUE), 2009 /* MSG_INTL(MSG_HELP_ST_VALUE) */ 2010 ELFEDIT_I18NHDL(MSG_HELP_ST_VALUE), 2011 opt_std, arg_st_value }, 2012 2013 /* sym:st_visibility */ 2014 { cmd_st_visibility, cpl_st_visibility, name_st_visibility, 2015 /* MSG_INTL(MSG_DESC_ST_VISIBILITY) */ 2016 ELFEDIT_I18NHDL(MSG_DESC_ST_VISIBILITY), 2017 /* MSG_INTL(MSG_HELP_ST_VISIBILITY) */ 2018 ELFEDIT_I18NHDL(MSG_HELP_ST_VISIBILITY), 2019 opt_std, arg_st_visibility }, 2020 2021 { NULL } 2022 }; 2023 2024 static elfedit_module_t module = { 2025 ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME), 2026 /* MSG_INTL(MSG_MOD_DESC) */ 2027 ELFEDIT_I18NHDL(MSG_MOD_DESC), 2028 cmds, mod_i18nhdl_to_str }; 2029 2030 return (&module); 2031 } 2032