1cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Recover relocatibility for addresses computed from debug information. 2cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Copyright (C) 2005, 2006, 2007, 2008 Red Hat, Inc. 3cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng This file is part of Red Hat elfutils. 4cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 5cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is free software; you can redistribute it and/or modify 6cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng it under the terms of the GNU General Public License as published by the 7cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Free Software Foundation; version 2 of the License. 8cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 9cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is distributed in the hope that it will be useful, but 10cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng WITHOUT ANY WARRANTY; without even the implied warranty of 11cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng General Public License for more details. 13cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 14cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng You should have received a copy of the GNU General Public License along 15cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng with Red Hat elfutils; if not, write to the Free Software Foundation, 16cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 17cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 18cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng In addition, as a special exception, Red Hat, Inc. gives You the 19cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng additional right to link the code of Red Hat elfutils with code licensed 20cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng under any Open Source Initiative certified open source license 21cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng (http://www.opensource.org/licenses/index.php) which requires the 22cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng distribution of source code with any binary distribution and to 23cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng distribute linked combinations of the two. Non-GPL Code permitted under 24cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng this exception must only link to the code of Red Hat elfutils through 25cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng those well defined interfaces identified in the file named EXCEPTION 26cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng found in the source code files (the "Approved Interfaces"). The files 27cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng of Non-GPL Code may instantiate templates or use macros or inline 28cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng functions from the Approved Interfaces without causing the resulting 29cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng work to be covered by the GNU General Public License. Only Red Hat, 30cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Inc. may make changes or additions to the list of Approved Interfaces. 31cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat's grant of this exception is conditioned upon your not adding 32cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng any new exceptions. If you wish to add a new Approved Interface or 33cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng exception, please contact Red Hat. You must obey the GNU General Public 34cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng License in all respects for all of the Red Hat elfutils code and other 35cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng code used in conjunction with Red Hat elfutils except the Non-GPL Code 36cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng covered by this exception. If you modify this file, you may extend this 37cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng exception to your version of the file, but you are not obligated to do 38cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng so. If you do not wish to provide this exception without modification, 39cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng you must delete this exception statement from your version and license 40cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng this file solely under the GPL without exception. 41cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 42cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Red Hat elfutils is an included package of the Open Invention Network. 43cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng An included package of the Open Invention Network is a package for which 44cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Open Invention Network licensees cross-license their patents. No patent 45cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng license is granted, either expressly or impliedly, by designation as an 46cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng included package. Should you wish to participate in the Open Invention 47cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Network licensing program, please visit www.openinventionnetwork.com 48cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng <http://www.openinventionnetwork.com>. */ 49cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 50cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng#include "libdwflP.h" 51cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 52cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstruct dwfl_relocation 53cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 54cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t count; 55cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct 56cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 57cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *scn; 58cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *relocs; 59cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng const char *name; 60cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Addr start, end; 61cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } refs[0]; 62cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}; 63cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 64cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 65cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstruct secref 66cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 67cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct secref *next; 68cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *scn; 69cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *relocs; 70cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng const char *name; 71cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Addr start, end; 72cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng}; 73cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 74cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int 75cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcompare_secrefs (const void *a, const void *b) 76cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 77cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct secref *const *p1 = a; 78cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct secref *const *p2 = b; 79cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 80cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* No signed difference calculation is correct here, since the 81cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng terms are unsigned and could be more than INT64_MAX apart. */ 82cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if ((*p1)->start < (*p2)->start) 83cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return -1; 84cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if ((*p1)->start > (*p2)->start) 85cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return 1; 86cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 87cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return 0; 88cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 89cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 90cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int 91cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcache_sections (Dwfl_Module *mod) 92cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 93cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct secref *refs = NULL; 94cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t nrefs = 0; 95cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 96cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t shstrndx; 97cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (elf_getshstrndx (mod->main.elf, &shstrndx) < 0)) 98cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 99cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf_error: 100cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (DWFL_E_LIBELF); 101cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return -1; 102cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 103cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 104cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng bool check_reloc_sections = false; 105cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *scn = NULL; 106cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) 107cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 108cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Shdr shdr_mem; 109cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 110cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shdr == NULL) 111cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto elf_error; 112cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 113cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if ((shdr->sh_flags & SHF_ALLOC) && shdr->sh_addr == 0) 114cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 115cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* This section might not yet have been looked at. */ 116cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (__libdwfl_relocate_value (mod, mod->main.elf, &shstrndx, 117cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng elf_ndxscn (scn), 118cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng &shdr->sh_addr) != DWFL_E_NOERROR) 119cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng continue; 120cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng shdr = gelf_getshdr (scn, &shdr_mem); 121cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (shdr == NULL)) 122cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto elf_error; 123cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 124cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 125cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shdr->sh_flags & SHF_ALLOC) 126cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 127cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng const char *name = elf_strptr (mod->main.elf, shstrndx, 128cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng shdr->sh_name); 129cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (name == NULL)) 130cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto elf_error; 131cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 132cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct secref *newref = alloca (sizeof *newref); 133cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng newref->scn = scn; 134cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng newref->relocs = NULL; 135cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng newref->name = name; 136cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng newref->start = shdr->sh_addr + mod->main.bias; 137cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng newref->end = newref->start + shdr->sh_size; 138cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng newref->next = refs; 139cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng refs = newref; 140cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ++nrefs; 141cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 142cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 143cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (mod->e_type == ET_REL 144cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && shdr->sh_size != 0 145cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA) 146cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && mod->dwfl->callbacks->section_address != NULL) 147cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 148cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shdr->sh_info < elf_ndxscn (scn)) 149cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 150cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* We've already looked at the section these relocs apply to. */ 151cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info); 152cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (likely (tscn != NULL)) 153cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (struct secref *sec = refs; sec != NULL; sec = sec->next) 154cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (sec->scn == tscn) 155cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 156cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sec->relocs = scn; 157cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 158cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 159cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 160cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 161cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* We'll have to do a second pass. */ 162cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng check_reloc_sections = true; 163cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 164cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 165cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 166cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs])); 167cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (mod->reloc_info == NULL) 168cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 169cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (DWFL_E_NOMEM); 170cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return -1; 171cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 172cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 173cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct secref **sortrefs = alloca (nrefs * sizeof sortrefs[0]); 174cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (size_t i = nrefs; i-- > 0; refs = refs->next) 175cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng sortrefs[i] = refs; 176cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng assert (refs == NULL); 177cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 178cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs); 179cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 180cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info->count = nrefs; 181cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (size_t i = 0; i < nrefs; ++i) 182cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 183cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info->refs[i].name = sortrefs[i]->name; 184cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info->refs[i].scn = sortrefs[i]->scn; 185cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs; 186cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info->refs[i].start = sortrefs[i]->start; 187cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info->refs[i].end = sortrefs[i]->end; 188cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 189cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 190cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (check_reloc_sections)) 191cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 192cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* There was a reloc section that preceded its target section. 193cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng So we have to scan again now that we have cached all the 194cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng possible target sections we care about. */ 195cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 196cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng scn = NULL; 197cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) 198cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 199cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Shdr shdr_mem; 200cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); 201cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shdr == NULL) 202cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng goto elf_error; 203cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 204cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shdr->sh_size != 0 205cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && (shdr->sh_type == SHT_REL || shdr->sh_type == SHT_RELA)) 206cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 207cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info); 208cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (likely (tscn != NULL)) 209cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng for (size_t i = 0; i < nrefs; ++i) 210cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (mod->reloc_info->refs[i].scn == tscn) 211cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 212cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info->refs[i].relocs = scn; 213cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 214cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 215cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 216cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 217cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 218cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 219cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return nrefs; 220cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 221cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 222cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 223cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengint 224cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengdwfl_module_relocations (Dwfl_Module *mod) 225cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 226cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (mod == NULL) 227cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return -1; 228cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 229cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (mod->reloc_info != NULL) 230cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return mod->reloc_info->count; 231cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 232cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng switch (mod->e_type) 233cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 234cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ET_REL: 235cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return cache_sections (mod); 236cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 237cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ET_DYN: 238cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return 1; 239cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 240cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ET_EXEC: 241cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng assert (mod->main.bias == 0); 242cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng assert (mod->debug.bias == 0); 243cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 244cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 245cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 246cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return 0; 247cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 248cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 249cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengconst char * 250cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengdwfl_module_relocation_info (Dwfl_Module *mod, unsigned int idx, 251cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf32_Word *shndxp) 252cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 253cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (mod == NULL) 254cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 255cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 256cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng switch (mod->e_type) 257cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 258cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ET_REL: 259cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 260cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 261cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ET_DYN: 262cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (idx != 0) 263cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 264cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shndxp) 265cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *shndxp = SHN_ABS; 266cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return ""; 267cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 268cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng default: 269cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 270cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 271cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 272cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (mod->reloc_info == NULL) && cache_sections (mod) < 0) 273cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 274cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 275cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct dwfl_relocation *sections = mod->reloc_info; 276cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 277cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (idx >= sections->count) 278cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 279cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 280cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (shndxp) 281cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *shndxp = elf_ndxscn (sections->refs[idx].scn); 282cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 283cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return sections->refs[idx].name; 284cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 285cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 286cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Check that MOD is valid and make sure its relocation has been done. */ 287cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic bool 288cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengcheck_module (Dwfl_Module *mod) 289cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 290cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (INTUSE(dwfl_module_getsymtab) (mod) < 0) 291cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 292cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Dwfl_Error error = dwfl_errno (); 293cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (error != DWFL_E_NO_SYMTAB) 294cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 295cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (error); 296cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return true; 297cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 298cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 299cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 300cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (mod->dw == NULL) 301cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 302cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Dwarf_Addr bias; 303cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (INTUSE(dwfl_module_getdwarf) (mod, &bias) == NULL) 304cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 305cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Dwfl_Error error = dwfl_errno (); 306cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (error != DWFL_E_NO_DWARF) 307cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 308cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (error); 309cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return true; 310cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 311cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 312cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 313cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 314cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return false; 315cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 316cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 317cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng/* Find the index in MOD->reloc_info.refs containing *ADDR. */ 318cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengstatic int 319cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengfind_section (Dwfl_Module *mod, Dwarf_Addr *addr) 320cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 321cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (mod->reloc_info == NULL) && cache_sections (mod) < 0) 322cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return -1; 323cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 324cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng struct dwfl_relocation *sections = mod->reloc_info; 325cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 326cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* The sections are sorted by address, so we can use binary search. */ 327cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t l = 0, u = sections->count; 328cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng while (l < u) 329cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 330cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng size_t idx = (l + u) / 2; 331cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (*addr < sections->refs[idx].start) 332cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng u = idx; 333cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else if (*addr > sections->refs[idx].end) 334cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng l = idx + 1; 335cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 336cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 337cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Consider the limit of a section to be inside it, unless it's 338cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng inside the next one. A section limit address can appear in 339cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng line records. */ 340cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (*addr == sections->refs[idx].end 341cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && idx < sections->count 342cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng && *addr == sections->refs[idx + 1].start) 343cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng ++idx; 344cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 345cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *addr -= sections->refs[idx].start; 346cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return idx; 347cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 348cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 349cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 350cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (DWFL_E (LIBDW, DWARF_E_NO_MATCH)); 351cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return -1; 352cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 353cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 354cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengint 355cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengdwfl_module_relocate_address (Dwfl_Module *mod, Dwarf_Addr *addr) 356cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 357cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (unlikely (check_module (mod))) 358cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return -1; 359cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 360cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng switch (mod->e_type) 361cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 362cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ET_REL: 363cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return find_section (mod, addr); 364cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 365cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng case ET_DYN: 366cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* All relative to first and only relocation base: module start. */ 367cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *addr -= mod->low_addr; 368cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 369cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 370cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng default: 371cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng /* Already absolute, dwfl_module_relocations returned zero. We 372cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng shouldn't really have been called, but it's a harmless no-op. */ 373cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng break; 374cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 375cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 376cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return 0; 377cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 378cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengINTDEF (dwfl_module_relocate_address) 379cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 380cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengElf_Scn * 381cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Chengdwfl_module_address_section (Dwfl_Module *mod, Dwarf_Addr *address, 382cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Dwarf_Addr *bias) 383cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng{ 384cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (check_module (mod)) 385cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 386cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 387cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng int idx = find_section (mod, address); 388cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (idx < 0) 389cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 390cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 391cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (mod->reloc_info->refs[idx].relocs != NULL) 392cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 393cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng assert (mod->e_type == ET_REL); 394cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 395cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *tscn = mod->reloc_info->refs[idx].scn; 396cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Elf_Scn *relocscn = mod->reloc_info->refs[idx].relocs; 397cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng Dwfl_Error result = __libdwfl_relocate_section (mod, mod->main.elf, 398cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng relocscn, tscn, true); 399cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng if (likely (result == DWFL_E_NOERROR)) 400cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng mod->reloc_info->refs[idx].relocs = NULL; 401cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng else 402cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng { 403cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng __libdwfl_seterrno (result); 404cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return NULL; 405cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 406cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng } 407cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng 408cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng *bias = mod->main.bias; 409cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng return mod->reloc_info->refs[idx].scn; 410cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben Cheng} 411cc6695e2684ce93cdf8bd2da63d55d2cf49ff076Ben ChengINTDEF (dwfl_module_address_section) 412