1*7304104dSAndroid Build Coastguard Worker /* Core file handling.
2*7304104dSAndroid Build Coastguard Worker Copyright (C) 2008-2010, 2013, 2015 Red Hat, Inc.
3*7304104dSAndroid Build Coastguard Worker Copyright (C) 2021 Mark J. Wielaard <[email protected]>
4*7304104dSAndroid Build Coastguard Worker This file is part of elfutils.
5*7304104dSAndroid Build Coastguard Worker
6*7304104dSAndroid Build Coastguard Worker This file is free software; you can redistribute it and/or modify
7*7304104dSAndroid Build Coastguard Worker it under the terms of either
8*7304104dSAndroid Build Coastguard Worker
9*7304104dSAndroid Build Coastguard Worker * the GNU Lesser General Public License as published by the Free
10*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 3 of the License, or (at
11*7304104dSAndroid Build Coastguard Worker your option) any later version
12*7304104dSAndroid Build Coastguard Worker
13*7304104dSAndroid Build Coastguard Worker or
14*7304104dSAndroid Build Coastguard Worker
15*7304104dSAndroid Build Coastguard Worker * the GNU General Public License as published by the Free
16*7304104dSAndroid Build Coastguard Worker Software Foundation; either version 2 of the License, or (at
17*7304104dSAndroid Build Coastguard Worker your option) any later version
18*7304104dSAndroid Build Coastguard Worker
19*7304104dSAndroid Build Coastguard Worker or both in parallel, as here.
20*7304104dSAndroid Build Coastguard Worker
21*7304104dSAndroid Build Coastguard Worker elfutils is distributed in the hope that it will be useful, but
22*7304104dSAndroid Build Coastguard Worker WITHOUT ANY WARRANTY; without even the implied warranty of
23*7304104dSAndroid Build Coastguard Worker MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24*7304104dSAndroid Build Coastguard Worker General Public License for more details.
25*7304104dSAndroid Build Coastguard Worker
26*7304104dSAndroid Build Coastguard Worker You should have received copies of the GNU General Public License and
27*7304104dSAndroid Build Coastguard Worker the GNU Lesser General Public License along with this program. If
28*7304104dSAndroid Build Coastguard Worker not, see <http://www.gnu.org/licenses/>. */
29*7304104dSAndroid Build Coastguard Worker
30*7304104dSAndroid Build Coastguard Worker #include <config.h>
31*7304104dSAndroid Build Coastguard Worker #include "libelfP.h" /* For NOTE_ALIGN. */
32*7304104dSAndroid Build Coastguard Worker #include "libdwflP.h"
33*7304104dSAndroid Build Coastguard Worker #include <gelf.h>
34*7304104dSAndroid Build Coastguard Worker
35*7304104dSAndroid Build Coastguard Worker /* On failure return, we update *NEXT to point back at OFFSET. */
36*7304104dSAndroid Build Coastguard Worker static inline Elf *
do_fail(int error,off_t * next,off_t offset)37*7304104dSAndroid Build Coastguard Worker do_fail (int error, off_t *next, off_t offset)
38*7304104dSAndroid Build Coastguard Worker {
39*7304104dSAndroid Build Coastguard Worker if (next != NULL)
40*7304104dSAndroid Build Coastguard Worker *next = offset;
41*7304104dSAndroid Build Coastguard Worker //__libelf_seterrno (error);
42*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E (LIBELF, error));
43*7304104dSAndroid Build Coastguard Worker return NULL;
44*7304104dSAndroid Build Coastguard Worker }
45*7304104dSAndroid Build Coastguard Worker
46*7304104dSAndroid Build Coastguard Worker #define fail(error) do_fail (error, next, offset)
47*7304104dSAndroid Build Coastguard Worker
48*7304104dSAndroid Build Coastguard Worker /* This is a prototype of what a new libelf interface might be.
49*7304104dSAndroid Build Coastguard Worker This implementation is pessimal for non-mmap cases and should
50*7304104dSAndroid Build Coastguard Worker be replaced by more diddling inside libelf internals. */
51*7304104dSAndroid Build Coastguard Worker static Elf *
elf_begin_rand(Elf * parent,off_t offset,off_t size,off_t * next)52*7304104dSAndroid Build Coastguard Worker elf_begin_rand (Elf *parent, off_t offset, off_t size, off_t *next)
53*7304104dSAndroid Build Coastguard Worker {
54*7304104dSAndroid Build Coastguard Worker if (parent == NULL)
55*7304104dSAndroid Build Coastguard Worker return NULL;
56*7304104dSAndroid Build Coastguard Worker
57*7304104dSAndroid Build Coastguard Worker off_t min = (parent->kind == ELF_K_ELF ?
58*7304104dSAndroid Build Coastguard Worker (parent->class == ELFCLASS32
59*7304104dSAndroid Build Coastguard Worker ? sizeof (Elf32_Ehdr) : sizeof (Elf64_Ehdr))
60*7304104dSAndroid Build Coastguard Worker : parent->kind == ELF_K_AR ? SARMAG
61*7304104dSAndroid Build Coastguard Worker : 0);
62*7304104dSAndroid Build Coastguard Worker
63*7304104dSAndroid Build Coastguard Worker if (unlikely (offset < min)
64*7304104dSAndroid Build Coastguard Worker || unlikely (offset >= (off_t) parent->maximum_size))
65*7304104dSAndroid Build Coastguard Worker return fail (ELF_E_RANGE);
66*7304104dSAndroid Build Coastguard Worker
67*7304104dSAndroid Build Coastguard Worker /* For an archive, fetch just the size field
68*7304104dSAndroid Build Coastguard Worker from the archive header to override SIZE. */
69*7304104dSAndroid Build Coastguard Worker if (parent->kind == ELF_K_AR)
70*7304104dSAndroid Build Coastguard Worker {
71*7304104dSAndroid Build Coastguard Worker /* File size, in ASCII decimal, right-padded with ASCII spaces.
72*7304104dSAndroid Build Coastguard Worker Max 10 characters. Not zero terminated. So make this ar_size
73*7304104dSAndroid Build Coastguard Worker array one larger and explicitly zero terminate it. As needed
74*7304104dSAndroid Build Coastguard Worker for strtoll. */
75*7304104dSAndroid Build Coastguard Worker #define AR_SIZE_CHARS 10
76*7304104dSAndroid Build Coastguard Worker char ar_size[AR_SIZE_CHARS + 1];
77*7304104dSAndroid Build Coastguard Worker ar_size[AR_SIZE_CHARS] = '\0';
78*7304104dSAndroid Build Coastguard Worker
79*7304104dSAndroid Build Coastguard Worker if (unlikely (parent->maximum_size - offset < sizeof (struct ar_hdr)))
80*7304104dSAndroid Build Coastguard Worker return fail (ELF_E_RANGE);
81*7304104dSAndroid Build Coastguard Worker
82*7304104dSAndroid Build Coastguard Worker if (parent->map_address != NULL)
83*7304104dSAndroid Build Coastguard Worker memcpy (ar_size, parent->map_address + parent->start_offset + offset,
84*7304104dSAndroid Build Coastguard Worker AR_SIZE_CHARS);
85*7304104dSAndroid Build Coastguard Worker else if (unlikely (pread_retry (parent->fildes,
86*7304104dSAndroid Build Coastguard Worker ar_size, AR_SIZE_CHARS,
87*7304104dSAndroid Build Coastguard Worker parent->start_offset + offset
88*7304104dSAndroid Build Coastguard Worker + offsetof (struct ar_hdr, ar_size))
89*7304104dSAndroid Build Coastguard Worker != AR_SIZE_CHARS))
90*7304104dSAndroid Build Coastguard Worker return fail (ELF_E_READ_ERROR);
91*7304104dSAndroid Build Coastguard Worker
92*7304104dSAndroid Build Coastguard Worker offset += sizeof (struct ar_hdr);
93*7304104dSAndroid Build Coastguard Worker
94*7304104dSAndroid Build Coastguard Worker char *endp;
95*7304104dSAndroid Build Coastguard Worker size = strtoll (ar_size, &endp, 10);
96*7304104dSAndroid Build Coastguard Worker if (unlikely (endp == ar_size)
97*7304104dSAndroid Build Coastguard Worker || unlikely ((off_t) parent->maximum_size - offset < size))
98*7304104dSAndroid Build Coastguard Worker return fail (ELF_E_INVALID_ARCHIVE);
99*7304104dSAndroid Build Coastguard Worker }
100*7304104dSAndroid Build Coastguard Worker
101*7304104dSAndroid Build Coastguard Worker if (unlikely ((off_t) parent->maximum_size - offset < size))
102*7304104dSAndroid Build Coastguard Worker return fail (ELF_E_RANGE);
103*7304104dSAndroid Build Coastguard Worker
104*7304104dSAndroid Build Coastguard Worker /* Even if we fail at this point, update *NEXT to point past the file. */
105*7304104dSAndroid Build Coastguard Worker if (next != NULL)
106*7304104dSAndroid Build Coastguard Worker *next = offset + size;
107*7304104dSAndroid Build Coastguard Worker
108*7304104dSAndroid Build Coastguard Worker if (unlikely (offset == 0)
109*7304104dSAndroid Build Coastguard Worker && unlikely (size == (off_t) parent->maximum_size))
110*7304104dSAndroid Build Coastguard Worker return elf_clone (parent, parent->cmd);
111*7304104dSAndroid Build Coastguard Worker
112*7304104dSAndroid Build Coastguard Worker /* Note the image is guaranteed live only as long as PARENT
113*7304104dSAndroid Build Coastguard Worker lives. Using elf_memory is quite suboptimal if the whole
114*7304104dSAndroid Build Coastguard Worker file is not mmap'd. We really should have something like
115*7304104dSAndroid Build Coastguard Worker a generalization of the archive support. */
116*7304104dSAndroid Build Coastguard Worker Elf_Data *data = elf_getdata_rawchunk (parent, offset, size, ELF_T_BYTE);
117*7304104dSAndroid Build Coastguard Worker if (data == NULL)
118*7304104dSAndroid Build Coastguard Worker return NULL;
119*7304104dSAndroid Build Coastguard Worker assert ((off_t) data->d_size == size);
120*7304104dSAndroid Build Coastguard Worker return elf_memory (data->d_buf, size);
121*7304104dSAndroid Build Coastguard Worker }
122*7304104dSAndroid Build Coastguard Worker
123*7304104dSAndroid Build Coastguard Worker
124*7304104dSAndroid Build Coastguard Worker int
dwfl_report_core_segments(Dwfl * dwfl,Elf * elf,size_t phnum,GElf_Phdr * notes)125*7304104dSAndroid Build Coastguard Worker dwfl_report_core_segments (Dwfl *dwfl, Elf *elf, size_t phnum, GElf_Phdr *notes)
126*7304104dSAndroid Build Coastguard Worker {
127*7304104dSAndroid Build Coastguard Worker if (unlikely (dwfl == NULL))
128*7304104dSAndroid Build Coastguard Worker return -1;
129*7304104dSAndroid Build Coastguard Worker
130*7304104dSAndroid Build Coastguard Worker int result = 0;
131*7304104dSAndroid Build Coastguard Worker
132*7304104dSAndroid Build Coastguard Worker if (notes != NULL)
133*7304104dSAndroid Build Coastguard Worker notes->p_type = PT_NULL;
134*7304104dSAndroid Build Coastguard Worker
135*7304104dSAndroid Build Coastguard Worker for (size_t ndx = 0; result >= 0 && ndx < phnum; ++ndx)
136*7304104dSAndroid Build Coastguard Worker {
137*7304104dSAndroid Build Coastguard Worker GElf_Phdr phdr_mem;
138*7304104dSAndroid Build Coastguard Worker GElf_Phdr *phdr = gelf_getphdr (elf, ndx, &phdr_mem);
139*7304104dSAndroid Build Coastguard Worker if (unlikely (phdr == NULL))
140*7304104dSAndroid Build Coastguard Worker {
141*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_LIBELF);
142*7304104dSAndroid Build Coastguard Worker return -1;
143*7304104dSAndroid Build Coastguard Worker }
144*7304104dSAndroid Build Coastguard Worker switch (phdr->p_type)
145*7304104dSAndroid Build Coastguard Worker {
146*7304104dSAndroid Build Coastguard Worker case PT_LOAD:
147*7304104dSAndroid Build Coastguard Worker result = dwfl_report_segment (dwfl, ndx, phdr, 0, NULL);
148*7304104dSAndroid Build Coastguard Worker break;
149*7304104dSAndroid Build Coastguard Worker
150*7304104dSAndroid Build Coastguard Worker case PT_NOTE:
151*7304104dSAndroid Build Coastguard Worker if (notes != NULL)
152*7304104dSAndroid Build Coastguard Worker {
153*7304104dSAndroid Build Coastguard Worker *notes = *phdr;
154*7304104dSAndroid Build Coastguard Worker notes = NULL;
155*7304104dSAndroid Build Coastguard Worker }
156*7304104dSAndroid Build Coastguard Worker break;
157*7304104dSAndroid Build Coastguard Worker }
158*7304104dSAndroid Build Coastguard Worker }
159*7304104dSAndroid Build Coastguard Worker
160*7304104dSAndroid Build Coastguard Worker return result;
161*7304104dSAndroid Build Coastguard Worker }
162*7304104dSAndroid Build Coastguard Worker
163*7304104dSAndroid Build Coastguard Worker /* Never read more than this much without mmap. */
164*7304104dSAndroid Build Coastguard Worker #define MAX_EAGER_COST 8192
165*7304104dSAndroid Build Coastguard Worker
166*7304104dSAndroid Build Coastguard Worker /* Dwfl_Module_Callback passed to and called by dwfl_segment_report_module
167*7304104dSAndroid Build Coastguard Worker to read in a segment as ELF image directly if possible or indicate an
168*7304104dSAndroid Build Coastguard Worker attempt must be made to read in the while segment right now. */
169*7304104dSAndroid Build Coastguard Worker static bool
core_file_read_eagerly(Dwfl_Module * mod,void ** userdata,const char * name,Dwarf_Addr start,void ** buffer,size_t * buffer_available,GElf_Off cost,GElf_Off worthwhile,GElf_Off whole,GElf_Off contiguous,void * arg,Elf ** elfp)170*7304104dSAndroid Build Coastguard Worker core_file_read_eagerly (Dwfl_Module *mod,
171*7304104dSAndroid Build Coastguard Worker void **userdata __attribute__ ((unused)),
172*7304104dSAndroid Build Coastguard Worker const char *name __attribute__ ((unused)),
173*7304104dSAndroid Build Coastguard Worker Dwarf_Addr start __attribute__ ((unused)),
174*7304104dSAndroid Build Coastguard Worker void **buffer, size_t *buffer_available,
175*7304104dSAndroid Build Coastguard Worker GElf_Off cost, GElf_Off worthwhile,
176*7304104dSAndroid Build Coastguard Worker GElf_Off whole,
177*7304104dSAndroid Build Coastguard Worker GElf_Off contiguous __attribute__ ((unused)),
178*7304104dSAndroid Build Coastguard Worker void *arg, Elf **elfp)
179*7304104dSAndroid Build Coastguard Worker {
180*7304104dSAndroid Build Coastguard Worker Elf *core = arg;
181*7304104dSAndroid Build Coastguard Worker
182*7304104dSAndroid Build Coastguard Worker /* The available buffer is often the whole segment when the core file
183*7304104dSAndroid Build Coastguard Worker was mmap'd if used together with the dwfl_elf_phdr_memory_callback.
184*7304104dSAndroid Build Coastguard Worker Which means that if it is complete we can just construct the whole
185*7304104dSAndroid Build Coastguard Worker ELF image right now without having to read in anything more. */
186*7304104dSAndroid Build Coastguard Worker if (whole <= *buffer_available)
187*7304104dSAndroid Build Coastguard Worker {
188*7304104dSAndroid Build Coastguard Worker /* All there ever was, we already have on hand. */
189*7304104dSAndroid Build Coastguard Worker
190*7304104dSAndroid Build Coastguard Worker if (core->map_address == NULL)
191*7304104dSAndroid Build Coastguard Worker {
192*7304104dSAndroid Build Coastguard Worker /* We already malloc'd the buffer. */
193*7304104dSAndroid Build Coastguard Worker *elfp = elf_memory (*buffer, whole);
194*7304104dSAndroid Build Coastguard Worker if (unlikely (*elfp == NULL))
195*7304104dSAndroid Build Coastguard Worker return false;
196*7304104dSAndroid Build Coastguard Worker
197*7304104dSAndroid Build Coastguard Worker (*elfp)->flags |= ELF_F_MALLOCED;
198*7304104dSAndroid Build Coastguard Worker *buffer = NULL;
199*7304104dSAndroid Build Coastguard Worker *buffer_available = 0;
200*7304104dSAndroid Build Coastguard Worker return true;
201*7304104dSAndroid Build Coastguard Worker }
202*7304104dSAndroid Build Coastguard Worker
203*7304104dSAndroid Build Coastguard Worker /* We can use the image inside the core file directly. */
204*7304104dSAndroid Build Coastguard Worker *elfp = elf_begin_rand (core, *buffer - core->map_address, whole, NULL);
205*7304104dSAndroid Build Coastguard Worker *buffer = NULL;
206*7304104dSAndroid Build Coastguard Worker *buffer_available = 0;
207*7304104dSAndroid Build Coastguard Worker return *elfp != NULL;
208*7304104dSAndroid Build Coastguard Worker }
209*7304104dSAndroid Build Coastguard Worker
210*7304104dSAndroid Build Coastguard Worker /* We don't have the whole file. Which either means the core file
211*7304104dSAndroid Build Coastguard Worker wasn't mmap'd, but needs to still be read in, or that the segment
212*7304104dSAndroid Build Coastguard Worker is truncated. Figure out if this is better than nothing. */
213*7304104dSAndroid Build Coastguard Worker
214*7304104dSAndroid Build Coastguard Worker if (worthwhile == 0)
215*7304104dSAndroid Build Coastguard Worker /* Caller doesn't think so. */
216*7304104dSAndroid Build Coastguard Worker return false;
217*7304104dSAndroid Build Coastguard Worker
218*7304104dSAndroid Build Coastguard Worker /*
219*7304104dSAndroid Build Coastguard Worker XXX would like to fall back to partial file via memory
220*7304104dSAndroid Build Coastguard Worker when build id find_elf fails
221*7304104dSAndroid Build Coastguard Worker also, link_map name may give file name from disk better than partial here
222*7304104dSAndroid Build Coastguard Worker requires find_elf hook re-doing the magic to fall back if no file found
223*7304104dSAndroid Build Coastguard Worker */
224*7304104dSAndroid Build Coastguard Worker
225*7304104dSAndroid Build Coastguard Worker if (whole > MAX_EAGER_COST && mod->build_id_len > 0)
226*7304104dSAndroid Build Coastguard Worker /* We can't cheaply read the whole file here, so we'd
227*7304104dSAndroid Build Coastguard Worker be using a partial file. But there is a build ID that could
228*7304104dSAndroid Build Coastguard Worker help us find the whole file, which might be more useful than
229*7304104dSAndroid Build Coastguard Worker what we have. We'll just rely on that. */
230*7304104dSAndroid Build Coastguard Worker return false;
231*7304104dSAndroid Build Coastguard Worker
232*7304104dSAndroid Build Coastguard Worker /* The file is either small (most likely the vdso) or big and incomplete,
233*7304104dSAndroid Build Coastguard Worker but we don't have a build-id. */
234*7304104dSAndroid Build Coastguard Worker
235*7304104dSAndroid Build Coastguard Worker if (core->map_address != NULL)
236*7304104dSAndroid Build Coastguard Worker /* It's cheap to get, so get it. */
237*7304104dSAndroid Build Coastguard Worker return true;
238*7304104dSAndroid Build Coastguard Worker
239*7304104dSAndroid Build Coastguard Worker /* Only use it if there isn't too much to be read. */
240*7304104dSAndroid Build Coastguard Worker return cost <= MAX_EAGER_COST;
241*7304104dSAndroid Build Coastguard Worker }
242*7304104dSAndroid Build Coastguard Worker
243*7304104dSAndroid Build Coastguard Worker static inline void
update_end(GElf_Phdr * pphdr,const GElf_Off align,GElf_Off * pend,GElf_Addr * pend_vaddr)244*7304104dSAndroid Build Coastguard Worker update_end (GElf_Phdr *pphdr, const GElf_Off align,
245*7304104dSAndroid Build Coastguard Worker GElf_Off *pend, GElf_Addr *pend_vaddr)
246*7304104dSAndroid Build Coastguard Worker {
247*7304104dSAndroid Build Coastguard Worker *pend = (pphdr->p_offset + pphdr->p_filesz + align - 1) & -align;
248*7304104dSAndroid Build Coastguard Worker *pend_vaddr = (pphdr->p_vaddr + pphdr->p_memsz + align - 1) & -align;
249*7304104dSAndroid Build Coastguard Worker }
250*7304104dSAndroid Build Coastguard Worker
251*7304104dSAndroid Build Coastguard Worker /* Use following contiguous segments to get towards SIZE. */
252*7304104dSAndroid Build Coastguard Worker static inline bool
do_more(size_t size,GElf_Phdr * pphdr,const GElf_Off align,Elf * elf,GElf_Off start,int * pndx,GElf_Off * pend,GElf_Addr * pend_vaddr)253*7304104dSAndroid Build Coastguard Worker do_more (size_t size, GElf_Phdr *pphdr, const GElf_Off align,
254*7304104dSAndroid Build Coastguard Worker Elf *elf, GElf_Off start, int *pndx,
255*7304104dSAndroid Build Coastguard Worker GElf_Off *pend, GElf_Addr *pend_vaddr)
256*7304104dSAndroid Build Coastguard Worker {
257*7304104dSAndroid Build Coastguard Worker while (*pend <= start || *pend - start < size)
258*7304104dSAndroid Build Coastguard Worker {
259*7304104dSAndroid Build Coastguard Worker if (pphdr->p_filesz < pphdr->p_memsz)
260*7304104dSAndroid Build Coastguard Worker /* This segment is truncated, so no following one helps us. */
261*7304104dSAndroid Build Coastguard Worker return false;
262*7304104dSAndroid Build Coastguard Worker
263*7304104dSAndroid Build Coastguard Worker if (unlikely (gelf_getphdr (elf, (*pndx)++, pphdr) == NULL))
264*7304104dSAndroid Build Coastguard Worker return false;
265*7304104dSAndroid Build Coastguard Worker
266*7304104dSAndroid Build Coastguard Worker if (pphdr->p_type == PT_LOAD)
267*7304104dSAndroid Build Coastguard Worker {
268*7304104dSAndroid Build Coastguard Worker if (pphdr->p_offset > *pend
269*7304104dSAndroid Build Coastguard Worker || pphdr->p_vaddr > *pend_vaddr)
270*7304104dSAndroid Build Coastguard Worker /* It's discontiguous! */
271*7304104dSAndroid Build Coastguard Worker return false;
272*7304104dSAndroid Build Coastguard Worker
273*7304104dSAndroid Build Coastguard Worker update_end (pphdr, align, pend, pend_vaddr);
274*7304104dSAndroid Build Coastguard Worker }
275*7304104dSAndroid Build Coastguard Worker }
276*7304104dSAndroid Build Coastguard Worker return true;
277*7304104dSAndroid Build Coastguard Worker }
278*7304104dSAndroid Build Coastguard Worker
279*7304104dSAndroid Build Coastguard Worker #define more(size) do_more (size, &phdr, align, elf, start, &ndx, &end, &end_vaddr)
280*7304104dSAndroid Build Coastguard Worker
281*7304104dSAndroid Build Coastguard Worker bool
dwfl_elf_phdr_memory_callback(Dwfl * dwfl,int ndx,void ** buffer,size_t * buffer_available,GElf_Addr vaddr,size_t minread,void * arg)282*7304104dSAndroid Build Coastguard Worker dwfl_elf_phdr_memory_callback (Dwfl *dwfl, int ndx,
283*7304104dSAndroid Build Coastguard Worker void **buffer, size_t *buffer_available,
284*7304104dSAndroid Build Coastguard Worker GElf_Addr vaddr,
285*7304104dSAndroid Build Coastguard Worker size_t minread,
286*7304104dSAndroid Build Coastguard Worker void *arg)
287*7304104dSAndroid Build Coastguard Worker {
288*7304104dSAndroid Build Coastguard Worker Elf *elf = arg;
289*7304104dSAndroid Build Coastguard Worker
290*7304104dSAndroid Build Coastguard Worker if (ndx == -1)
291*7304104dSAndroid Build Coastguard Worker {
292*7304104dSAndroid Build Coastguard Worker /* Called for cleanup. */
293*7304104dSAndroid Build Coastguard Worker if (elf->map_address == NULL)
294*7304104dSAndroid Build Coastguard Worker free (*buffer);
295*7304104dSAndroid Build Coastguard Worker *buffer = NULL;
296*7304104dSAndroid Build Coastguard Worker *buffer_available = 0;
297*7304104dSAndroid Build Coastguard Worker return false;
298*7304104dSAndroid Build Coastguard Worker }
299*7304104dSAndroid Build Coastguard Worker
300*7304104dSAndroid Build Coastguard Worker const GElf_Off align = dwfl->segment_align ?: 1;
301*7304104dSAndroid Build Coastguard Worker GElf_Phdr phdr;
302*7304104dSAndroid Build Coastguard Worker
303*7304104dSAndroid Build Coastguard Worker do
304*7304104dSAndroid Build Coastguard Worker if (unlikely (gelf_getphdr (elf, ndx++, &phdr) == NULL))
305*7304104dSAndroid Build Coastguard Worker return false;
306*7304104dSAndroid Build Coastguard Worker while (phdr.p_type != PT_LOAD
307*7304104dSAndroid Build Coastguard Worker || ((phdr.p_vaddr + phdr.p_memsz + align - 1) & -align) <= vaddr);
308*7304104dSAndroid Build Coastguard Worker
309*7304104dSAndroid Build Coastguard Worker GElf_Off start = vaddr - phdr.p_vaddr + phdr.p_offset;
310*7304104dSAndroid Build Coastguard Worker GElf_Off end;
311*7304104dSAndroid Build Coastguard Worker GElf_Addr end_vaddr;
312*7304104dSAndroid Build Coastguard Worker
313*7304104dSAndroid Build Coastguard Worker update_end (&phdr, align, &end, &end_vaddr);
314*7304104dSAndroid Build Coastguard Worker
315*7304104dSAndroid Build Coastguard Worker /* We need at least this much. */
316*7304104dSAndroid Build Coastguard Worker if (! more (minread))
317*7304104dSAndroid Build Coastguard Worker return false;
318*7304104dSAndroid Build Coastguard Worker
319*7304104dSAndroid Build Coastguard Worker /* See how much more we can get of what the caller wants. */
320*7304104dSAndroid Build Coastguard Worker (void) more (*buffer_available);
321*7304104dSAndroid Build Coastguard Worker
322*7304104dSAndroid Build Coastguard Worker /* If it's already on hand anyway, use as much as there is. */
323*7304104dSAndroid Build Coastguard Worker if (elf->map_address != NULL && start < elf->maximum_size)
324*7304104dSAndroid Build Coastguard Worker (void) more (elf->maximum_size - start);
325*7304104dSAndroid Build Coastguard Worker
326*7304104dSAndroid Build Coastguard Worker /* Make sure we don't look past the end of the actual file,
327*7304104dSAndroid Build Coastguard Worker even if the headers tell us to. */
328*7304104dSAndroid Build Coastguard Worker if (unlikely (end > elf->maximum_size))
329*7304104dSAndroid Build Coastguard Worker end = elf->maximum_size;
330*7304104dSAndroid Build Coastguard Worker
331*7304104dSAndroid Build Coastguard Worker /* If the file is too small, there is nothing at all to get. */
332*7304104dSAndroid Build Coastguard Worker if (unlikely (start >= end))
333*7304104dSAndroid Build Coastguard Worker return false;
334*7304104dSAndroid Build Coastguard Worker
335*7304104dSAndroid Build Coastguard Worker if (end - start < minread)
336*7304104dSAndroid Build Coastguard Worker return false;
337*7304104dSAndroid Build Coastguard Worker
338*7304104dSAndroid Build Coastguard Worker if (elf->map_address != NULL)
339*7304104dSAndroid Build Coastguard Worker {
340*7304104dSAndroid Build Coastguard Worker void *contents = elf->map_address + elf->start_offset + start;
341*7304104dSAndroid Build Coastguard Worker size_t size = end - start;
342*7304104dSAndroid Build Coastguard Worker
343*7304104dSAndroid Build Coastguard Worker if (minread == 0) /* String mode. */
344*7304104dSAndroid Build Coastguard Worker {
345*7304104dSAndroid Build Coastguard Worker const void *eos = memchr (contents, '\0', size);
346*7304104dSAndroid Build Coastguard Worker if (unlikely (eos == NULL) || unlikely (eos == contents))
347*7304104dSAndroid Build Coastguard Worker return false;
348*7304104dSAndroid Build Coastguard Worker size = eos + 1 - contents;
349*7304104dSAndroid Build Coastguard Worker }
350*7304104dSAndroid Build Coastguard Worker
351*7304104dSAndroid Build Coastguard Worker if (*buffer == NULL)
352*7304104dSAndroid Build Coastguard Worker {
353*7304104dSAndroid Build Coastguard Worker *buffer = contents;
354*7304104dSAndroid Build Coastguard Worker *buffer_available = size;
355*7304104dSAndroid Build Coastguard Worker }
356*7304104dSAndroid Build Coastguard Worker else
357*7304104dSAndroid Build Coastguard Worker {
358*7304104dSAndroid Build Coastguard Worker *buffer_available = MIN (size, *buffer_available);
359*7304104dSAndroid Build Coastguard Worker memcpy (*buffer, contents, *buffer_available);
360*7304104dSAndroid Build Coastguard Worker }
361*7304104dSAndroid Build Coastguard Worker }
362*7304104dSAndroid Build Coastguard Worker else
363*7304104dSAndroid Build Coastguard Worker {
364*7304104dSAndroid Build Coastguard Worker void *into = *buffer;
365*7304104dSAndroid Build Coastguard Worker if (*buffer == NULL)
366*7304104dSAndroid Build Coastguard Worker {
367*7304104dSAndroid Build Coastguard Worker *buffer_available = MIN (minread ?: 512,
368*7304104dSAndroid Build Coastguard Worker MAX (4096, MIN (end - start,
369*7304104dSAndroid Build Coastguard Worker *buffer_available)));
370*7304104dSAndroid Build Coastguard Worker into = malloc (*buffer_available);
371*7304104dSAndroid Build Coastguard Worker if (unlikely (into == NULL))
372*7304104dSAndroid Build Coastguard Worker {
373*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NOMEM);
374*7304104dSAndroid Build Coastguard Worker return false;
375*7304104dSAndroid Build Coastguard Worker }
376*7304104dSAndroid Build Coastguard Worker }
377*7304104dSAndroid Build Coastguard Worker
378*7304104dSAndroid Build Coastguard Worker ssize_t nread = pread_retry (elf->fildes, into, *buffer_available, start);
379*7304104dSAndroid Build Coastguard Worker if (nread < (ssize_t) minread)
380*7304104dSAndroid Build Coastguard Worker {
381*7304104dSAndroid Build Coastguard Worker if (into != *buffer)
382*7304104dSAndroid Build Coastguard Worker free (into);
383*7304104dSAndroid Build Coastguard Worker if (nread < 0)
384*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_ERRNO);
385*7304104dSAndroid Build Coastguard Worker return false;
386*7304104dSAndroid Build Coastguard Worker }
387*7304104dSAndroid Build Coastguard Worker
388*7304104dSAndroid Build Coastguard Worker if (minread == 0) /* String mode. */
389*7304104dSAndroid Build Coastguard Worker {
390*7304104dSAndroid Build Coastguard Worker const void *eos = memchr (into, '\0', nread);
391*7304104dSAndroid Build Coastguard Worker if (unlikely (eos == NULL) || unlikely (eos == into))
392*7304104dSAndroid Build Coastguard Worker {
393*7304104dSAndroid Build Coastguard Worker if (*buffer == NULL)
394*7304104dSAndroid Build Coastguard Worker free (into);
395*7304104dSAndroid Build Coastguard Worker return false;
396*7304104dSAndroid Build Coastguard Worker }
397*7304104dSAndroid Build Coastguard Worker nread = eos + 1 - into;
398*7304104dSAndroid Build Coastguard Worker }
399*7304104dSAndroid Build Coastguard Worker
400*7304104dSAndroid Build Coastguard Worker if (*buffer == NULL)
401*7304104dSAndroid Build Coastguard Worker *buffer = into;
402*7304104dSAndroid Build Coastguard Worker *buffer_available = nread;
403*7304104dSAndroid Build Coastguard Worker }
404*7304104dSAndroid Build Coastguard Worker
405*7304104dSAndroid Build Coastguard Worker return true;
406*7304104dSAndroid Build Coastguard Worker }
407*7304104dSAndroid Build Coastguard Worker
408*7304104dSAndroid Build Coastguard Worker /* Free the contents of R_DEBUG_INFO without the R_DEBUG_INFO memory itself. */
409*7304104dSAndroid Build Coastguard Worker
410*7304104dSAndroid Build Coastguard Worker static void
clear_r_debug_info(struct r_debug_info * r_debug_info)411*7304104dSAndroid Build Coastguard Worker clear_r_debug_info (struct r_debug_info *r_debug_info)
412*7304104dSAndroid Build Coastguard Worker {
413*7304104dSAndroid Build Coastguard Worker while (r_debug_info->module != NULL)
414*7304104dSAndroid Build Coastguard Worker {
415*7304104dSAndroid Build Coastguard Worker struct r_debug_info_module *module = r_debug_info->module;
416*7304104dSAndroid Build Coastguard Worker r_debug_info->module = module->next;
417*7304104dSAndroid Build Coastguard Worker elf_end (module->elf);
418*7304104dSAndroid Build Coastguard Worker if (module->fd != -1)
419*7304104dSAndroid Build Coastguard Worker close (module->fd);
420*7304104dSAndroid Build Coastguard Worker free (module);
421*7304104dSAndroid Build Coastguard Worker }
422*7304104dSAndroid Build Coastguard Worker }
423*7304104dSAndroid Build Coastguard Worker
424*7304104dSAndroid Build Coastguard Worker bool
425*7304104dSAndroid Build Coastguard Worker internal_function
__libdwfl_dynamic_vaddr_get(Elf * elf,GElf_Addr * vaddrp)426*7304104dSAndroid Build Coastguard Worker __libdwfl_dynamic_vaddr_get (Elf *elf, GElf_Addr *vaddrp)
427*7304104dSAndroid Build Coastguard Worker {
428*7304104dSAndroid Build Coastguard Worker size_t phnum;
429*7304104dSAndroid Build Coastguard Worker if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
430*7304104dSAndroid Build Coastguard Worker return false;
431*7304104dSAndroid Build Coastguard Worker for (size_t i = 0; i < phnum; ++i)
432*7304104dSAndroid Build Coastguard Worker {
433*7304104dSAndroid Build Coastguard Worker GElf_Phdr phdr_mem;
434*7304104dSAndroid Build Coastguard Worker GElf_Phdr *phdr = gelf_getphdr (elf, i, &phdr_mem);
435*7304104dSAndroid Build Coastguard Worker if (unlikely (phdr == NULL))
436*7304104dSAndroid Build Coastguard Worker return false;
437*7304104dSAndroid Build Coastguard Worker if (phdr->p_type == PT_DYNAMIC)
438*7304104dSAndroid Build Coastguard Worker {
439*7304104dSAndroid Build Coastguard Worker *vaddrp = phdr->p_vaddr;
440*7304104dSAndroid Build Coastguard Worker return true;
441*7304104dSAndroid Build Coastguard Worker }
442*7304104dSAndroid Build Coastguard Worker }
443*7304104dSAndroid Build Coastguard Worker return false;
444*7304104dSAndroid Build Coastguard Worker }
445*7304104dSAndroid Build Coastguard Worker
446*7304104dSAndroid Build Coastguard Worker NEW_VERSION (dwfl_core_file_report, ELFUTILS_0.158)
447*7304104dSAndroid Build Coastguard Worker int
dwfl_core_file_report(Dwfl * dwfl,Elf * elf,const char * executable)448*7304104dSAndroid Build Coastguard Worker dwfl_core_file_report (Dwfl *dwfl, Elf *elf, const char *executable)
449*7304104dSAndroid Build Coastguard Worker {
450*7304104dSAndroid Build Coastguard Worker size_t phnum;
451*7304104dSAndroid Build Coastguard Worker if (unlikely (elf_getphdrnum (elf, &phnum) != 0))
452*7304104dSAndroid Build Coastguard Worker {
453*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_LIBELF);
454*7304104dSAndroid Build Coastguard Worker return -1;
455*7304104dSAndroid Build Coastguard Worker }
456*7304104dSAndroid Build Coastguard Worker
457*7304104dSAndroid Build Coastguard Worker bool cleanup_user_core = false;
458*7304104dSAndroid Build Coastguard Worker if (dwfl->user_core != NULL)
459*7304104dSAndroid Build Coastguard Worker free (dwfl->user_core->executable_for_core);
460*7304104dSAndroid Build Coastguard Worker if (executable == NULL)
461*7304104dSAndroid Build Coastguard Worker {
462*7304104dSAndroid Build Coastguard Worker if (dwfl->user_core != NULL)
463*7304104dSAndroid Build Coastguard Worker dwfl->user_core->executable_for_core = NULL;
464*7304104dSAndroid Build Coastguard Worker }
465*7304104dSAndroid Build Coastguard Worker else
466*7304104dSAndroid Build Coastguard Worker {
467*7304104dSAndroid Build Coastguard Worker if (dwfl->user_core == NULL)
468*7304104dSAndroid Build Coastguard Worker {
469*7304104dSAndroid Build Coastguard Worker cleanup_user_core = true;
470*7304104dSAndroid Build Coastguard Worker dwfl->user_core = calloc (1, sizeof (struct Dwfl_User_Core));
471*7304104dSAndroid Build Coastguard Worker if (dwfl->user_core == NULL)
472*7304104dSAndroid Build Coastguard Worker {
473*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NOMEM);
474*7304104dSAndroid Build Coastguard Worker return -1;
475*7304104dSAndroid Build Coastguard Worker }
476*7304104dSAndroid Build Coastguard Worker dwfl->user_core->fd = -1;
477*7304104dSAndroid Build Coastguard Worker }
478*7304104dSAndroid Build Coastguard Worker dwfl->user_core->executable_for_core = strdup (executable);
479*7304104dSAndroid Build Coastguard Worker if (dwfl->user_core->executable_for_core == NULL)
480*7304104dSAndroid Build Coastguard Worker {
481*7304104dSAndroid Build Coastguard Worker if (cleanup_user_core)
482*7304104dSAndroid Build Coastguard Worker {
483*7304104dSAndroid Build Coastguard Worker free (dwfl->user_core);
484*7304104dSAndroid Build Coastguard Worker dwfl->user_core = NULL;
485*7304104dSAndroid Build Coastguard Worker }
486*7304104dSAndroid Build Coastguard Worker __libdwfl_seterrno (DWFL_E_NOMEM);
487*7304104dSAndroid Build Coastguard Worker return -1;
488*7304104dSAndroid Build Coastguard Worker }
489*7304104dSAndroid Build Coastguard Worker }
490*7304104dSAndroid Build Coastguard Worker
491*7304104dSAndroid Build Coastguard Worker /* First report each PT_LOAD segment. */
492*7304104dSAndroid Build Coastguard Worker GElf_Phdr notes_phdr;
493*7304104dSAndroid Build Coastguard Worker int ndx = dwfl_report_core_segments (dwfl, elf, phnum, ¬es_phdr);
494*7304104dSAndroid Build Coastguard Worker if (unlikely (ndx <= 0))
495*7304104dSAndroid Build Coastguard Worker {
496*7304104dSAndroid Build Coastguard Worker if (cleanup_user_core)
497*7304104dSAndroid Build Coastguard Worker {
498*7304104dSAndroid Build Coastguard Worker free (dwfl->user_core->executable_for_core);
499*7304104dSAndroid Build Coastguard Worker free (dwfl->user_core);
500*7304104dSAndroid Build Coastguard Worker dwfl->user_core = NULL;
501*7304104dSAndroid Build Coastguard Worker }
502*7304104dSAndroid Build Coastguard Worker return ndx;
503*7304104dSAndroid Build Coastguard Worker }
504*7304104dSAndroid Build Coastguard Worker
505*7304104dSAndroid Build Coastguard Worker /* Next, we should follow the chain from DT_DEBUG. */
506*7304104dSAndroid Build Coastguard Worker
507*7304104dSAndroid Build Coastguard Worker const void *auxv = NULL;
508*7304104dSAndroid Build Coastguard Worker const void *note_file = NULL;
509*7304104dSAndroid Build Coastguard Worker size_t auxv_size = 0;
510*7304104dSAndroid Build Coastguard Worker size_t note_file_size = 0;
511*7304104dSAndroid Build Coastguard Worker if (likely (notes_phdr.p_type == PT_NOTE))
512*7304104dSAndroid Build Coastguard Worker {
513*7304104dSAndroid Build Coastguard Worker /* PT_NOTE -> NT_AUXV -> AT_PHDR -> PT_DYNAMIC -> DT_DEBUG */
514*7304104dSAndroid Build Coastguard Worker
515*7304104dSAndroid Build Coastguard Worker Elf_Data *notes = elf_getdata_rawchunk (elf,
516*7304104dSAndroid Build Coastguard Worker notes_phdr.p_offset,
517*7304104dSAndroid Build Coastguard Worker notes_phdr.p_filesz,
518*7304104dSAndroid Build Coastguard Worker (notes_phdr.p_align == 8
519*7304104dSAndroid Build Coastguard Worker ? ELF_T_NHDR8
520*7304104dSAndroid Build Coastguard Worker : ELF_T_NHDR));
521*7304104dSAndroid Build Coastguard Worker if (likely (notes != NULL))
522*7304104dSAndroid Build Coastguard Worker {
523*7304104dSAndroid Build Coastguard Worker size_t pos = 0;
524*7304104dSAndroid Build Coastguard Worker GElf_Nhdr nhdr;
525*7304104dSAndroid Build Coastguard Worker size_t name_pos;
526*7304104dSAndroid Build Coastguard Worker size_t desc_pos;
527*7304104dSAndroid Build Coastguard Worker while ((pos = gelf_getnote (notes, pos, &nhdr,
528*7304104dSAndroid Build Coastguard Worker &name_pos, &desc_pos)) > 0)
529*7304104dSAndroid Build Coastguard Worker if (nhdr.n_namesz == sizeof "CORE"
530*7304104dSAndroid Build Coastguard Worker && !memcmp (notes->d_buf + name_pos, "CORE", sizeof "CORE"))
531*7304104dSAndroid Build Coastguard Worker {
532*7304104dSAndroid Build Coastguard Worker if (nhdr.n_type == NT_AUXV)
533*7304104dSAndroid Build Coastguard Worker {
534*7304104dSAndroid Build Coastguard Worker auxv = notes->d_buf + desc_pos;
535*7304104dSAndroid Build Coastguard Worker auxv_size = nhdr.n_descsz;
536*7304104dSAndroid Build Coastguard Worker }
537*7304104dSAndroid Build Coastguard Worker if (nhdr.n_type == NT_FILE)
538*7304104dSAndroid Build Coastguard Worker {
539*7304104dSAndroid Build Coastguard Worker note_file = notes->d_buf + desc_pos;
540*7304104dSAndroid Build Coastguard Worker note_file_size = nhdr.n_descsz;
541*7304104dSAndroid Build Coastguard Worker }
542*7304104dSAndroid Build Coastguard Worker }
543*7304104dSAndroid Build Coastguard Worker }
544*7304104dSAndroid Build Coastguard Worker }
545*7304104dSAndroid Build Coastguard Worker
546*7304104dSAndroid Build Coastguard Worker /* Now we have NT_AUXV contents. From here on this processing could be
547*7304104dSAndroid Build Coastguard Worker used for a live process with auxv read from /proc. */
548*7304104dSAndroid Build Coastguard Worker
549*7304104dSAndroid Build Coastguard Worker struct r_debug_info r_debug_info;
550*7304104dSAndroid Build Coastguard Worker memset (&r_debug_info, 0, sizeof r_debug_info);
551*7304104dSAndroid Build Coastguard Worker int retval = dwfl_link_map_report (dwfl, auxv, auxv_size,
552*7304104dSAndroid Build Coastguard Worker dwfl_elf_phdr_memory_callback, elf,
553*7304104dSAndroid Build Coastguard Worker &r_debug_info);
554*7304104dSAndroid Build Coastguard Worker int listed = retval > 0 ? retval : 0;
555*7304104dSAndroid Build Coastguard Worker
556*7304104dSAndroid Build Coastguard Worker /* Now sniff segment contents for modules hinted by information gathered
557*7304104dSAndroid Build Coastguard Worker from DT_DEBUG. */
558*7304104dSAndroid Build Coastguard Worker
559*7304104dSAndroid Build Coastguard Worker ndx = 0;
560*7304104dSAndroid Build Coastguard Worker do
561*7304104dSAndroid Build Coastguard Worker {
562*7304104dSAndroid Build Coastguard Worker int seg = dwfl_segment_report_module (dwfl, ndx, NULL,
563*7304104dSAndroid Build Coastguard Worker &dwfl_elf_phdr_memory_callback, elf,
564*7304104dSAndroid Build Coastguard Worker core_file_read_eagerly, elf,
565*7304104dSAndroid Build Coastguard Worker elf->maximum_size,
566*7304104dSAndroid Build Coastguard Worker note_file, note_file_size,
567*7304104dSAndroid Build Coastguard Worker &r_debug_info);
568*7304104dSAndroid Build Coastguard Worker if (unlikely (seg < 0))
569*7304104dSAndroid Build Coastguard Worker {
570*7304104dSAndroid Build Coastguard Worker clear_r_debug_info (&r_debug_info);
571*7304104dSAndroid Build Coastguard Worker return seg;
572*7304104dSAndroid Build Coastguard Worker }
573*7304104dSAndroid Build Coastguard Worker if (seg > ndx)
574*7304104dSAndroid Build Coastguard Worker {
575*7304104dSAndroid Build Coastguard Worker ndx = seg;
576*7304104dSAndroid Build Coastguard Worker ++listed;
577*7304104dSAndroid Build Coastguard Worker }
578*7304104dSAndroid Build Coastguard Worker else
579*7304104dSAndroid Build Coastguard Worker ++ndx;
580*7304104dSAndroid Build Coastguard Worker }
581*7304104dSAndroid Build Coastguard Worker while (ndx < (int) phnum);
582*7304104dSAndroid Build Coastguard Worker
583*7304104dSAndroid Build Coastguard Worker /* Now report the modules from dwfl_link_map_report which were not filtered
584*7304104dSAndroid Build Coastguard Worker out by dwfl_segment_report_module. */
585*7304104dSAndroid Build Coastguard Worker
586*7304104dSAndroid Build Coastguard Worker Dwfl_Module **lastmodp = &dwfl->modulelist;
587*7304104dSAndroid Build Coastguard Worker while (*lastmodp != NULL)
588*7304104dSAndroid Build Coastguard Worker lastmodp = &(*lastmodp)->next;
589*7304104dSAndroid Build Coastguard Worker for (struct r_debug_info_module *module = r_debug_info.module;
590*7304104dSAndroid Build Coastguard Worker module != NULL; module = module->next)
591*7304104dSAndroid Build Coastguard Worker {
592*7304104dSAndroid Build Coastguard Worker if (module->elf == NULL)
593*7304104dSAndroid Build Coastguard Worker continue;
594*7304104dSAndroid Build Coastguard Worker GElf_Addr file_dynamic_vaddr;
595*7304104dSAndroid Build Coastguard Worker if (! __libdwfl_dynamic_vaddr_get (module->elf, &file_dynamic_vaddr))
596*7304104dSAndroid Build Coastguard Worker continue;
597*7304104dSAndroid Build Coastguard Worker Dwfl_Module *mod;
598*7304104dSAndroid Build Coastguard Worker mod = __libdwfl_report_elf (dwfl, xbasename (module->name), module->name,
599*7304104dSAndroid Build Coastguard Worker module->fd, module->elf,
600*7304104dSAndroid Build Coastguard Worker module->l_ld - file_dynamic_vaddr,
601*7304104dSAndroid Build Coastguard Worker true, true);
602*7304104dSAndroid Build Coastguard Worker if (mod == NULL)
603*7304104dSAndroid Build Coastguard Worker continue;
604*7304104dSAndroid Build Coastguard Worker ++listed;
605*7304104dSAndroid Build Coastguard Worker module->elf = NULL;
606*7304104dSAndroid Build Coastguard Worker module->fd = -1;
607*7304104dSAndroid Build Coastguard Worker /* Move this module to the end of the list, so that we end
608*7304104dSAndroid Build Coastguard Worker up with a list in the same order as the link_map chain. */
609*7304104dSAndroid Build Coastguard Worker if (mod->next != NULL)
610*7304104dSAndroid Build Coastguard Worker {
611*7304104dSAndroid Build Coastguard Worker if (*lastmodp != mod)
612*7304104dSAndroid Build Coastguard Worker {
613*7304104dSAndroid Build Coastguard Worker lastmodp = &dwfl->modulelist;
614*7304104dSAndroid Build Coastguard Worker while (*lastmodp != mod)
615*7304104dSAndroid Build Coastguard Worker lastmodp = &(*lastmodp)->next;
616*7304104dSAndroid Build Coastguard Worker }
617*7304104dSAndroid Build Coastguard Worker *lastmodp = mod->next;
618*7304104dSAndroid Build Coastguard Worker mod->next = NULL;
619*7304104dSAndroid Build Coastguard Worker while (*lastmodp != NULL)
620*7304104dSAndroid Build Coastguard Worker lastmodp = &(*lastmodp)->next;
621*7304104dSAndroid Build Coastguard Worker *lastmodp = mod;
622*7304104dSAndroid Build Coastguard Worker }
623*7304104dSAndroid Build Coastguard Worker lastmodp = &mod->next;
624*7304104dSAndroid Build Coastguard Worker }
625*7304104dSAndroid Build Coastguard Worker
626*7304104dSAndroid Build Coastguard Worker clear_r_debug_info (&r_debug_info);
627*7304104dSAndroid Build Coastguard Worker
628*7304104dSAndroid Build Coastguard Worker /* We return the number of modules we found if we found any.
629*7304104dSAndroid Build Coastguard Worker If we found none, we return -1 instead of 0 if there was an
630*7304104dSAndroid Build Coastguard Worker error rather than just nothing found. */
631*7304104dSAndroid Build Coastguard Worker return listed > 0 ? listed : retval;
632*7304104dSAndroid Build Coastguard Worker }
633*7304104dSAndroid Build Coastguard Worker NEW_INTDEF (dwfl_core_file_report)
634*7304104dSAndroid Build Coastguard Worker
635*7304104dSAndroid Build Coastguard Worker #ifdef SYMBOL_VERSIONING
636*7304104dSAndroid Build Coastguard Worker int _compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf);
637*7304104dSAndroid Build Coastguard Worker COMPAT_VERSION_NEWPROTO (dwfl_core_file_report, ELFUTILS_0.146,
638*7304104dSAndroid Build Coastguard Worker without_executable)
639*7304104dSAndroid Build Coastguard Worker
640*7304104dSAndroid Build Coastguard Worker int
_compat_without_executable_dwfl_core_file_report(Dwfl * dwfl,Elf * elf)641*7304104dSAndroid Build Coastguard Worker _compat_without_executable_dwfl_core_file_report (Dwfl *dwfl, Elf *elf)
642*7304104dSAndroid Build Coastguard Worker {
643*7304104dSAndroid Build Coastguard Worker return dwfl_core_file_report (dwfl, elf, NULL);
644*7304104dSAndroid Build Coastguard Worker }
645*7304104dSAndroid Build Coastguard Worker #endif
646