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 <stdlib.h> 29 #include <stdio.h> 30 #include <unistd.h> 31 #include <libintl.h> 32 #include <_machelf.h> 33 #include <libelf.h> 34 #include <link.h> 35 #include <strings.h> 36 #include <ctype.h> 37 #include "msg.h" 38 #include <elfedit.h> 39 #include <conv.h> 40 #include <sys/elf_SPARC.h> 41 #include <sys/elf_amd64.h> 42 43 44 45 /* 46 * ELFCLASS specific code that would otherwise be found in util.c 47 */ 48 49 50 51 52 /* 53 * When you modify ELF constructs, you need to tell libelf that you've 54 * done so. Otherwise, the changes may not be flushed back to the 55 * output file. 56 * 57 * The elfedit_modified_*() functions exist to simplify the calls to 58 * the underlying elf_flag*() functions. 59 */ 60 void 61 elfedit_modified_ehdr(elfedit_obj_state_t *obj_state) 62 { 63 (void) elf_flagehdr(obj_state->os_elf, ELF_C_SET, ELF_F_DIRTY); 64 } 65 66 void 67 elfedit_modified_phdr(elfedit_obj_state_t *obj_state) 68 { 69 (void) elf_flagphdr(obj_state->os_elf, ELF_C_SET, ELF_F_DIRTY); 70 } 71 72 void 73 elfedit_modified_shdr(elfedit_section_t *s) 74 { 75 (void) elf_flagshdr(s->sec_scn, ELF_C_SET, ELF_F_DIRTY); 76 } 77 78 void 79 elfedit_modified_data(elfedit_section_t *s) 80 { 81 (void) elf_flagdata(s->sec_data, ELF_C_SET, ELF_F_DIRTY); 82 } 83 84 85 86 /* 87 * Prepare an elfedit_dyn_elt_t structure for use. 88 */ 89 void 90 elfedit_dyn_elt_init(elfedit_dyn_elt_t *elt) 91 { 92 elt->dn_seen = 0; 93 } 94 95 /* 96 * Given a dynamic section item, save it in the given elfedit_dyn_elt_t 97 * structure and mark that structure to show that it is present. 98 */ 99 void 100 elfedit_dyn_elt_save(elfedit_dyn_elt_t *elt, Word ndx, Dyn *dyn) 101 { 102 elt->dn_seen = 1; 103 elt->dn_ndx = ndx; 104 elt->dn_dyn = *dyn; 105 } 106 107 108 /* 109 * Return the index of the first section that has the given name. 110 * 111 * entry: 112 * obj_state - Object state. 113 * shnam - Name of desired section 114 * 115 * exit: 116 * On success, returns the section index. On failure, an error 117 * is issued, and this routine does not return to the caller. 118 */ 119 Word 120 elfedit_name_to_shndx(elfedit_obj_state_t *obj_state, const char *shnam) 121 { 122 elfedit_section_t *sec = obj_state->os_secarr; 123 Word ndx; 124 Word shnum = obj_state->os_shnum; 125 126 for (ndx = 0; ndx < shnum; ndx++, sec++) { 127 if (strcmp(shnam, sec->sec_name) == 0) { 128 elfedit_msg(ELFEDIT_MSG_DEBUG, 129 MSG_INTL(MSG_DEBUG_SHNAM2NDX), 130 EC_WORD(sec->sec_shndx), sec->sec_name, shnam); 131 return (ndx); 132 } 133 } 134 135 /* If didn't return in loop above, the name doesn't match */ 136 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSECNAM), shnam); 137 /*NOTREACHED*/ 138 return (SHN_UNDEF); 139 } 140 141 142 143 /* 144 * Return the index of the first section that has the given type. 145 * 146 * entry: 147 * obj_state - Object state. 148 * shtype - Type of desired section 149 * 150 * exit: 151 * On success, returns the section index. On failure, an error 152 * is issued, and this routine does not return to the caller. 153 */ 154 Word 155 elfedit_type_to_shndx(elfedit_obj_state_t *obj_state, Word shtype) 156 { 157 Conv_inv_buf_t inv_buf; 158 elfedit_section_t *sec = obj_state->os_secarr; 159 Word ndx; 160 Word shnum = obj_state->os_shnum; 161 162 for (ndx = 0; ndx < shnum; ndx++, sec++) { 163 if (shtype == sec->sec_shdr->sh_type) { 164 elfedit_msg(ELFEDIT_MSG_DEBUG, 165 MSG_INTL(MSG_DEBUG_SHNAM2NDX), 166 EC_WORD(sec->sec_shndx), sec->sec_name, 167 conv_sec_type(obj_state->os_ehdr->e_machine, 168 shtype, 0, &inv_buf)); 169 return (ndx); 170 } 171 } 172 173 /* If didn't return in loop above, the name doesn't match */ 174 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSECTYP), 175 conv_sec_type(obj_state->os_ehdr->e_machine, shtype, 0, &inv_buf)); 176 /*NOTREACHED*/ 177 return (SHN_UNDEF); 178 } 179 180 181 182 /* 183 * Locate the index of the first symbol that has the given name 184 * 185 * entry: 186 * obj_state - Object state. 187 * symsec - Symbol section 188 * strsec = String section 189 * name - String giving name of symbol to lookup 190 * msg_type - ELFEDIT_MSG_ type code to use with message 191 * issued if name does not exist in symbol table. 192 * ret_symndx - Address of variable to receive index. 193 * 194 * exit: 195 * On success, issues debug message, sets *ret_symndx, and returns 196 * True (1). 197 * 198 * On failure, issues a message using msg_type to determine 199 * the type of message sent. If the message does not take control away 200 * from the caller, False (0) is returned. 201 * 202 * note: 203 * Although the string table is referenced by the sh_link field of 204 * the symbol table, we require the user to supply it rather than 205 * look it up. The reason for this is that the caller will usually 206 * have looked it up, and we wish to avoid multiple debug messages 207 * from being issued to that effect. 208 */ 209 int 210 elfedit_name_to_symndx(elfedit_section_t *symsec, elfedit_section_t *strsec, 211 const char *name, elfedit_msg_t msg_type, Word *ret_symndx) 212 213 { 214 Sym *sym = (Sym *) symsec->sec_data->d_buf; 215 Word cnt = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize; 216 Word ndx, offset; 217 const char *curname; 218 219 for (ndx = 0; ndx < cnt; ndx++) { 220 offset = sym[ndx].st_name; 221 222 curname = elfedit_offset_to_str(strsec, offset, 223 ELFEDIT_MSG_ERR, 0); 224 if (strcmp(curname, name) == 0) { 225 elfedit_msg(ELFEDIT_MSG_DEBUG, 226 MSG_INTL(MSG_DEBUG_SYMNAM2NDX), 227 EC_WORD(symsec->sec_shndx), 228 symsec->sec_name, EC_WORD(ndx), name); 229 *ret_symndx = ndx; 230 return (1); 231 } 232 } 233 234 /* If didn't return in loop above, the name doesn't match */ 235 elfedit_msg(msg_type, MSG_INTL(MSG_ERR_NOSYM), 236 EC_WORD(symsec->sec_shndx), symsec->sec_name, name); 237 /*NOTREACHED*/ 238 return (0); /* lint */ 239 } 240 241 242 /* 243 * Given a section index, turn it into a descriptive string. 244 * - If it is one of the special reserved indexes, the 245 * symbolic name is returned. 246 * - If it is a regular section, in range for the file, 247 * the name associated with the section is returned. 248 * - Otherwise, the number is formatted as numeric ASCII. 249 * 250 * exit: 251 * A pointer to the static buffer containing the name is 252 * returned. This pointer is valid until the next call 253 * to elfedit_shndx_to_name(), and which point it may 254 * be overwritten. 255 */ 256 const char * 257 elfedit_shndx_to_name(elfedit_obj_state_t *obj_state, Word shndx) 258 { 259 /* 260 * This routine can be called twice within a single C statement, 261 * so we use alternating buffers on each call to allow this 262 * without requiring the caller to supply a buffer (the size of 263 * which they don't know). 264 */ 265 static char buf1[64], buf2[64]; 266 static char *buf; 267 268 if ((obj_state->os_ehdr->e_machine == EM_AMD64) && 269 (shndx == SHN_AMD64_LCOMMON)) 270 return (MSG_ORIG(MSG_SHN_AMD64_LCOMMON)); 271 272 switch (shndx) { 273 case SHN_UNDEF: 274 return (MSG_ORIG(MSG_SHN_UNDEF)); 275 case SHN_SUNW_IGNORE: 276 return (MSG_ORIG(MSG_SHN_SUNW_IGNORE)); 277 case SHN_BEFORE: 278 return (MSG_ORIG(MSG_SHN_BEFORE)); 279 case SHN_AFTER: 280 return (MSG_ORIG(MSG_SHN_AFTER)); 281 case SHN_AMD64_LCOMMON: 282 if (obj_state->os_ehdr->e_machine == EM_AMD64) 283 return (MSG_ORIG(MSG_SHN_AMD64_LCOMMON)); 284 break; 285 case SHN_ABS: 286 return (MSG_ORIG(MSG_SHN_ABS)); 287 case SHN_COMMON: 288 return (MSG_ORIG(MSG_SHN_COMMON)); 289 case SHN_XINDEX: 290 return (MSG_ORIG(MSG_SHN_XINDEX)); 291 } 292 293 294 /* 295 * If it is outside of the reserved area, and inside the 296 * range of section indexes in the ELF file, then show 297 * the section name. 298 */ 299 if ((shndx < obj_state->os_shnum) && 300 ((shndx < SHN_LORESERVE) || (shndx > SHN_HIRESERVE))) 301 return (obj_state->os_secarr[shndx].sec_name); 302 303 /* Switch buffers */ 304 buf = (buf == buf1) ? buf2 : buf1; 305 306 /* 307 * If we haven't identified it by now, format the 308 * number in a static buffer and return that. 309 */ 310 (void) snprintf(buf, sizeof (buf1), 311 MSG_ORIG(MSG_FMT_WORDVAL), shndx); 312 return (buf); 313 } 314 315 316 /* 317 * Locate the arbitrary section specified by shndx for this object. 318 * 319 * exit: 320 * Returns section descriptor on success. On failure, does not return. 321 */ 322 elfedit_section_t * 323 elfedit_sec_get(elfedit_obj_state_t *obj_state, Word shndx) 324 { 325 elfedit_section_t *sec; 326 327 if ((shndx == 0) || (shndx >= obj_state->os_shnum)) 328 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADSECNDX), 329 EC_WORD(shndx), EC_WORD(obj_state->os_shnum - 1)); 330 331 sec = &obj_state->os_secarr[shndx]; 332 333 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSEC), 334 EC_WORD(shndx), sec->sec_name); 335 return (sec); 336 } 337 338 339 /* 340 * Locate the capabilities section for this object 341 * 342 * entry: 343 * obj_state - Object state for open object to query. 344 * cap - Address of variable to recieve pointer to capabilities 345 * section data buffer. 346 * num - Address of variable to receive number of items 347 * referenced by cap. 348 * 349 * exit: 350 * On success, returns section descriptor, and sets the 351 * variables referenced by cap and num. On failure, 352 * does not return. 353 */ 354 elfedit_section_t * 355 elfedit_sec_getcap(elfedit_obj_state_t *obj_state, Cap **cap, Word *num) 356 { 357 Word cnt; 358 elfedit_section_t *cache; 359 360 for (cnt = 1; cnt < obj_state->os_shnum; cnt++) { 361 cache = &obj_state->os_secarr[cnt]; 362 if (cache->sec_shdr->sh_type == SHT_SUNW_cap) { 363 elfedit_msg(ELFEDIT_MSG_DEBUG, 364 MSG_INTL(MSG_DEBUG_FNDCAP), 365 EC_WORD(cnt), cache->sec_name); 366 *cap = (Cap *) cache->sec_data->d_buf; 367 *num = cache->sec_shdr->sh_size / 368 cache->sec_shdr->sh_entsize; 369 return (cache); 370 } 371 } 372 373 /* If here, this object has no capabilities section */ 374 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOCAP)); 375 376 /*NOTREACHED*/ 377 return (NULL); 378 } 379 380 381 /* 382 * Locate the dynamic section for this object 383 * 384 * entry: 385 * obj_state - Object state for open object to query. 386 * dyn - Address of variable to recieve pointer to dynamic 387 * section data buffer. 388 * numdyn - Address of variable to receive number of items 389 * referenced by dyn. 390 * 391 * exit: 392 * On success, returns section descriptor, and sets the 393 * variables referenced by dyn and numdyn. On failure, 394 * does not return. 395 */ 396 elfedit_section_t * 397 elfedit_sec_getdyn(elfedit_obj_state_t *obj_state, Dyn **dyn, Word *num) 398 { 399 elfedit_section_t *cache; 400 401 if (obj_state->os_dynndx != SHN_UNDEF) { 402 cache = &obj_state->os_secarr[obj_state->os_dynndx]; 403 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDDYN), 404 EC_WORD(cache->sec_shndx), cache->sec_name); 405 *dyn = (Dyn *) cache->sec_data->d_buf; 406 *num = cache->sec_shdr->sh_size / cache->sec_shdr->sh_entsize; 407 return (cache); 408 } 409 410 /* If here, this object has no dynamic section */ 411 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NODYN)); 412 413 /*NOTREACHED*/ 414 return (NULL); 415 } 416 417 418 /* 419 * Locate the syminfo section for this object 420 * 421 * entry: 422 * obj_state - Object state for open object to query. 423 * syminfo - Address of variable to recieve pointer to syminfo 424 * section data buffer. 425 * num - Address of variable to receive number of items 426 * referenced by syminfo. 427 * 428 * exit: 429 * On success, returns section descriptor, and sets the 430 * variables referenced by syminfo and num. On failure, 431 * does not return. 432 */ 433 elfedit_section_t * 434 elfedit_sec_getsyminfo(elfedit_obj_state_t *obj_state, Syminfo **syminfo, 435 Word *num) 436 { 437 Word cnt; 438 elfedit_section_t *cache; 439 440 for (cnt = 1; cnt < obj_state->os_shnum; cnt++) { 441 cache = &obj_state->os_secarr[cnt]; 442 if (cache->sec_shdr->sh_type == SHT_SUNW_syminfo) { 443 elfedit_msg(ELFEDIT_MSG_DEBUG, 444 MSG_INTL(MSG_DEBUG_FNDSYMINFO), 445 EC_WORD(cnt), cache->sec_name); 446 *syminfo = (Syminfo *) cache->sec_data->d_buf; 447 *num = cache->sec_shdr->sh_size / 448 cache->sec_shdr->sh_entsize; 449 return (cache); 450 } 451 } 452 453 /* If here, this object has no syminfo section */ 454 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMINFO)); 455 456 /*NOTREACHED*/ 457 return (NULL); 458 } 459 460 461 /* 462 * Check the given section to see if it is a known symbol table type. 463 * 464 * entry: 465 * sec - Section to check 466 * issue_err - True if this routine should issue an error and 467 * not return to the caller if sec is not a symbol table. 468 * atoui_list - NULL, or address of variable to receive a pointer to 469 * an array of elfedit_atoui_sym_t items describing the 470 * type of symbol table found. This array is useful for 471 * doing command completion. 472 * 473 * exit: 474 * If sec is a symbol table: 475 * - If atoui_list is non-NULL, *atoui_list is set to the 476 * appropriate ELFEDIT_CONST_xx list of items. 477 * - True (1) is returned 478 * If sec is not a symbol table and issue_err is True: 479 * - An error is issued, and this routine does not 480 * return to the caller. 481 * Otherwise: 482 * - If atoui_list is non-NULL, *atoui_list is set to NULL. 483 * - False (0) is returned 484 */ 485 int 486 elfedit_sec_issymtab(elfedit_section_t *sec, int issue_err, 487 elfedit_atoui_sym_t **atoui_list) 488 { 489 elfedit_const_t const_type; 490 int ret = 1; 491 492 /* Is the section a symbol table? */ 493 switch (sec->sec_shdr->sh_type) { 494 case SHT_SYMTAB: 495 const_type = ELFEDIT_CONST_SHT_SYMTAB; 496 break; 497 case SHT_DYNSYM: 498 const_type = ELFEDIT_CONST_SHT_DYNSYM; 499 break; 500 case SHT_SUNW_LDYNSYM: 501 const_type = ELFEDIT_CONST_SHT_LDYNSYM; 502 break; 503 default: 504 if (issue_err) 505 elfedit_msg(ELFEDIT_MSG_ERR, 506 MSG_INTL(MSG_ERR_NOTSYMTAB), 507 EC_WORD(sec->sec_shndx), sec->sec_name); 508 ret = 0; 509 break; 510 } 511 512 if (atoui_list != NULL) 513 *atoui_list = (ret == 0) ? NULL : 514 elfedit_const_to_atoui(const_type); 515 516 return (ret); 517 } 518 519 520 521 /* 522 * Locate a symbol table section for this object 523 * 524 * entry: 525 * obj_state - Object state for open object to query. 526 * by_index - If True, we want to locate the section with the 527 * section index given by index. If False, we return 528 * the section with the name given by name. 529 * index, name - Key to search for. See by_index. 530 * sym - Address of variable to recieve pointer to symbol 531 * section data buffer. 532 * numsym - Address of variable to receive number of symbols 533 * referenced by sym. 534 * aux_info - Address of variable to receive pointer to the 535 * elfedit_symtab_t struct that ties the symbol table and 536 * its related auxiliary sections together. NULL if this 537 * information is not required. 538 * 539 * exit: 540 * On success, returns section descriptor, and sets the 541 * variables referenced by sym, and numsym. On failure, 542 * does not return. 543 */ 544 elfedit_section_t * 545 elfedit_sec_getsymtab(elfedit_obj_state_t *obj_state, int by_index, 546 Word index, const char *name, Sym **sym, Word *num, 547 elfedit_symtab_t **aux_info) 548 { 549 Word ndx; 550 elfedit_section_t *symsec = NULL; 551 elfedit_symtab_t *symtab; 552 const char *type_name; 553 554 /* If looking it up by index, make sure the index is in range */ 555 if (by_index && (index >= obj_state->os_shnum)) 556 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_BADSECNDX), 557 EC_WORD(index), EC_WORD(obj_state->os_shnum - 1)); 558 559 /* 560 * Look at each known symbol table in turn until the desired 561 * one is hit, or there are no more. 562 */ 563 symtab = obj_state->os_symtab; 564 for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) { 565 elfedit_section_t *s = 566 &obj_state->os_secarr[symtab->symt_shndx]; 567 568 if ((by_index && (symtab->symt_shndx == index)) || 569 (!by_index && (strcmp(s->sec_name, name) == 0))) { 570 symsec = s; 571 break; 572 } 573 } 574 575 /* Did we get a section? */ 576 if (symsec == NULL) 577 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSYMTAB)); 578 579 /* Got it. Report to the user and return the necessary data */ 580 (void) elfedit_sec_issymtab(symsec, 1, NULL); 581 type_name = elfedit_atoconst_value_to_str(ELFEDIT_CONST_SHT_ALLSYMTAB, 582 symsec->sec_shdr->sh_type, 1); 583 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSYMTAB), 584 EC_WORD(symsec->sec_shndx), symsec->sec_name, type_name); 585 *sym = (Sym *) symsec->sec_data->d_buf; 586 *num = symsec->sec_shdr->sh_size / symsec->sec_shdr->sh_entsize; 587 if (aux_info != NULL) 588 *aux_info = symtab; 589 return (symsec); 590 } 591 592 593 594 /* 595 * Locate the extended symbol index section associated with a symbol 596 * table section. 597 * 598 * entry: 599 * obj_state - Object state for open object to query. 600 * symsec - Symbol table section for which extended index 601 * index section is required. 602 * xshndx - Address of variable to recieve pointer to section index 603 * array data buffer. 604 * numxshndx - Address of variable to receive number of indices 605 * referenced by ndx. 606 * 607 * exit: 608 * On success, returns extended index section descriptor, and sets the 609 * variables referenced by xshndx, and numxshndx. On failure, 610 * does not return. 611 * 612 * note: 613 * Since the extended section index is found in the sec_xshndx field 614 * of the elfedit_section_t, the caller may be tempted to bypass this 615 * routine and access it directly. That temptation should be resisted, 616 * as this routine performs useful error checking, and also handles 617 * the issuing of the standard MSG_DEBUG messages. 618 */ 619 elfedit_section_t * 620 elfedit_sec_getxshndx(elfedit_obj_state_t *obj_state, 621 elfedit_section_t *symsec, Word **xshndx, Word *num) 622 { 623 elfedit_section_t *xshndxsec; 624 elfedit_symtab_t *symtab; 625 Word ndx; 626 627 /* Sanity check: symsec must be a symbol table */ 628 (void) elfedit_sec_issymtab(symsec, 1, NULL); 629 630 symtab = obj_state->os_symtab; 631 for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) 632 if (symsec->sec_shndx == symtab->symt_shndx) 633 break; 634 635 /* 636 * Issue error if the symbol table lacks an extended index section. 637 * The caller won't ask unless they encounter an SHN_XINDEX value, 638 * in which case the lack of the index section denotes a corrupt 639 * ELF file. 640 */ 641 if ((ndx == obj_state->os_symtabnum) || 642 (symtab->symt_xshndx == SHN_UNDEF)) 643 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOXSHSEC), 644 EC_WORD(symsec->sec_shndx), symsec->sec_name); 645 646 /* Got it. Report to the user and return the necessary data */ 647 xshndxsec = &obj_state->os_secarr[symtab->symt_xshndx]; 648 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDXSHNDX), 649 EC_WORD(symsec->sec_shndx), symsec->sec_name, 650 EC_WORD(xshndxsec->sec_shndx), xshndxsec->sec_name); 651 *xshndx = (Word *) xshndxsec->sec_data->d_buf; 652 *num = xshndxsec->sec_shdr->sh_size / xshndxsec->sec_shdr->sh_entsize; 653 return (xshndxsec); 654 } 655 656 657 658 /* 659 * Locate the versym section associated with a symbol table section. 660 * 661 * entry: 662 * obj_state - Object state for open object to query. 663 * symsec - Symbol table section for which extended index 664 * index section is required. 665 * versym - Address of variable to recieve pointer to section index 666 * array data buffer. 667 * numversym - Address of variable to receive number of indices 668 * referenced by ndx. 669 * 670 * exit: 671 * On success, returns versym section descriptor, and sets the 672 * variables referenced by versym, and numversym. On failure, 673 * does not return. 674 * 675 * note: 676 * Since the versym section index is found in the sec_versym field 677 * of the elfedit_section_t, the caller may be tempted to bypass this 678 * routine and access it directly. That temptation should be resisted, 679 * as this routine performs useful error checking, and also handles 680 * the issuing of the standard MSG_DEBUG messages. 681 */ 682 elfedit_section_t * 683 elfedit_sec_getversym(elfedit_obj_state_t *obj_state, 684 elfedit_section_t *symsec, Versym **versym, Word *num) 685 { 686 elfedit_section_t *versymsec; 687 elfedit_symtab_t *symtab; 688 Word ndx; 689 690 /* Sanity check: symsec must be a symbol table */ 691 (void) elfedit_sec_issymtab(symsec, 1, NULL); 692 693 symtab = obj_state->os_symtab; 694 for (ndx = 0; ndx < obj_state->os_symtabnum; ndx++, symtab++) 695 if (symsec->sec_shndx == symtab->symt_shndx) 696 break; 697 /* 698 * Issue error if the symbol table lacks a versym section. 699 * The caller won't ask unless they see a non-null 700 * aux.symtab.sec_versym, so this should not be a problem. 701 */ 702 if ((ndx == obj_state->os_symtabnum) || 703 (symtab->symt_versym == SHN_UNDEF)) 704 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOVERSYMSEC), 705 EC_WORD(symsec->sec_shndx), symsec->sec_name); 706 707 /* Got it. Report to the user and return the necessary data */ 708 versymsec = &obj_state->os_secarr[symtab->symt_versym]; 709 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDVERSYM), 710 EC_WORD(symsec->sec_shndx), symsec->sec_name, 711 EC_WORD(versymsec->sec_shndx), versymsec->sec_name); 712 *versym = (Versym *) versymsec->sec_data->d_buf; 713 *num = versymsec->sec_shdr->sh_size / versymsec->sec_shdr->sh_entsize; 714 return (versymsec); 715 } 716 717 718 719 /* 720 * Locate the string table specified by shndx for this object. 721 * 722 * entry: 723 * obj_state - Object state. 724 * shndx - Section index for string table section 725 * allow_shflags - If False (0), only sections of type SHT_STRTAB 726 * are accepted as being string tables, and any other type 727 * will fail. If True (1), non-stringtable sections with 728 * their SHF_STRINGS flag set are also accepted. 729 * 730 * exit: 731 * Returns section descriptor on success. On failure, does not return. 732 * 733 * note: 734 * At this time, we can only support SHF_STRINGS sections that 735 * use single byte characters and which do not require alignment >1. 736 * SHF_STRINGS sections that have multi-byte characters or alignment 737 * are not currently supported and will draw an error even if 738 * allow_shflags is True. 739 */ 740 elfedit_section_t * 741 elfedit_sec_getstr(elfedit_obj_state_t *obj_state, Word shndx, 742 int allow_shflags) 743 { 744 elfedit_section_t *strsec; 745 746 if ((shndx == 0) || (shndx >= obj_state->os_shnum)) 747 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_STRSHNDX), 748 EC_WORD(shndx), EC_WORD(obj_state->os_shnum - 1)); 749 750 strsec = &obj_state->os_secarr[shndx]; 751 if (strsec->sec_shdr->sh_type == SHT_STRTAB) { 752 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTRTAB), 753 EC_WORD(shndx), strsec->sec_name); 754 } else if (allow_shflags && 755 ((strsec->sec_shdr->sh_flags & SHF_STRINGS) != 0) && 756 (strsec->sec_shdr->sh_entsize <= 1) && 757 (strsec->sec_shdr->sh_addralign <= 1)) { 758 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTRTABFL), 759 EC_WORD(shndx), strsec->sec_name); 760 } else { 761 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH), 762 EC_WORD(shndx), strsec->sec_name); 763 } 764 765 return (strsec); 766 } 767 768 769 /* 770 * Returns the offset of the specified string from within 771 * the given section. 772 * 773 * entry: 774 * sec - Descriptor for section 775 * tail_ign - If non-zero, the # of characters at the end of the 776 * section that should be ignored and not searched. 777 * str - String we are looking for. 778 * ret_offset - Address of variable to receive result 779 * 780 * exit: 781 * Returns 1 for success, and 0 for failure. If successful, *ret_offset 782 * is set to the offset of the found string within the section. 783 */ 784 int 785 elfedit_sec_findstr(elfedit_section_t *sec, Word tail_ign, 786 const char *str, Word *ret_offset) 787 { 788 int str_fch = *str; /* First character in str */ 789 Word len; /* # characters in table */ 790 char *s; /* ptr to strings within table */ 791 const char *tail; /* 1 past final character of table */ 792 793 794 /* Size of the section, minus the reserved part (if any) at the end */ 795 len = sec->sec_shdr->sh_size - tail_ign; 796 797 /* 798 * Move through the section character by character looking for 799 * a match. Moving character by character instead of skipping 800 * from NULL terminated string to string allows us to use 801 * the tails longer strings (i.e. we want "bar", and "foobar" exists). 802 * We look at the first character manually before calling strcmp() 803 * to lower the cost of this approach. 804 */ 805 s = (char *)sec->sec_data->d_buf; 806 tail = s + len; 807 for (; s <= tail; s++) { 808 if ((*s == str_fch) && (strcmp(s, str) == 0)) { 809 *ret_offset = s - (char *)sec->sec_data->d_buf; 810 elfedit_msg(ELFEDIT_MSG_DEBUG, 811 MSG_INTL(MSG_DEBUG_EXISTSTR), 812 EC_WORD(sec->sec_shndx), sec->sec_name, 813 EC_WORD(*ret_offset), s); 814 return (1); 815 } 816 } 817 818 /* Didn't find it. Report failure */ 819 return (0); 820 } 821 822 823 /* 824 * Locate the DT_SUNW_STRPAD element of the given dynamic section if 825 * it exists. 826 * 827 * entry: 828 * dynsec - Dynamic section descriptor 829 * dyn_strpad - Address of variable to receive the results. 830 * The caller is responsible for calling elfedit_dyn_elt_init() 831 * on this variable beforehand. 832 * 833 * exit: 834 * The dynamic section is searched, and if a DT_SUNW_STRPAD element 835 * is found, dyn_strpad is updated via elfedit_dyn_elt_save() to 836 * reference it. 837 * 838 * Returns the final value of dyn_strpad->dn_seen. 839 */ 840 int 841 elfedit_dynstr_getpad(elfedit_section_t *dynsec, elfedit_dyn_elt_t *dyn_strpad) 842 { 843 Dyn *dyn = (Dyn *) dynsec->sec_data->d_buf; 844 Word numdyn = dynsec->sec_shdr->sh_size / dynsec->sec_shdr->sh_entsize; 845 Word i; 846 847 /* Go through dynamic section tags and find the STRPAD entry */ 848 for (i = 0; i < numdyn; i++) { 849 if (dyn[i].d_tag == DT_SUNW_STRPAD) { 850 elfedit_dyn_elt_save(dyn_strpad, i, &dyn[i]); 851 break; 852 } 853 } 854 855 return (dyn_strpad->dn_seen); 856 } 857 858 859 860 /* 861 * Given references to the dynamic section, its string table, 862 * and the DT_SUNW_STRPAD entry of the dynamic section, returns 863 * the offset of the specified string from within the given string table, 864 * adding it if possible. 865 * 866 * entry: 867 * dynsec - Dynamic section descriptor 868 * strsec - Descriptor for string table assocated with dynamic section 869 * dyn_strpad - DT_SUNW_STRPAD element from dynamic section 870 * str - String we are looking for. 871 * 872 * exit: 873 * On success, the offset of the given string within the string 874 * table is returned. If the string does not exist within the table, 875 * but there is a valid DT_SUNW_STRPAD reserved section, then we 876 * add the string, and update the dynamic section STRPAD element 877 * to reflect the space we use. 878 * 879 * This routine does not return on failure. 880 */ 881 Word 882 elfedit_dynstr_insert(elfedit_section_t *dynsec, elfedit_section_t *strsec, 883 elfedit_dyn_elt_t *dyn_strpad, const char *str) 884 { 885 Word ins_off; /* Table offset to 1st reserved byte */ 886 char *s; /* ptr to strings within table */ 887 Word len; /* Length of str inc. NULL byte */ 888 Word tail_ign; /* # reserved bytes at end of strtab */ 889 890 891 tail_ign = dyn_strpad->dn_seen ? dyn_strpad->dn_dyn.d_un.d_val : 0; 892 893 /* Does the string already existin the string table? */ 894 if (elfedit_sec_findstr(strsec, tail_ign, str, &len)) 895 return (len); 896 897 /* 898 * The desired string does not already exist. Do we have 899 * room to add it? 900 */ 901 len = strlen(str) + 1; 902 if (!dyn_strpad->dn_seen || (len > dyn_strpad->dn_dyn.d_un.d_val)) 903 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), 904 EC_WORD(strsec->sec_shdr->sh_link), 905 strsec->sec_name); 906 907 908 /* 909 * We will add the string at the first byte of the reserved NULL 910 * area at the end. The DT_SUNW_STRPAD dynamic element gives us 911 * the size of that reserved space. 912 */ 913 ins_off = strsec->sec_shdr->sh_size - tail_ign; 914 s = ((char *)strsec->sec_data->d_buf) + ins_off; 915 916 /* Announce the operation */ 917 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ADDSTR), 918 EC_WORD(strsec->sec_shndx), strsec->sec_name, 919 EC_WORD(ins_off), EC_WORD(len), 920 EC_WORD(dyn_strpad->dn_dyn.d_un.d_val), str); 921 922 /* 923 * Copy the string into the pad area at the end, and 924 * mark the data area as dirty so libelf will flush our 925 * changes to the string data. 926 */ 927 (void) strncpy(s, str, dyn_strpad->dn_dyn.d_un.d_val); 928 elfedit_modified_data(strsec); 929 930 /* Update the DT_STRPAD dynamic entry */ 931 dyn_strpad->dn_dyn.d_un.d_val -= len; 932 ((Dyn *) dynsec->sec_data->d_buf)[dyn_strpad->dn_ndx] = 933 dyn_strpad->dn_dyn; 934 elfedit_modified_data(dynsec); 935 936 return (ins_off); 937 } 938 939 940 /* 941 * Test to see if a call to elfedit_strtab_insert() will succeed. 942 * 943 * entry: 944 * obj_state - Object state for open object to query. 945 * strsec - Descriptor for string table 946 * dynsec - NULL, or descriptor for dynamic section. Providing 947 * a non-NULL value here will prevent elfedit_strtab_insert() 948 * from looking it up, and the duplicate debug message that 949 * would result. 950 * str - String we are looking for. 951 * 952 * exit: 953 * If the string exists within the string table, or if an attempt 954 * to insert it will be successful, quietly return. Otherwise, throw 955 * the error elfedit_strtab_insert() would throw under the 956 * same circumstances. 957 * 958 */ 959 void 960 elfedit_strtab_insert_test(elfedit_obj_state_t *obj_state, 961 elfedit_section_t *strsec, elfedit_section_t *dynsec, const char *str) 962 { 963 Word len; /* Length of str inc. NULL byte */ 964 int is_dynstr = 0; 965 Word tail_ign = 0; 966 967 968 /* 969 * The dynstr is a special case, because we can add strings 970 * to it under certain circumstances. So, we look for the 971 * dynamic section, and if it exists, compare its sh_link to 972 * the string section index. If they match, it is the dynstr, 973 * and we use elfedit_dynstr_insert() to do the work. 974 */ 975 if (dynsec == NULL) { 976 if (obj_state->os_dynndx != SHN_UNDEF) { 977 dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; 978 if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) && 979 (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) { 980 is_dynstr = 1; 981 elfedit_msg(ELFEDIT_MSG_DEBUG, 982 MSG_INTL(MSG_DEBUG_FNDDYN), 983 EC_WORD(dynsec->sec_shndx), 984 dynsec->sec_name); 985 } 986 } 987 } else { 988 if (strsec->sec_shndx == dynsec->sec_shdr->sh_link) 989 is_dynstr = 1; 990 } 991 992 993 if (is_dynstr) { 994 elfedit_dyn_elt_t dyn_strpad; 995 996 /* Determine the size of the STRPAD area, if any */ 997 elfedit_dyn_elt_init(&dyn_strpad); 998 if (elfedit_dynstr_getpad(dynsec, &dyn_strpad) != 0) 999 tail_ign = dyn_strpad.dn_dyn.d_un.d_val; 1000 } 1001 1002 /* 1003 * If the string is already in the string table, we 1004 * can't fail. 1005 */ 1006 if (elfedit_sec_findstr(strsec, tail_ign, str, &len) != 0) 1007 return; 1008 1009 /* 1010 * It's not in the table, but if this is the dynstr, and 1011 * there is enough room, we will be able to add it. 1012 */ 1013 if (is_dynstr && (tail_ign > strlen(str))) 1014 return; 1015 1016 /* Can't do it. Issue error */ 1017 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), 1018 EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name); 1019 } 1020 1021 1022 /* 1023 * Returns the offset of the specified string from within 1024 * the given string table, adding it if possible. 1025 * 1026 * entry: 1027 * obj_state - Object state for open object to query. 1028 * strsec - Descriptor for string table 1029 * dynsec - NULL, or descriptor for dynamic section. Providing 1030 * a non-NULL value here will prevent elfedit_strtab_insert() 1031 * from looking it up, and the duplicate debug message that 1032 * would result. 1033 * str - String we are looking for. 1034 * 1035 * exit: 1036 * On success, the offset of the given string within the string 1037 * table is returned. If the string does not exist within the table, 1038 * and it is possible to add it, elfedit_strtab_insert() will 1039 * add the string, and then return the offset. 1040 * 1041 * If the string does not exist in the string table, and cannot 1042 * be added, this routine issues an error message and does not 1043 * return to the caller. 1044 */ 1045 Word 1046 elfedit_strtab_insert(elfedit_obj_state_t *obj_state, elfedit_section_t *strsec, 1047 elfedit_section_t *dynsec, const char *str) 1048 { 1049 Word len; /* Length of str inc. NULL byte */ 1050 int is_dynstr = 0; 1051 elfedit_dyn_elt_t dyn_strpad; 1052 1053 1054 /* 1055 * The dynstr is a special case, because we can add strings 1056 * to it under certain circumstances. So, we look for the 1057 * dynamic section, and if it exists, compare its sh_link to 1058 * the string section index. If they match, it is the dynstr, 1059 * and we use elfedit_dynstr_insert() to do the work. 1060 */ 1061 if (dynsec == NULL) { 1062 if (obj_state->os_dynndx != SHN_UNDEF) { 1063 dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; 1064 if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) && 1065 (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) { 1066 is_dynstr = 1; 1067 elfedit_msg(ELFEDIT_MSG_DEBUG, 1068 MSG_INTL(MSG_DEBUG_FNDDYN), 1069 EC_WORD(dynsec->sec_shndx), 1070 dynsec->sec_name); 1071 } 1072 } 1073 } else { 1074 if (strsec->sec_shndx == dynsec->sec_shdr->sh_link) 1075 is_dynstr = 1; 1076 } 1077 1078 if (is_dynstr) { 1079 elfedit_dyn_elt_init(&dyn_strpad); 1080 (void) elfedit_dynstr_getpad(dynsec, &dyn_strpad); 1081 return (elfedit_dynstr_insert(dynsec, strsec, 1082 &dyn_strpad, str)); 1083 } 1084 1085 /* 1086 * This is not the dynstr, so we are limited to strings that 1087 * already exist within it. Try to find one. 1088 */ 1089 if (elfedit_sec_findstr(strsec, 0, str, &len)) 1090 return (len); 1091 1092 /* Can't do it. Issue error */ 1093 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), 1094 EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name); 1095 /*NOTREACHED*/ 1096 1097 return (0); 1098 } 1099 1100 1101 /* 1102 * Return the string found at the given offset within the specified 1103 * string table. 1104 * 1105 * entry: 1106 * strsec - Section descriptor for string table section 1107 * offset - Offset of desired string in string table 1108 * msg_type - ELFEDIT_MSG_ type code to use with message 1109 * issued if offset is out of range for the symbol table. 1110 * debug_msg - True if should issue debug message for string found. 1111 * 1112 * exit: 1113 * If the offset is within the section, the string pointer 1114 * is returned. Otherwise an error is issued using msg_type 1115 * to determine the type of message. If this routine retains 1116 * control after the message is issued, a safe string is returned. 1117 */ 1118 const char * 1119 elfedit_offset_to_str(elfedit_section_t *strsec, Word offset, 1120 elfedit_msg_t msg_type, int debug_msg) 1121 { 1122 const char *str; 1123 1124 /* Make sure it is a string table section */ 1125 if (strsec->sec_shdr->sh_type != SHT_STRTAB) 1126 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH), 1127 EC_WORD(strsec->sec_shndx), strsec->sec_name); 1128 1129 /* Ensure the offset is in range */ 1130 if (offset >= strsec->sec_data->d_size) { 1131 elfedit_msg(msg_type, MSG_INTL(MSG_ERR_BADSTROFF), 1132 EC_WORD(strsec->sec_shndx), strsec->sec_name, 1133 EC_WORD(offset), EC_WORD(strsec->sec_data->d_size - 1)); 1134 /* 1135 * If the msg_type is a type that returns, give the 1136 * user a safe string to use. 1137 */ 1138 str = MSG_INTL(MSG_BADSYMOFFSETNAM); 1139 } else { 1140 /* Return the string */ 1141 str = ((const char *)strsec->sec_data->d_buf) + offset; 1142 } 1143 1144 if (debug_msg) 1145 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTR), 1146 EC_WORD(strsec->sec_shndx), strsec->sec_name, 1147 EC_WORD(offset), str); 1148 return (str); 1149 } 1150 1151 1152 /* 1153 * Given a string table section, and a dynamic section entry 1154 * that supplies a string offset, return the string found at 1155 * the given offset. This routine is a convenience wrapper on 1156 * elfedit_offset_to_str(). 1157 * 1158 * exit: 1159 * As per elfedit_offset_to_str(). 1160 */ 1161 const char * 1162 elfedit_dyn_offset_to_str(elfedit_section_t *strsec, elfedit_dyn_elt_t *dynelt) 1163 { 1164 return (elfedit_offset_to_str(strsec, dynelt->dn_dyn.d_un.d_val, 1165 ELFEDIT_MSG_ERR, 0)); 1166 } 1167 1168 1169 /* 1170 * Given a section, fabricate a string for the form: 1171 * 1172 * "[#: name]" 1173 * 1174 * as used at the beginning of debug messages. A pointer to static 1175 * memory is returned, and is good until the next such call. 1176 */ 1177 const char * 1178 elfedit_sec_msgprefix(elfedit_section_t *sec) 1179 { 1180 static char *buf; 1181 static size_t bufsize; 1182 1183 size_t need; 1184 1185 need = 64 + strlen(sec->sec_name); 1186 if (need > bufsize) { 1187 buf = elfedit_realloc(MSG_INTL(MSG_ALLOC_SECMSGPRE), buf, need); 1188 bufsize = need; 1189 } 1190 1191 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_SECMSGPRE), 1192 EC_WORD(sec->sec_shndx), sec->sec_name); 1193 1194 return (buf); 1195 } 1196