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