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 <ctype.h> 30 #include <unistd.h> 31 #include <elfedit.h> 32 #include <strings.h> 33 #include <debug.h> 34 #include <conv.h> 35 #include <str_msg.h> 36 37 38 39 40 #define MAXNDXSIZE 10 41 42 43 44 /* 45 * This module uses shared code for several of the commands. 46 * It is sometimes necessary to know which specific command 47 * is active. 48 */ 49 typedef enum { 50 STR_CMD_T_DUMP = 0, /* str:dump */ 51 STR_CMD_T_SET = 1, /* str:set */ 52 STR_CMD_T_ADD = 2, /* str:add */ 53 STR_CMD_T_ZERO = 3, /* str:zero */ 54 } STR_CMD_T; 55 56 57 58 #ifndef _ELF64 59 /* 60 * We supply this function for the msg module. Only one copy is needed. 61 */ 62 const char * 63 _str_msg(Msg mid) 64 { 65 return (gettext(MSG_ORIG(mid))); 66 } 67 68 #endif 69 70 71 72 /* 73 * This function is supplied to elfedit through our elfedit_module_t 74 * definition. It translates the opaque elfedit_i18nhdl_t handles 75 * in our module interface into the actual strings for elfedit to 76 * use. 77 * 78 * note: 79 * This module uses Msg codes for its i18n handle type. 80 * So the translation is simply to use MSG_INTL() to turn 81 * it into a string and return it. 82 */ 83 static const char * 84 mod_i18nhdl_to_str(elfedit_i18nhdl_t hdl) 85 { 86 Msg msg = (Msg)hdl; 87 88 return (MSG_INTL(msg)); 89 } 90 91 92 93 /* 94 * The sym_opt_t enum specifies a bit value for every optional 95 * argument allowed by a command in this module. 96 */ 97 typedef enum { 98 STR_OPT_F_ANY = 1, /* -any: treat any sec. as strtab */ 99 STR_OPT_F_END = 2, /* -end: zero to end of strtab */ 100 STR_OPT_F_NOTERM = 4, /* -noterm: str:set won't term string */ 101 STR_OPT_F_SHNAME = 8, /* -shnam name: section spec. by name */ 102 STR_OPT_F_SHNDX = 16, /* -shndx ndx: strtab spec. by index */ 103 STR_OPT_F_SHTYP = 32, /* -shtyp type: section spec. by type */ 104 STR_OPT_F_STRNDX = 64, /* -strndx: String specified by index */ 105 } str_opt_t; 106 107 108 /* 109 * A variable of type ARGSTATE is used by each command to maintain 110 * information about the string table section being used, and for any 111 * auxiliary sections that are related to it. 112 */ 113 typedef struct { 114 elfedit_obj_state_t *obj_state; 115 str_opt_t optmask; /* Mask of options used */ 116 int argc; /* # of plain arguments */ 117 const char **argv; /* Plain arguments */ 118 119 struct { /* String table */ 120 elfedit_section_t *sec; 121 Word ndx; /* Table offset if (argc > 0) */ 122 } str; 123 struct { /* Dynamic section */ 124 elfedit_section_t *sec; 125 Dyn *data; 126 Word n; 127 elfedit_dyn_elt_t strpad; 128 } dyn; 129 } ARGSTATE; 130 131 132 133 /* 134 * Given an ELF SHT_ section type constant, shndx_to_strtab() returns 135 * one of the following 136 */ 137 138 typedef enum { 139 SHTOSTR_NONE = 0, /* Type can't lead to a string table */ 140 SHTOSTR_STRTAB = 1, /* type is SHT_STRTAB */ 141 SHTOSTR_LINK_STRTAB = 2, /* sh_link for type yields strtab */ 142 SHTOSTR_LINK_SYMTAB = 3, /* sh_link for type yields symtab */ 143 SHTOSTR_SHF_STRINGS = 4, /* Not strtab, but SHF_STRINGS set */ 144 } SHTOSTR_T; 145 146 static SHTOSTR_T 147 shtype_to_strtab(Word sh_type, Word sh_flags) 148 { 149 /* 150 * A string table section always leads to itself. A 151 * non-string table that has it's SHF_STRINGS section flag 152 * set trumps anything else. 153 */ 154 if (sh_type == SHT_STRTAB) 155 return (SHTOSTR_STRTAB); 156 if (sh_flags & SHF_STRINGS) 157 return (SHTOSTR_SHF_STRINGS); 158 159 /* 160 * Look at non-stringtable section types that can lead to 161 * string tables via sh_link. 162 */ 163 switch (sh_type) { 164 /* These sections reference a string table via sh_link */ 165 case SHT_DYNAMIC: 166 case SHT_SYMTAB: 167 case SHT_DYNSYM: 168 case SHT_SUNW_LDYNSYM: 169 case SHT_SUNW_verdef: 170 case SHT_SUNW_verneed: 171 return (SHTOSTR_LINK_STRTAB); 172 173 /* 174 * These sections reference a symbol table via sh_link. 175 * Symbol tables, in turn, reference a string table 176 * via their sh_link. 177 */ 178 case SHT_HASH: 179 case SHT_REL: 180 case SHT_RELA: 181 case SHT_GROUP: 182 case SHT_SYMTAB_SHNDX: 183 case SHT_SUNW_move: 184 case SHT_SUNW_syminfo: 185 case SHT_SUNW_versym: 186 case SHT_SUNW_symsort: 187 case SHT_SUNW_tlssort: 188 return (SHTOSTR_LINK_SYMTAB); 189 } 190 191 /* Types that lead to string tables were caught above */ 192 return (SHTOSTR_NONE); 193 } 194 195 /* 196 * Given a section index, attempt to convert it into an index 197 * to a string table section. 198 */ 199 static Word 200 shndx_to_strtab(elfedit_obj_state_t *obj_state, Word ndx) 201 { 202 /* 203 * Locate and validate the string table. In the case where 204 * a non-string table section is given that references a string 205 * table, we will use the referenced table. 206 */ 207 if (ndx < obj_state->os_shnum) { 208 Shdr *shdr = obj_state->os_secarr[ndx].sec_shdr; 209 210 switch (shtype_to_strtab(shdr->sh_type, shdr->sh_flags)) { 211 212 /* Sections that reference a string table via sh_link */ 213 case SHTOSTR_LINK_STRTAB: 214 ndx = shdr->sh_link; 215 break; 216 217 /* 218 * Sections that reference a symbol tabel via sh_link, 219 * which in turn reference a string table via their sh_link. 220 */ 221 case SHTOSTR_LINK_SYMTAB: 222 ndx = shdr->sh_link; 223 if (ndx < obj_state->os_shnum) 224 ndx = 225 obj_state->os_secarr[ndx].sec_shdr->sh_link; 226 break; 227 } 228 } 229 230 return (ndx); 231 } 232 233 234 235 /* 236 * Standard argument processing for string table module 237 * 238 * entry 239 * obj_state, argc, argv - Standard command arguments 240 * optmask - Mask of allowed optional arguments. 241 * argstate - Address of ARGSTATE block to be initialized 242 * 243 * exit: 244 * On success, *argstate is initialized. On error, 245 * an error is issued and this routine does not return. 246 */ 247 static void 248 process_args(elfedit_obj_state_t *obj_state, int argc, const char *argv[], 249 STR_CMD_T cmd, ARGSTATE *argstate, int *print_only) 250 { 251 elfedit_getopt_state_t getopt_state; 252 elfedit_getopt_ret_t *getopt_ret; 253 Word ndx; 254 int argc_ok; 255 256 bzero(argstate, sizeof (*argstate)); 257 argstate->obj_state = obj_state; 258 259 /* 260 * By default, we use the section name string table pointed at 261 * by the ELF header. 262 */ 263 ndx = obj_state->os_ehdr->e_shstrndx; 264 265 elfedit_getopt_init(&getopt_state, &argc, &argv); 266 267 /* Add each new option to the options mask */ 268 while ((getopt_ret = elfedit_getopt(&getopt_state)) != NULL) { 269 argstate->optmask |= getopt_ret->gor_idmask; 270 271 switch (getopt_ret->gor_idmask) { 272 case STR_OPT_F_SHNAME: /* -shnam name */ 273 ndx = elfedit_name_to_shndx(obj_state, 274 getopt_ret->gor_value); 275 break; 276 277 case STR_OPT_F_SHNDX: /* -shndx index */ 278 ndx = elfedit_atoui(getopt_ret->gor_value, NULL); 279 break; 280 281 case STR_OPT_F_SHTYP: /* -shtyp type */ 282 ndx = elfedit_type_to_shndx(obj_state, 283 elfedit_atoconst(getopt_ret->gor_value, 284 ELFEDIT_CONST_SHT)); 285 break; 286 } 287 } 288 289 /* 290 * Usage error if there are the wrong number of plain arguments. 291 */ 292 switch (cmd) { 293 case STR_CMD_T_DUMP: 294 argc_ok = (argc == 0) || (argc == 1); 295 *print_only = 1; 296 break; 297 case STR_CMD_T_SET: 298 argc_ok = (argc == 1) || (argc == 2); 299 *print_only = (argc == 1); 300 break; 301 case STR_CMD_T_ADD: 302 argc_ok = (argc == 1); 303 *print_only = 0; 304 break; 305 case STR_CMD_T_ZERO: 306 /* 307 * The second argument (count) and the -end option are 308 * mutally exclusive. 309 */ 310 argc_ok = ((argc == 1) || (argc == 2)) && 311 !((argc == 2) && (argstate->optmask & STR_OPT_F_END)); 312 *print_only = 0; 313 break; 314 default: 315 argc_ok = 0; /* Unknown command? */ 316 break; 317 } 318 if (!argc_ok) 319 elfedit_command_usage(); 320 321 /* If there may be an arbitrary amount of output, use a pager */ 322 if (argc == 0) 323 elfedit_pager_init(); 324 325 /* Return the updated values of argc/argv */ 326 argstate->argc = argc; 327 argstate->argv = argv; 328 329 if (argstate->optmask & STR_OPT_F_ANY) { 330 /* Take the arbitrary section */ 331 argstate->str.sec = elfedit_sec_get(obj_state, ndx); 332 333 } else { 334 /* 335 * Locate and validate the string table. In the case where 336 * a non-string table section is given that references a string 337 * table, we will use the referenced table. 338 */ 339 ndx = shndx_to_strtab(obj_state, ndx); 340 341 /* 342 * If ndx is a string table, the following will issue the 343 * proper debug messages. If it is out of range, or of any 344 * other type, an error is issued and it doesn't return. 345 */ 346 argstate->str.sec = elfedit_sec_getstr(obj_state, ndx, 1); 347 } 348 349 /* 350 * If there is a dynamic section, check its sh_link to the 351 * string table index. If these match, then we have the 352 * dynamic string table. In that case, fetch the dynamic 353 * section and locate the DT_SUNW_STRPAD entry, causing 354 * debug messages to be issued. 355 */ 356 argstate->dyn.sec = NULL; 357 elfedit_dyn_elt_init(&argstate->dyn.strpad); 358 if (obj_state->os_dynndx != SHN_UNDEF) { 359 elfedit_section_t *dynsec = 360 &obj_state->os_secarr[obj_state->os_dynndx]; 361 362 if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) && 363 (argstate->str.sec->sec_shndx == 364 dynsec->sec_shdr->sh_link)) { 365 argstate->dyn.sec = elfedit_sec_getdyn(obj_state, 366 &argstate->dyn.data, &argstate->dyn.n); 367 (void) elfedit_dynstr_getpad(dynsec, 368 &argstate->dyn.strpad); 369 370 /* 371 * Does the pad value make sense? 372 * Issue debug message and ignore it if not. 373 */ 374 if ((argstate->dyn.strpad.dn_seen != 0) && 375 (argstate->dyn.strpad.dn_dyn.d_un.d_val > 376 argstate->str.sec->sec_data->d_size)) { 377 argstate->dyn.strpad.dn_seen = 0; 378 elfedit_msg(ELFEDIT_MSG_DEBUG, 379 MSG_INTL(MSG_DEBUG_BADSTRPAD), 380 EC_WORD(argstate->str.sec->sec_shndx), 381 argstate->str.sec->sec_name, 382 EC_XWORD(argstate->dyn.strpad.dn_dyn. 383 d_un.d_val), 384 EC_XWORD(argstate->str.sec-> 385 sec_data->d_size)); 386 387 } 388 } 389 } 390 391 /* Locate the string table offset if argument is present */ 392 if ((argc > 0) && (cmd != STR_CMD_T_ADD)) { 393 /* 394 * If the -strndx option was specified, arg is an index 395 * into the string table. Otherwise it is a string 396 * to be looked up. 397 */ 398 if (argstate->optmask & STR_OPT_F_STRNDX) { 399 argstate->str.ndx = (elfedit_atoui_range(argv[0], 400 MSG_ORIG(MSG_STR_STRING), 0, 401 argstate->str.sec->sec_data->d_size - 1, NULL)); 402 } else { 403 if (elfedit_sec_findstr(argstate->str.sec, 0, argv[0], 404 &argstate->str.ndx) == 0) 405 elfedit_msg(ELFEDIT_MSG_ERR, 406 MSG_INTL(MSG_ERR_STRNOTFND), 407 EC_WORD(argstate->str.sec->sec_shndx), 408 argstate->str.sec->sec_name, argv[0]); 409 } 410 } else { 411 argstate->str.ndx = 0; 412 } 413 } 414 415 416 417 /* 418 * Print string table values, taking output style into account. 419 * 420 * entry: 421 * autoprint - If True, output is only produced if the elfedit 422 * autoprint flag is set. If False, output is always produced. 423 * argstate - State block for current symbol table. 424 */ 425 static void 426 print_strtab(int autoprint, ARGSTATE *argstate) 427 { 428 char index[(MAXNDXSIZE * 2) + 4]; 429 elfedit_outstyle_t outstyle; 430 const char *str, *limit, *tbl_limit; 431 Word ndx; 432 433 434 if (autoprint && ((elfedit_flags() & ELFEDIT_F_AUTOPRINT) == 0)) 435 return; 436 437 outstyle = elfedit_outstyle(); 438 if (outstyle == ELFEDIT_OUTSTYLE_DEFAULT) { 439 elfedit_printf(MSG_INTL(MSG_FMT_STRTAB), 440 argstate->str.sec->sec_name); 441 if (argstate->dyn.strpad.dn_seen) 442 elfedit_printf(MSG_INTL(MSG_FMT_DYNSTRPAD), 443 EC_WORD(argstate->str.sec->sec_data->d_size - 444 argstate->dyn.strpad.dn_dyn.d_un.d_val), 445 EC_WORD(argstate->str.sec->sec_data->d_size - 1), 446 EC_WORD(argstate->dyn.strpad.dn_dyn.d_un.d_val)); 447 elfedit_printf(MSG_INTL(MSG_FMT_DUMPTITLE)); 448 } 449 450 str = argstate->str.sec->sec_data->d_buf; 451 tbl_limit = str + argstate->str.sec->sec_data->d_size; 452 ndx = argstate->str.ndx; 453 if (argstate->argc > 0) { 454 str += ndx; 455 /* 456 * If first byte is NULL and this is the default output style, 457 * then we want to display the range of NULL bytes, and we 458 * push limit out to the last one in the sequence. Otherwise, 459 * just display the string. 460 */ 461 if ((*str == '\0') && (outstyle == ELFEDIT_OUTSTYLE_DEFAULT)) { 462 limit = str; 463 while (((limit + 1) < tbl_limit) && 464 (*(limit + 1) == '\0')) 465 limit++; 466 } else { 467 limit = str + strlen(str) + 1; 468 } 469 } else { 470 /* Display the entire string table */ 471 limit = tbl_limit; 472 } 473 474 475 while (str < limit) { 476 Word skip = strlen(str) + 1; 477 Word start_ndx; 478 479 if (outstyle != ELFEDIT_OUTSTYLE_DEFAULT) { 480 elfedit_printf(MSG_ORIG(MSG_FMT_STRNL), str); 481 str += skip; 482 ndx += skip; 483 continue; 484 } 485 486 start_ndx = ndx; 487 if (*str == '\0') 488 while (((str + 1) < limit) && (*(str + 1) == '\0')) { 489 ndx++; 490 str++; 491 } 492 493 if (start_ndx != ndx) { 494 (void) snprintf(index, sizeof (index), 495 MSG_ORIG(MSG_FMT_INDEXRANGE), 496 EC_XWORD(start_ndx), EC_XWORD(ndx)); 497 } else { 498 (void) snprintf(index, sizeof (index), 499 MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(ndx)); 500 } 501 elfedit_printf(MSG_ORIG(MSG_FMT_DUMPENTRY), index); 502 elfedit_write(MSG_ORIG(MSG_STR_DQUOTE), MSG_STR_DQUOTE_SIZE); 503 if (start_ndx == ndx) 504 elfedit_str_to_c_literal(str, elfedit_write); 505 elfedit_write(MSG_ORIG(MSG_STR_DQUOTENL), 506 MSG_STR_DQUOTENL_SIZE); 507 str += skip; 508 ndx += skip; 509 } 510 } 511 512 513 /* 514 * Command body for str:set, handling the case where the 3rd 515 * argument (new-str) is present. 516 */ 517 static elfedit_cmdret_t 518 cmd_body_set(ARGSTATE *argstate) 519 { 520 elfedit_section_t *strsec = argstate->str.sec; 521 const char *newstr = argstate->argv[1]; 522 Word ndx = argstate->str.ndx; 523 char *oldstr; 524 int i, len, ncp; 525 526 len = strlen(newstr); 527 ncp = len; 528 if (!(argstate->optmask & STR_OPT_F_NOTERM)) 529 ncp++; 530 531 /* NULL string with no termination? Nothing to do */ 532 if (ncp == 0) 533 return (ELFEDIT_CMDRET_NONE); 534 535 /* Does it fit? */ 536 if ((ndx + ncp) > strsec->sec_data->d_size) 537 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOFIT), 538 EC_WORD(strsec->sec_shndx), strsec->sec_name, 539 EC_WORD(ndx), newstr); 540 541 /* Does it clobber the final NULL termination? */ 542 if (((ndx + ncp) == strsec->sec_data->d_size) && 543 (argstate->optmask & STR_OPT_F_NOTERM)) 544 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_FINALNULL), 545 EC_WORD(strsec->sec_shndx), strsec->sec_name, 546 EC_WORD(ndx), newstr); 547 548 /* 549 * strtab[0] is always supposed to contain a NULL byte. You're not 550 * supposed to mess with it. We will carry out this operation, 551 * but with a debug message indicating that it is unorthodox. 552 */ 553 if ((ndx == 0) && (*newstr != '\0')) 554 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_CHGSTR0), 555 EC_WORD(strsec->sec_shndx), strsec->sec_name, 556 EC_WORD(ndx), newstr); 557 558 /* Does it alter the existing value? */ 559 oldstr = ndx + (char *)strsec->sec_data->d_buf; 560 for (i = 0; i < ncp; i++) 561 if (newstr[i] != oldstr[i]) 562 break; 563 if (i == ncp) { /* No change */ 564 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_OK), 565 strsec->sec_shndx, strsec->sec_name, ndx, newstr); 566 return (ELFEDIT_CMDRET_NONE); 567 } 568 569 /* 570 * If the new string is longer than the old one, then it will 571 * clobber the start of the following string. The resulting 572 * string table is perfectly legal, but issue a debug message 573 * letting the user know. 574 */ 575 i = strlen(oldstr); 576 if (len > i) 577 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_LONGSTR), 578 EC_WORD(strsec->sec_shndx), strsec->sec_name, 579 EC_WORD(ndx), len, i); 580 581 /* 582 * If we have strayed into the reserved part of the dynstr, then 583 * update DT_SUNW_STRPAD. 584 */ 585 if (argstate->dyn.strpad.dn_seen) { 586 elfedit_dyn_elt_t *strpad = &argstate->dyn.strpad; 587 Word new_pad_ndx = ndx + len + 1; 588 Word pad_ndx = argstate->str.sec->sec_data->d_size - 589 strpad->dn_dyn.d_un.d_val; 590 591 if (new_pad_ndx > pad_ndx) { 592 elfedit_msg(ELFEDIT_MSG_DEBUG, 593 MSG_INTL(MSG_DEBUG_ADDDYNSTR), 594 EC_WORD(strsec->sec_shndx), strsec->sec_name, 595 EC_WORD(ndx), EC_WORD(new_pad_ndx - pad_ndx), 596 EC_WORD(strpad->dn_dyn.d_un.d_val), 597 newstr); 598 599 strpad->dn_dyn.d_un.d_val = 600 argstate->dyn.data[strpad->dn_ndx].d_un.d_val = 601 (argstate->str.sec->sec_data->d_size - new_pad_ndx); 602 elfedit_modified_data(argstate->dyn.sec); 603 } 604 } 605 606 607 608 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_S_CHG), 609 strsec->sec_shndx, strsec->sec_name, ndx, len, oldstr, newstr); 610 bcopy(newstr, oldstr, ncp); 611 612 return (ELFEDIT_CMDRET_MOD); 613 } 614 615 616 /* 617 * Command body for str:zero 618 */ 619 static elfedit_cmdret_t 620 cmd_body_zero(ARGSTATE *argstate) 621 { 622 elfedit_section_t *strsec = argstate->str.sec; 623 Word count; 624 Word ndx = argstate->str.ndx; 625 char *oldstr = ndx + (char *)strsec->sec_data->d_buf; 626 Word i; 627 628 /* How many bytes to zero? */ 629 if (argstate->optmask & STR_OPT_F_END) 630 count = strsec->sec_data->d_size - argstate->str.ndx; 631 else if (argstate->argc == 2) 632 count = elfedit_atoui_range(argstate->argv[1], 633 MSG_ORIG(MSG_STR_COUNT), 0, 634 argstate->str.sec->sec_data->d_size - argstate->str.ndx, 635 NULL); 636 else 637 count = strlen(oldstr); 638 639 /* Does it alter the existing value? */ 640 for (i = 0; i < count; i++) 641 if (oldstr[i] != '\0') 642 break; 643 if (i == count) { /* No change */ 644 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_Z_OK), 645 strsec->sec_shndx, strsec->sec_name, ndx); 646 return (ELFEDIT_CMDRET_NONE); 647 } 648 649 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_Z_CHG), 650 strsec->sec_shndx, strsec->sec_name, ndx, count); 651 bzero(oldstr, count); 652 653 return (ELFEDIT_CMDRET_MOD); 654 } 655 656 657 /* 658 * Common body for the str: module commands. 659 * 660 * entry: 661 * cmd - One of the STR_CMD_T_* constants listed above, specifying 662 * which command to implement. 663 * obj_state, argc, argv - Standard command arguments 664 */ 665 static elfedit_cmdret_t 666 cmd_body(STR_CMD_T cmd, elfedit_obj_state_t *obj_state, 667 int argc, const char *argv[]) 668 { 669 ARGSTATE argstate; 670 elfedit_cmdret_t ret = ELFEDIT_CMDRET_NONE; 671 int print_only; 672 673 process_args(obj_state, argc, argv, cmd, &argstate, &print_only); 674 675 /* 676 * If this call call does not change data, display the current 677 * value(s) and return. 678 */ 679 if (print_only) { 680 print_strtab(0, &argstate); 681 return (ELFEDIT_CMDRET_NONE); 682 } 683 684 switch (cmd) { 685 /* NOTE: STR_CMD_T_DUMP can't get here --- it's always print_only */ 686 687 case STR_CMD_T_SET: 688 ret = cmd_body_set(&argstate); 689 break; 690 691 case STR_CMD_T_ADD: 692 argstate.str.ndx = elfedit_strtab_insert(obj_state, 693 argstate.str.sec, argstate.dyn.sec, argstate.argv[0]); 694 break; 695 696 case STR_CMD_T_ZERO: 697 ret = cmd_body_zero(&argstate); 698 break; 699 } 700 701 /* 702 * If we modified the strtab section, tell libelf. 703 */ 704 if (ret == ELFEDIT_CMDRET_MOD) 705 elfedit_modified_data(argstate.str.sec); 706 707 /* Do autoprint */ 708 print_strtab(1, &argstate); 709 710 return (ret); 711 } 712 713 714 715 716 /* 717 * Command completion functions for the various commands 718 */ 719 720 static void 721 add_shtyp_match(Word sh_type, void *cpldata) 722 { 723 char buf[128]; 724 const char *s; 725 char *s2; 726 727 s = elfedit_atoconst_value_to_str(ELFEDIT_CONST_SHT, sh_type, 0); 728 elfedit_cpl_match(cpldata, s, 1); 729 730 /* 731 * To get the informal tag names that are lowercase 732 * and lack the leading SHT_, we copy the string we 733 * have into a buffer and process it. 734 */ 735 if (strlen(s) < 4) 736 return; 737 (void) strlcpy(buf, s + 4, sizeof (buf)); 738 for (s2 = buf; *s2 != '\0'; s2++) 739 if (isupper(*s2)) 740 *s2 = tolower(*s2); 741 elfedit_cpl_match(cpldata, buf, 1); 742 } 743 744 /* 745 * Handle filling in the values for -shnam, -shndx, and -shtyp options. 746 */ 747 /*ARGSUSED*/ 748 static void 749 cpl_sh_opt(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 750 const char *argv[], int num_opt) 751 { 752 enum { NAME, INDEX, TYPE } op; 753 elfedit_section_t *sec; 754 Word ndx; 755 756 if ((argc != num_opt) || (argc < 2)) 757 return; 758 759 if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) { 760 op = NAME; 761 } else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) { 762 op = INDEX; 763 764 } else if (strcmp(argv[argc - 2], MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) { 765 op = TYPE; 766 767 if (obj_state == NULL) { /* No object available */ 768 elfedit_atoui_sym_t *atoui_sym; 769 770 atoui_sym = elfedit_const_to_atoui(ELFEDIT_CONST_SHT); 771 for (; atoui_sym->sym_name != NULL; atoui_sym++) 772 if (shtype_to_strtab(atoui_sym->sym_value, 0) != 773 SHTOSTR_NONE) 774 elfedit_cpl_match(cpldata, 775 atoui_sym->sym_name, 1); 776 } 777 } else { 778 return; 779 } 780 781 if (obj_state == NULL) /* No object available */ 782 return; 783 784 /* 785 * Loop over the section headers and supply command completion 786 * for the items in the file that can yield a string table. 787 */ 788 sec = obj_state->os_secarr; 789 for (ndx = 0; ndx < obj_state->os_shnum; ndx++, sec++) { 790 Shdr *shdr = sec->sec_shdr; 791 SHTOSTR_T shtostr_type; 792 793 shtostr_type = shtype_to_strtab(shdr->sh_type, shdr->sh_flags); 794 if (shtostr_type == SHTOSTR_NONE) 795 continue; 796 797 switch (op) { 798 case NAME: 799 elfedit_cpl_match(cpldata, sec->sec_name, 0); 800 break; 801 case INDEX: 802 elfedit_cpl_ndx(cpldata, sec->sec_shndx); 803 break; 804 case TYPE: 805 if (shtostr_type != SHTOSTR_SHF_STRINGS) 806 add_shtyp_match(shdr->sh_type, cpldata); 807 break; 808 } 809 } 810 } 811 812 813 /* 814 * Most of the commands accept an -shXXX option for the string table 815 * and a string first argument. This routine examines which argument 816 * is being processed, and supplies completion for these items. 817 */ 818 static void 819 cpl_sec_str(elfedit_obj_state_t *obj_state, void *cpldata, int argc, 820 const char *argv[], int num_opt) 821 { 822 const char *str, *limit; 823 elfedit_section_t *sec; 824 Word strtab_ndx; 825 Word ndx; 826 827 /* Handle -shXXX options */ 828 cpl_sh_opt(obj_state, cpldata, argc, argv, num_opt); 829 830 /* Without object state, there's no data to work from */ 831 if (obj_state == NULL) 832 return; 833 834 /* If not first plain arg, return */ 835 if (argc != (num_opt + 1)) 836 return; 837 838 /* 839 * Look at the options, looking for two things: 840 * 1) A -shXXX option specifying a section. If so, turn that 841 * into a section index if possible. 842 * 2) Was -strndx used? If so, we are looking at an integer 843 * value and have nothing to complete. 844 */ 845 strtab_ndx = obj_state->os_ehdr->e_shstrndx; 846 for (ndx = 0; ndx < num_opt; ndx++) { 847 if (strcmp(argv[ndx], MSG_ORIG(MSG_STR_MINUS_STRNDX)) == 0) 848 return; 849 850 if ((ndx+1) < num_opt) { 851 if (strcmp(argv[ndx], 852 MSG_ORIG(MSG_STR_MINUS_SHNAM)) == 0) { 853 Word i; 854 855 for (i = 1; i < obj_state->os_shnum; i++) 856 if (strcmp(obj_state->os_secarr[i]. 857 sec_name, argv[ndx+1]) == 0) { 858 strtab_ndx = i; 859 break; 860 } 861 } else if (strcmp(argv[ndx], 862 MSG_ORIG(MSG_STR_MINUS_SHNDX)) == 0) { 863 elfedit_atoui_t val; 864 865 if (elfedit_atoui2(argv[ndx+1], NULL, 866 &val) != 0) 867 strtab_ndx = val; 868 } else if (strcmp(argv[ndx], 869 MSG_ORIG(MSG_STR_MINUS_SHTYP)) == 0) { 870 elfedit_atoui_t sh_type; 871 Word i; 872 873 if (elfedit_atoconst2(argv[ndx+1], 874 ELFEDIT_CONST_SHT, &sh_type) == 0) 875 continue; 876 for (i = 1; i < obj_state->os_shnum; i++) 877 if (obj_state->os_secarr[i].sec_shdr-> 878 sh_type == sh_type) { 879 strtab_ndx = i; 880 break; 881 } 882 } 883 } 884 } 885 886 /* 887 * Locate and validate the string table. In the case where 888 * a non-string table section is given that references a string 889 * table, we will use the referenced table. 890 */ 891 strtab_ndx = shndx_to_strtab(obj_state, strtab_ndx); 892 if ((strtab_ndx >= obj_state->os_shnum) || 893 (obj_state->os_secarr[strtab_ndx].sec_shdr->sh_type != SHT_STRTAB)) 894 return; 895 sec = &obj_state->os_secarr[strtab_ndx]; 896 897 str = sec->sec_data->d_buf; 898 limit = str + sec->sec_data->d_size; 899 while (str < limit) { 900 if (*str != '\0') 901 elfedit_cpl_match(cpldata, str, 0); 902 str += strlen(str) + 1; 903 } 904 } 905 906 907 908 /* 909 * Implementation functions for the commands 910 */ 911 static elfedit_cmdret_t 912 cmd_dump(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 913 { 914 return (cmd_body(STR_CMD_T_DUMP, obj_state, argc, argv)); 915 } 916 917 static elfedit_cmdret_t 918 cmd_set(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 919 { 920 return (cmd_body(STR_CMD_T_SET, obj_state, argc, argv)); 921 } 922 923 static elfedit_cmdret_t 924 cmd_add(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 925 { 926 return (cmd_body(STR_CMD_T_ADD, obj_state, argc, argv)); 927 } 928 929 static elfedit_cmdret_t 930 cmd_zero(elfedit_obj_state_t *obj_state, int argc, const char *argv[]) 931 { 932 return (cmd_body(STR_CMD_T_ZERO, obj_state, argc, argv)); 933 } 934 935 936 937 /*ARGSUSED*/ 938 elfedit_module_t * 939 elfedit_init(elfedit_module_version_t version) 940 { 941 /* str:dump */ 942 static const char *name_dump[] = { 943 MSG_ORIG(MSG_CMD_DUMP), 944 MSG_ORIG(MSG_STR_EMPTY), /* "" makes this the default command */ 945 NULL 946 }; 947 static elfedit_cmd_optarg_t opt_dump[] = { 948 { MSG_ORIG(MSG_STR_MINUS_ANY), 949 /* MSG_INTL(MSG_OPTDESC_ANY) */ 950 ELFEDIT_I18NHDL(MSG_OPTDESC_ANY), 0, 951 STR_OPT_F_ANY, 0 }, 952 { ELFEDIT_STDOA_OPT_O, NULL, 953 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 954 { MSG_ORIG(MSG_STR_MINUS_SHNAM), 955 /* MSG_INTL(MSG_OPTDESC_SHNAM) */ 956 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, 957 STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP }, 958 { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, 959 { MSG_ORIG(MSG_STR_MINUS_SHNDX), 960 /* MSG_INTL(MSG_OPTDESC_SHNDX) */ 961 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, 962 STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP }, 963 { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, 964 { MSG_ORIG(MSG_STR_MINUS_SHTYP), 965 /* MSG_INTL(MSG_OPTDESC_SHTYP) */ 966 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, 967 STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX }, 968 { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, 969 { MSG_ORIG(MSG_STR_MINUS_STRNDX), 970 /* MSG_INTL(MSG_OPTDESC_STRNDX) */ 971 ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0, 972 STR_OPT_F_STRNDX, 0 }, 973 { NULL } 974 }; 975 static elfedit_cmd_optarg_t arg_dump[] = { 976 { MSG_ORIG(MSG_STR_STRING), 977 /* MSG_INTL(MSG_A1_STRING) */ 978 ELFEDIT_I18NHDL(MSG_A1_STRING), 979 ELFEDIT_CMDOA_F_OPT }, 980 { NULL } 981 }; 982 983 /* str:set */ 984 static const char *name_set[] = { 985 MSG_ORIG(MSG_CMD_SET), NULL }; 986 static elfedit_cmd_optarg_t opt_set[] = { 987 { MSG_ORIG(MSG_STR_MINUS_ANY), 988 /* MSG_INTL(MSG_OPTDESC_ANY) */ 989 ELFEDIT_I18NHDL(MSG_OPTDESC_ANY), 0, 990 STR_OPT_F_ANY, 0 }, 991 { ELFEDIT_STDOA_OPT_O, NULL, 992 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 993 { MSG_ORIG(MSG_STR_MINUS_NOTERM), 994 /* MSG_INTL(MSG_OPTDESC_NOTERM) */ 995 ELFEDIT_I18NHDL(MSG_OPTDESC_NOTERM), 0, 996 STR_OPT_F_NOTERM, 0 }, 997 { MSG_ORIG(MSG_STR_MINUS_SHNAM), 998 /* MSG_INTL(MSG_OPTDESC_SHNAM) */ 999 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, 1000 STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP }, 1001 { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, 1002 { MSG_ORIG(MSG_STR_MINUS_SHNDX), 1003 /* MSG_INTL(MSG_OPTDESC_SHNDX) */ 1004 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, 1005 STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP }, 1006 { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, 1007 { MSG_ORIG(MSG_STR_MINUS_SHTYP), 1008 /* MSG_INTL(MSG_OPTDESC_SHTYP) */ 1009 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, 1010 STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX }, 1011 { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, 1012 { MSG_ORIG(MSG_STR_MINUS_STRNDX), 1013 /* MSG_INTL(MSG_OPTDESC_STRNDX) */ 1014 ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0, 1015 STR_OPT_F_STRNDX, 0 }, 1016 { NULL } 1017 }; 1018 static elfedit_cmd_optarg_t arg_set[] = { 1019 { MSG_ORIG(MSG_STR_STRING), 1020 /* MSG_INTL(MSG_A1_STRING) */ 1021 ELFEDIT_I18NHDL(MSG_A1_STRING), 1022 0 }, 1023 { MSG_ORIG(MSG_STR_NEWSTRING), 1024 /* MSG_INTL(MSG_A2_NEWSTRING) */ 1025 ELFEDIT_I18NHDL(MSG_A2_NEWSTRING), 1026 ELFEDIT_CMDOA_F_OPT }, 1027 { NULL } 1028 }; 1029 1030 /* str:add */ 1031 static const char *name_add[] = { 1032 MSG_ORIG(MSG_CMD_ADD), NULL }; 1033 static elfedit_cmd_optarg_t opt_add[] = { 1034 { ELFEDIT_STDOA_OPT_O, NULL, 1035 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 1036 { MSG_ORIG(MSG_STR_MINUS_SHNAM), 1037 /* MSG_INTL(MSG_OPTDESC_SHNAM) */ 1038 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, 1039 STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP }, 1040 { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, 1041 { MSG_ORIG(MSG_STR_MINUS_SHNDX), 1042 /* MSG_INTL(MSG_OPTDESC_SHNDX) */ 1043 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, 1044 STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP }, 1045 { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, 1046 { MSG_ORIG(MSG_STR_MINUS_SHTYP), 1047 /* MSG_INTL(MSG_OPTDESC_SHTYP) */ 1048 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, 1049 STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX }, 1050 { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, 1051 { NULL } 1052 }; 1053 static elfedit_cmd_optarg_t arg_add[] = { 1054 { MSG_ORIG(MSG_STR_NEWSTRING), 1055 /* MSG_INTL(MSG_A1_NEWSTRING) */ 1056 ELFEDIT_I18NHDL(MSG_A1_NEWSTRING), 1057 0 }, 1058 { NULL } 1059 }; 1060 1061 /* str:zero */ 1062 static const char *name_zero[] = { 1063 MSG_ORIG(MSG_CMD_ZERO), NULL }; 1064 static elfedit_cmd_optarg_t opt_zero[] = { 1065 { MSG_ORIG(MSG_STR_MINUS_ANY), 1066 /* MSG_INTL(MSG_OPTDESC_ANY) */ 1067 ELFEDIT_I18NHDL(MSG_OPTDESC_ANY), 0, 1068 STR_OPT_F_ANY, 0 }, 1069 { ELFEDIT_STDOA_OPT_O, NULL, 1070 ELFEDIT_CMDOA_F_INHERIT, 0, 0 }, 1071 { MSG_ORIG(MSG_STR_MINUS_SHNAM), 1072 /* MSG_INTL(MSG_OPTDESC_SHNAM) */ 1073 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNAM), ELFEDIT_CMDOA_F_VALUE, 1074 STR_OPT_F_SHNAME, STR_OPT_F_SHNDX | STR_OPT_F_SHTYP }, 1075 { MSG_ORIG(MSG_STR_NAME), NULL, 0 }, 1076 { MSG_ORIG(MSG_STR_MINUS_SHNDX), 1077 /* MSG_INTL(MSG_OPTDESC_SHNDX) */ 1078 ELFEDIT_I18NHDL(MSG_OPTDESC_SHNDX), ELFEDIT_CMDOA_F_VALUE, 1079 STR_OPT_F_SHNDX, STR_OPT_F_SHNAME | STR_OPT_F_SHTYP }, 1080 { MSG_ORIG(MSG_STR_INDEX), NULL, 0 }, 1081 { MSG_ORIG(MSG_STR_MINUS_SHTYP), 1082 /* MSG_INTL(MSG_OPTDESC_SHTYP) */ 1083 ELFEDIT_I18NHDL(MSG_OPTDESC_SHTYP), ELFEDIT_CMDOA_F_VALUE, 1084 STR_OPT_F_SHTYP, STR_OPT_F_SHNAME | STR_OPT_F_SHNDX }, 1085 { MSG_ORIG(MSG_STR_TYPE), NULL, 0 }, 1086 { MSG_ORIG(MSG_STR_MINUS_STRNDX), 1087 /* MSG_INTL(MSG_OPTDESC_STRNDX) */ 1088 ELFEDIT_I18NHDL(MSG_OPTDESC_STRNDX), 0, 1089 STR_OPT_F_STRNDX, 0 }, 1090 { MSG_ORIG(MSG_STR_MINUS_END), 1091 /* MSG_INTL(MSG_OPTDESC_END) */ 1092 ELFEDIT_I18NHDL(MSG_OPTDESC_END), 0, 1093 STR_OPT_F_END, 0 }, 1094 { NULL } 1095 }; 1096 static elfedit_cmd_optarg_t arg_zero[] = { 1097 { MSG_ORIG(MSG_STR_STRING), 1098 /* MSG_INTL(MSG_A1_STRING) */ 1099 ELFEDIT_I18NHDL(MSG_A1_STRING), 1100 0 }, 1101 { MSG_ORIG(MSG_STR_COUNT), 1102 /* MSG_INTL(MSG_A2_COUNT) */ 1103 ELFEDIT_I18NHDL(MSG_A2_COUNT), 1104 ELFEDIT_CMDOA_F_OPT }, 1105 { NULL } 1106 }; 1107 1108 1109 static elfedit_cmd_t cmds[] = { 1110 /* str:dump */ 1111 { cmd_dump, cpl_sec_str, name_dump, 1112 /* MSG_INTL(MSG_DESC_DUMP) */ 1113 ELFEDIT_I18NHDL(MSG_DESC_DUMP), 1114 /* MSG_INTL(MSG_HELP_DUMP) */ 1115 ELFEDIT_I18NHDL(MSG_HELP_DUMP), 1116 opt_dump, arg_dump }, 1117 1118 /* str:set */ 1119 { cmd_set, cpl_sec_str, name_set, 1120 /* MSG_INTL(MSG_DESC_SET) */ 1121 ELFEDIT_I18NHDL(MSG_DESC_SET), 1122 /* MSG_INTL(MSG_HELP_SET) */ 1123 ELFEDIT_I18NHDL(MSG_HELP_SET), 1124 opt_set, arg_set }, 1125 1126 /* str:add */ 1127 { cmd_add, cpl_sh_opt, name_add, 1128 /* MSG_INTL(MSG_DESC_ADD) */ 1129 ELFEDIT_I18NHDL(MSG_DESC_ADD), 1130 /* MSG_INTL(MSG_HELP_ADD) */ 1131 ELFEDIT_I18NHDL(MSG_HELP_ADD), 1132 opt_add, arg_add }, 1133 1134 /* str:zero */ 1135 { cmd_zero, cpl_sec_str, name_zero, 1136 /* MSG_INTL(MSG_DESC_ZERO) */ 1137 ELFEDIT_I18NHDL(MSG_DESC_ZERO), 1138 /* MSG_INTL(MSG_HELP_ZERO) */ 1139 ELFEDIT_I18NHDL(MSG_HELP_ZERO), 1140 opt_zero, arg_zero }, 1141 1142 { NULL } 1143 }; 1144 1145 static elfedit_module_t module = { 1146 ELFEDIT_VER_CURRENT, MSG_ORIG(MSG_MOD_NAME), 1147 /* MSG_INTL(MSG_MOD_DESC) */ 1148 ELFEDIT_I18NHDL(MSG_MOD_DESC), 1149 cmds, mod_i18nhdl_to_str }; 1150 1151 return (&module); 1152 } 1153