blob: 35d9f485949a192e65986b5bec98c2549d973660 [file] [log] [blame]
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00001/* Report a module to libdwfl based on ELF program headers.
Roland McGrathf95760a2010-01-07 20:24:34 -08002 Copyright (C) 2005-2010 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ulrich Drepperb08d5a82005-07-26 05:00:05 +00007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * 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
Ulrich Drepper361df7d2006-04-04 21:38:57 +000021 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 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/>. */
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000028
29#include "libdwflP.h"
30#include <fcntl.h>
31#include <unistd.h>
32
Roland McGrathe4c22ea2007-10-23 13:07:39 +000033
34/* We start every ET_REL module at a moderately aligned boundary.
35 This keeps the low addresses easy to read compared to a layout
36 starting at 0 (as when using -e). It also makes it unlikely
37 that a middle section will have a larger alignment and require
38 rejiggering (see below). */
39#define REL_MIN_ALIGN ((GElf_Xword) 0x100)
40
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000041Dwfl_Module *
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000042internal_function
43__libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
Roland McGrath5453abf2009-02-10 17:33:49 -080044 int fd, Elf *elf, GElf_Addr base, bool sanity)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000045{
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000046 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
47 if (ehdr == NULL)
48 {
49 elf_error:
50 __libdwfl_seterrno (DWFL_E_LIBELF);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000051 return NULL;
52 }
53
Roland McGrath1743d7f2010-11-12 16:46:47 -080054 GElf_Addr vaddr = 0;
55 GElf_Addr address_sync = 0;
Roland McGrathd17fac72005-08-23 08:20:21 +000056 GElf_Addr start = 0, end = 0, bias = 0;
57 switch (ehdr->e_type)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000058 {
Roland McGrathd17fac72005-08-23 08:20:21 +000059 case ET_REL:
60 /* For a relocatable object, we do an arbitrary section layout.
61 By updating the section header in place, we leave the layout
62 information to be found by relocation. */
63
Roland McGrathe4c22ea2007-10-23 13:07:39 +000064 start = end = base = (base + REL_MIN_ALIGN - 1) & -REL_MIN_ALIGN;
Roland McGrathd17fac72005-08-23 08:20:21 +000065
Roland McGrathe4c22ea2007-10-23 13:07:39 +000066 bool first = true;
Roland McGrathd17fac72005-08-23 08:20:21 +000067 Elf_Scn *scn = NULL;
68 while ((scn = elf_nextscn (elf, scn)) != NULL)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000069 {
Roland McGrathd17fac72005-08-23 08:20:21 +000070 GElf_Shdr shdr_mem;
71 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
Roland McGrathe4c22ea2007-10-23 13:07:39 +000072 if (unlikely (shdr == NULL))
Roland McGrathd17fac72005-08-23 08:20:21 +000073 goto elf_error;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +000074
Roland McGrathd17fac72005-08-23 08:20:21 +000075 if (shdr->sh_flags & SHF_ALLOC)
76 {
77 const GElf_Xword align = shdr->sh_addralign ?: 1;
Roland McGrathe4c22ea2007-10-23 13:07:39 +000078 const GElf_Addr next = (end + align - 1) & -align;
79 if (shdr->sh_addr == 0
80 /* Once we've started doing layout we have to do it all,
81 unless we just layed out the first section at 0 when
82 it already was at 0. */
83 || (bias == 0 && end > start && end != next))
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000084 {
Roland McGrathe4c22ea2007-10-23 13:07:39 +000085 shdr->sh_addr = next;
Ulrich Drepperb597dfa2007-10-16 05:21:27 +000086 if (end == base)
87 /* This is the first section assigned a location.
88 Use its aligned address as the module's base. */
Roland McGrathe4c22ea2007-10-23 13:07:39 +000089 start = base = shdr->sh_addr;
90 else if (unlikely (base & (align - 1)))
91 {
92 /* If BASE has less than the maximum alignment of
93 any section, we eat more than the optimal amount
94 of padding and so make the module's apparent
95 size come out larger than it would when placed
96 at zero. So reset the layout with a better base. */
97
98 start = end = base = (base + align - 1) & -align;
99 Elf_Scn *prev_scn = NULL;
100 do
101 {
102 prev_scn = elf_nextscn (elf, prev_scn);
103 GElf_Shdr prev_shdr_mem;
104 GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn,
105 &prev_shdr_mem);
106 if (unlikely (prev_shdr == NULL))
107 goto elf_error;
108 if (prev_shdr->sh_flags & SHF_ALLOC)
109 {
110 const GElf_Xword prev_align
111 = prev_shdr->sh_addralign ?: 1;
112
113 prev_shdr->sh_addr
114 = (end + prev_align - 1) & -prev_align;
115 end = prev_shdr->sh_addr + prev_shdr->sh_size;
116
117 if (unlikely (! gelf_update_shdr (prev_scn,
118 prev_shdr)))
119 goto elf_error;
120 }
121 }
122 while (prev_scn != scn);
123 continue;
124 }
125
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000126 end = shdr->sh_addr + shdr->sh_size;
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000127 if (likely (shdr->sh_addr != 0)
128 && unlikely (! gelf_update_shdr (scn, shdr)))
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000129 goto elf_error;
130 }
131 else
132 {
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000133 /* The address is already assigned. Just track it. */
134 if (first || end < shdr->sh_addr + shdr->sh_size)
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000135 end = shdr->sh_addr + shdr->sh_size;
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000136 if (first || bias > shdr->sh_addr)
137 /* This is the lowest address in the module. */
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000138 bias = shdr->sh_addr;
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000139
140 if ((shdr->sh_addr - bias + base) & (align - 1))
141 /* This section winds up misaligned using BASE.
142 Adjust BASE upwards to make it congruent to
143 the lowest section address in the file modulo ALIGN. */
144 base = (((base + align - 1) & -align)
145 + (bias & (align - 1)));
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000146 }
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000147
148 first = false;
Roland McGrathd17fac72005-08-23 08:20:21 +0000149 }
150 }
151
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000152 if (bias != 0)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000153 {
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000154 /* The section headers had nonzero sh_addr values. The layout
155 was already done. We've just collected the total span.
156 Now just compute the bias from the requested base. */
157 start = base;
158 end = end - bias + start;
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000159 bias = start - bias;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000160 }
Roland McGrathd17fac72005-08-23 08:20:21 +0000161 break;
162
163 /* Everything else has to have program headers. */
164
165 case ET_EXEC:
166 case ET_CORE:
167 /* An assigned base address is meaningless for these. */
168 base = 0;
169
170 case ET_DYN:
Roland McGrathf95760a2010-01-07 20:24:34 -0800171 default:;
172 size_t phnum;
173 if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
174 goto elf_error;
175 for (size_t i = 0; i < phnum; ++i)
Roland McGrathd17fac72005-08-23 08:20:21 +0000176 {
177 GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000178 if (unlikely (ph == NULL))
Roland McGrathd17fac72005-08-23 08:20:21 +0000179 goto elf_error;
180 if (ph->p_type == PT_LOAD)
181 {
Roland McGrath1743d7f2010-11-12 16:46:47 -0800182 vaddr = ph->p_vaddr & -ph->p_align;
183 address_sync = ph->p_vaddr + ph->p_memsz;
Roland McGrathd17fac72005-08-23 08:20:21 +0000184 if ((base & (ph->p_align - 1)) != 0)
185 base = (base + ph->p_align - 1) & -ph->p_align;
186 start = base + (ph->p_vaddr & -ph->p_align);
187 break;
188 }
189 }
Roland McGrath1743d7f2010-11-12 16:46:47 -0800190 bias = start - vaddr;
Roland McGrathd17fac72005-08-23 08:20:21 +0000191
Roland McGrathf95760a2010-01-07 20:24:34 -0800192 for (size_t i = phnum; i-- > 0;)
Roland McGrathd17fac72005-08-23 08:20:21 +0000193 {
194 GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
Roland McGrathe4c22ea2007-10-23 13:07:39 +0000195 if (unlikely (ph == NULL))
Roland McGrathd17fac72005-08-23 08:20:21 +0000196 goto elf_error;
Roland McGrathe738ad22009-01-27 16:41:54 -0800197 if (ph->p_type == PT_LOAD
198 && ph->p_vaddr + ph->p_memsz > 0)
Roland McGrathd17fac72005-08-23 08:20:21 +0000199 {
200 end = base + (ph->p_vaddr + ph->p_memsz);
201 break;
202 }
203 }
204
Roland McGrath5453abf2009-02-10 17:33:49 -0800205 if (end == 0 && sanity)
Roland McGrathd17fac72005-08-23 08:20:21 +0000206 {
207 __libdwfl_seterrno (DWFL_E_NO_PHDR);
Roland McGrathd17fac72005-08-23 08:20:21 +0000208 return NULL;
209 }
210 break;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000211 }
212
Roland McGrathd17fac72005-08-23 08:20:21 +0000213 Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end);
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000214 if (m != NULL)
215 {
216 if (m->main.name == NULL)
217 {
218 m->main.name = strdup (file_name);
219 m->main.fd = fd;
220 }
221 else if ((fd >= 0 && m->main.fd != fd)
222 || strcmp (m->main.name, file_name))
223 {
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000224 overlap:
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000225 m->gc = true;
226 __libdwfl_seterrno (DWFL_E_OVERLAP);
Mark Wielaard2256e362009-06-18 13:31:56 +0200227 return NULL;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000228 }
229
230 /* Preinstall the open ELF handle for the module. */
231 if (m->main.elf == NULL)
232 {
233 m->main.elf = elf;
Roland McGrath1743d7f2010-11-12 16:46:47 -0800234 m->main.vaddr = vaddr;
235 m->main.address_sync = address_sync;
236 m->main_bias = bias;
Roland McGrathd17fac72005-08-23 08:20:21 +0000237 m->e_type = ehdr->e_type;
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000238 }
239 else
240 {
241 elf_end (elf);
Roland McGrath1743d7f2010-11-12 16:46:47 -0800242 if (m->main_bias != bias
243 || m->main.vaddr != vaddr || m->main.address_sync != address_sync)
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000244 goto overlap;
245 }
246 }
247 return m;
248}
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000249
250Dwfl_Module *
251dwfl_report_elf (Dwfl *dwfl, const char *name,
252 const char *file_name, int fd, GElf_Addr base)
253{
254 bool closefd = false;
255 if (fd < 0)
256 {
257 closefd = true;
258 fd = open64 (file_name, O_RDONLY);
259 if (fd < 0)
260 {
261 __libdwfl_seterrno (DWFL_E_ERRNO);
262 return NULL;
263 }
264 }
265
Roland McGrathbca43152009-01-05 23:59:32 -0800266 Elf *elf;
267 Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, false);
268 if (error != DWFL_E_NOERROR)
269 {
270 __libdwfl_seterrno (error);
271 return NULL;
272 }
273
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000274 Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name,
Roland McGrath5453abf2009-02-10 17:33:49 -0800275 fd, elf, base, true);
Ulrich Drepperb597dfa2007-10-16 05:21:27 +0000276 if (mod == NULL)
277 {
278 elf_end (elf);
279 if (closefd)
280 close (fd);
281 }
282
283 return mod;
284}
Ulrich Drepperb08d5a82005-07-26 05:00:05 +0000285INTDEF (dwfl_report_elf)