Brian Silverman | 8649792 | 2018-02-10 19:28:39 -0500 | [diff] [blame] | 1 | /* Recover relocatibility for addresses computed from debug information. |
| 2 | Copyright (C) 2005-2009, 2012 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 | #ifdef HAVE_CONFIG_H |
| 30 | # include <config.h> |
| 31 | #endif |
| 32 | |
| 33 | #include "libdwflP.h" |
| 34 | #include <fcntl.h> |
| 35 | #include <unistd.h> |
| 36 | |
| 37 | /* Since dwfl_report_elf lays out the sections already, this will only be |
| 38 | called when the section headers of the debuginfo file are being |
| 39 | consulted instead, or for the section placed at 0. With binutils |
| 40 | strip-to-debug, the symbol table is in the debuginfo file and relocation |
| 41 | looks there. */ |
| 42 | int |
| 43 | dwfl_offline_section_address (Dwfl_Module *mod, |
| 44 | void **userdata __attribute__ ((unused)), |
| 45 | const char *modname __attribute__ ((unused)), |
| 46 | Dwarf_Addr base __attribute__ ((unused)), |
| 47 | const char *secname __attribute__ ((unused)), |
| 48 | Elf32_Word shndx, |
| 49 | const GElf_Shdr *shdr __attribute__ ((unused)), |
| 50 | Dwarf_Addr *addr) |
| 51 | { |
| 52 | assert (mod->e_type == ET_REL); |
| 53 | assert (shdr->sh_addr == 0); |
| 54 | assert (shdr->sh_flags & SHF_ALLOC); |
| 55 | assert (shndx != 0); |
| 56 | |
| 57 | if (mod->debug.elf == NULL) |
| 58 | /* We are only here because sh_addr is zero even though layout is complete. |
| 59 | The first section in the first file under -e is placed at 0. */ |
| 60 | return 0; |
| 61 | |
| 62 | /* The section numbers might not match between the two files. |
| 63 | The best we can rely on is the order of SHF_ALLOC sections. */ |
| 64 | |
| 65 | Elf_Scn *ourscn = elf_getscn (mod->debug.elf, shndx); |
| 66 | Elf_Scn *scn = NULL; |
| 67 | uint_fast32_t skip_alloc = 0; |
| 68 | while ((scn = elf_nextscn (mod->debug.elf, scn)) != ourscn) |
| 69 | { |
| 70 | assert (scn != NULL); |
| 71 | GElf_Shdr shdr_mem; |
| 72 | GElf_Shdr *sh = gelf_getshdr (scn, &shdr_mem); |
| 73 | if (unlikely (sh == NULL)) |
| 74 | return -1; |
| 75 | if (sh->sh_flags & SHF_ALLOC) |
| 76 | ++skip_alloc; |
| 77 | } |
| 78 | |
| 79 | scn = NULL; |
| 80 | while ((scn = elf_nextscn (mod->main.elf, scn)) != NULL) |
| 81 | { |
| 82 | GElf_Shdr shdr_mem; |
| 83 | GElf_Shdr *main_shdr = gelf_getshdr (scn, &shdr_mem); |
| 84 | if (unlikely (main_shdr == NULL)) |
| 85 | return -1; |
| 86 | if ((main_shdr->sh_flags & SHF_ALLOC) && skip_alloc-- == 0) |
| 87 | { |
| 88 | assert (main_shdr->sh_flags == shdr->sh_flags); |
| 89 | *addr = main_shdr->sh_addr; |
| 90 | return 0; |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | /* This should never happen. */ |
| 95 | return -1; |
| 96 | } |
| 97 | INTDEF (dwfl_offline_section_address) |
| 98 | |
| 99 | /* Forward declarations. */ |
| 100 | static Dwfl_Module *process_elf (Dwfl *dwfl, const char *name, |
| 101 | const char *file_name, int fd, Elf *elf); |
| 102 | static Dwfl_Module *process_archive (Dwfl *dwfl, const char *name, |
| 103 | const char *file_name, int fd, Elf *elf, |
| 104 | int (*predicate) (const char *module, |
| 105 | const char *file)); |
| 106 | |
| 107 | /* Report one module for an ELF file, or many for an archive. |
| 108 | Always consumes ELF and FD. */ |
| 109 | static Dwfl_Module * |
| 110 | process_file (Dwfl *dwfl, const char *name, const char *file_name, int fd, |
| 111 | Elf *elf, int (*predicate) (const char *module, |
| 112 | const char *file)) |
| 113 | { |
| 114 | switch (elf_kind (elf)) |
| 115 | { |
| 116 | default: |
| 117 | case ELF_K_NONE: |
| 118 | __libdwfl_seterrno (elf == NULL ? DWFL_E_LIBELF : DWFL_E_BADELF); |
| 119 | return NULL; |
| 120 | |
| 121 | case ELF_K_ELF: |
| 122 | return process_elf (dwfl, name, file_name, fd, elf); |
| 123 | |
| 124 | case ELF_K_AR: |
| 125 | return process_archive (dwfl, name, file_name, fd, elf, predicate); |
| 126 | } |
| 127 | } |
| 128 | |
| 129 | /* Report the open ELF file as a module. Always consumes ELF and FD. */ |
| 130 | static Dwfl_Module * |
| 131 | process_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd, |
| 132 | Elf *elf) |
| 133 | { |
| 134 | Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name, fd, elf, |
| 135 | dwfl->offline_next_address, true, |
| 136 | false); |
| 137 | if (mod != NULL) |
| 138 | { |
| 139 | /* If this is an ET_EXEC file with fixed addresses, the address range |
| 140 | it consumed may or may not intersect with the arbitrary range we |
| 141 | will use for relocatable modules. Make sure we always use a free |
| 142 | range for the offline allocations. If this module did use |
| 143 | offline_next_address, it may have rounded it up for the module's |
| 144 | alignment requirements. */ |
| 145 | if ((dwfl->offline_next_address >= mod->low_addr |
| 146 | || mod->low_addr - dwfl->offline_next_address < OFFLINE_REDZONE) |
| 147 | && dwfl->offline_next_address < mod->high_addr + OFFLINE_REDZONE) |
| 148 | dwfl->offline_next_address = mod->high_addr + OFFLINE_REDZONE; |
| 149 | |
| 150 | /* Don't keep the file descriptor around. */ |
| 151 | if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0) |
| 152 | { |
| 153 | close (mod->main.fd); |
| 154 | mod->main.fd = -1; |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | return mod; |
| 159 | } |
| 160 | |
| 161 | /* Always consumes MEMBER. Returns elf_next result on success. |
| 162 | For errors returns ELF_C_NULL with *MOD set to null. */ |
| 163 | static Elf_Cmd |
| 164 | process_archive_member (Dwfl *dwfl, const char *name, const char *file_name, |
| 165 | int (*predicate) (const char *module, const char *file), |
| 166 | int fd, Elf *member, Dwfl_Module **mod) |
| 167 | { |
| 168 | const Elf_Arhdr *h = elf_getarhdr (member); |
| 169 | if (unlikely (h == NULL)) |
| 170 | { |
| 171 | __libdwfl_seterrno (DWFL_E_LIBELF); |
| 172 | fail: |
| 173 | elf_end (member); |
| 174 | *mod = NULL; |
| 175 | return ELF_C_NULL; |
| 176 | } |
| 177 | |
| 178 | if (!strcmp (h->ar_name, "/") || !strcmp (h->ar_name, "//") |
| 179 | || !strcmp (h->ar_name, "/SYM64/")) |
| 180 | { |
| 181 | skip:; |
| 182 | /* Skip this and go to the next. */ |
| 183 | Elf_Cmd result = elf_next (member); |
| 184 | elf_end (member); |
| 185 | return result; |
| 186 | } |
| 187 | |
| 188 | char *member_name; |
| 189 | if (unlikely (asprintf (&member_name, "%s(%s)", file_name, h->ar_name) < 0)) |
| 190 | { |
| 191 | nomem: |
| 192 | __libdwfl_seterrno (DWFL_E_NOMEM); |
| 193 | elf_end (member); |
| 194 | *mod = NULL; |
| 195 | return ELF_C_NULL; |
| 196 | } |
| 197 | |
| 198 | char *module_name = NULL; |
| 199 | if (name == NULL || name[0] == '\0') |
| 200 | name = h->ar_name; |
| 201 | else if (unlikely (asprintf (&module_name, "%s:%s", name, h->ar_name) < 0)) |
| 202 | { |
| 203 | free (member_name); |
| 204 | goto nomem; |
| 205 | } |
| 206 | else |
| 207 | name = module_name; |
| 208 | |
| 209 | if (predicate != NULL) |
| 210 | { |
| 211 | /* Let the predicate decide whether to use this one. */ |
| 212 | int want = (*predicate) (name, member_name); |
| 213 | if (want <= 0) |
| 214 | { |
| 215 | free (member_name); |
| 216 | free (module_name); |
| 217 | if (unlikely (want < 0)) |
| 218 | { |
| 219 | __libdwfl_seterrno (DWFL_E_CB); |
| 220 | goto fail; |
| 221 | } |
| 222 | goto skip; |
| 223 | } |
| 224 | } |
| 225 | |
| 226 | /* We let __libdwfl_report_elf cache the fd in mod->main.fd, |
| 227 | though it's the same fd for all the members. |
| 228 | On module teardown we will close it only on the last Elf reference. */ |
| 229 | *mod = process_file (dwfl, name, member_name, fd, member, predicate); |
| 230 | free (member_name); |
| 231 | free (module_name); |
| 232 | |
| 233 | if (*mod == NULL) /* process_file called elf_end. */ |
| 234 | return ELF_C_NULL; |
| 235 | |
| 236 | /* Advance the archive-reading offset for the next iteration. */ |
| 237 | return elf_next (member); |
| 238 | } |
| 239 | |
| 240 | /* Report each member of the archive as its own module. */ |
| 241 | static Dwfl_Module * |
| 242 | process_archive (Dwfl *dwfl, const char *name, const char *file_name, int fd, |
| 243 | Elf *archive, |
| 244 | int (*predicate) (const char *module, const char *file)) |
| 245 | |
| 246 | { |
| 247 | Dwfl_Module *mod = NULL; |
| 248 | Elf *member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive); |
| 249 | if (unlikely (member == NULL)) /* Empty archive. */ |
| 250 | { |
| 251 | __libdwfl_seterrno (DWFL_E_BADELF); |
| 252 | return NULL; |
| 253 | } |
| 254 | |
| 255 | while (process_archive_member (dwfl, name, file_name, predicate, |
| 256 | fd, member, &mod) != ELF_C_NULL) |
| 257 | member = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, archive); |
| 258 | |
| 259 | /* We can drop the archive Elf handle even if we're still using members |
| 260 | in live modules. When the last module's elf_end on a member returns |
| 261 | zero, that module will close FD. If no modules survived the predicate, |
| 262 | we are all done with the file right here. */ |
| 263 | if (mod != NULL /* If no modules, caller will clean up. */ |
| 264 | && elf_end (archive) == 0) |
| 265 | close (fd); |
| 266 | |
| 267 | return mod; |
| 268 | } |
| 269 | |
| 270 | Dwfl_Module * |
| 271 | internal_function |
| 272 | __libdwfl_report_offline (Dwfl *dwfl, const char *name, |
| 273 | const char *file_name, int fd, bool closefd, |
| 274 | int (*predicate) (const char *module, |
| 275 | const char *file)) |
| 276 | { |
| 277 | Elf *elf; |
| 278 | Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, true); |
| 279 | if (error != DWFL_E_NOERROR) |
| 280 | { |
| 281 | __libdwfl_seterrno (error); |
| 282 | return NULL; |
| 283 | } |
| 284 | Dwfl_Module *mod = process_file (dwfl, name, file_name, fd, elf, predicate); |
| 285 | if (mod == NULL) |
| 286 | { |
| 287 | elf_end (elf); |
| 288 | if (closefd) |
| 289 | close (fd); |
| 290 | } |
| 291 | return mod; |
| 292 | } |
| 293 | |
| 294 | Dwfl_Module * |
| 295 | dwfl_report_offline (Dwfl *dwfl, const char *name, |
| 296 | const char *file_name, int fd) |
| 297 | { |
| 298 | if (dwfl == NULL) |
| 299 | return NULL; |
| 300 | |
| 301 | bool closefd = false; |
| 302 | if (fd < 0) |
| 303 | { |
| 304 | closefd = true; |
| 305 | fd = open (file_name, O_RDONLY); |
| 306 | if (fd < 0) |
| 307 | { |
| 308 | __libdwfl_seterrno (DWFL_E_ERRNO); |
| 309 | return NULL; |
| 310 | } |
| 311 | } |
| 312 | |
| 313 | return __libdwfl_report_offline (dwfl, name, file_name, fd, closefd, NULL); |
| 314 | } |
| 315 | INTDEF (dwfl_report_offline) |