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