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