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