1 /* Report a module to libdwfl based on ELF program headers.
2 Copyright (C) 2005-2010 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
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)
43 __libdwfl_elf_address_range (Elf *elf, GElf_Addr base, bool add_p_vaddr,
44 bool sanity, GElf_Addr *vaddrp,
45 GElf_Addr *address_syncp, GElf_Addr *startp,
46 GElf_Addr *endp, GElf_Addr *biasp,
49 GElf_Ehdr ehdr_mem, *ehdr = gelf_getehdr (elf, &ehdr_mem);
53 __libdwfl_seterrno (DWFL_E_LIBELF);
58 GElf_Addr address_sync = 0;
59 GElf_Addr start = 0, end = 0, bias = 0;
63 /* For a relocatable object, we do an arbitrary section layout.
64 By updating the section header in place, we leave the layout
65 information to be found by relocation. */
67 start = end = base = (base + REL_MIN_ALIGN - 1) & -REL_MIN_ALIGN;
71 while ((scn = elf_nextscn (elf, scn)) != NULL)
74 GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
75 if (unlikely (shdr == NULL))
78 if (shdr->sh_flags & SHF_ALLOC)
80 const GElf_Xword align = shdr->sh_addralign ?: 1;
81 const GElf_Addr next = (end + align - 1) & -align;
82 if (shdr->sh_addr == 0
83 /* Once we've started doing layout we have to do it all,
84 unless we just layed out the first section at 0 when
85 it already was at 0. */
86 || (bias == 0 && end > start && end != next))
90 /* This is the first section assigned a location.
91 Use its aligned address as the module's base. */
92 start = base = shdr->sh_addr;
93 else if (unlikely (base & (align - 1)))
95 /* If BASE has less than the maximum alignment of
96 any section, we eat more than the optimal amount
97 of padding and so make the module's apparent
98 size come out larger than it would when placed
99 at zero. So reset the layout with a better base. */
101 start = end = base = (base + align - 1) & -align;
102 Elf_Scn *prev_scn = NULL;
105 prev_scn = elf_nextscn (elf, prev_scn);
106 GElf_Shdr prev_shdr_mem;
107 GElf_Shdr *prev_shdr = gelf_getshdr (prev_scn,
109 if (unlikely (prev_shdr == NULL))
111 if (prev_shdr->sh_flags & SHF_ALLOC)
113 const GElf_Xword prev_align
114 = prev_shdr->sh_addralign ?: 1;
117 = (end + prev_align - 1) & -prev_align;
118 end = prev_shdr->sh_addr + prev_shdr->sh_size;
120 if (unlikely (! gelf_update_shdr (prev_scn,
125 while (prev_scn != scn);
129 end = shdr->sh_addr + shdr->sh_size;
130 if (likely (shdr->sh_addr != 0)
131 && unlikely (! gelf_update_shdr (scn, shdr)))
136 /* The address is already assigned. Just track it. */
137 if (first || end < shdr->sh_addr + shdr->sh_size)
138 end = shdr->sh_addr + shdr->sh_size;
139 if (first || bias > shdr->sh_addr)
140 /* This is the lowest address in the module. */
141 bias = shdr->sh_addr;
143 if ((shdr->sh_addr - bias + base) & (align - 1))
144 /* This section winds up misaligned using BASE.
145 Adjust BASE upwards to make it congruent to
146 the lowest section address in the file modulo ALIGN. */
147 base = (((base + align - 1) & -align)
148 + (bias & (align - 1)));
157 /* The section headers had nonzero sh_addr values. The layout
158 was already done. We've just collected the total span.
159 Now just compute the bias from the requested base. */
161 end = end - bias + start;
166 /* Everything else has to have program headers. */
170 /* An assigned base address is meaningless for these. */
177 if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
179 for (size_t i = 0; i < phnum; ++i)
181 GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
182 if (unlikely (ph == NULL))
184 if (ph->p_type == PT_LOAD)
186 vaddr = ph->p_vaddr & -ph->p_align;
187 address_sync = ph->p_vaddr + ph->p_memsz;
193 start = base + vaddr;
202 for (size_t i = phnum; i-- > 0;)
204 GElf_Phdr phdr_mem, *ph = gelf_getphdr (elf, i, &phdr_mem);
205 if (unlikely (ph == NULL))
207 if (ph->p_type == PT_LOAD
208 && ph->p_vaddr + ph->p_memsz > 0)
210 end = bias + (ph->p_vaddr + ph->p_memsz);
215 if (end == 0 && sanity)
217 __libdwfl_seterrno (DWFL_E_NO_PHDR);
225 *address_syncp = address_sync;
233 *e_typep = ehdr->e_type;
239 __libdwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name,
240 int fd, Elf *elf, GElf_Addr base, bool add_p_vaddr,
243 GElf_Addr vaddr, address_sync, start, end, bias;
245 if (! __libdwfl_elf_address_range (elf, base, add_p_vaddr, sanity, &vaddr,
246 &address_sync, &start, &end, &bias,
249 Dwfl_Module *m = INTUSE(dwfl_report_module) (dwfl, name, start, end);
252 if (m->main.name == NULL)
254 m->main.name = strdup (file_name);
257 else if ((fd >= 0 && m->main.fd != fd)
258 || strcmp (m->main.name, file_name))
262 __libdwfl_seterrno (DWFL_E_OVERLAP);
266 /* Preinstall the open ELF handle for the module. */
267 if (m->main.elf == NULL)
270 m->main.vaddr = vaddr;
271 m->main.address_sync = address_sync;
278 if (m->main_bias != bias
279 || m->main.vaddr != vaddr || m->main.address_sync != address_sync)
287 dwfl_report_elf (Dwfl *dwfl, const char *name, const char *file_name, int fd,
288 GElf_Addr base, bool add_p_vaddr)
290 bool closefd = false;
294 fd = open64 (file_name, O_RDONLY);
297 __libdwfl_seterrno (DWFL_E_ERRNO);
303 Dwfl_Error error = __libdw_open_file (&fd, &elf, closefd, false);
304 if (error != DWFL_E_NOERROR)
306 __libdwfl_seterrno (error);
310 Dwfl_Module *mod = __libdwfl_report_elf (dwfl, name, file_name,
311 fd, elf, base, add_p_vaddr, true);
321 INTDEF (dwfl_report_elf)
322 NEW_VERSION (dwfl_report_elf, ELFUTILS_0.156)
326 _compat_without_add_p_vaddr_dwfl_report_elf (Dwfl *dwfl, const char *name,
327 const char *file_name, int fd,
329 COMPAT_VERSION_NEWPROTO (dwfl_report_elf, ELFUTILS_0.122, without_add_p_vaddr)
332 _compat_without_add_p_vaddr_dwfl_report_elf (Dwfl *dwfl, const char *name,
333 const char *file_name, int fd,
336 return dwfl_report_elf (dwfl, name, file_name, fd, base, true);