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