blob: 21c9e84685d8776e34408d0996075e11cd297fb7 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Report a module to libdwfl based on ELF program headers.
2 Copyright (C) 2005 Red Hat, Inc.
3
4 This program is Open Source software; you can redistribute it and/or
5 modify it under the terms of the Open Software License version 1.0 as
6 published by the Open Source Initiative.
7
8 You should have received a copy of the Open Software License along
9 with this program; if not, you may obtain a copy of the Open Software
10 License version 1.0 from http://www.opensource.org/licenses/osl.php or
11 by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
12 3001 King Ranch Road, Ukiah, CA 95482. */
13
14#include "libdwflP.h"
15#include <fcntl.h>
16#include <unistd.h>
17
18
19Dwfl_Module *
20dwfl_report_elf (Dwfl *dwfl, const char *name,
21 const char *file_name, int fd, GElf_Addr base)
22{
23 bool closefd = false;
24
25 if (fd < 0)
26 {
27 fd = open64 (file_name, O_RDONLY);
28 if (fd < 0)
29 {
30 __libdwfl_seterrno (DWFL_E_ERRNO);
31 return NULL;
32 }
33 closefd = true;
34 }
35
36 Elf *elf = elf_begin (fd, ELF_C_READ_MMAP_PRIVATE, NULL);
37
38 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
39 if (ehdr == NULL)
40 {
41 elf_error:
42 __libdwfl_seterrno (DWFL_E_LIBELF);
43 if (closefd)
44 close (fd);
45 return NULL;
46 }
47
48 GElf_Addr start = 0, end = 0;
49 for (uint_fast16_t i = 0; i < ehdr->e_phnum; ++i)
50 {
51 GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
52 if (ph == NULL)
53 goto elf_error;
54 if (ph->p_type == PT_LOAD)
55 {
56 start = base + (ph->p_vaddr & -ph->p_align);
57 break;
58 }
59 }
60
61 for (uint_fast16_t i = ehdr->e_phnum; i-- > 0;)
62 {
63 GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
64 if (ph == NULL)
65 goto elf_error;
66 if (ph->p_type == PT_LOAD)
67 {
68 end = base + (ph->p_vaddr + ph->p_memsz);
69 break;
70 }
71 }
72
73 if (end == 0)
74 {
75 __libdwfl_seterrno (DWFL_E_NO_PHDR);
76 if (closefd)
77 close (fd);
78 return NULL;
79 }
80
81 Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name,
82 base + start, base + end);
83 if (m != NULL)
84 {
85 if (m->main.name == NULL)
86 {
87 m->main.name = strdup (file_name);
88 m->main.fd = fd;
89 }
90 else if ((fd >= 0 && m->main.fd != fd)
91 || strcmp (m->main.name, file_name))
92 {
93 elf_end (elf);
94 overlap:
95 if (closefd)
96 close (fd);
97 m->gc = true;
98 __libdwfl_seterrno (DWFL_E_OVERLAP);
99 m = NULL;
100 }
101
102 /* Preinstall the open ELF handle for the module. */
103 if (m->main.elf == NULL)
104 {
105 m->main.elf = elf;
106 m->main.bias = base;
107 }
108 else
109 {
110 elf_end (elf);
111 if (m->main.bias != base)
112 goto overlap;
113 }
114 }
115 return m;
116}
117INTDEF (dwfl_report_elf)