blob: 56a40fa6de2652ba30c6b5953f5e5c038ed694cc [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Find debugging and symbol information for a module in libdwfl.
2 Copyright (C) 2005 Red Hat, Inc.
Ulrich Drepper361df7d2006-04-04 21:38:57 +00003 This file is part of Red Hat elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004
Ulrich Drepper361df7d2006-04-04 21:38:57 +00005 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.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00008
Ulrich Drepper361df7d2006-04-04 21:38:57 +00009 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,
Ulrich Drepper1e9ef502006-04-04 22:29:06 +000016 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
Ulrich Drepper361df7d2006-04-04 21:38:57 +000017
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>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000049
50#include "libdwflP.h"
51#include <fcntl.h>
52#include <string.h>
Roland McGrathd17fac72005-08-23 08:20:21 +000053#include <unistd.h>
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000054#include "../libdw/libdwP.h" /* DWARF_E_* values are here. */
55
56
57/* Open libelf FILE->fd and compute the load base of ELF as loaded in MOD.
58 When we return success, FILE->elf and FILE->bias are set up. */
59static inline Dwfl_Error
60open_elf (Dwfl_Module *mod, struct dwfl_file *file)
61{
62 if (file->elf == NULL)
63 {
64 if (file->fd < 0)
65 return CBFAIL;
66
67 file->elf = elf_begin (file->fd, ELF_C_READ_MMAP_PRIVATE, NULL);
68 }
69
70 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (file->elf, &ehdr_mem);
71 if (ehdr == NULL)
72 return DWFL_E (LIBELF, elf_errno ());
73
Roland McGrathd17fac72005-08-23 08:20:21 +000074 mod->e_type = ehdr->e_type;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000075
76 file->bias = 0;
77 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
78 {
79 GElf_Phdr ph_mem;
80 GElf_Phdr *ph = gelf_getphdr (file->elf, i, &ph_mem);
81 if (ph == NULL)
82 return DWFL_E_LIBELF;
83 if (ph->p_type == PT_LOAD)
84 {
85 file->bias = ((mod->low_addr & -ph->p_align)
86 - (ph->p_vaddr & -ph->p_align));
87 break;
88 }
89 }
90
91 return DWFL_E_NOERROR;
92}
93
94/* Find the main ELF file for this module and open libelf on it.
95 When we return success, MOD->main.elf and MOD->main.bias are set up. */
96static void
97find_file (Dwfl_Module *mod)
98{
99 if (mod->main.elf != NULL /* Already done. */
100 || mod->elferr != DWFL_E_NOERROR) /* Cached failure. */
101 return;
102
103 mod->main.fd = (*mod->dwfl->callbacks->find_elf) (MODCB_ARGS (mod),
104 &mod->main.name,
105 &mod->main.elf);
106 mod->elferr = open_elf (mod, &mod->main);
107}
108
109/* Find the separate debuginfo file for this module and open libelf on it.
110 When we return success, MOD->debug is set up. */
111static Dwfl_Error
112find_debuginfo (Dwfl_Module *mod)
113{
Roland McGrathd17fac72005-08-23 08:20:21 +0000114 if (mod->debug.elf != NULL)
115 return DWFL_E_NOERROR;
116
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000117 size_t shstrndx;
118 if (elf_getshstrndx (mod->main.elf, &shstrndx) < 0)
119 return DWFL_E_LIBELF;
120
121 Elf_Scn *scn = elf_getscn (mod->main.elf, 0);
122 if (scn == NULL)
123 return DWFL_E_LIBELF;
124 do
125 {
126 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
127 if (shdr == NULL)
128 return DWFL_E_LIBELF;
129
130 const char *name = elf_strptr (mod->main.elf, shstrndx, shdr->sh_name);
131 if (name == NULL)
132 return DWFL_E_LIBELF;
133
134 if (!strcmp (name, ".gnu_debuglink"))
135 break;
136
137 scn = elf_nextscn (mod->main.elf, scn);
138 } while (scn != NULL);
139
140 const char *debuglink_file = NULL;
141 GElf_Word debuglink_crc = 0;
142 if (scn != NULL)
143 {
144 /* Found the .gnu_debuglink section. Extract its contents. */
145 Elf_Data *rawdata = elf_rawdata (scn, NULL);
146 if (rawdata == NULL)
147 return DWFL_E_LIBELF;
148
149 Elf_Data crcdata =
150 {
151 .d_type = ELF_T_WORD,
152 .d_buf = &debuglink_crc,
153 .d_size = sizeof debuglink_crc,
154 .d_version = EV_CURRENT,
155 };
156 Elf_Data conv =
157 {
158 .d_type = ELF_T_WORD,
159 .d_buf = rawdata->d_buf + rawdata->d_size - sizeof debuglink_crc,
160 .d_size = sizeof debuglink_crc,
161 .d_version = EV_CURRENT,
162 };
163
164 GElf_Ehdr ehdr_mem;
165 GElf_Ehdr *ehdr = gelf_getehdr (mod->main.elf, &ehdr_mem);
166 if (ehdr == NULL)
167 return DWFL_E_LIBELF;
168
169 Elf_Data *d = gelf_xlatetom (mod->main.elf, &crcdata, &conv,
170 ehdr->e_ident[EI_DATA]);
171 if (d == NULL)
172 return DWFL_E_LIBELF;
173 assert (d == &crcdata);
174
175 debuglink_file = rawdata->d_buf;
176 }
177
178 mod->debug.fd = (*mod->dwfl->callbacks->find_debuginfo) (MODCB_ARGS (mod),
179 mod->main.name,
180 debuglink_file,
181 debuglink_crc,
182 &mod->debug.name);
183 return open_elf (mod, &mod->debug);
184}
185
186
187/* Try to find a symbol table in FILE. */
188static Dwfl_Error
189load_symtab (struct dwfl_file *file, struct dwfl_file **symfile,
190 Elf_Scn **symscn, Elf_Scn **xndxscn,
191 size_t *syments, GElf_Word *strshndx)
192{
193 Elf_Scn *scn = NULL;
194 while ((scn = elf_nextscn (file->elf, scn)) != NULL)
195 {
196 GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
197 if (shdr != NULL)
198 switch (shdr->sh_type)
199 {
200 case SHT_SYMTAB:
201 *symscn = scn;
202 *symfile = file;
203 *strshndx = shdr->sh_link;
204 *syments = shdr->sh_size / shdr->sh_entsize;
205 if (*symscn != NULL && *xndxscn != NULL)
206 return DWFL_E_NOERROR;
207 break;
208
209 case SHT_DYNSYM:
210 /* Use this if need be, but keep looking for SHT_SYMTAB. */
211 *symscn = scn;
212 *symfile = file;
213 *strshndx = shdr->sh_link;
214 *syments = shdr->sh_size / shdr->sh_entsize;
215 break;
216
217 case SHT_SYMTAB_SHNDX:
218 *xndxscn = scn;
219 break;
220
221 default:
222 break;
223 }
224 }
225 return DWFL_E_NO_SYMTAB;
226}
227
228/* Try to find a symbol table in either MOD->main.elf or MOD->debug.elf. */
229static void
230find_symtab (Dwfl_Module *mod)
231{
232 if (mod->symdata != NULL /* Already done. */
233 || mod->symerr != DWFL_E_NOERROR) /* Cached previous failure. */
234 return;
235
236 find_file (mod);
237 mod->symerr = mod->elferr;
238 if (mod->symerr != DWFL_E_NOERROR)
239 return;
240
241 /* First see if the main ELF file has the debugging information. */
242 Elf_Scn *symscn = NULL, *xndxscn = NULL;
243 GElf_Word strshndx;
244 mod->symerr = load_symtab (&mod->main, &mod->symfile, &symscn,
245 &xndxscn, &mod->syments, &strshndx);
246 switch (mod->symerr)
247 {
248 default:
249 return;
250
251 case DWFL_E_NOERROR:
252 break;
253
254 case DWFL_E_NO_SYMTAB:
255 /* Now we have to look for a separate debuginfo file. */
256 mod->symerr = find_debuginfo (mod);
257 switch (mod->symerr)
258 {
259 default:
260 return;
261
262 case DWFL_E_NOERROR:
263 mod->symerr = load_symtab (&mod->debug, &mod->symfile, &symscn,
264 &xndxscn, &mod->syments, &strshndx);
265 break;
266
267 case DWFL_E_CB: /* The find_debuginfo hook failed. */
268 mod->symerr = DWFL_E_NO_SYMTAB;
269 break;
270 }
271
272 switch (mod->symerr)
273 {
274 default:
275 return;
276
277 case DWFL_E_NOERROR:
278 break;
279
280 case DWFL_E_NO_SYMTAB:
281 if (symscn == NULL)
282 return;
283 /* We still have the dynamic symbol table. */
284 mod->symerr = DWFL_E_NOERROR;
285 break;
286 }
287 break;
288 }
289
290 /* This does some sanity checks on the string table section. */
291 if (elf_strptr (mod->symfile->elf, strshndx, 0) == NULL)
292 {
293 elferr:
294 mod->symerr = DWFL_E (LIBELF, elf_errno ());
295 return;
296 }
297
298 /* Cache the data; MOD->syments was set above. */
299
Roland McGrath3712b282005-08-23 05:58:42 +0000300 mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx),
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000301 NULL);
302 if (mod->symstrdata == NULL)
303 goto elferr;
304
305 if (xndxscn == NULL)
306 mod->symxndxdata = NULL;
307 else
308 {
Roland McGrath3712b282005-08-23 05:58:42 +0000309 mod->symxndxdata = elf_getdata (xndxscn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000310 if (mod->symxndxdata == NULL)
311 goto elferr;
312 }
313
Roland McGrath3712b282005-08-23 05:58:42 +0000314 mod->symdata = elf_getdata (symscn, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000315 if (mod->symdata == NULL)
316 goto elferr;
317}
318
319
Roland McGrath994b4892005-12-05 22:46:21 +0000320/* Try to open a libebl backend for MOD. */
321Dwfl_Error
322internal_function_def
323__libdwfl_module_getebl (Dwfl_Module *mod)
324{
325 if (mod->ebl == NULL)
326 {
327 find_file (mod);
328 if (mod->elferr != DWFL_E_NOERROR)
329 return mod->elferr;
330
331 mod->ebl = ebl_openbackend (mod->main.elf);
332 if (mod->ebl == NULL)
333 return DWFL_E_LIBEBL;
334 }
335 return DWFL_E_NOERROR;
336}
337
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000338/* Try to start up libdw on DEBUGFILE. */
339static Dwfl_Error
Roland McGrathd17fac72005-08-23 08:20:21 +0000340load_dw (Dwfl_Module *mod, struct dwfl_file *debugfile)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000341{
Roland McGrathd17fac72005-08-23 08:20:21 +0000342 if (mod->e_type == ET_REL)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000343 {
344 const Dwfl_Callbacks *const cb = mod->dwfl->callbacks;
345
346 /* The debugging sections have to be relocated. */
347 if (cb->section_address == NULL)
348 return DWFL_E_NOREL;
349
Roland McGrath994b4892005-12-05 22:46:21 +0000350 Dwfl_Error error = __libdwfl_module_getebl (mod);
351 if (error != DWFL_E_NOERROR)
352 return error;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000353
354 find_symtab (mod);
355 Dwfl_Error result = mod->symerr;
356 if (result == DWFL_E_NOERROR)
Roland McGrathd17fac72005-08-23 08:20:21 +0000357 result = __libdwfl_relocate (mod, debugfile->elf);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000358 if (result != DWFL_E_NOERROR)
359 return result;
Roland McGrathd17fac72005-08-23 08:20:21 +0000360
361 /* Don't keep the file descriptors around. */
362 if (mod->main.fd != -1 && elf_cntl (mod->main.elf, ELF_C_FDREAD) == 0)
363 {
364 close (mod->main.fd);
365 mod->main.fd = -1;
366 }
367 if (debugfile->fd != -1 && elf_cntl (debugfile->elf, ELF_C_FDREAD) == 0)
368 {
369 close (debugfile->fd);
370 debugfile->fd = -1;
371 }
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000372 }
373
Roland McGrathd17fac72005-08-23 08:20:21 +0000374 mod->dw = INTUSE(dwarf_begin_elf) (debugfile->elf, DWARF_C_READ, NULL);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000375 if (mod->dw == NULL)
376 {
Roland McGrath4959bf82005-08-09 10:31:08 +0000377 int err = INTUSE(dwarf_errno) ();
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000378 return err == DWARF_E_NO_DWARF ? DWFL_E_NO_DWARF : DWFL_E (LIBDW, err);
379 }
380
381 /* Until we have iterated through all CU's, we might do lazy lookups. */
382 mod->lazycu = 1;
383
384 return DWFL_E_NOERROR;
385}
386
387/* Try to start up libdw on either the main file or the debuginfo file. */
388static void
389find_dw (Dwfl_Module *mod)
390{
391 if (mod->dw != NULL /* Already done. */
392 || mod->dwerr != DWFL_E_NOERROR) /* Cached previous failure. */
393 return;
394
395 find_file (mod);
396 mod->dwerr = mod->elferr;
397 if (mod->dwerr != DWFL_E_NOERROR)
398 return;
399
400 /* First see if the main ELF file has the debugging information. */
Roland McGrathd17fac72005-08-23 08:20:21 +0000401 mod->dwerr = load_dw (mod, &mod->main);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000402 switch (mod->dwerr)
403 {
404 case DWFL_E_NOERROR:
405 mod->debug.elf = mod->main.elf;
406 mod->debug.bias = mod->main.bias;
407 return;
408
409 case DWFL_E_NO_DWARF:
410 break;
411
412 default:
413 goto canonicalize;
414 }
415
416 /* Now we have to look for a separate debuginfo file. */
417 mod->dwerr = find_debuginfo (mod);
418 switch (mod->dwerr)
419 {
420 case DWFL_E_NOERROR:
Roland McGrathd17fac72005-08-23 08:20:21 +0000421 mod->dwerr = load_dw (mod, &mod->debug);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000422 break;
423
424 case DWFL_E_CB: /* The find_debuginfo hook failed. */
425 mod->dwerr = DWFL_E_NO_DWARF;
426 return;
427
428 default:
429 break;
430 }
431
432 canonicalize:
433 mod->dwerr = __libdwfl_canon_error (mod->dwerr);
434}
435
436
437Elf *
438dwfl_module_getelf (Dwfl_Module *mod, GElf_Addr *loadbase)
439{
440 if (mod == NULL)
441 return NULL;
442
443 find_file (mod);
444 if (mod->elferr == DWFL_E_NOERROR)
445 {
446 *loadbase = mod->main.bias;
447 return mod->main.elf;
448 }
449
450 __libdwfl_seterrno (mod->elferr);
451 return NULL;
452}
453INTDEF (dwfl_module_getelf)
454
455
456Dwarf *
457dwfl_module_getdwarf (Dwfl_Module *mod, Dwarf_Addr *bias)
458{
459 if (mod == NULL)
460 return NULL;
461
462 find_dw (mod);
463 if (mod->dwerr == DWFL_E_NOERROR)
464 {
465 *bias = mod->debug.bias;
466 return mod->dw;
467 }
468
469 __libdwfl_seterrno (mod->dwerr);
470 return NULL;
471}
472INTDEF (dwfl_module_getdwarf)
473
474
475const char *
476dwfl_module_addrname (Dwfl_Module *mod, GElf_Addr addr)
477{
478 if (mod == NULL)
479 return NULL;
480
481 find_symtab (mod);
482 if (mod->symerr != DWFL_E_NOERROR)
483 {
484 __libdwfl_seterrno (mod->symerr);
485 return NULL;
486 }
487
488 addr -= mod->symfile->bias;
489
490 /* Look through the symbol table for a matching symbol. */
491 size_t symshstrndx = SHN_UNDEF;
492 for (size_t i = 1; i < mod->syments; ++i)
493 {
494 GElf_Sym sym_mem;
495 GElf_Word shndx;
496 GElf_Sym *sym = gelf_getsymshndx (mod->symdata, mod->symxndxdata,
497 i, &sym_mem, &shndx);
498 if (sym != NULL)
499 {
500 GElf_Addr symaddr = sym->st_value;
501
502 if (sym->st_shndx != SHN_XINDEX)
503 shndx = sym->st_shndx;
504
Roland McGrathd17fac72005-08-23 08:20:21 +0000505 if (mod->e_type == ET_REL)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000506 /* In an ET_REL file, the symbol table values are relative
507 to the section, not to the module's load base. */
508 switch (shndx)
509 {
510 case SHN_UNDEF: /* Undefined symbol can't match an address. */
511 case SHN_COMMON: /* Nor can a common defn. */
512 continue;
513
514 case SHN_ABS: /* Symbol value is already absolute. */
515 break;
516
517 default:
518 {
519 Dwfl_Error result = DWFL_E_LIBELF;
520 if (likely (symshstrndx != SHN_UNDEF)
521 || elf_getshstrndx (mod->symfile->elf,
522 &symshstrndx) == 0)
523 result = __libdwfl_relocate_value (mod, symshstrndx,
524 shndx, &symaddr);
525 if (unlikely (result != DWFL_E_NOERROR))
526 {
527 __libdwfl_seterrno (result);
528 return NULL;
529 }
530 break;
531 }
532 }
533
534 if (symaddr <= addr && addr < symaddr + sym->st_size)
535 {
536 if (unlikely (sym->st_name >= mod->symstrdata->d_size))
537 {
538 __libdwfl_seterrno (DWFL_E_BADSTROFF);
539 return NULL;
540 }
541 return (const char *) mod->symstrdata->d_buf + sym->st_name;
542 }
543 }
544 }
545
546 return NULL;
547}