1 /* Find debugging and symbol information for a module in libdwfl. 2 Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 5 Red Hat elfutils is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by the 7 Free Software Foundation; version 2 of the License. 8 9 Red Hat elfutils is distributed in the hope that it will be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 General Public License for more details. 13 14 You should have received a copy of the GNU General Public License along 15 with Red Hat elfutils; if not, write to the Free Software Foundation, 16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 17 18 In addition, as a special exception, Red Hat, Inc. gives You the 19 additional right to link the code of Red Hat elfutils with code licensed 20 under any Open Source Initiative certified open source license 21 (http://www.opensource.org/licenses/index.php) which requires the 22 distribution of source code with any binary distribution and to 23 distribute linked combinations of the two. Non-GPL Code permitted under 24 this exception must only link to the code of Red Hat elfutils through 25 those well defined interfaces identified in the file named EXCEPTION 26 found in the source code files (the "Approved Interfaces"). The files 27 of Non-GPL Code may instantiate templates or use macros or inline 28 functions from the Approved Interfaces without causing the resulting 29 work to be covered by the GNU General Public License. Only Red Hat, 30 Inc. may make changes or additions to the list of Approved Interfaces. 31 Red Hat's grant of this exception is conditioned upon your not adding 32 any new exceptions. If you wish to add a new Approved Interface or 33 exception, please contact Red Hat. You must obey the GNU General Public 34 License in all respects for all of the Red Hat elfutils code and other 35 code used in conjunction with Red Hat elfutils except the Non-GPL Code 36 covered by this exception. If you modify this file, you may extend this 37 exception to your version of the file, but you are not obligated to do 38 so. If you do not wish to provide this exception without modification, 39 you must delete this exception statement from your version and license 40 this file solely under the GPL without exception. 41 42 Red Hat elfutils is an included package of the Open Invention Network. 43 An included package of the Open Invention Network is a package for which 44 Open Invention Network licensees cross-license their patents. No patent 45 license is granted, either expressly or impliedly, by designation as an 46 included package. Should you wish to participate in the Open Invention 47 Network licensing program, please visit www.openinventionnetwork.com 48 <http://www.openinventionnetwork.com>. */ 49 50 #include "libdwflP.h" 51 #include <fcntl.h> 52 #include <string.h> 53 #include <unistd.h> 54 #include "../libdw/libdwP.h" /* DWARF_E_* values are here. */ 55 56 /* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD. 57 When we return success, FILE->elf and FILE->bias are set up. */ 58 static inline Dwfl_Error 59 open_elf (Dwfl_Module *mod, struct dwfl_file *file) 60 { 61 if (file->elf == NULL) 62 { 63 /* If there was a pre-primed file name left that the callback left 64 behind, try to open that file name. */ 65 if (file->fd < 0 && file->name != NULL) 66 file->fd = TEMP_FAILURE_RETRY (open64 (file->name, O_RDONLY)); 67 68 if (file->fd < 0) 69 return CBFAIL; 70 71 file->elf = elf_begin (file->fd, ELF_C_READ_MMAP_PRIVATE, NULL); 72 } 73 74 if (unlikely (elf_kind (file->elf) != ELF_K_ELF)) 75 { 76 close (file->fd); 77 file->fd = -1; 78 return DWFL_E_BADELF; 79 } 80 81 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem); 82 if (ehdr == NULL) 83 { 84 elf_error: 85 close (file->fd); 86 file->fd = -1; 87 return DWFL_E (LIBELF, elf_errno ()); 88 } 89 90 /* The addresses in an ET_EXEC file are absolute. The lowest p_vaddr of 91 the main file can differ from that of the debug file due to prelink. 92 But that doesn't not change addresses that symbols, debuginfo, or 93 sh_addr of any program sections refer to. */ 94 file->bias = 0; 95 if (mod->e_type != ET_EXEC) 96 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i) 97 { 98 GElf_Phdr ph_mem; 99 GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem); 100 if (ph == NULL) 101 goto elf_error; 102 if (ph->p_type == PT_LOAD) 103 { 104 file->bias = ((mod->low_addr & -ph->p_align) 105 - (ph->p_vaddr & -ph->p_align)); 106 break; 107 } 108 } 109 110 mod->e_type = ehdr->e_type; 111 112 /* Relocatable Linux kernels are ET_EXEC but act like ET_DYN. */ 113 if (mod->e_type == ET_EXEC && file->bias != 0) 114 mod->e_type = ET_DYN; 115 116 return DWFL_E_NOERROR; 117 } 118 119 /* Find the main ELF file for this module and open libelf on it. 120 When we return success, MOD->main.elf and MOD->main.bias are set up. */ 121 static void 122 find_file (Dwfl_Module *mod) 123 { 124 if (mod->main.elf != NULL /* Already done. */ 125 || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */ 126 return; 127 128 mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod), 129 &mod->main.name, 130 &mod->main.elf); 131 mod->elferr = open_elf (mod, &mod->main); 132 133 if (mod->elferr == DWFL_E_NOERROR && !mod->main.valid) 134 { 135 /* Clear any explicitly reported build ID, just in case it was wrong. 136 We'll fetch it from the file when asked. */ 137 free (mod->build_id_bits); 138 mod->build_id_bits = NULL; 139 mod->build_id_len = 0; 140 } 141 } 142 143 /* Search an ELF file for a ".gnu_debuglink" section. */ 144 static const char * 145 find_debuglink (Elf *elf, GElf_Word *crc) 146 { 147 size_t shstrndx; 148 if (elf_getshstrndx (elf, &shstrndx) < 0) 149 return NULL; 150 151 Elf_Scn *scn = NULL; 152 while ((scn = elf_nextscn (elf, scn)) != NULL) 153 { 154 GElf_Shdr shdr_mem; 155 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 156 if (shdr == NULL) 157 return NULL; 158 159 const char *name = elf_strptr (elf, shstrndx, shdr->sh_name); 160 if (name == NULL) 161 return NULL; 162 163 if (!strcmp (name, ".gnu_debuglink")) 164 break; 165 } 166 167 if (scn == NULL) 168 return NULL; 169 170 /* Found the .gnu_debuglink section. Extract its contents. */ 171 Elf_Data *rawdata = elf_rawdata (scn, NULL); 172 if (rawdata == NULL) 173 return NULL; 174 175 Elf_Data crcdata = 176 { 177 .d_type = ELF_T_WORD, 178 .d_buf = crc, 179 .d_size = sizeof *crc, 180 .d_version = EV_CURRENT, 181 }; 182 Elf_Data conv = 183 { 184 .d_type = ELF_T_WORD, 185 .d_buf = rawdata->d_buf + rawdata->d_size - sizeof *crc, 186 .d_size = sizeof *crc, 187 .d_version = EV_CURRENT, 188 }; 189 190 GElf_Ehdr ehdr_mem; 191 GElf_Ehdr *ehdr = gelf_getehdr (elf, &ehdr_mem); 192 if (ehdr == NULL) 193 return NULL; 194 195 Elf_Data *d = gelf_xlatetom (elf, &crcdata, &conv, ehdr->e_ident[EI_DATA]); 196 if (d == NULL) 197 return NULL; 198 assert (d == &crcdata); 199 200 return rawdata->d_buf; 201 } 202 203 204 /* Find the separate debuginfo file for this module and open libelf on it. 205 When we return success, MOD->debug is set up. */ 206 static Dwfl_Error 207 find_debuginfo (Dwfl_Module *mod) 208 { 209 if (mod->debug.elf != NULL) 210 return DWFL_E_NOERROR; 211 212 GElf_Word debuglink_crc = 0; 213 const char *debuglink_file = find_debuglink (mod->main.elf, &debuglink_crc); 214 215 mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod), 216 mod->main.name, 217 debuglink_file, 218 debuglink_crc, 219 &mod->debug.name); 220 return open_elf (mod, &mod->debug); 221 } 222 223 224 /* Try to find a symbol table in FILE. 225 Returns DWFL_E_NOERROR if a proper one is found. 226 Returns DWFL_E_NO_SYMTAB if not, but still sets results for SHT_DYNSYM. */ 227 static Dwfl_Error 228 load_symtab (struct dwfl_file *file, struct dwfl_file **symfile, 229 Elf_Scn **symscn, Elf_Scn **xndxscn, 230 size_t *syments, GElf_Word *strshndx) 231 { 232 bool symtab = false; 233 Elf_Scn *scn = NULL; 234 while ((scn = elf_nextscn (file->elf, scn)) != NULL) 235 { 236 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); 237 if (shdr != NULL) 238 switch (shdr->sh_type) 239 { 240 case SHT_SYMTAB: 241 symtab = true; 242 *symscn = scn; 243 *symfile = file; 244 *strshndx = shdr->sh_link; 245 *syments = shdr->sh_size / shdr->sh_entsize; 246 if (*xndxscn != NULL) 247 return DWFL_E_NOERROR; 248 break; 249 250 case SHT_DYNSYM: 251 if (symtab) 252 break; 253 /* Use this if need be, but keep looking for SHT_SYMTAB. */ 254 *symscn = scn; 255 *symfile = file; 256 *strshndx = shdr->sh_link; 257 *syments = shdr->sh_size / shdr->sh_entsize; 258 break; 259 260 case SHT_SYMTAB_SHNDX: 261 *xndxscn = scn; 262 if (symtab) 263 return DWFL_E_NOERROR; 264 break; 265 266 default: 267 break; 268 } 269 } 270 271 if (symtab) 272 /* We found one, though no SHT_SYMTAB_SHNDX to go with it. */ 273 return DWFL_E_NOERROR; 274 275 /* We found no SHT_SYMTAB, so any SHT_SYMTAB_SHNDX was bogus. 276 We might have found an SHT_DYNSYM and set *SYMSCN et al though. */ 277 *xndxscn = NULL; 278 return DWFL_E_NO_SYMTAB; 279 } 280 281 282 /* Translate addresses into file offsets. 283 OFFS[*] start out zero and remain zero if unresolved. */ 284 static void 285 find_offsets (Elf *elf, const GElf_Ehdr *ehdr, size_t n, 286 GElf_Addr addrs[n], GElf_Off offs[n]) 287 { 288 size_t unsolved = n; 289 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i) 290 { 291 GElf_Phdr phdr_mem; 292 GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem); 293 if (phdr != NULL && phdr->p_type == PT_LOAD && phdr->p_memsz > 0) 294 for (size_t j = 0; j < n; ++j) 295 if (offs[j] == 0 296 && addrs[j] >= phdr->p_vaddr 297 && addrs[j] - phdr->p_vaddr < phdr->p_filesz) 298 { 299 offs[j] = addrs[j] - phdr->p_vaddr + phdr->p_offset; 300 if (--unsolved == 0) 301 break; 302 } 303 } 304 } 305 306 /* Try to find a dynamic symbol table via phdrs. */ 307 static void 308 find_dynsym (Dwfl_Module *mod) 309 { 310 GElf_Ehdr ehdr_mem; 311 GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem); 312 313 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i) 314 { 315 GElf_Phdr phdr_mem; 316 GElf_Phdr *phdr = gelf_getphdr (mod->main.elf, i, &phdr_mem); 317 if (phdr == NULL) 318 break; 319 320 if (phdr->p_type == PT_DYNAMIC) 321 { 322 /* Examine the dynamic section for the pointers we need. */ 323 324 Elf_Data *data = elf_getdata_rawchunk (mod->main.elf, 325 phdr->p_offset, phdr->p_filesz, 326 ELF_T_DYN); 327 if (data == NULL) 328 continue; 329 330 enum 331 { 332 i_symtab, 333 i_strtab, 334 i_hash, 335 i_gnu_hash, 336 i_max 337 }; 338 GElf_Addr addrs[i_max] = { 0, }; 339 GElf_Xword strsz = 0; 340 size_t n = data->d_size / gelf_fsize (mod->main.elf, 341 ELF_T_DYN, 1, EV_CURRENT); 342 for (size_t j = 0; j < n; ++j) 343 { 344 GElf_Dyn dyn_mem; 345 GElf_Dyn *dyn = gelf_getdyn (data, j, &dyn_mem); 346 if (dyn != NULL) 347 switch (dyn->d_tag) 348 { 349 case DT_SYMTAB: 350 addrs[i_symtab] = dyn->d_un.d_ptr; 351 continue; 352 353 case DT_HASH: 354 addrs[i_hash] = dyn->d_un.d_ptr; 355 continue; 356 357 case DT_GNU_HASH: 358 addrs[i_gnu_hash] = dyn->d_un.d_ptr; 359 continue; 360 361 case DT_STRTAB: 362 addrs[i_strtab] = dyn->d_un.d_ptr; 363 continue; 364 365 case DT_STRSZ: 366 strsz = dyn->d_un.d_val; 367 continue; 368 369 default: 370 continue; 371 372 case DT_NULL: 373 break; 374 } 375 break; 376 } 377 378 /* Translate pointers into file offsets. */ 379 GElf_Off offs[i_max] = { 0, }; 380 find_offsets (mod->main.elf, ehdr, i_max, addrs, offs); 381 382 /* Figure out the size of the symbol table. */ 383 if (offs[i_hash] != 0) 384 { 385 /* In the original format, .hash says the size of .dynsym. */ 386 387 size_t entsz = SH_ENTSIZE_HASH (ehdr); 388 data = elf_getdata_rawchunk (mod->main.elf, 389 offs[i_hash] + entsz, entsz, 390 entsz == 4 ? ELF_T_WORD 391 : ELF_T_XWORD); 392 if (data != NULL) 393 mod->syments = (entsz == 4 394 ? *(const GElf_Word *) data->d_buf 395 : *(const GElf_Xword *) data->d_buf); 396 } 397 if (offs[i_gnu_hash] != 0 && mod->syments == 0) 398 { 399 /* In the new format, we can derive it with some work. */ 400 401 const struct 402 { 403 Elf32_Word nbuckets; 404 Elf32_Word symndx; 405 Elf32_Word maskwords; 406 Elf32_Word shift2; 407 } *header; 408 409 data = elf_getdata_rawchunk (mod->main.elf, offs[i_gnu_hash], 410 sizeof *header, ELF_T_WORD); 411 if (data != NULL) 412 { 413 header = data->d_buf; 414 Elf32_Word nbuckets = header->nbuckets; 415 Elf32_Word symndx = header->symndx; 416 GElf_Off buckets_at = (offs[i_gnu_hash] + sizeof *header 417 + (gelf_getclass (mod->main.elf) 418 * sizeof (Elf32_Word) 419 * header->maskwords)); 420 421 data = elf_getdata_rawchunk (mod->main.elf, buckets_at, 422 nbuckets * sizeof (Elf32_Word), 423 ELF_T_WORD); 424 if (data != NULL && symndx < nbuckets) 425 { 426 const Elf32_Word *const buckets = data->d_buf; 427 Elf32_Word maxndx = symndx; 428 for (Elf32_Word bucket = 0; bucket < nbuckets; ++bucket) 429 if (buckets[bucket] > maxndx) 430 maxndx = buckets[bucket]; 431 432 GElf_Off hasharr_at = (buckets_at 433 + nbuckets * sizeof (Elf32_Word)); 434 hasharr_at += (maxndx - symndx) * sizeof (Elf32_Word); 435 do 436 { 437 data = elf_getdata_rawchunk (mod->main.elf, 438 hasharr_at, 439 sizeof (Elf32_Word), 440 ELF_T_WORD); 441 if (data != NULL 442 && (*(const Elf32_Word *) data->d_buf & 1u)) 443 { 444 mod->syments = maxndx + 1; 445 break; 446 } 447 ++maxndx; 448 hasharr_at += sizeof (Elf32_Word); 449 } while (data != NULL); 450 } 451 } 452 } 453 if (offs[i_strtab] > offs[i_symtab] && mod->syments == 0) 454 mod->syments = ((offs[i_strtab] - offs[i_symtab]) 455 / gelf_fsize (mod->main.elf, 456 ELF_T_SYM, 1, EV_CURRENT)); 457 458 if (mod->syments > 0) 459 { 460 mod->symdata = elf_getdata_rawchunk (mod->main.elf, 461 offs[i_symtab], 462 gelf_fsize (mod->main.elf, 463 ELF_T_SYM, 464 mod->syments, 465 EV_CURRENT), 466 ELF_T_SYM); 467 if (mod->symdata != NULL) 468 { 469 mod->symstrdata = elf_getdata_rawchunk (mod->main.elf, 470 offs[i_strtab], 471 strsz, 472 ELF_T_BYTE); 473 if (mod->symstrdata == NULL) 474 mod->symdata = NULL; 475 } 476 if (mod->symdata == NULL) 477 mod->symerr = DWFL_E (LIBELF, elf_errno ()); 478 else 479 { 480 mod->symfile = &mod->main; 481 mod->symerr = DWFL_E_NOERROR; 482 } 483 return; 484 } 485 } 486 } 487 } 488 489 /* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf. */ 490 static void 491 find_symtab (Dwfl_Module *mod) 492 { 493 if (mod->symdata != NULL /* Already done. */ 494 || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure. */ 495 return; 496 497 find_file (mod); 498 mod->symerr = mod->elferr; 499 if (mod->symerr != DWFL_E_NOERROR) 500 return; 501 502 /* First see if the main ELF file has the debugging information. */ 503 Elf_Scn *symscn = NULL, *xndxscn = NULL; 504 GElf_Word strshndx = 0; 505 mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn, 506 &xndxscn, &mod->syments, &strshndx); 507 switch (mod->symerr) 508 { 509 default: 510 return; 511 512 case DWFL_E_NOERROR: 513 break; 514 515 case DWFL_E_NO_SYMTAB: 516 /* Now we have to look for a separate debuginfo file. */ 517 mod->symerr = find_debuginfo (mod); 518 switch (mod->symerr) 519 { 520 default: 521 return; 522 523 case DWFL_E_NOERROR: 524 mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn, 525 &xndxscn, &mod->syments, &strshndx); 526 break; 527 528 case DWFL_E_CB: /* The find_debuginfo hook failed. */ 529 mod->symerr = DWFL_E_NO_SYMTAB; 530 break; 531 } 532 533 switch (mod->symerr) 534 { 535 default: 536 return; 537 538 case DWFL_E_NOERROR: 539 break; 540 541 case DWFL_E_NO_SYMTAB: 542 if (symscn != NULL) 543 { 544 /* We still have the dynamic symbol table. */ 545 mod->symerr = DWFL_E_NOERROR; 546 break; 547 } 548 549 /* Last ditch, look for dynamic symbols without section headers. */ 550 find_dynsym (mod); 551 return; 552 } 553 break; 554 } 555 556 /* This does some sanity checks on the string table section. */ 557 if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL) 558 { 559 elferr: 560 mod->symerr = DWFL_E (LIBELF, elf_errno ()); 561 return; 562 } 563 564 /* Cache the data; MOD->syments was set above. */ 565 566 mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx), 567 NULL); 568 if (mod->symstrdata == NULL) 569 goto elferr; 570 571 if (xndxscn == NULL) 572 mod->symxndxdata = NULL; 573 else 574 { 575 mod->symxndxdata = elf_getdata (xndxscn, NULL); 576 if (mod->symxndxdata == NULL) 577 goto elferr; 578 } 579 580 mod->symdata = elf_getdata (symscn, NULL); 581 if (mod->symdata == NULL) 582 goto elferr; 583 } 584 585 586 /* Try to open a libebl backend for MOD. */ 587 Dwfl_Error 588 internal_function 589 __libdwfl_module_getebl (Dwfl_Module *mod) 590 { 591 if (mod->ebl == NULL) 592 { 593 find_file (mod); 594 if (mod->elferr != DWFL_E_NOERROR) 595 return mod->elferr; 596 597 mod->ebl = ebl_openbackend (mod->main.elf); 598 if (mod->ebl == NULL) 599 return DWFL_E_LIBEBL; 600 } 601 return DWFL_E_NOERROR; 602 } 603 604 /* Try to start up libdw on DEBUGFILE. */ 605 static Dwfl_Error 606 load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile) 607 { 608 if (mod->e_type == ET_REL && !debugfile->relocated) 609 { 610 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks; 611 612 /* The debugging sections have to be relocated. */ 613 if (cb->section_address == NULL) 614 return DWFL_E_NOREL; 615 616 Dwfl_Error error = __libdwfl_module_getebl (mod); 617 if (error != DWFL_E_NOERROR) 618 return error; 619 620 find_symtab (mod); 621 Dwfl_Error result = mod->symerr; 622 if (result == DWFL_E_NOERROR) 623 result = __libdwfl_relocate (mod, debugfile->elf, true); 624 if (result != DWFL_E_NOERROR) 625 return result; 626 627 /* Don't keep the file descriptors around. */ 628 if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0) 629 { 630 close (mod->main.fd); 631 mod->main.fd = -1; 632 } 633 if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0) 634 { 635 close (debugfile->fd); 636 debugfile->fd = -1; 637 } 638 } 639 640 mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL); 641 if (mod->dw == NULL) 642 { 643 int err = INTUSE(dwarf_errno) (); 644 return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err); 645 } 646 647 /* Until we have iterated through all CU's, we might do lazy lookups. */ 648 mod->lazycu = 1; 649 650 return DWFL_E_NOERROR; 651 } 652 653 /* Try to start up libdw on either the main file or the debuginfo file. */ 654 static void 655 find_dw (Dwfl_Module *mod) 656 { 657 if (mod->dw != NULL /* Already done. */ 658 || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure. */ 659 return; 660 661 find_file (mod); 662 mod->dwerr = mod->elferr; 663 if (mod->dwerr != DWFL_E_NOERROR) 664 return; 665 666 /* First see if the main ELF file has the debugging information. */ 667 mod->dwerr = load_dw (mod, &mod->main); 668 switch (mod->dwerr) 669 { 670 case DWFL_E_NOERROR: 671 mod->debug.elf = mod->main.elf; 672 mod->debug.bias = mod->main.bias; 673 return; 674 675 case DWFL_E_NO_DWARF: 676 break; 677 678 default: 679 goto canonicalize; 680 } 681 682 /* Now we have to look for a separate debuginfo file. */ 683 mod->dwerr = find_debuginfo (mod); 684 switch (mod->dwerr) 685 { 686 case DWFL_E_NOERROR: 687 mod->dwerr = load_dw (mod, &mod->debug); 688 break; 689 690 case DWFL_E_CB: /* The find_debuginfo hook failed. */ 691 mod->dwerr = DWFL_E_NO_DWARF; 692 return; 693 694 default: 695 break; 696 } 697 698 canonicalize: 699 mod->dwerr = __libdwfl_canon_error (mod->dwerr); 700 } 701 702 703 Elf * 704 dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase) 705 { 706 if (mod == NULL) 707 return NULL; 708 709 find_file (mod); 710 if (mod->elferr == DWFL_E_NOERROR) 711 { 712 if (mod->e_type == ET_REL && ! mod->main.relocated) 713 { 714 /* Before letting them get at the Elf handle, 715 apply all the relocations we know how to. */ 716 717 mod->main.relocated = true; 718 if (likely (__libdwfl_module_getebl (mod) == DWFL_E_NOERROR)) 719 { 720 (void) __libdwfl_relocate (mod, mod->main.elf, false); 721 722 if (mod->debug.elf == mod->main.elf) 723 mod->debug.relocated = true; 724 else if (mod->debug.elf != NULL && ! mod->debug.relocated) 725 { 726 mod->debug.relocated = true; 727 (void) __libdwfl_relocate (mod, mod->debug.elf, false); 728 } 729 } 730 } 731 732 *loadbase = mod->main.bias; 733 return mod->main.elf; 734 } 735 736 __libdwfl_seterrno (mod->elferr); 737 return NULL; 738 } 739 INTDEF (dwfl_module_getelf) 740 741 742 Dwarf * 743 dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias) 744 { 745 if (mod == NULL) 746 return NULL; 747 748 find_dw (mod); 749 if (mod->dwerr == DWFL_E_NOERROR) 750 { 751 /* If dwfl_module_getelf was used previously, then partial apply 752 relocation to miscellaneous sections in the debug file too. */ 753 if (mod->e_type == ET_REL 754 && mod->main.relocated && ! mod->debug.relocated) 755 { 756 mod->debug.relocated = true; 757 if (mod->debug.elf != mod->main.elf) 758 (void) __libdwfl_relocate (mod, mod->debug.elf, false); 759 } 760 761 *bias = mod->debug.bias; 762 return mod->dw; 763 } 764 765 __libdwfl_seterrno (mod->dwerr); 766 return NULL; 767 } 768 INTDEF (dwfl_module_getdwarf) 769 770 int 771 dwfl_module_getsymtab (Dwfl_Module *mod) 772 { 773 if (mod == NULL) 774 return -1; 775 776 find_symtab (mod); 777 if (mod->symerr == DWFL_E_NOERROR) 778 return mod->syments; 779 780 __libdwfl_seterrno (mod->symerr); 781 return -1; 782 } 783 INTDEF (dwfl_module_getsymtab) 784