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