1 /* Relocate debug information. 2 Copyright (C) 2005-2010 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 52 typedef uint8_t GElf_Byte; 53 54 /* Adjust *VALUE to add the load address of the SHNDX section. 55 We update the section header in place to cache the result. */ 56 57 Dwfl_Error 58 internal_function 59 __libdwfl_relocate_value (Dwfl_Module *mod, Elf *elf, size_t *shstrndx, 60 Elf32_Word shndx, GElf_Addr *value) 61 { 62 assert (mod->e_type == ET_REL); 63 64 Elf_Scn *refscn = elf_getscn (elf, shndx); 65 GElf_Shdr refshdr_mem, *refshdr = gelf_getshdr (refscn, &refshdr_mem); 66 if (refshdr == NULL) 67 return DWFL_E_LIBELF; 68 69 if (refshdr->sh_addr == 0 && (refshdr->sh_flags & SHF_ALLOC)) 70 { 71 /* This is a loaded section. Find its actual 72 address and update the section header. */ 73 74 if (*shstrndx == SHN_UNDEF 75 && unlikely (elf_getshdrstrndx (elf, shstrndx) < 0)) 76 return DWFL_E_LIBELF; 77 78 const char *name = elf_strptr (elf, *shstrndx, refshdr->sh_name); 79 if (unlikely (name == NULL)) 80 return DWFL_E_LIBELF; 81 82 if ((*mod->dwfl->callbacks->section_address) (MODCB_ARGS (mod), 83 name, shndx, refshdr, 84 &refshdr->sh_addr)) 85 return CBFAIL; 86 87 if (refshdr->sh_addr == (Dwarf_Addr) -1l) 88 /* The callback indicated this section wasn't really loaded but we 89 don't really care. */ 90 refshdr->sh_addr = 0; /* Make no adjustment below. */ 91 92 /* Update the in-core file's section header to show the final 93 load address (or unloadedness). This serves as a cache, 94 so we won't get here again for the same section. */ 95 if (likely (refshdr->sh_addr != 0) 96 && unlikely (! gelf_update_shdr (refscn, refshdr))) 97 return DWFL_E_LIBELF; 98 } 99 100 if (refshdr->sh_flags & SHF_ALLOC) 101 /* Apply the adjustment. */ 102 *value += dwfl_adjusted_address (mod, refshdr->sh_addr); 103 104 return DWFL_E_NOERROR; 105 } 106 107 108 /* Cache used by relocate_getsym. */ 109 struct reloc_symtab_cache 110 { 111 Elf *symelf; 112 Elf_Data *symdata; 113 Elf_Data *symxndxdata; 114 Elf_Data *symstrdata; 115 size_t symshstrndx; 116 size_t strtabndx; 117 }; 118 #define RELOC_SYMTAB_CACHE(cache) \ 119 struct reloc_symtab_cache cache = \ 120 { NULL, NULL, NULL, NULL, SHN_UNDEF, SHN_UNDEF } 121 122 /* This is just doing dwfl_module_getsym, except that we must always use 123 the symbol table in RELOCATED itself when it has one, not MOD->symfile. */ 124 static Dwfl_Error 125 relocate_getsym (Dwfl_Module *mod, 126 Elf *relocated, struct reloc_symtab_cache *cache, 127 int symndx, GElf_Sym *sym, GElf_Word *shndx) 128 { 129 if (cache->symdata == NULL) 130 { 131 if (mod->symfile == NULL || mod->symfile->elf != relocated) 132 { 133 /* We have to look up the symbol table in the file we are 134 relocating, if it has its own. These reloc sections refer to 135 the symbol table in this file, and a symbol table in the main 136 file might not match. However, some tools did produce ET_REL 137 .debug files with relocs but no symtab of their own. */ 138 Elf_Scn *scn = NULL; 139 while ((scn = elf_nextscn (relocated, scn)) != NULL) 140 { 141 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem); 142 if (shdr != NULL) 143 switch (shdr->sh_type) 144 { 145 default: 146 continue; 147 case SHT_SYMTAB: 148 cache->symelf = relocated; 149 cache->symdata = elf_getdata (scn, NULL); 150 cache->strtabndx = shdr->sh_link; 151 if (unlikely (cache->symdata == NULL)) 152 return DWFL_E_LIBELF; 153 break; 154 case SHT_SYMTAB_SHNDX: 155 cache->symxndxdata = elf_getdata (scn, NULL); 156 if (unlikely (cache->symxndxdata == NULL)) 157 return DWFL_E_LIBELF; 158 break; 159 } 160 if (cache->symdata != NULL && cache->symxndxdata != NULL) 161 break; 162 } 163 } 164 if (cache->symdata == NULL) 165 { 166 /* We might not have looked for a symbol table file yet, 167 when coming from __libdwfl_relocate_section. */ 168 if (unlikely (mod->symfile == NULL) 169 && unlikely (INTUSE(dwfl_module_getsymtab) (mod) < 0)) 170 return dwfl_errno (); 171 172 /* The symbol table we have already cached is the one from 173 the file being relocated, so it's what we need. Or else 174 this is an ET_REL .debug file with no .symtab of its own; 175 the symbols refer to the section indices in the main file. */ 176 cache->symelf = mod->symfile->elf; 177 cache->symdata = mod->symdata; 178 cache->symxndxdata = mod->symxndxdata; 179 cache->symstrdata = mod->symstrdata; 180 } 181 } 182 183 if (unlikely (gelf_getsymshndx (cache->symdata, cache->symxndxdata, 184 symndx, sym, shndx) == NULL)) 185 return DWFL_E_LIBELF; 186 187 if (sym->st_shndx != SHN_XINDEX) 188 *shndx = sym->st_shndx; 189 190 switch (sym->st_shndx) 191 { 192 case SHN_ABS: 193 case SHN_UNDEF: 194 return DWFL_E_NOERROR; 195 196 case SHN_COMMON: 197 sym->st_value = 0; /* Value is size, not helpful. */ 198 return DWFL_E_NOERROR; 199 } 200 201 return __libdwfl_relocate_value (mod, cache->symelf, &cache->symshstrndx, 202 *shndx, &sym->st_value); 203 } 204 205 /* Handle an undefined symbol. We really only support ET_REL for Linux 206 kernel modules, and offline archives. The behavior of the Linux module 207 loader is very simple and easy to mimic. It only matches magically 208 exported symbols, and we match any defined symbols. But we get the same 209 answer except when the module's symbols are undefined and would prevent 210 it from being loaded. */ 211 static Dwfl_Error 212 resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab, 213 GElf_Sym *sym, GElf_Word shndx) 214 { 215 /* First we need its name. */ 216 if (sym->st_name != 0) 217 { 218 if (symtab->symstrdata == NULL) 219 { 220 /* Cache the strtab for this symtab. */ 221 assert (referer->symfile == NULL 222 || referer->symfile->elf != symtab->symelf); 223 symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf, 224 symtab->strtabndx), 225 NULL); 226 if (unlikely (symtab->symstrdata == NULL)) 227 return DWFL_E_LIBELF; 228 } 229 if (unlikely (sym->st_name >= symtab->symstrdata->d_size)) 230 return DWFL_E_BADSTROFF; 231 232 const char *name = symtab->symstrdata->d_buf; 233 name += sym->st_name; 234 235 for (Dwfl_Module *m = referer->dwfl->modulelist; m != NULL; m = m->next) 236 if (m != referer) 237 { 238 /* Get this module's symtab. 239 If we got a fresh error reading the table, report it. 240 If we just have no symbols in this module, no harm done. */ 241 if (m->symdata == NULL 242 && m->symerr == DWFL_E_NOERROR 243 && INTUSE(dwfl_module_getsymtab) (m) < 0 244 && m->symerr != DWFL_E_NO_SYMTAB) 245 return m->symerr; 246 247 for (size_t ndx = 1; ndx < m->syments; ++ndx) 248 { 249 sym = gelf_getsymshndx (m->symdata, m->symxndxdata, 250 ndx, sym, &shndx); 251 if (unlikely (sym == NULL)) 252 return DWFL_E_LIBELF; 253 if (sym->st_shndx != SHN_XINDEX) 254 shndx = sym->st_shndx; 255 256 /* We are looking for a defined global symbol with a name. */ 257 if (shndx == SHN_UNDEF || shndx == SHN_COMMON 258 || GELF_ST_BIND (sym->st_info) == STB_LOCAL 259 || sym->st_name == 0) 260 continue; 261 262 /* Get this candidate symbol's name. */ 263 if (unlikely (sym->st_name >= m->symstrdata->d_size)) 264 return DWFL_E_BADSTROFF; 265 const char *n = m->symstrdata->d_buf; 266 n += sym->st_name; 267 268 /* Does the name match? */ 269 if (strcmp (name, n)) 270 continue; 271 272 /* We found it! */ 273 if (shndx == SHN_ABS) /* XXX maybe should apply bias? */ 274 return DWFL_E_NOERROR; 275 276 if (m->e_type != ET_REL) 277 { 278 sym->st_value = dwfl_adjusted_st_value (m, sym->st_value); 279 return DWFL_E_NOERROR; 280 } 281 282 /* In an ET_REL file, the symbol table values are relative 283 to the section, not to the module's load base. */ 284 size_t symshstrndx = SHN_UNDEF; 285 return __libdwfl_relocate_value (m, m->symfile->elf, 286 &symshstrndx, 287 shndx, &sym->st_value); 288 } 289 } 290 } 291 292 return DWFL_E_RELUNDEF; 293 } 294 295 static Dwfl_Error 296 relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr, 297 size_t shstrndx, struct reloc_symtab_cache *reloc_symtab, 298 Elf_Scn *scn, GElf_Shdr *shdr, 299 Elf_Scn *tscn, bool debugscn, bool partial) 300 { 301 /* First, fetch the name of the section these relocations apply to. */ 302 GElf_Shdr tshdr_mem; 303 GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem); 304 const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name); 305 if (tname == NULL) 306 return DWFL_E_LIBELF; 307 308 if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0)) 309 /* No contents to relocate. */ 310 return DWFL_E_NOERROR; 311 312 if (debugscn && ! ebl_debugscn_p (mod->ebl, tname)) 313 /* This relocation section is not for a debugging section. 314 Nothing to do here. */ 315 return DWFL_E_NOERROR; 316 317 /* Fetch the section data that needs the relocations applied. */ 318 Elf_Data *tdata = elf_rawdata (tscn, NULL); 319 if (tdata == NULL) 320 return DWFL_E_LIBELF; 321 322 /* Apply one relocation. Returns true for any invalid data. */ 323 Dwfl_Error relocate (GElf_Addr offset, const GElf_Sxword *addend, 324 int rtype, int symndx) 325 { 326 /* First see if this is a reloc we can handle. 327 If we are skipping it, don't bother resolving the symbol. */ 328 329 if (unlikely (rtype == 0)) 330 /* In some odd situations, the linker can leave R_*_NONE relocs 331 behind. This is probably bogus ld -r behavior, but the only 332 cases it's known to appear in are harmless: DWARF data 333 referring to addresses in a section that has been discarded. 334 So we just pretend it's OK without further relocation. */ 335 return DWFL_E_NOERROR; 336 337 Elf_Type type = ebl_reloc_simple_type (mod->ebl, rtype); 338 if (unlikely (type == ELF_T_NUM)) 339 return DWFL_E_BADRELTYPE; 340 341 /* First, resolve the symbol to an absolute value. */ 342 GElf_Addr value; 343 344 if (symndx == STN_UNDEF) 345 /* When strip removes a section symbol referring to a 346 section moved into the debuginfo file, it replaces 347 that symbol index in relocs with STN_UNDEF. We 348 don't actually need the symbol, because those relocs 349 are always references relative to the nonallocated 350 debugging sections, which start at zero. */ 351 value = 0; 352 else 353 { 354 GElf_Sym sym; 355 GElf_Word shndx; 356 Dwfl_Error error = relocate_getsym (mod, relocated, reloc_symtab, 357 symndx, &sym, &shndx); 358 if (unlikely (error != DWFL_E_NOERROR)) 359 return error; 360 361 if (shndx == SHN_UNDEF || shndx == SHN_COMMON) 362 { 363 /* Maybe we can figure it out anyway. */ 364 error = resolve_symbol (mod, reloc_symtab, &sym, shndx); 365 if (error != DWFL_E_NOERROR 366 && !(error == DWFL_E_RELUNDEF && shndx == SHN_COMMON)) 367 return error; 368 } 369 370 value = sym.st_value; 371 } 372 373 /* These are the types we can relocate. */ 374 #define TYPES DO_TYPE (BYTE, Byte); DO_TYPE (HALF, Half); \ 375 DO_TYPE (WORD, Word); DO_TYPE (SWORD, Sword); \ 376 DO_TYPE (XWORD, Xword); DO_TYPE (SXWORD, Sxword) 377 size_t size; 378 switch (type) 379 { 380 #define DO_TYPE(NAME, Name) \ 381 case ELF_T_##NAME: \ 382 size = sizeof (GElf_##Name); \ 383 break 384 TYPES; 385 #undef DO_TYPE 386 default: 387 return DWFL_E_BADRELTYPE; 388 } 389 390 if (offset + size > tdata->d_size) 391 return DWFL_E_BADRELOFF; 392 393 #define DO_TYPE(NAME, Name) GElf_##Name Name; 394 union { TYPES; } tmpbuf; 395 #undef DO_TYPE 396 Elf_Data tmpdata = 397 { 398 .d_type = type, 399 .d_buf = &tmpbuf, 400 .d_size = size, 401 .d_version = EV_CURRENT, 402 }; 403 Elf_Data rdata = 404 { 405 .d_type = type, 406 .d_buf = tdata->d_buf + offset, 407 .d_size = size, 408 .d_version = EV_CURRENT, 409 }; 410 411 /* XXX check for overflow? */ 412 if (addend) 413 { 414 /* For the addend form, we have the value already. */ 415 value += *addend; 416 switch (type) 417 { 418 #define DO_TYPE(NAME, Name) \ 419 case ELF_T_##NAME: \ 420 tmpbuf.Name = value; \ 421 break 422 TYPES; 423 #undef DO_TYPE 424 default: 425 abort (); 426 } 427 } 428 else 429 { 430 /* Extract the original value and apply the reloc. */ 431 Elf_Data *d = gelf_xlatetom (relocated, &tmpdata, &rdata, 432 ehdr->e_ident[EI_DATA]); 433 if (d == NULL) 434 return DWFL_E_LIBELF; 435 assert (d == &tmpdata); 436 switch (type) 437 { 438 #define DO_TYPE(NAME, Name) \ 439 case ELF_T_##NAME: \ 440 tmpbuf.Name += (GElf_##Name) value; \ 441 break 442 TYPES; 443 #undef DO_TYPE 444 default: 445 abort (); 446 } 447 } 448 449 /* Now convert the relocated datum back to the target 450 format. This will write into rdata.d_buf, which 451 points into the raw section data being relocated. */ 452 Elf_Data *s = gelf_xlatetof (relocated, &rdata, &tmpdata, 453 ehdr->e_ident[EI_DATA]); 454 if (s == NULL) 455 return DWFL_E_LIBELF; 456 assert (s == &rdata); 457 458 /* We have applied this relocation! */ 459 return DWFL_E_NOERROR; 460 } 461 462 /* Fetch the relocation section and apply each reloc in it. */ 463 Elf_Data *reldata = elf_getdata (scn, NULL); 464 if (reldata == NULL) 465 return DWFL_E_LIBELF; 466 467 Dwfl_Error result = DWFL_E_NOERROR; 468 bool first_badreltype = true; 469 inline void check_badreltype (void) 470 { 471 if (first_badreltype) 472 { 473 first_badreltype = false; 474 if (ebl_get_elfmachine (mod->ebl) == EM_NONE) 475 /* This might be because ebl_openbackend failed to find 476 any libebl_CPU.so library. Diagnose that clearly. */ 477 result = DWFL_E_UNKNOWN_MACHINE; 478 } 479 } 480 481 size_t nrels = shdr->sh_size / shdr->sh_entsize; 482 size_t complete = 0; 483 if (shdr->sh_type == SHT_REL) 484 for (size_t relidx = 0; !result && relidx < nrels; ++relidx) 485 { 486 GElf_Rel rel_mem, *r = gelf_getrel (reldata, relidx, &rel_mem); 487 if (r == NULL) 488 return DWFL_E_LIBELF; 489 result = relocate (r->r_offset, NULL, 490 GELF_R_TYPE (r->r_info), 491 GELF_R_SYM (r->r_info)); 492 check_badreltype (); 493 if (partial) 494 switch (result) 495 { 496 case DWFL_E_NOERROR: 497 /* We applied the relocation. Elide it. */ 498 memset (&rel_mem, 0, sizeof rel_mem); 499 gelf_update_rel (reldata, relidx, &rel_mem); 500 ++complete; 501 break; 502 case DWFL_E_BADRELTYPE: 503 case DWFL_E_RELUNDEF: 504 /* We couldn't handle this relocation. Skip it. */ 505 result = DWFL_E_NOERROR; 506 break; 507 default: 508 break; 509 } 510 } 511 else 512 for (size_t relidx = 0; !result && relidx < nrels; ++relidx) 513 { 514 GElf_Rela rela_mem, *r = gelf_getrela (reldata, relidx, 515 &rela_mem); 516 if (r == NULL) 517 return DWFL_E_LIBELF; 518 result = relocate (r->r_offset, &r->r_addend, 519 GELF_R_TYPE (r->r_info), 520 GELF_R_SYM (r->r_info)); 521 check_badreltype (); 522 if (partial) 523 switch (result) 524 { 525 case DWFL_E_NOERROR: 526 /* We applied the relocation. Elide it. */ 527 memset (&rela_mem, 0, sizeof rela_mem); 528 gelf_update_rela (reldata, relidx, &rela_mem); 529 ++complete; 530 break; 531 case DWFL_E_BADRELTYPE: 532 case DWFL_E_RELUNDEF: 533 /* We couldn't handle this relocation. Skip it. */ 534 result = DWFL_E_NOERROR; 535 break; 536 default: 537 break; 538 } 539 } 540 541 if (likely (result == DWFL_E_NOERROR)) 542 { 543 if (!partial || complete == nrels) 544 /* Mark this relocation section as being empty now that we have 545 done its work. This affects unstrip -R, so e.g. it emits an 546 empty .rela.debug_info along with a .debug_info that has 547 already been fully relocated. */ 548 nrels = 0; 549 else if (complete != 0) 550 { 551 /* We handled some of the relocations but not all. 552 We've zeroed out the ones we processed. 553 Now remove them from the section. */ 554 555 size_t next = 0; 556 if (shdr->sh_type == SHT_REL) 557 for (size_t relidx = 0; relidx < nrels; ++relidx) 558 { 559 GElf_Rel rel_mem; 560 GElf_Rel *r = gelf_getrel (reldata, relidx, &rel_mem); 561 if (r->r_info != 0 || r->r_offset != 0) 562 { 563 if (next != relidx) 564 gelf_update_rel (reldata, next, r); 565 ++next; 566 } 567 } 568 else 569 for (size_t relidx = 0; relidx < nrels; ++relidx) 570 { 571 GElf_Rela rela_mem; 572 GElf_Rela *r = gelf_getrela (reldata, relidx, &rela_mem); 573 if (r->r_info != 0 || r->r_offset != 0 || r->r_addend != 0) 574 { 575 if (next != relidx) 576 gelf_update_rela (reldata, next, r); 577 ++next; 578 } 579 } 580 nrels = next; 581 } 582 583 shdr->sh_size = reldata->d_size = nrels * shdr->sh_entsize; 584 gelf_update_shdr (scn, shdr); 585 } 586 587 return result; 588 } 589 590 Dwfl_Error 591 internal_function 592 __libdwfl_relocate (Dwfl_Module *mod, Elf *debugfile, bool debug) 593 { 594 assert (mod->e_type == ET_REL); 595 596 GElf_Ehdr ehdr_mem; 597 const GElf_Ehdr *ehdr = gelf_getehdr (debugfile, &ehdr_mem); 598 if (ehdr == NULL) 599 return DWFL_E_LIBELF; 600 601 size_t d_shstrndx; 602 if (elf_getshdrstrndx (debugfile, &d_shstrndx) < 0) 603 return DWFL_E_LIBELF; 604 605 RELOC_SYMTAB_CACHE (reloc_symtab); 606 607 /* Look at each section in the debuginfo file, and process the 608 relocation sections for debugging sections. */ 609 Dwfl_Error result = DWFL_E_NOERROR; 610 Elf_Scn *scn = NULL; 611 while (result == DWFL_E_NOERROR 612 && (scn = elf_nextscn (debugfile, scn)) != NULL) 613 { 614 GElf_Shdr shdr_mem; 615 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 616 617 if ((shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) 618 && shdr->sh_size != 0) 619 { 620 /* It's a relocation section. */ 621 622 Elf_Scn *tscn = elf_getscn (debugfile, shdr->sh_info); 623 if (unlikely (tscn == NULL)) 624 result = DWFL_E_LIBELF; 625 else 626 result = relocate_section (mod, debugfile, ehdr, d_shstrndx, 627 &reloc_symtab, scn, shdr, tscn, 628 debug, !debug); 629 } 630 } 631 632 return result; 633 } 634 635 Dwfl_Error 636 internal_function 637 __libdwfl_relocate_section (Dwfl_Module *mod, Elf *relocated, 638 Elf_Scn *relocscn, Elf_Scn *tscn, bool partial) 639 { 640 GElf_Ehdr ehdr_mem; 641 GElf_Shdr shdr_mem; 642 643 RELOC_SYMTAB_CACHE (reloc_symtab); 644 645 size_t shstrndx; 646 if (elf_getshdrstrndx (relocated, &shstrndx) < 0) 647 return DWFL_E_LIBELF; 648 649 return (__libdwfl_module_getebl (mod) 650 ?: relocate_section (mod, relocated, 651 gelf_getehdr (relocated, &ehdr_mem), shstrndx, 652 &reloc_symtab, 653 relocscn, gelf_getshdr (relocscn, &shdr_mem), 654 tscn, false, partial)); 655 } 656