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