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 <machdep.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 * exit: 723 * Returns section descriptor on success. On failure, does not return. 724 */ 725 elfedit_section_t * 726 elfedit_sec_getstr(elfedit_obj_state_t *obj_state, Word shndx) 727 { 728 elfedit_section_t *strsec; 729 730 if ((shndx == 0) || (shndx >= obj_state->os_shnum)) 731 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_STRSHNDX), 732 EC_WORD(shndx), EC_WORD(obj_state->os_shnum - 1)); 733 734 strsec = &obj_state->os_secarr[shndx]; 735 if (strsec->sec_shdr->sh_type != SHT_STRTAB) 736 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH), 737 EC_WORD(shndx), strsec->sec_name); 738 739 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTRTAB), 740 EC_WORD(shndx), strsec->sec_name); 741 return (strsec); 742 } 743 744 745 /* 746 * Returns the offset of the specified string from within 747 * the given section. 748 * 749 * entry: 750 * sec - Descriptor for section 751 * tail_ign - If non-zero, the # of characters at the end of the 752 * section that should be ignored and not searched. 753 * str - String we are looking for. 754 * ret_offset - Address of variable to receive result 755 * 756 * exit: 757 * Returns 1 for success, and 0 for failure. If successful, *ret_offset 758 * is set to the offset of the found string within the section. 759 */ 760 int 761 elfedit_sec_findstr(elfedit_section_t *sec, Word tail_ign, 762 const char *str, Word *ret_offset) 763 { 764 int str_fch = *str; /* First character in str */ 765 Word len; /* # characters in table */ 766 char *s; /* ptr to strings within table */ 767 const char *tail; /* 1 past final character of table */ 768 769 770 /* Size of the section, minus the reserved part (if any) at the end */ 771 len = sec->sec_shdr->sh_size - tail_ign; 772 773 /* 774 * Move through the section character by character looking for 775 * a match. Moving character by character instead of skipping 776 * from NULL terminated string to string allows us to use 777 * the tails longer strings (i.e. we want "bar", and "foobar" exists). 778 * We look at the first character manually before calling strcmp() 779 * to lower the cost of this approach. 780 */ 781 s = (char *)sec->sec_data->d_buf; 782 tail = s + len; 783 for (; s <= tail; s++) { 784 if ((*s == str_fch) && (strcmp(s, str) == 0)) { 785 *ret_offset = s - (char *)sec->sec_data->d_buf; 786 elfedit_msg(ELFEDIT_MSG_DEBUG, 787 MSG_INTL(MSG_DEBUG_EXISTSTR), 788 EC_WORD(sec->sec_shndx), sec->sec_name, 789 EC_WORD(*ret_offset), s); 790 return (1); 791 } 792 } 793 794 /* Didn't find it. Report failure */ 795 return (0); 796 } 797 798 799 /* 800 * Locate the DT_SUNW_STRPAD element of the given dynamic section if 801 * it exists. 802 * 803 * entry: 804 * dynsec - Dynamic section descriptor 805 * dyn_strpad - Address of variable to receive the results. 806 * The caller is responsible for calling elfedit_dyn_elt_init() 807 * on this variable beforehand. 808 * 809 * exit: 810 * The dynamic section is searched, and if a DT_SUNW_STRPAD element 811 * is found, dyn_strpad is updated via elfedit_dyn_elt_save() to 812 * reference it. 813 * 814 * Returns the final value of dyn_strpad->dn_seen. 815 */ 816 int 817 elfedit_dynstr_getpad(elfedit_section_t *dynsec, elfedit_dyn_elt_t *dyn_strpad) 818 { 819 Dyn *dyn = (Dyn *) dynsec->sec_data->d_buf; 820 Word numdyn = dynsec->sec_shdr->sh_size / dynsec->sec_shdr->sh_entsize; 821 Word i; 822 823 /* Go through dynamic section tags and find the STRPAD entry */ 824 for (i = 0; i < numdyn; i++) { 825 if (dyn[i].d_tag == DT_SUNW_STRPAD) { 826 elfedit_dyn_elt_save(dyn_strpad, i, &dyn[i]); 827 break; 828 } 829 } 830 831 return (dyn_strpad->dn_seen); 832 } 833 834 835 836 /* 837 * Given references to the dynamic section, its string table, 838 * and the DT_SUNW_STRPAD entry of the dynamic section, returns 839 * the offset of the specified string from within the given string table, 840 * adding it if possible. 841 * 842 * entry: 843 * dynsec - Dynamic section descriptor 844 * strsec - Descriptor for string table assocated with dynamic section 845 * dyn_strpad - DT_SUNW_STRPAD element from dynamic section 846 * str - String we are looking for. 847 * 848 * exit: 849 * On success, the offset of the given string within the string 850 * table is returned. If the string does not exist within the table, 851 * but there is a valid DT_SUNW_STRPAD reserved section, then we 852 * add the string, and update the dynamic section STRPAD element 853 * to reflect the space we use. 854 * 855 * This routine does not return on failure. 856 */ 857 Word 858 elfedit_dynstr_insert(elfedit_section_t *dynsec, elfedit_section_t *strsec, 859 elfedit_dyn_elt_t *dyn_strpad, const char *str) 860 { 861 Word ins_off; /* Table offset to 1st reserved byte */ 862 char *s; /* ptr to strings within table */ 863 Word len; /* Length of str inc. NULL byte */ 864 Word tail_ign; /* # reserved bytes at end of strtab */ 865 866 867 tail_ign = dyn_strpad->dn_seen ? dyn_strpad->dn_dyn.d_un.d_val : 0; 868 869 /* Does the string already existin the string table? */ 870 if (elfedit_sec_findstr(strsec, tail_ign, str, &len)) 871 return (len); 872 873 /* 874 * The desired string does not already exist. Do we have 875 * room to add it? 876 */ 877 len = strlen(str) + 1; 878 if (!dyn_strpad->dn_seen || (len > dyn_strpad->dn_dyn.d_un.d_val)) 879 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), 880 EC_WORD(strsec->sec_shdr->sh_link), 881 strsec->sec_name); 882 883 884 /* 885 * We will add the string at the first byte of the reserved NULL 886 * area at the end. The DT_SUNW_STRPAD dynamic element gives us 887 * the size of that reserved space. 888 */ 889 ins_off = strsec->sec_shdr->sh_size - tail_ign; 890 s = ((char *)strsec->sec_data->d_buf) + ins_off; 891 892 /* Announce the operation */ 893 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_ADDSTR), 894 EC_WORD(strsec->sec_shndx), strsec->sec_name, 895 EC_WORD(ins_off), EC_WORD(len), 896 EC_WORD(dyn_strpad->dn_dyn.d_un.d_val), str); 897 898 /* 899 * Copy the string into the pad area at the end, and 900 * mark the data area as dirty so libelf will flush our 901 * changes to the string data. 902 */ 903 (void) strncpy(s, str, dyn_strpad->dn_dyn.d_un.d_val); 904 elfedit_modified_data(strsec); 905 906 /* Update the DT_STRPAD dynamic entry */ 907 dyn_strpad->dn_dyn.d_un.d_val -= len; 908 ((Dyn *) dynsec->sec_data->d_buf)[dyn_strpad->dn_ndx] = 909 dyn_strpad->dn_dyn; 910 elfedit_modified_data(dynsec); 911 912 return (ins_off); 913 } 914 915 916 /* 917 * Test to see if a call to elfedit_strtab_insert() will succeed. 918 * 919 * entry: 920 * obj_state - Object state for open object to query. 921 * strsec - Descriptor for string table 922 * dynsec - NULL, or descriptor for dynamic section. Providing 923 * a non-NULL value here will prevent elfedit_strtab_insert() 924 * from looking it up, and the duplicate debug message that 925 * would result. 926 * str - String we are looking for. 927 * 928 * exit: 929 * If the string exists within the string table, or if an attempt 930 * to insert it will be successful, quietly return. Otherwise, throw 931 * the error elfedit_strtab_insert() would throw under the 932 * same circumstances. 933 * 934 */ 935 void 936 elfedit_strtab_insert_test(elfedit_obj_state_t *obj_state, 937 elfedit_section_t *strsec, elfedit_section_t *dynsec, const char *str) 938 { 939 Word len; /* Length of str inc. NULL byte */ 940 int is_dynstr = 0; 941 Word tail_ign = 0; 942 943 944 /* 945 * The dynstr is a special case, because we can add strings 946 * to it under certain circumstances. So, we look for the 947 * dynamic section, and if it exists, compare its sh_link to 948 * the string section index. If they match, it is the dynstr, 949 * and we use elfedit_dynstr_insert() to do the work. 950 */ 951 if (dynsec == NULL) { 952 if (obj_state->os_dynndx != SHN_UNDEF) { 953 dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; 954 if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) && 955 (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) { 956 is_dynstr = 1; 957 elfedit_msg(ELFEDIT_MSG_DEBUG, 958 MSG_INTL(MSG_DEBUG_FNDDYN), 959 EC_WORD(dynsec->sec_shndx), 960 dynsec->sec_name); 961 } 962 } 963 } else { 964 if (strsec->sec_shndx == dynsec->sec_shdr->sh_link) 965 is_dynstr = 1; 966 } 967 968 969 if (is_dynstr) { 970 elfedit_dyn_elt_t dyn_strpad; 971 972 /* Determine the size of the STRPAD area, if any */ 973 elfedit_dyn_elt_init(&dyn_strpad); 974 if (elfedit_dynstr_getpad(dynsec, &dyn_strpad) != 0) 975 tail_ign = dyn_strpad.dn_dyn.d_un.d_val; 976 } 977 978 /* 979 * If the string is already in the string table, we 980 * can't fail. 981 */ 982 if (elfedit_sec_findstr(strsec, tail_ign, str, &len) != 0) 983 return; 984 985 /* 986 * It's not in the table, but if this is the dynstr, and 987 * there is enough room, we will be able to add it. 988 */ 989 if (is_dynstr && (tail_ign > strlen(str))) 990 return; 991 992 /* Can't do it. Issue error */ 993 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), 994 EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name); 995 } 996 997 998 /* 999 * Returns the offset of the specified string from within 1000 * the given string table, adding it if possible. 1001 * 1002 * entry: 1003 * obj_state - Object state for open object to query. 1004 * strsec - Descriptor for string table 1005 * dynsec - NULL, or descriptor for dynamic section. Providing 1006 * a non-NULL value here will prevent elfedit_strtab_insert() 1007 * from looking it up, and the duplicate debug message that 1008 * would result. 1009 * str - String we are looking for. 1010 * 1011 * exit: 1012 * On success, the offset of the given string within the string 1013 * table is returned. If the string does not exist within the table, 1014 * and it is possible to add it, elfedit_strtab_insert() will 1015 * add the string, and then return the offset. 1016 * 1017 * If the string does not exist in the string table, and cannot 1018 * be added, this routine issues an error message and does not 1019 * return to the caller. 1020 */ 1021 Word 1022 elfedit_strtab_insert(elfedit_obj_state_t *obj_state, elfedit_section_t *strsec, 1023 elfedit_section_t *dynsec, const char *str) 1024 { 1025 Word len; /* Length of str inc. NULL byte */ 1026 int is_dynstr = 0; 1027 elfedit_dyn_elt_t dyn_strpad; 1028 1029 1030 /* 1031 * The dynstr is a special case, because we can add strings 1032 * to it under certain circumstances. So, we look for the 1033 * dynamic section, and if it exists, compare its sh_link to 1034 * the string section index. If they match, it is the dynstr, 1035 * and we use elfedit_dynstr_insert() to do the work. 1036 */ 1037 if (dynsec == NULL) { 1038 if (obj_state->os_dynndx != SHN_UNDEF) { 1039 dynsec = &obj_state->os_secarr[obj_state->os_dynndx]; 1040 if ((dynsec->sec_shdr->sh_type == SHT_DYNAMIC) && 1041 (strsec->sec_shndx == dynsec->sec_shdr->sh_link)) { 1042 is_dynstr = 1; 1043 elfedit_msg(ELFEDIT_MSG_DEBUG, 1044 MSG_INTL(MSG_DEBUG_FNDDYN), 1045 EC_WORD(dynsec->sec_shndx), 1046 dynsec->sec_name); 1047 } 1048 } 1049 } else { 1050 if (strsec->sec_shndx == dynsec->sec_shdr->sh_link) 1051 is_dynstr = 1; 1052 } 1053 1054 if (is_dynstr) { 1055 elfedit_dyn_elt_init(&dyn_strpad); 1056 (void) elfedit_dynstr_getpad(dynsec, &dyn_strpad); 1057 return (elfedit_dynstr_insert(dynsec, strsec, 1058 &dyn_strpad, str)); 1059 } 1060 1061 /* 1062 * This is not the dynstr, so we are limited to strings that 1063 * already exist within it. Try to find one. 1064 */ 1065 if (elfedit_sec_findstr(strsec, 0, str, &len)) 1066 return (len); 1067 1068 /* Can't do it. Issue error */ 1069 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOSTRPAD), 1070 EC_WORD(strsec->sec_shdr->sh_link), strsec->sec_name); 1071 /*NOTREACHED*/ 1072 1073 return (0); 1074 } 1075 1076 1077 /* 1078 * Return the string found at the given offset within the specified 1079 * string table. 1080 * 1081 * entry: 1082 * strsec - Section descriptor for string table section 1083 * offset - Offset of desired string in string table 1084 * msg_type - ELFEDIT_MSG_ type code to use with message 1085 * issued if offset is out of range for the symbol table. 1086 * debug_msg - True if should issue debug message for string found. 1087 * 1088 * exit: 1089 * If the offset is within the section, the string pointer 1090 * is returned. Otherwise an error is issued using msg_type 1091 * to determine the type of message. If this routine retains 1092 * control after the message is issued, a safe string is returned. 1093 */ 1094 const char * 1095 elfedit_offset_to_str(elfedit_section_t *strsec, Word offset, 1096 elfedit_msg_t msg_type, int debug_msg) 1097 { 1098 const char *str; 1099 1100 /* Make sure it is a string table section */ 1101 if (strsec->sec_shdr->sh_type != SHT_STRTAB) 1102 elfedit_msg(ELFEDIT_MSG_ERR, MSG_INTL(MSG_ERR_NOTSTRSH), 1103 EC_WORD(strsec->sec_shndx), strsec->sec_name); 1104 1105 /* Ensure the offset is in range */ 1106 if (offset >= strsec->sec_data->d_size) { 1107 elfedit_msg(msg_type, MSG_INTL(MSG_ERR_BADSTROFF), 1108 EC_WORD(strsec->sec_shndx), strsec->sec_name, 1109 EC_WORD(offset), EC_WORD(strsec->sec_data->d_size - 1)); 1110 /* 1111 * If the msg_type is a type that returns, give the 1112 * user a safe string to use. 1113 */ 1114 str = MSG_INTL(MSG_BADSYMOFFSETNAM); 1115 } else { 1116 /* Return the string */ 1117 str = ((const char *)strsec->sec_data->d_buf) + offset; 1118 } 1119 1120 if (debug_msg) 1121 elfedit_msg(ELFEDIT_MSG_DEBUG, MSG_INTL(MSG_DEBUG_FNDSTR), 1122 EC_WORD(strsec->sec_shndx), strsec->sec_name, 1123 EC_WORD(offset), str); 1124 return (str); 1125 } 1126 1127 1128 /* 1129 * Given a string table section, and a dynamic section entry 1130 * that supplies a string offset, return the string found at 1131 * the given offset. This routine is a convenience wrapper on 1132 * elfedit_offset_to_str(). 1133 * 1134 * exit: 1135 * As per elfedit_offset_to_str(). 1136 */ 1137 const char * 1138 elfedit_dyn_offset_to_str(elfedit_section_t *strsec, elfedit_dyn_elt_t *dynelt) 1139 { 1140 return (elfedit_offset_to_str(strsec, dynelt->dn_dyn.d_un.d_val, 1141 ELFEDIT_MSG_ERR, 0)); 1142 } 1143 1144 1145 /* 1146 * Given a section, fabricate a string for the form: 1147 * 1148 * "[#: name]" 1149 * 1150 * as used at the beginning of debug messages. A pointer to static 1151 * memory is returned, and is good until the next such call. 1152 */ 1153 const char * 1154 elfedit_sec_msgprefix(elfedit_section_t *sec) 1155 { 1156 static char *buf; 1157 static size_t bufsize; 1158 1159 size_t need; 1160 1161 need = 64 + strlen(sec->sec_name); 1162 if (need > bufsize) { 1163 buf = elfedit_realloc(MSG_INTL(MSG_ALLOC_SECMSGPRE), buf, need); 1164 bufsize = need; 1165 } 1166 1167 (void) snprintf(buf, bufsize, MSG_ORIG(MSG_FMT_SECMSGPRE), 1168 EC_WORD(sec->sec_shndx), sec->sec_name); 1169 1170 return (buf); 1171 } 1172