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