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 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <unistd.h> 29 #include <elfedit.h> 30 #include <strings.h> 31 #include <debug.h> 32 #include <conv.h> 33 #include <syminfo_msg.h> 34 35 36 37 /* 38 * This module uses shared code for several of the commands. 39 * It is sometimes necessary to know which specific command 40 * is active. 41 */ 42 typedef enum { 43 SYMINFO_CMD_T_DUMP = 0, /* syminfo:dump */ 44 45 SYMINFO_CMD_T_SI_BOUNDTO = 1, /* syminfo:si_boundto */ 46 SYMINFO_CMD_T_SI_FLAGS = 2 /* syminfo:si_boundto */ 47 } SYMINFO_CMD_T; 48 49 50 51 #ifndef _ELF64 52 /* 53 * We supply this function for the msg module. Only one copy is needed. 54 */ 55 const char * 56 _syminfo_msg(Msg mid) 57 { 58 return (gettext(MSG_ORIG(mid))); 59 } 60 61 #endif 62 63 64 65 /* 66 * This function is supplied to elfedit through our elfedit_module_t 67 * definition. It translates the opaque elfedit_i18nhdl_t handles 68 * in our module interface into the actual strings for elfedit to 69 * use. 70 * 71 * note: 72 * This module uses Msg codes for its i18n handle type. 73 * So the translation is simply to use MSG_INTL() to turn 74 * it into a string and return it. 75 */ 76 static const char * 77 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl) 78 { 79 Msg msg = (Msg)hdl; 80 81 return (MSG_INTL(msg)); 82 } 83 84 85 86 /* 87 * The sym_opt_t enum specifies a bit value for every optional 88 * argument allowed by a command in this module. 89 */ 90 typedef enum { 91 SYMINFO_OPT_F_AND = 1, /* -and: AND (&) values to dest */ 92 SYMINFO_OPT_F_CMP = 2, /* -cmp: Complement (~) values */ 93 SYMINFO_OPT_F_NEEDED = 4, /* -needed: arg is name of object to */ 94 /* be referenced via DT_NEEDED */ 95 /* dynamic entry */ 96 SYMINFO_OPT_F_OR = 8, /* -or: OR (|) values to dest */ 97 SYMINFO_OPT_F_SYMNDX = 16 /* -symndx: Sym specified by index */ 98 } syminfo_opt_t; 99 100 101 /* 102 * A variable of type ARGSTATE is used by each command to maintain 103 * information about the syminfo section being used, as and for any 104 * auxiliary sections that are related to it. This helps us to ensure 105 * that we only fetch each section a single time: 106 * - More efficient 107 * - Prevents multiple ELFEDIT_MSG_DEBUG messages from 108 * being produced for a given section. 109 */ 110 typedef struct { 111 elfedit_obj_state_t *obj_state; 112 syminfo_opt_t optmask; /* Mask of options used */ 113 int argc; /* # of plain arguments */ 114 const char **argv; /* Plain arguments */ 115 struct { /* Syminfo */ 116 elfedit_section_t *sec; 117 Syminfo *data; 118 Word n; 119 } syminfo; 120 struct { /* Symbol table */ 121 elfedit_section_t *sec; 122 Sym *data; 123 Word n; 124 } sym; 125 struct { /* String table */ 126 elfedit_section_t *sec; 127 } str; 128 struct { /* Dynamic section */ 129 elfedit_section_t *sec; 130 Dyn *data; 131 Word n; 132 } dynamic; 133 } ARGSTATE; 134 135 136 137 /* 138 * Standard argument processing for syminfo module 139 * 140 * entry 141 * obj_state, argc, argv - Standard command arguments 142 * optmask - Mask of allowed optional arguments. 143 * argstate - Address of ARGSTATE block to be initialized 144 * 145 * exit: 146 * On success, *argstate is initialized. On error, 147 * an error is issued and this routine does not return. 148 * 149 * note: 150 * Only the syminfo section is initially referenced by 151 * argstate. Use the argstate_add_XXX() routines below to 152 * access any other sections needed. 153 */ 154 static void 155 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[], 156 SYMINFO_CMD_T cmd, ARGSTATE *argstate) 157 { 158 elfedit_getopt_state_t getopt_state; 159 elfedit_getopt_ret_t *getopt_ret; 160 161 bzero(argstate, sizeof (*argstate)); 162 argstate->obj_state = obj_state; 163 164 elfedit_getopt_init(&getopt_state, &argc, &argv); 165 166 /* Add each new option to the options mask */ 167 while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) 168 argstate->optmask |= getopt_ret->gor_idmask; 169 170 /* 171 * Usage error if there are too many plain arguments. 172 * - syminfo:dump accepts a single argument 173 * - syminfo:si_boundto accepts 2 arguments 174 * - syminfo:si_flags accepts an unbounded number 175 */ 176 if (((cmd == SYMINFO_CMD_T_DUMP) && (argc > 1)) || 177 ((cmd == SYMINFO_CMD_T_SI_BOUNDTO) && (argc > 2))) 178 elfedit_command_usage(); 179 180 /* If there may be an arbitrary amount of output, use a pager */ 181 if (argc == 0) 182 elfedit_pager_init(); 183 184 /* Return the updated values of argc/argv */ 185 argstate->argc = argc; 186 argstate->argv = argv; 187 188 /* Locate the syminfo section */ 189 argstate->syminfo.sec = elfedit_sec_getsyminfo(obj_state, 190 &argstate->syminfo.data, &argstate->syminfo.n); 191 } 192 193 194 195 /* 196 * We maintain the state of the current syminfo table in a ARGSTATE 197 * structure. A syminfo is related to the dynamic symbol table, and 198 * can reference the dynamic section of the object. We don't look those 199 * things up unless we actually need them, both to be efficient, and 200 * to prevent duplicate ELFEDIT_MSG_DEBUG messages from being issued 201 * as they are located. Hence, process_args() is used to initialze the 202 * state block with just the syminfo section, and then one of the 203 * argstate_add_XXX() functions is used as needed to fetch the 204 * additional sections. 205 * 206 * entry: 207 * argstate - State block for current symbol table. 208 * 209 * exit: 210 * If the needed auxiliary section is not found, an error is 211 * issued and the argstate_add_XXX() routine does not return. 212 * Otherwise, the fields in argstate have been filled in, ready 213 * for use. 214 * 215 */ 216 static void 217 argstate_add_sym(ARGSTATE *argstate) 218 { 219 if (argstate->sym.sec != NULL) 220 return; 221 222 argstate->sym.sec = elfedit_sec_getsymtab(argstate->obj_state, 223 1, argstate->syminfo.sec->sec_shdr->sh_link, NULL, 224 &argstate->sym.data, &argstate->sym.n, NULL); 225 } 226 static void 227 argstate_add_str(ARGSTATE *argstate) 228 { 229 if (argstate->str.sec != NULL) 230 return; 231 232 argstate_add_sym(argstate); 233 argstate->str.sec = elfedit_sec_getstr(argstate->obj_state, 234 argstate->sym.sec->sec_shdr->sh_link, 0); 235 } 236 static void 237 argstate_add_dynamic(ARGSTATE *argstate) 238 { 239 if (argstate->dynamic.sec != NULL) 240 return; 241 242 argstate->dynamic.sec = elfedit_sec_getdyn(argstate->obj_state, 243 &argstate->dynamic.data, &argstate->dynamic.n); 244 } 245 246 247 248 /* 249 * Display syminfo section entries in the style used by elfdump. 250 * 251 * entry: 252 * argstate - State block for current symbol table. 253 * ndx - Index of first symbol to display 254 * cnt - Number of symbols to display 255 */ 256 static void 257 dump_syminfo(ARGSTATE *argstate, Word ndx, Word cnt) 258 { 259 Syminfo *syminfo; 260 Sym *sym; 261 Dyn *dyn; 262 263 syminfo = argstate->syminfo.data + ndx; 264 265 argstate_add_sym(argstate); 266 sym = argstate->sym.data + ndx; 267 268 argstate_add_str(argstate); 269 270 argstate_add_dynamic(argstate); 271 dyn = argstate->dynamic.data; 272 273 /* 274 * Loop through the syminfo entries. 275 */ 276 Elf_syminfo_title(0); 277 278 for (; cnt-- > 0; ndx++, syminfo++, sym++) { 279 const char *needed = NULL, *name; 280 281 name = elfedit_offset_to_str(argstate->str.sec, 282 sym->st_name, ELFEDIT_MSG_ERR, 0); 283 284 if ((syminfo->si_boundto < SYMINFO_BT_LOWRESERVE) && 285 (syminfo->si_boundto < argstate->dynamic.n) && 286 ((dyn[syminfo->si_boundto].d_tag == DT_NEEDED) || 287 (dyn[syminfo->si_boundto].d_tag == DT_USED))) 288 needed = elfedit_offset_to_str(argstate->str.sec, 289 dyn[syminfo->si_boundto].d_un.d_val, 290 ELFEDIT_MSG_ERR, 0); 291 else 292 needed = MSG_ORIG(MSG_STR_EMPTY); 293 294 Elf_syminfo_entry(0, ndx, syminfo, name, needed); 295 } 296 } 297 298 299 300 /* 301 * Print syminfo values, taking the calling command, and output style 302 * into account. 303 * 304 * entry: 305 * cmd - SYMINFO_CMD_T_* value giving identify of caller 306 * autoprint - If True, output is only produced if the elfedit 307 * autoprint flag is set. If False, output is always produced. 308 * argstate - State block for current symbol table. 309 * ndx - Index of first symbol to display 310 * cnt - Number of symbols to display 311 */ 312 static void 313 print_syminfo(SYMINFO_CMD_T cmd, int autoprint, ARGSTATE *argstate, 314 Word ndx, Word cnt) 315 { 316 elfedit_outstyle_t outstyle; 317 Syminfo *syminfo; 318 319 if ((autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) || 320 (cnt == 0)) 321 return; 322 323 /* 324 * Pick an output style. syminfo:dump is required to use the default 325 * style. The other commands use the current output style. 326 */ 327 outstyle = (cmd == SYMINFO_CMD_T_DUMP) ? 328 ELFEDIT_OUTSTYLE_DEFAULT : elfedit_outstyle(); 329 330 /* 331 * If doing default output, use elfdump style where we 332 * show all symbol attributes. In this case, the command 333 * that called us doesn't matter 334 */ 335 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { 336 dump_syminfo(argstate, ndx, cnt); 337 return; 338 } 339 340 syminfo = argstate->syminfo.data; 341 342 switch (cmd) { 343 case SYMINFO_CMD_T_SI_BOUNDTO: 344 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 345 /* Find the dynamic section and string table */ 346 argstate_add_dynamic(argstate); 347 argstate_add_str(argstate); 348 } 349 350 for (syminfo += ndx; cnt--; syminfo++) { 351 Half bndto = syminfo->si_boundto; 352 353 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 354 const char *str = NULL; 355 356 switch (bndto) { 357 case SYMINFO_BT_SELF: 358 str = elfedit_atoconst_value_to_str( 359 ELFEDIT_CONST_SYMINFO_BT, 360 SYMINFO_BT_SELF, 1); 361 break; 362 case SYMINFO_BT_PARENT: 363 str = elfedit_atoconst_value_to_str( 364 ELFEDIT_CONST_SYMINFO_BT, 365 SYMINFO_BT_PARENT, 1); 366 break; 367 case SYMINFO_BT_NONE: 368 str = elfedit_atoconst_value_to_str( 369 ELFEDIT_CONST_SYMINFO_BT, 370 SYMINFO_BT_NONE, 1); 371 break; 372 } 373 if ((str == NULL) && 374 (bndto < SYMINFO_BT_LOWRESERVE) && 375 (argstate->dynamic.sec != NULL) && 376 (bndto < argstate->dynamic.n) && 377 (argstate->dynamic.data[bndto].d_tag == 378 DT_NEEDED)) 379 str = elfedit_offset_to_str( 380 argstate->str.sec, 381 argstate->dynamic.data[bndto]. 382 d_un.d_val, ELFEDIT_MSG_ERR, 0); 383 384 if (str != NULL) { 385 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), 386 str); 387 continue; 388 } 389 } 390 391 /* 392 * If we reach this point, we are either in numeric 393 * mode, or we were unable to find a string above. 394 * In either case, output as integer. 395 */ 396 elfedit_printf(MSG_ORIG(MSG_FMT_WORDVALNL), 397 EC_WORD(bndto)); 398 } 399 break; 400 401 case SYMINFO_CMD_T_SI_FLAGS: 402 for (syminfo += ndx; cnt--; syminfo++) { 403 if (outstyle == ELFEDIT_OUTSTYLE_SIMPLE) { 404 Conv_syminfo_flags_buf_t buf; 405 406 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), 407 conv_syminfo_flags(syminfo->si_flags, 408 CONV_FMT_NOBKT, &buf)); 409 } else { 410 elfedit_printf(MSG_ORIG(MSG_FMT_HEXNUMNL), 411 EC_WORD(syminfo->si_flags)); 412 } 413 } 414 break; 415 } 416 } 417 418 419 /* 420 * Convert the given argument string into a symbol table index. 421 * 422 * entry: 423 * argstate - State block for current symbol table. 424 * arg - String containing symbol index argument. 425 * 426 * exit: 427 * On success, returns the symbol index. On failure, an error 428 * is issued and this routine does not return. 429 */ 430 static Word 431 arg_to_symndx(ARGSTATE *argstate, const char *arg) 432 { 433 Word symndx; 434 435 /* 436 * If the -symndx option was specified, arg is an index 437 * into the symbol table. 438 */ 439 if (argstate->optmask & SYMINFO_OPT_F_SYMNDX) 440 return (elfedit_atoui_range(arg, MSG_ORIG(MSG_STR_SYM), 441 0, argstate->syminfo.n - 1, NULL)); 442 443 /* 444 * arg is a symbol name. Return the index of the first symbol 445 * that matches 446 */ 447 argstate_add_sym(argstate); 448 argstate_add_str(argstate); 449 450 (void) elfedit_name_to_symndx(argstate->sym.sec, 451 argstate->str.sec, arg, ELFEDIT_MSG_ERR, &symndx); 452 453 return (symndx); 454 } 455 456 457 /* 458 * Given a string argument representing an object, return the index of 459 * the dynamic section that should be used for the si_boundto value. 460 */ 461 static Half 462 needed_to_boundto(ARGSTATE *argstate, const char *arg) 463 { 464 Conv_inv_buf_t inv_buf; 465 elfedit_dyn_elt_t strpad_elt; 466 elfedit_dyn_elt_t null_elt; 467 elfedit_section_t *dynsec; 468 Word null_cnt; 469 Dyn *dyn; 470 Word str_offset, ndx, numdyn; 471 int have_string; 472 473 argstate_add_str(argstate); 474 argstate_add_dynamic(argstate); 475 dynsec = argstate->dynamic.sec; 476 numdyn = argstate->dynamic.n; 477 478 /* Locate DT_SUNW_STRPAD element if present and locate the DT_NULLs */ 479 elfedit_dyn_elt_init(&strpad_elt); 480 elfedit_dyn_elt_init(&null_elt); 481 null_cnt = 0; 482 strpad_elt.dn_dyn.d_un.d_val = 0; 483 dyn = argstate->dynamic.data; 484 for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 485 switch (dyn->d_tag) { 486 case DT_NULL: 487 /* Count all the nulls, remember the first one */ 488 null_cnt++; 489 if (!null_elt.dn_seen) 490 elfedit_dyn_elt_save(&null_elt, ndx, dyn); 491 break; 492 493 case DT_SUNW_STRPAD: 494 if (elfedit_test_osabi(argstate->obj_state, 495 ELFOSABI_SOLARIS, 0)) 496 elfedit_dyn_elt_save(&strpad_elt, ndx, dyn); 497 break; 498 } 499 } 500 501 /* 502 * Look up the string in the string table and get its offset. If 503 * this succeeds, then it is possible that there is a DT_NEEDED 504 * dynamic entry that references it. 505 */ 506 have_string = elfedit_sec_findstr(argstate->str.sec, 507 strpad_elt.dn_dyn.d_un.d_val, arg, &str_offset) != 0; 508 if (have_string) { 509 dyn = argstate->dynamic.data; 510 for (ndx = 0; ndx < numdyn; dyn++, ndx++) { 511 if (((dyn->d_tag == DT_NEEDED) || 512 (dyn->d_tag == DT_USED)) && 513 (dyn->d_un.d_val == str_offset)) 514 goto done; 515 } 516 } 517 518 /* 519 * It doesn't already exist. We might be able to add a DT_NEEDED 520 * to the dynamic section if an extra DT_NULL is available. 521 * Otherwise, we have to fail here. 522 */ 523 if (null_cnt < 2) 524 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOEXTRANULL), 525 EC_WORD(dynsec->sec_shndx), dynsec->sec_name); 526 527 /* 528 * If the string is not already in the string table, try to 529 * insert it. If it succeeds, we will convert the DT_NULL. 530 * Otherwise, an error will be issued and control will not 531 * return here. 532 */ 533 if (!have_string) 534 str_offset = elfedit_dynstr_insert(dynsec, 535 argstate->str.sec, &strpad_elt, arg); 536 537 /* Convert the extra DT_NULL */ 538 ndx = null_elt.dn_ndx; 539 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CONVNULL), 540 EC_WORD(dynsec->sec_shndx), dynsec->sec_name, EC_WORD(ndx), 541 conv_dyn_tag(DT_NEEDED, 542 argstate->obj_state->os_ehdr->e_ident[EI_OSABI], 543 argstate->obj_state->os_ehdr->e_machine, 544 0, &inv_buf)); 545 dyn = argstate->dynamic.data + ndx; 546 dyn->d_tag = DT_NEEDED; 547 dyn->d_un.d_val = str_offset; 548 elfedit_modified_data(dynsec); 549 550 done: 551 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDNEEDED), 552 dynsec->sec_shndx, dynsec->sec_name, ndx, arg); 553 return (ndx); 554 } 555 556 /* 557 * Common body for the syminfo: module commands. These commands 558 * share a large amount of common behavior, so it is convenient 559 * to centralize things and use the cmd argument to handle the 560 * small differences. 561 * 562 * entry: 563 * cmd - One of the SYMINFO_CMD_T_* constants listed above, specifying 564 * which command to implement. 565 * obj_state, argc, argv - Standard command arguments 566 */ 567 static elfedit_cmdret_t 568 cmd_body(SYMINFO_CMD_T cmd, elfedit_obj_state_t *obj_state, 569 int argc, const char *argv[]) 570 { 571 ARGSTATE argstate; 572 Word ndx; 573 Syminfo *syminfo; 574 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 575 576 process_args(obj_state, argc, argv, cmd, &argstate); 577 578 /* If there are no arguments, dump the whole table and return */ 579 if (argstate.argc == 0) { 580 print_syminfo(cmd, 0, &argstate, 0, argstate.syminfo.n); 581 return (ELFEDIT_CMDRET_NONE); 582 } 583 584 /* The first argument is the symbol name/index */ 585 ndx = arg_to_symndx(&argstate, argstate.argv[0]); 586 587 /* If there is a single argument, display that item and return */ 588 if (argstate.argc == 1) { 589 print_syminfo(cmd, 0, &argstate, ndx, 1); 590 return (ELFEDIT_CMDRET_NONE); 591 } 592 593 syminfo = &argstate.syminfo.data[ndx]; 594 595 /* 596 * Syminfo [0] holds the value SYMINFO_CURRENT, as a versioning 597 * technique. You're not supposed to mess with it. 598 */ 599 if (ndx == 0) 600 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSYMINFO0), 601 EC_WORD(argstate.syminfo.sec->sec_shndx), 602 argstate.syminfo.sec->sec_name, EC_WORD(ndx)); 603 604 /* The second value supplies a new value for the item */ 605 switch (cmd) { 606 /* 607 * SYMINFO_CMD_T_DUMP can't get here: It never has more than 608 * one argument, and is handled above. 609 */ 610 611 case SYMINFO_CMD_T_SI_BOUNDTO: 612 { 613 const char *name = MSG_ORIG(MSG_CMD_SI_BOUNDTO); 614 Half boundto; 615 616 if (argstate.optmask & SYMINFO_OPT_F_NEEDED) 617 boundto = needed_to_boundto(&argstate, 618 argstate.argv[1]); 619 else 620 boundto = elfedit_atoconst_range( 621 argstate.argv[1], MSG_ORIG(MSG_STR_VALUE), 622 0, 0xffff, ELFEDIT_CONST_SYMINFO_BT); 623 624 if (syminfo->si_boundto == boundto) { 625 elfedit_msg(ELFEDIT_MSG_DEBUG, 626 MSG_INTL(MSG_DEBUG_X_OK), 627 argstate.syminfo.sec->sec_shndx, 628 argstate.syminfo.sec->sec_name, ndx, name, 629 syminfo->si_boundto); 630 } else { 631 elfedit_msg(ELFEDIT_MSG_DEBUG, 632 MSG_INTL(MSG_DEBUG_X_CHG), 633 argstate.syminfo.sec->sec_shndx, 634 argstate.syminfo.sec->sec_name, ndx, name, 635 syminfo->si_boundto, boundto); 636 ret = ELFEDIT_CMDRET_MOD; 637 syminfo->si_boundto = boundto; 638 } 639 } 640 break; 641 642 case SYMINFO_CMD_T_SI_FLAGS: 643 { 644 Conv_syminfo_flags_buf_t flags_buf1, flags_buf2; 645 const char *name = MSG_ORIG(MSG_CMD_SI_FLAGS); 646 Half flags = 0; 647 int i; 648 649 /* Collect the arguments */ 650 for (i = 1; i < argstate.argc; i++) 651 flags |= (Word) 652 elfedit_atoconst(argstate.argv[i], 653 ELFEDIT_CONST_SYMINFO_FLG); 654 655 /* Complement the value? */ 656 if (argstate.optmask & SYMINFO_OPT_F_CMP) 657 flags = ~flags; 658 659 /* Perform any requested bit operations */ 660 if (argstate.optmask & SYMINFO_OPT_F_AND) 661 flags &= syminfo->si_flags; 662 else if (argstate.optmask & SYMINFO_OPT_F_OR) 663 flags |= syminfo->si_flags; 664 665 /* Set the value */ 666 if (syminfo->si_flags == flags) { 667 elfedit_msg(ELFEDIT_MSG_DEBUG, 668 MSG_INTL(MSG_DEBUG_S_OK), 669 argstate.syminfo.sec->sec_shndx, 670 argstate.syminfo.sec->sec_name, ndx, name, 671 conv_syminfo_flags(syminfo->si_flags, 672 0, &flags_buf1)); 673 } else { 674 elfedit_msg(ELFEDIT_MSG_DEBUG, 675 MSG_INTL(MSG_DEBUG_S_CHG), 676 argstate.syminfo.sec->sec_shndx, 677 argstate.syminfo.sec->sec_name, ndx, name, 678 conv_syminfo_flags(syminfo->si_flags, 679 0, &flags_buf1), 680 conv_syminfo_flags(flags, 0, &flags_buf2)); 681 ret = ELFEDIT_CMDRET_MOD; 682 syminfo->si_flags = flags; 683 } 684 } 685 break; 686 } 687 688 /* 689 * If we modified the syminfo section, tell libelf. 690 */ 691 if (ret == ELFEDIT_CMDRET_MOD) 692 elfedit_modified_data(argstate.syminfo.sec); 693 694 /* Do autoprint */ 695 print_syminfo(cmd, 1, &argstate, ndx, 1); 696 697 return (ret); 698 } 699 700 701 702 703 /* 704 * Command completion functions for the various commands 705 */ 706 /*ARGSUSED*/ 707 static void 708 cpl_si_boundto(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 709 const char *argv[], int num_opt) 710 { 711 int i; 712 713 /* 714 * If -needed option is not present, the second argument can be 715 * an SYMINFO_BT_ value. 716 */ 717 if (argc != (num_opt + 2)) 718 return; 719 720 /* Is -needed there? If so, no completion is possible so return */ 721 for (i = 0; i < num_opt; i++) 722 if (strcmp(argv[i], MSG_ORIG(MSG_STR_MINUS_NEEDED)) == 0) 723 return; 724 725 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_BT); 726 } 727 728 /*ARGSUSED*/ 729 static void 730 cpl_si_flags(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 731 const char *argv[], int num_opt) 732 { 733 /* The second argument can be an SYMINFO_FLG_ value */ 734 if (argc == (num_opt + 2)) 735 elfedit_cpl_atoconst(cpldata, ELFEDIT_CONST_SYMINFO_FLG); 736 } 737 738 739 740 /* 741 * Implementation functions for the commands 742 */ 743 static elfedit_cmdret_t 744 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 745 { 746 return (cmd_body(SYMINFO_CMD_T_DUMP, obj_state, argc, argv)); 747 } 748 749 750 static elfedit_cmdret_t 751 cmd_si_boundto(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 752 { 753 return (cmd_body(SYMINFO_CMD_T_SI_BOUNDTO, obj_state, argc, argv)); 754 } 755 756 757 static elfedit_cmdret_t 758 cmd_si_flags(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 759 { 760 return (cmd_body(SYMINFO_CMD_T_SI_FLAGS, obj_state, argc, argv)); 761 } 762 763 764 765 766 /*ARGSUSED*/ 767 elfedit_module_t * 768 elfedit_init(elfedit_module_version_t version) 769 { 770 /* sym:dump */ 771 static const char *name_dump[] = { 772 MSG_ORIG(MSG_CMD_DUMP), 773 MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */ 774 NULL 775 }; 776 static elfedit_cmd_optarg_t opt_dump[] = { 777 { MSG_ORIG(MSG_STR_MINUS_SYMNDX), 778 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ 779 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, 780 SYMINFO_OPT_F_SYMNDX, 0 }, 781 { NULL } 782 }; 783 static elfedit_cmd_optarg_t arg_dump[] = { 784 { MSG_ORIG(MSG_STR_SYM), 785 /* MSG_INTL(MSG_A1_SYM) */ 786 ELFEDIT_I18NHDL(MSG_A1_SYM), 787 ELFEDIT_CMDOA_F_OPT }, 788 { NULL } 789 }; 790 791 /* sym:si_boundto */ 792 static const char *name_si_boundto[] = { 793 MSG_ORIG(MSG_CMD_SI_BOUNDTO), NULL }; 794 static elfedit_cmd_optarg_t opt_si_boundto[] = { 795 { MSG_ORIG(MSG_STR_MINUS_NEEDED), 796 /* MSG_INTL(MSG_OPTDESC_NEEDED) */ 797 ELFEDIT_I18NHDL(MSG_OPTDESC_NEEDED), 0, 798 SYMINFO_OPT_F_NEEDED, 0 }, 799 { ELFEDIT_STDOA_OPT_O, 0, 800 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 801 { MSG_ORIG(MSG_STR_MINUS_SYMNDX), 802 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ 803 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, 804 SYMINFO_OPT_F_SYMNDX, 0 }, 805 { NULL } 806 }; 807 static elfedit_cmd_optarg_t arg_si_boundto[] = { 808 { MSG_ORIG(MSG_STR_SYM), 809 /* MSG_INTL(MSG_A1_SYM) */ 810 ELFEDIT_I18NHDL(MSG_A1_SYM), 811 ELFEDIT_CMDOA_F_OPT }, 812 { MSG_ORIG(MSG_STR_VALUE), 813 /* MSG_INTL(MSG_A2_DESC_SI_BOUNDTO) */ 814 ELFEDIT_I18NHDL(MSG_A2_DESC_SI_BOUNDTO), 815 ELFEDIT_CMDOA_F_OPT }, 816 { NULL } 817 }; 818 819 /* sym:si_flags */ 820 static const char *name_si_flags[] = { 821 MSG_ORIG(MSG_CMD_SI_FLAGS), NULL }; 822 static elfedit_cmd_optarg_t opt_si_flags[] = { 823 { ELFEDIT_STDOA_OPT_AND, 0, ELFEDIT_CMDOA_F_INHERIT, 824 SYMINFO_OPT_F_AND, SYMINFO_OPT_F_OR }, 825 { ELFEDIT_STDOA_OPT_CMP, 0, 826 ELFEDIT_CMDOA_F_INHERIT, SYMINFO_OPT_F_CMP, 0 }, 827 { ELFEDIT_STDOA_OPT_O, 0, 828 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 829 { ELFEDIT_STDOA_OPT_OR, 0, ELFEDIT_CMDOA_F_INHERIT, 830 SYMINFO_OPT_F_OR, SYMINFO_OPT_F_AND }, 831 { MSG_ORIG(MSG_STR_MINUS_SYMNDX), 832 /* MSG_INTL(MSG_OPTDESC_SYMNDX) */ 833 ELFEDIT_I18NHDL(MSG_OPTDESC_SYMNDX), 0, 834 SYMINFO_OPT_F_SYMNDX, 0 }, 835 { NULL } 836 }; 837 static elfedit_cmd_optarg_t arg_si_flags[] = { 838 { MSG_ORIG(MSG_STR_SYM), 839 /* MSG_INTL(MSG_A1_SYM) */ 840 ELFEDIT_I18NHDL(MSG_A1_SYM), 841 ELFEDIT_CMDOA_F_OPT }, 842 { MSG_ORIG(MSG_STR_VALUE), 843 /* MSG_INTL(MSG_A2_DESC_SI_FLAGS) */ 844 ELFEDIT_I18NHDL(MSG_A2_DESC_SI_FLAGS), 845 ELFEDIT_CMDOA_F_OPT | ELFEDIT_CMDOA_F_MULT }, 846 { NULL } 847 }; 848 849 static elfedit_cmd_t cmds[] = { 850 /* sym:dump */ 851 { cmd_dump, NULL, name_dump, 852 /* MSG_INTL(MSG_DESC_DUMP) */ 853 ELFEDIT_I18NHDL(MSG_DESC_DUMP), 854 /* MSG_INTL(MSG_HELP_DUMP) */ 855 ELFEDIT_I18NHDL(MSG_HELP_DUMP), 856 opt_dump, arg_dump }, 857 858 /* sym:si_boundto */ 859 { cmd_si_boundto, cpl_si_boundto, name_si_boundto, 860 /* MSG_INTL(MSG_DESC_SI_BOUNDTO) */ 861 ELFEDIT_I18NHDL(MSG_DESC_SI_BOUNDTO), 862 /* MSG_INTL(MSG_HELP_SI_BOUNDTO) */ 863 ELFEDIT_I18NHDL(MSG_HELP_SI_BOUNDTO), 864 opt_si_boundto, arg_si_boundto }, 865 866 /* sym:si_flags */ 867 { cmd_si_flags, cpl_si_flags, name_si_flags, 868 /* MSG_INTL(MSG_DESC_SI_FLAGS) */ 869 ELFEDIT_I18NHDL(MSG_DESC_SI_FLAGS), 870 /* MSG_INTL(MSG_HELP_SI_FLAGS) */ 871 ELFEDIT_I18NHDL(MSG_HELP_SI_FLAGS), 872 opt_si_flags, arg_si_flags }, 873 874 { NULL } 875 }; 876 877 static elfedit_module_t module = { 878 ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME), 879 /* MSG_INTL(MSG_MOD_DESC) */ 880 ELFEDIT_I18NHDL(MSG_MOD_DESC), 881 cmds, mod_i18nhdl_to_str }; 882 883 return (&module); 884 } 885